LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Receiving pointer by reference from DLL

Solved!
Go to solution

@rolfk wrote:

wiebe@CARYA wrote:

 

The only 'complication' that LabVIEW adds is that you can easily abort a VI, before deallocating memory or calling proper close functions. 


The main "complication" LabVIEW has with this is that you do not have to worry about these sort of things when programming in LabVIEW. That makes programmers assume that it must be the same when using the Call Library Node, but LabVIEW can't do that for you. The DLL/shared library interface was developed around the rules implied by C. C has certain low level rules and a lot of conventions but no strict definition about how to allocate memory, pass it around and all that stuff. The Call Library Node has to work with these constraints and can't invent its own rules.


I agree.


@rolfk wrote:

The only real rule in C about this is that if it crashes you did something wrong, if it doesn't crash you still very possibly did something wrong and it will come and bite you later on!

 

There is no way a function in a shared library can tell the caller, look I expect here a parameter, it is an array, needs to have 30 bytes preallocated and I will fill in up to 29 and terminate it with a zero byte at the end. Or this is an array, I will allocate whatever I deem necessary from heap XYZ and hand it back to you, you do need to deallocate it with exactly the matching heap function as soon as you are done with it or our beloved system memory manager will quickly get very unhappy with us two.


I agree that this isn't LabVIEW's problem. But it still is a (minor) problem.

 

It would be nice if there was a (easier) way to make dlls with an open and close functionality behave more like LabVIEW references. Some way to ty the open call to the top level data space, and the close to an automatic call when the TLDS stops existing. That way, wrappers could simply make an open VI, a close VI, and ty the close VI to the TLDS lifetime. When the Top Level Vi is aborted, the dll could still get a change to close properly, like other references.

 

I now do something like this with a dynamic VI, that dequeues a queue allocated in the TLDS. The dequeue stops waiting when the TLDS stops, and it calls the close. Not perfect, but efficient.

 

Kind of like this idea: Means-to-register-a-DVR-cleanup-callback-fior-use-when-DVR

0 Kudos
Message 21 of 26
(822 Views)

wiebe@CARYA wrote:

It would be nice if there was a (easier) way to make dlls with an open and close functionality behave more like LabVIEW references. Some way to ty the open call to the top level data space, and the close to an automatic call when the TLDS stops existing. That way, wrappers could simply make an open VI, a close VI, and ty the close VI to the TLDS lifetime. When the Top Level Vi is aborted, the dll could still get a change to close properly, like other references.

 

Kind of like this idea: Means-to-register-a-DVR-cleanup-callback-fior-use-when-DVR


Well one option is the (IMHO misnamed) Callback configuration in the Call Library Node. This allows you to be informed when LabVIEW aborts a VI hierarchy. Basically the Call Library Node that calls any possibly lengthy function is configured to also use these callbacks that the DLL must provide.

LabVIEW calls MgErr Reserve(InstanceDataPtr *state) when it loads (more correctly instantiates) the according VI diagram. This is an important detail for reentrant VIs if you happen to set that VI as reentrant, as each instance will in fact receive its own Reserve() call to the function. The reserve function allocates a memory block to store whatever information the DLL wants to maintain across calls and returns the pointer to it.

 

When the VI is closed (or more correctly its instance removed from memory) the according Unreserve() function is called. This function checks the data started in the InstanceState and optionally aborts any ongoing operation and deallocates possible handles stored in there and then deallocates the memory block itself.

 

The Abort() function is really a subset of the Unreserve(). It is called when the according VI hierarchy is aborted by the user. This function will have to abort any operation that may be still going on based on information retrieved from the state stored in that memory block.

 

Now the most interesting part is that you can configure the Call Library Node to pass in an extra parameter called InstanceDataPtr. This parameter is only visible on the diagram as a grayed out parameter pair, since you can not pass any data to it from the diagram. LabVIEW will instead pass the instance data pointer that was created when calling the Reserve() function. The function can use this to store its state in it just before calling a lengthy operation and LabVIEW will then call the Abort() function when the user hits the Abort button and this can signal to the lengthy function to abort through information stored in the InstanceDataPtr.

 

This functionality could also be "abused" for connection cleanup. You would most likely configure the Open function call to use these callbacks and store any connection information in the InstanceDataPtr. One complication here is that this function will typically be called to open multiple connections so you would have to store each of them somehow. And the Abort() call has no way to distinguish for which connections it was called but simply would have to abort them all. For most use cases this should not matter but it would kind of mess with situations where you have multiple top level hierarchies that all use this function and you abort one of them.

 

This isn't trivial but there is IMHO no trivial solution to such a problem. Multithreading together with proper resource management is always going to be a mess. LabVIEW hides a lot of that behind a neat interface for its own functionality but can't do that for you when DLLs are involved, since there is no strict standard how to deal with these things in C. It could try to hide it behind standard functions but that would require the DLL to behave according to a very strict standard defined by the LabVIEW functions and that would make this only useful for DLLs you write entirely yourself, not for 3rd party DLLs. And it would not make the DLL implementation easier, only the LabVIEW access interface.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 22 of 26
(808 Views)

@rolfk wrote:

wiebe@CARYA wrote:

It would be nice if there was a (easier) way to make dlls with an open and close functionality behave more like LabVIEW references. Some way to ty the open call to the top level data space, and the close to an automatic call when the TLDS stops existing. That way, wrappers could simply make an open VI, a close VI, and ty the close VI to the TLDS lifetime. When the Top Level Vi is aborted, the dll could still get a change to close properly, like other references.

 

Kind of like this idea: Means-to-register-a-DVR-cleanup-callback-fior-use-when-DVR


Well one option is the (IMHO misnamed) Callback configuration in the Call Library Node. This allows you to be informed when LabVIEW aborts a VI hierarchy. Basically the Call Library Node that calls any possibly lengthy function is configured to also use these callbacks that the DLL must provide.


The reason I've never looked into this is that AFAIK you need to tailor the dll to work with LabVIEW. The change a 3rd party dll will work nicely with this seems 0.

 

It's not possible to provide a callback function that is in another dll than the one that is called. So even a small utility dll isn't possible, you'd have to change the source and recompile.

0 Kudos
Message 23 of 26
(800 Views)

wiebe@CARYA wrote:

@rolfk wrote:

wiebe@CARYA wrote:

It would be nice if there was a (easier) way to make dlls with an open and close functionality behave more like LabVIEW references. Some way to ty the open call to the top level data space, and the close to an automatic call when the TLDS stops existing. That way, wrappers could simply make an open VI, a close VI, and ty the close VI to the TLDS lifetime. When the Top Level Vi is aborted, the dll could still get a change to close properly, like other references.

 

Kind of like this idea: Means-to-register-a-DVR-cleanup-callback-fior-use-when-DVR


Well one option is the (IMHO misnamed) Callback configuration in the Call Library Node. This allows you to be informed when LabVIEW aborts a VI hierarchy. Basically the Call Library Node that calls any possibly lengthy function is configured to also use these callbacks that the DLL must provide.


The reason I've never looked into this is that AFAIK you need to tailor the dll to work with LabVIEW. The change a 3rd party dll will work nicely with this seems 0.

 

It's not possible to provide a callback function that is in another dll than the one that is called. So even a small utility dll isn't possible, you'd have to change the source and recompile.


That's where wrapper DLLs come into place. And yes IMHO there is no easy way to make this work with arbitrary DLLs directly. Whatever LabVIEW functionality would be provided you have to tie it somehow together if the DLL developer hasn't provided a LabVIEW compatible way already. There will always be an impedance mismatch if the DLL wasn't written specifically for use with LabVIEW!

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 24 of 26
(794 Views)

@rolfk wrote:

wiebe@CARYA wrote:

@rolfk wrote:

wiebe@CARYA wrote:

It would be nice if there was a (easier) way to make dlls with an open and close functionality behave more like LabVIEW references. Some way to ty the open call to the top level data space, and the close to an automatic call when the TLDS stops existing. That way, wrappers could simply make an open VI, a close VI, and ty the close VI to the TLDS lifetime. When the Top Level Vi is aborted, the dll could still get a change to close properly, like other references.

 

Kind of like this idea: Means-to-register-a-DVR-cleanup-callback-fior-use-when-DVR


Well one option is the (IMHO misnamed) Callback configuration in the Call Library Node. This allows you to be informed when LabVIEW aborts a VI hierarchy. Basically the Call Library Node that calls any possibly lengthy function is configured to also use these callbacks that the DLL must provide.


The reason I've never looked into this is that AFAIK you need to tailor the dll to work with LabVIEW. The change a 3rd party dll will work nicely with this seems 0.

 

It's not possible to provide a callback function that is in another dll than the one that is called. So even a small utility dll isn't possible, you'd have to change the source and recompile.


That's where wrapper DLLs come into place. And yes IMHO there is no easy way to make this work with arbitrary DLLs directly. Whatever LabVIEW functionality would be provided you have to tie it somehow together if the DLL developer hasn't provided a LabVIEW compatible way already. There will always be an impedance mismatch if the DLL wasn't written specifically for use with LabVIEW!


It feels to me that LabVIEW could make some steps towards better integration. I don't have any concrete ideas (well, maybe a few), but I'm sure if we stick our heads together (remotely), we can think of a few things to eliminate some difficulties.

 

Of course, it's a niche, and resources are probably needed elsewhere.

0 Kudos
Message 25 of 26
(789 Views)

wiebe@CARYA wrote:


It feels to me that LabVIEW could make some steps towards better integration. I don't have any concrete ideas (well, maybe a few), but I'm sure if we stick our heads together (remotely), we can think of a few things to eliminate some difficulties.

 

Of course, it's a niche, and resources are probably needed elsewhere.


It's definitely a niche. And what is more it requires a pretty deep understanding of advanced C concepts, no matter what! There is no way to make this work with arbitrary DLLs by someone who isn't able to write some real C code well beyond the simple "Hello world" program according to a precooked recipy.

 

Should the LabVIEW developers spend a lot of time for something like this? Maybe if they wouldn't have other things to do, but that won't happen for a long time. 😀

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 26 of 26
(750 Views)