LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Call library function node with dynamic memory

Solved!
Go to solution

Hi all:

I'm building DLL files with C++, so I use "Call library function node" in LabVIEW. And I want to create two DLL files called by two nodes respectively. The first DLL includes one line:  int *p = new int[100];

And then the first DLL will output this pointer "p" which is used later as an input by the other DLL (see fig1). However, doing so will get an error message 1097. I think the problem is because I dynamically allocated a sequence of memory for pointer "p", and didn't delete it at the end (see fig2). But, the thing is I must output the pointer "p" which means I can't delete it. So is there any solution or any alternative which can do this job?

I've been bothered by this problem for long time. So please let me know :(((((

 

 

Download All
0 Kudos
Message 1 of 6
(3,121 Views)
Solution
Accepted by topic author jiawaichen77

If the DLLs are designed for you to call from LabVIEW, the simplest way to solve this problem is to have LabVIEW handle the memory.

Pass an array of ints into your first function, then pass the same array (output with modifications as needed by the first) to the second.

 

Note this means you won't have any "new" calls in your DLL(s) (or deletes). You'll probably use something like Initialize Array with the appropriate type and size in LabVIEW.

 

If you must allocate in your C++ DLL, you could potentially link to the LabVIEW extcode (via extcode.h and the .lib(?) files) and use LabVIEW's Memory Manager calls to have LabVIEW allocate memory for your function (in C++). This is more complicated but could be a possibility.

 

If you're compiling both libraries, then with care I believe it is possible to have one create and the other delete memory, but note that this becomes dependent on compiler settings - C++ doesn't have a standard/constant ABI, so the memory deallocator not matching the allocator (I think these are the appropriate terms - hope for a clearer response from Rolfk) will cause problems for you.

 

Can you instead have A.dll allocate the memory and return the pointer, then pass the memory into B.dll, then call a 3rd function in A.dll to deallocate (delete) the memory? This way your memory will be allocated and deleted in the same library, avoiding the potential problems in the previous paragraph.


GCentral
0 Kudos
Message 2 of 6
(3,111 Views)
Solution
Accepted by topic author jiawaichen77

You forgot to attach the VIs. Images are better than 100 words I know, but a LabVIEW diagram does contain a lot more than just the visual information, such as the actual configuration for your Call Library Node parameters. That is the most important part here.

 

Basically for the first function you will need to configure the function to return a pointer sized integer and for the other function as a pointer sized integer passed by value. That is the logical thing. But you have other potential problems with this setup.

 

The fact that you don't delete the memory at the end won't cause error 1097 (it "only" creates a memory leak), the fact that you either configure the parameter to the second function wrong, or attempt to access an array element beyond index 99 would however cause this problem.

 

The biggest problem you have with this setup is possible memory management trouble. If you do not allocate and deallocate the pointer in the same DLL you might end up with memory manager problems. Each C(++) module (and a DLL is a collection of C(++) modules and according C runtime library, will link to its own C runtime library memory manager. If you decide to include the C runtime as static module in your DLL, there will be always different memory managers in each DLL so the new operator in one DLL will allocate memory from the C runtime memory heap maintained by the included memory manager in that DLL and the dispose operator in the second DLL will try to tell the local memory manager to deallocate that memory pointer and that memory manager will simply bark as it never allocated that pointer in the first place.

 

Making the DLL to link to the dynamic C runtime instead, will only work as long as you compile both DLLs with the same C compiler. If you ever end up recompiling one of the DLLs in another compiler (version) it will link to its version specific dynamic C runtime library and you end up with the same problem again. So allocation and deallocation of a particular memory buffer should ALWAYS be done in the same DLL (or in the executable that calls the DLL)!

Mix and match of malloc()/free() (new/dispose) in different modules is always a bad idea.

 

By far the easiest memory management approach is to always let the caller (here LabVIEW) manage any memory buffer, which means that you have to do according steps in the LabVIEW diagram such as using an Intialize Arrary to set an array parameter to the necessary size before calling the DLL function and/or using the Minimum Size configuration parameter for Array and String parameters passed as Data Pointer in the Call Library Node configuration.

Rolf Kalbermatter
My Blog
0 Kudos
Message 3 of 6
(3,106 Views)

Thank you for responding,

I'm using Intialize Arrary to create an array before going into the first DLL function as you suggested. I create a 1-D array with size of 10. But the outcome seems to be wrong.

fig1 is my DLL function.

fig2 is my Call library function node setting.

fig3 is my LabVIEW outcome.

 

Download All
0 Kudos
Message 4 of 6
(3,076 Views)

fig1.jpg

Change int to int8_t

 

Right click the dll config node, let LabVIEW create the C file for you.

image.png

 

 

 

George Zou
0 Kudos
Message 5 of 6
(3,071 Views)

George already told you what you should have done. The main fault (the rest are more beauty mistakes) is that you declare the function to take an array of ints as parameter. An int used to be 16 bit under DOS but that is 30 years ago. It’s since on almost all platforms a 32 bit number. In LabVIEW you however configure the parameter to be an array of bytes (8 bit). The C code does what you told it, it treats the array as int32 values filling in your first number into the first four bytes and the second number into the next 4 bytes. LabVIEW also does what you told it to do, it allocates an array of 10 int32 values but coerces them to an array of 10 8 bit values as you told it in the CLN configuration that the array is supposed to be of 8 bit numbers.

You were lucky that you didn’t attempt to assign a 3rd number to the array because LabVIEW passes in a memory buffer of 10 bytes but your third variable would try to write to byte 9 to 12 and bummmm 💥. Either the CLN returns a 1097 error, which indicates there was some memory corruption or similar going on (but ignoring that error is baaaaaad) or Windows shuts down LabVIEW immediately as it detected that something bad was going on! Either way you are in trouble! It could also be that neither can detect that something went bad, which is the most nasty situation for you. The memory corruption happened anyhow and something went corrupt but you only will find out (sometimes much) later when some unrelated code section crashes on you!

Rolf Kalbermatter
My Blog
0 Kudos
Message 6 of 6
(3,049 Views)