LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

LStrHandleArray Documentation

So, I created a DLL in LabVIEW to extract properties from a binary file.  The *.h file that LabVIEW created has my own functions (i.e. void __cdecl GetChannelProperties(uintptr_t *ChannelRef, LStrHandleArray * CahnnelPropertyNameValueArray)), along with three functions to help me create and work with the parameters to my functions:

LStrHandleArray __cdecl AllocateLStrHandleArray (int32 *dimSizeArr);

MgErr __cdecl ResizeLStrHandleArray (LStrHandleArray *hdlPtr, int32 *dimSizeArr);

MgErr __cdecl DeAllocateLStrHandleArray (LStrHandleArray *hdlPtr);

 

I have searched the help of LabVIEW, LabWindows CVI, and on-line for documentation on these functions, but cannot find any.  Doesn't National Instruments have documentation for these functions somewhere?

0 Kudos
Message 1 of 14
(3,532 Views)

Hi steveh01,

 

I haven't been able to find documentation specifically on these functions on our website, however what questions did you have about these functions?

 

Is there some reason the LabVIEW Binary functionality doesn't work (as opposed to CVI)? For example, the Simple Binary File.lvproj writes to and reads from a binary file.

 

Furthermore, if this does need to be CVI approach, the help with the LabVIEW functions may shed some light on what you are trying to do. Generally our functions in LabWindows CVI have a parallel in LabVIEW.

 

I hope that was helpful, but do let me know what further questions you may have.

 

Thanks,

Timothy D.
Applications Engineering
National Instruments
0 Kudos
Message 2 of 14
(3,487 Views)

Tim,

 

LabVIEW will not work because I am writing an application that allows the user to batch-edit file properties. (among other things - At this point most of the application is already done.)  The complexity of the task requires pointer capability in the code, which LabVIEW does not provide.  However, I do need a data plug-in that is only available in LabVIEW.  Suffice it to say, I need to use LabVIEW to create some DLLs that LabWindows CVI can use.

 

In LabVIEW the functions look pretty simple.  A reference > A get properties command > An output string array of the properties.  Just build your DLL and you're done, right?  Well, the behind-the-scenes C-code that represents a thick pink wire (string array) gets a bit messier.  Without documentation it's just a shot in the dark.

 

My first struggle is correctly allocating a LabVIEW String Handle Array (LStrHandleArray).  Its definition that LabVIEW generated in the *.h file is as follows:

typedef struct {

     int32_t dimSizes[2];

     LStrHandle Value[1];

} LStrHandleArrayBase;

 

typedef LStrHandleArrayBase **LStrHandleArray;

 

Now looking at the extcode.h file, I see that the structure of an LStrHandle is:

typedef struct {

     int32 cnt;   // number of bytes that follow

     uChar str[1];  // cnt bytes

} LStr, *LStrPtr, **LStrHandle;

 

So, a LStrHandleArray and LStrHandle are double pointers to a structure that holds the number of items, and the items themselves.  I am guessing that the two numbers in dimSizes[2] are: (1) The number of strings, and (2) the length of the strings.  It took quite a bit of time to figure out how to define variables to call AllocateLStrHandleArray:

int 32 LHAsize[2] = {NumA, NumB};

LStrHandleArray FileProperties;

FileProperties = AllocateLStrHandleArray(LHAsize);

 

Even this is only yielding partial success, since FileProperties is instantiated without anything inside the Value[0] part.  I might not be providing everything that AllocateLStrHandleArray is expecting in the *dimSizeArr input parameter.  There is just no way to tell without documentation.  So, I wonder if this is something where we can pass this up the chain & get a real answer (some documentation).  I have done my share of searching on-line, and know there are a handful of others with the same un-answered questions.  Some people do painful experimentation to find a work-around, but if LabVIEW generated it, there really should be a de-facto source.

 

 

 

0 Kudos
Message 3 of 14
(3,476 Views)

You're barking up the wrong tree with several of your assumptions here.

 

typedef struct {
     int32_t dimSizes[2];
     LStrHandle Value[1];
} LStrHandleArrayBase;

This is a two dimensional array of LabVIEW strings.

Array and strings are in LabVIEW always so called handles. A handle is a double reference to a memory buffer. Because of the double reference, the buffer can be reallocated dynamically without invalidating the handle that other code may have stored somewhere.

 

So the actual structure in memory for this is a pointer to a pointer to above structure where the two dimSize values define the number of columns and rows in the 2D array. The actual array data is stored in the Value[] array which is only for the definition a one element array. The real allocation of the entire structure is 2 * 4 bytes for the dimSize array and (columns * rows) * sizeof(LStrHandle) bytes for the array.

 

Each LStrHandle is again a handle, so a pointer to a pointer to a structure that stores first a 32 bit integer that indicates the number of bytes in the string and then the actual string without any zero termination byte.

 

You CANNOT allocate these handles at will with your own memory manager calls. You MUST call the LabVIEW memory manager functions for that and specifically the memory manager functions of the LabVIEW kernel in which those handles are managed.

 

int32 LHAsize[2] = {columns, rows}; // could be also {rows, columns} I never remember!

LStrHandleArray FileProperties = AllocateLStrHandleArray(LHAsize);

This is only the first step to allocate the entire structure. As LabVIEW has no idea what the actual string sizes inside that array should be, it "allocates" the default empty string/array for the elements and incidentially LabVIEW allows for a very very long time already (somewhere around 6.0) for the NULL handle, to mean the same as a properly allocated handle whose dimSize(s) is 0.

 

So the next step will be to go through the actual array and fill in the string handles according to what you need:

MgErr err;
if (FileProperties == NULL)
err = mFullErr; if (!err)
{
LStrHandle *stringElm = (*FileProperties)->Value;
int32_t i, numElements = (*FileProperties)->dimSizes[0] * (*FileProperties)->dimSizes[1];
for (i = 0; i < numElements; i++, stringElm++) { /* Find out how long this string needs to be */ int32_t stringLen = strlen(whatever_string); if (*stringElm) err = DSSetHSzClr(*stringElm, sizeof(int32_t) + stringLen); else { *stringElm = DSNewHClr(sizeof(int32_t) + stringLen); if (*stringElm == NULL) err = mFullErr; } if (!err)
{ strcpy(LStrBuf(**stringElm), whatever_string);
LStrLen(**stringElm) = stringLen;
}
} }

Above used DS... functions are LabVIEW memory manager functions. They are declared in extcode.h and you can link in labviewv.lib in the cintools directory which will link to the correct LabVIEW runtime to reference these functions. They work for LabVIEW strings but if you use them for more complex LabVIEW arrays types, you will likely run into trouble pretty soon by using these functions directly as LabVIEW has specific alignment requirements depending on the target architecture (32-bit/64-bit Windows, 32-bit/64-bit Linux, 32-bit/64-bit MacOSX, and the various RT platforms).

 

This is just the bare minimum and you need somewhere to determine where to get the strings from that you want to fill in here. If you find this complicated and cumbersome, then you might realize why many people prefer to program in LabVIEW instead of C. As someone from LabVIEW R&D (AristosQueue) used to write in his tagline:

 

I write C(++) code so the LabVIEW users don't have to!

Rolf Kalbermatter
My Blog
Message 4 of 14
(3,462 Views)

Hi Steve, Sorry to bring this old thread up. I was wondering if you had any success finding the documentation. I am facing the same issue.

 

Many thanks!

 

0 Kudos
Message 5 of 14
(1,945 Views)

What is the issue? If you want to write some C code to create a DLL to call from LabVIEW, what I wrote is as much documentation as you will be able to find.

 

If you just want to write some C code without interfacing it to LabVIEW, why do you want to do that? LabVIEW array handles are one way to represent arrays, but not the only one. Without needing to interface to LabVIEW somehow, there is no single reason to implement your own arrays in the same way.

Rolf Kalbermatter
My Blog
0 Kudos
Message 6 of 14
(1,936 Views)

Hi,

 

I have to use a LabView generated dll in C. I am using  DSNewHandle and AllocateLStrHandleArrayfunctions for memory allocation but I keep getting this error:"Exception thrown at 0x763FB922 in Monotk.exe: Microsoft C++ exception: LVExcept at memory location 0x0429E2BC.
Exception thrown at 0x763FB922 in Monotk.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000."

 

My function " int32_t __cdecl GetAllComponentsFromConfigBrowser(LStrHandleArray *Names,
LStrHandleArray *UniqueIDs)" should return a list of names and IDs of all devices connected to the computer. 

 

At this point I'm pretty lost and don't know how to debug the program. Any advice is truly appreciated!

 

Here is my code: 

"

int32 LHAsize_LStrHandleArrayBase = sizeof(LStrHandleArrayBase); 
int32 LHA = sizeof(LStr);

 

LStrHandle Mono_name_LStr = DSNewHandle(LHA);
LStrHandle Mono_ID_LStr = DSNewHandle(LHA);

 

 

LStrHandleArray Mono_name = AllocateLStrHandleArray(LHAsize_LStrHandleArrayBase);
LStrHandleArray Mono_ID = AllocateLStrHandleArray(LHAsize_LStrHandleArrayBase);

 

if ((Mono_name == NULL) || (Mono_ID == NULL) || (Mono_name_LStr == NULL) || (Mono_ID_LStr == NULL))
err = mFullErr;
else
{

(*Mono_name)->String[0] = (*Mono_name_LStr)->str;
(*Mono_ID)->String[0] = (*Mono_ID_LStr)->str;

 

(*Mono_name_LStr)->cnt = 200;
(*Mono_ID_LStr)->cnt = 200;

 

GetAllComponentsFromConfigBrowser(*Mono_name, *Mono_ID);

"

0 Kudos
Message 7 of 14
(1,932 Views)

Well that code of yours is highly inappropriate. You are misusing the dereference operator where you should instead use the reference operator and quite a few other totally inappropriate things.

And LabVIEW handles are fully dynamic memory buffers and need to be handled accordingly. And being fully dynamic they do not require you to allocate them beforehand before calling the function UNLESS you need to store some information in them for the function to use. In your case it looks like this function simply will return information without needing any information from the caller about what it needs to do.

 

In this case you can make everything a lot simpler:

 

LStrHandleArray Mono_name = NULL;
LStrHandleArray Mono_ID = NULL;

GetAllComponentsFromConfigBrowser(&Mono_name, &Mono_ID);

..... do your stuff

err = DisposeLStrHandleArray(&Mono_name);
err = DisposeLStrHandleArray(&Mono_ID);

 

Initializing the two handles to NULL will inform the function that they are invalid and need to first get allocated. If they are not NULL the function assumes that they are already valid handles and will try to dereference them to see how much data they contain and then try to resize them to the size it needs. Being uninitialized, this of course must catastrophically fail just as when they are not EXACTLY as the data type they expect, allocated accordingly too and filled in with the correct information, to start with, which was your case.

 

DisposeLStrHandleArray() or something similar is one of the functions your DLL exports in addition to your real LabVIEW function you want to use.

 

But seeing how you totally messed up the variable dereferences in your code already, the "....... do your stuff here" is certainly going to be a MAJOR hassle for you. There you will have double double dereferences all the time inside loops and your C pointer programming knowledge will be exercised to the max to even just get the information out of those array handles.

Rolf Kalbermatter
My Blog
0 Kudos
Message 8 of 14
(1,922 Views)

Thank you for your response. 

LStrHandleArray Mono_name = NULL;
LStrHandleArray Mono_ID = NULL;

GetAllComponentsFromConfigBrowser(&Mono_name, &Mono_ID);

I tried the code above and it triggers the same breakpoint unfortunately.  

0 Kudos
Message 9 of 14
(1,854 Views)

Post your code! At this time it is all only: My car doesn't work but it is at the other end of the world. Please make it work again!

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 14
(1,849 Views)