LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

allocating memory for an LStrHandle

Solved!
Go to solution

Hello,

 

I know this thing about allocating memory and LStrings has been posted a lot already but I couldn´t find the answer to my question.

 

I am currently working with external code (c++) and calling a vi function.

I want to pass normal c++ strings by:

1) declaring normal c++ string

2) converting c++ string into an Lstring + pass it as Lstringhandle (this works fine!)

3) initialize an Lstrhandle for my result (this would work just fine if i knew the length of the resulting Lstring!!!but since the application is set out to call ANY vi function i do not know what the function is doing and therefore i dont know the length of the result string)

 

My problem is really fundamental but how do i get the actual length of the modified LString?

 

Let´s say my vi function concatenates 2 strings and returns the result, then the signature of my vi-function would look something like this:

 

void __cdecl Concat(LstrHandle *string1, LStrHandle *string2, LStrHandle result);

 

so at some point i need to know the length of the result.

 

Any ideas?

 

(it is important that the strings are Lstrings and that they are passed as pointers!!!)

 

I already tried usinig labviews manager functions but this will not work for the whole problem this little one is integrated in.

 

i appreciate any ideas and help!

thank you...

 

 

 

0 Kudos
Message 1 of 9
(3,616 Views)

Strings are ususally null terminated U8 Arrays.  If you look at the array of chars (U8) until you get a null (0) value you can determine the string length. 

orry if I didnt understand the question/

Paul Falkenstein
Coleman Technologies Inc.
CLA, CPI, AIA-Vision
Labview 4.0- 2013, RT, Vision, FPGA
0 Kudos
Message 2 of 9
(3,610 Views)

You're dealing with handles, not pointers, so you do not need to know the eventual length of the resulting string in order to allocate it.  Use the LabVIEW Manager functions to allocate a new LStrHandle (use DSNewHandle).  Set the length to 1 and initialize the string to a single null, as shown here.  Pass that empty, newly-initialized LStrHandle to the VI.  When the LabVIEW run-time runs the VI, it will resize the LStrHandle to the correct size for the result.  When the function returns, you can look at the "cnt" field in the underlying LStr struct to determine the length.  The "str" field will contain the actual string (NOT null-terminated, since the length is known).

 

Falkpl: in LabVIEW, a string is stored with its length and is not null-terminated.  When you pass a C string to a DLL through Call Library Function, LabVIEW will reallocate the string and add a null.  The question here appears to be about the reverse - calling a VI from C/C++ - and using the native LabVIEW string format.

0 Kudos
Message 3 of 9
(3,606 Views)
Solution
Accepted by topic author Gabriella_

@Gabriella_ wrote:

Hello,

 

void __cdecl Concat(LStrHandle *string1, LStrHandle *string2, LStrHandle result);

 

so at some point i need to know the length of the result.

 


If your function receives the string1 and string2 as input and returns result, then the passing the first two by reference and the latter by value, seems quite a bit backwards.


Since string1 and string2 are inputs, that function is supposed to use, they need to be defined and allocated anyhow properly by the caller. But for output handles passed by reference it is absolutely valid in LabVIEW since about version 6 to pass in a NULL handle and the LabVIEW code takes care of allocating a new handle in that case.

 

So basically if you declare your function like this when you create your LabVIEW DLL:

 

void __cdecl Concat(LStrHandle string1, LStrHandle string2, LStrHandle *result);

 

it is absolutely valid to call this function like this in your C code:

 

LStrHandle string1; //initialize to some string

LStrHandle string2; //initialize to some string

LStrHandle result = NULL;

 

 Concat(string1, string2, &result);

 

and result will contain a valid string handle on successfull return.

 

If the output parameter is declared by value, then you obviously can't pass in a NULL handle as the function has no way of returning a new handle then. Then you would indeed have to allocate an empty handle like this:

 

LStrHandle result2 = (LStrHandle)DSNewHClr(sizeof(int32));

 

This allocates a handle with only room for the numElm value and initializes it to 0.

 

 

Rolf Kalbermatter
My Blog
0 Kudos
Message 4 of 9
(3,588 Views)

Okey i was just trying your suggestion to not pass the input values as pointers but i just realized that i have no idea how i can do that. If i am changing to LStrHandle the signature is automatically created and the inputs are passed as pointers.

 

I attached an screenshot of the vi-prototype dialog.

 

Thank you for your help!

0 Kudos
Message 5 of 9
(3,579 Views)

labview manager functions didnt work; if i am trying to use those function i get a Fatal error message that "LABVIEW.LIB was not called from a LabVIEW process".

 

0 Kudos
Message 6 of 9
(3,573 Views)

@Gabriella_ wrote:

labview manager functions didnt work; if i am trying to use those function i get a Fatal error message that "LABVIEW.LIB was not called from a LabVIEW process".

 


Right! The LabVIEW.lib code can only be called from a process that is a LabVIEW process. Have you linked labview.lib or labviewv.lib?

 

The second has a small chance to pick up the LabVIEW runtime DLL that is loaded by the LabVIEW DLL and then it would work. I never understood exactly the issue about labviewv.lib and labview.lib as I'm never calling LabVIEW DLLs from C code, but always C code from DLLs, but I have a hunch that this might be the reason for these two libs.

 

As to the other problem: Can't you change the Pass By: parameter fromLabVIEW Handle Pointer to LabVIEW Handle?

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 9
(3,549 Views)

hi Rolf,

 

thank you so far for your help.

I figured it out yesterday: even though i am not able to pass the parameters by value; anyways as you said i just tried the most trivial thing and initialized my LStrHandle with NULL and this worked just fine. As you said, labview is able to deal with it and is propably doing all the memory allocation...

 

and now to the labview.lib. i tried linking labview.lib. I havent heard of labviewv.lib so far (but its also easy to overread the 'v' at the end)-

I think I am going to read more stuff about that, because it would be lot more comfortable to use the labview manager functions.

 

Thanks a lot for your help!

 

 

 

0 Kudos
Message 8 of 9
(3,542 Views)

Well you have to be careful here. labviewv.lib may help or not. But in general if you try to use LabVIEW native datatypes the only safe way to modify them in any way that requires allocation, resizing or deallocation in your C code is to use the LabVIEW manager functions. And they are only available if  your C code resides in some environment that has access to the LabVIEW kernel, either the LabVIEW development system kernel or the runtime engine kernel.

 

For instance if you call your function in your C code, you can of course pass in NULL handles and the LabVIEW DLL will return allocated handles if necessary. But if you do not deallocate those handles after use you create a nasty memory leak and to deallocate them you have to use the LabVIEW manager functions. Therefore it is a lot easier to use standard C datatypes instead in your LabVIEW DLL interface if you intend to call that DLL from non LabVIEW applications. They have more strict semantics in that the caller is always responsible to allocate and deallocate any buffers it passes to the function, irrespective if they are input or output buffers. That can have performance implications but is the only safe way of handling buffer passing across function interfaces that do not follow a very specific paradigma and are guaranteed to use the same memory manager. It even can go wrong with standard C memory management if you are not careful to make sure the malloc() called by one component is coming from the same C runtime than the free() that is called elsewhere. Making memory managment for buffer parameters always the sole responsibility of the caller is the only way to guarantee that you do not run into these issues, if you can't control the compilation of all the components that are involved in trying to manage those buffers.

 

For LabVIEW DLLs being loaded into a non LabVIEW process, the DLL loads up the runtime engine to execute its internal LabVIEW resources but that runtime engine is not generally available to the rest of the process. labviewv.lib may or may not help here. The documentation about what labviewv.lib does or doesn't do is more or less non-existent. My suspection so far was always that it is meant to solve the case when you load a Non-LabVIEW DLL into LabVIEW that tries to load a LabVIEW DLL too. Here we have a potential conflict. The LabVIEW DLL will detect that it is loaded into a LabVIEW process and will use that kernel, if and only if the DLL was created in the same LabVIEW version as it is loaded into. Otherwise the calling LabVIEW process does not know how to interpret the version specific LabVIEW resources inside that DLL and therefore the DLL loads the according runtime engine instead. Now we have two LabVIEW kernels in the same process and which one should the non-LabVIEW DLL link to when using any LabVIEW manager functions?

I think labview.lib will always link to the calling LabVIEW kernel while labviewv.lib probably will try to link to the runtime engine instead. However I can't see how that would work, if the non-LabVIEW DLL tries to both manipulate data passed in from the calling process as well as data it passes to the DLL. To make that work would require a much more involved patching of the according runtime import table of the LabVIEW DLL to always use the calling processes manager functions if available but that would also require them to be used internally in the runtime engine throughout. Maybe that is what is happening but then I don't see what labviewv.lib would have to do in all this and also what purpose it could possibly have. The only technical reference on the NI website to labviewv.lib that I could find has to say this:

 

Use the Call Library Function Node  to call shared libraries from inside LabVIEW. The shared library also can link back to LabVIEW and call exported functions such as DSNewHandle. When you want to build a shared library that is called from LabVIEW and also calls back to LabVIEW, statically link your shared library with labviewv.lib. You also can load C-built shared libraries from different versions of LabVIEW at the same time. The library, labviewv.lib addresses multiple LabVIEW Run-Time engines in memory at the same time. The library allows a shared library to track the appropriate Run-Time Engine to call for the given thread even if multiple versions of LabVIEW are in memory at the same time. All C-built shared libraries should link with labviewv.lib and the different versions of LabVIEW resolve automatically.

 

It is not clear how it will resove the issue when a non-LabVIEW DLL would use memory manager fucntions to both operate on data passed from the calling LabVIEW process as well as data passed to the LabVIEW DLL. Personally I always wanted to find out how that works, but haven't come across a need for this scenario, so never spend the time to investigate in more details.

Rolf Kalbermatter
My Blog
Message 9 of 9
(3,538 Views)