LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Allocate/Cleanup dll object in DLLMain

I started writing a wrapper for nanotecs nanolib motorcontroller library. Until now I allocate a controller object and store the objects address in a labview numeric control.

I call this controller afterwards from various different call library nodes in a state machine. 

 

Can I move the object allocation into DLLMain , store the ptr somehow accessible for the dll and clean up on DLLMain detach? I never saw an example doing this?

Actor Framework
0 Kudos
Message 1 of 11
(989 Views)

Why not?

 

I implemented several times some kind of a dynamic lookup table for the opened objects (handles,pointers,refnum). This enables the DLL functions to validate the objects passed from the caller (labview or any other programming language). It also enables me to savely close all opened objects before the DLL is removed from memory (or whenever I want to close them all) and/or to reference them using anything else (string - in your case it could be a name of the controller).

0 Kudos
Message 2 of 11
(955 Views)

Can you show us a some sample code? This sounds very interesting but so far I didn't find something similiar on this forum.

Actor Framework
0 Kudos
Message 3 of 11
(947 Views)

@Quiztus2 wrote:

Can you show us a some sample code? This sounds very interesting but so far I didn't find something similiar on this forum.


That is because it's not LabVIEW, only LabVIEW related.

 

It's very much a niche array too.

 

Also, these solutions are usually very case specific.

 

DllMain entry point (Process.h) - Win32 apps | Microsoft Learn 

 

I've used DLL_PROCESS_ATTACH,  DLL_THREAD_ATTACH, DLL_THREAD_DETACH and DLL_PROCESS_DETACH in the past, years ago and for very specific cases (so I won't post them here).

 

It simply works are expected. 

0 Kudos
Message 4 of 11
(941 Views)

The methods you described are surely highly coupled to  the status of the VI holding the call library node.

So some discussion which method would be called when first calling library node, stopping VI, closing VI is definitely in the scope of this forum.

Actor Framework
0 Kudos
Message 5 of 11
(933 Views)

for example: my lvserial library does this. The source is open and can be found here. It's plain C code, nothing special - not optimized for tausands of objects/pointers/handles. Look for plist.c, plist.h and in lvserial.c for the usage of ListAppendElement(), ListCheckHandle(), ListGetElement(), ListRemoveHandle() and in DLLMain the functions ListCreate() and ListDispose().

 

0 Kudos
Message 6 of 11
(922 Views)

But watch out what you do in DLLMain. I did in the past also load secondary libraries in there despite the warning in the Microsoft documentation for LoadLibrary() to not do such things in DLLMain. Worked like a charm for a long time until Windows 10 version 1909 or so. Suddenly LabVIEW would consistently lock up as soon as it tried to load my DLL. Solution was to remove all the LoadLibrary() calls from DLLMain and instead call the according initialization routine on first use during normal function calls.

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 11
(909 Views)

@rolfk wrote:

But watch out what you do in DLLMain.


good point ... lot of functions cannot be used in DLLMain even some kernel calls.

0 Kudos
Message 8 of 11
(894 Views)

@Quiztus2 wrote:

The methods you described are surely highly coupled to  the status of the VI holding the call library node.

So some discussion which method would be called when first calling library node, stopping VI, closing VI is definitely in the scope of this forum.


DLL_PROCESS_ATTACH:  Initialize once for each new process.

DLL_THREAD_ATTACH:  Do thread-specific initialization.

DLL_THREAD_DETACH:  Do thread-specific cleanup

DLL_PROCESS_DETACH: Perform any necessary cleanup

 

The lifetime of a VI has little to do with it.

 

It also makes a difference if you specify the path on the diagram.

 

In general (IIRC) process attach is called once, when the dll is loaded for static CLFN, and when first called when the path is specified on the diagram.

 

I think process detach is called when all calling VIs leave memory (not when they stop running).

 

The thread events are much more complex, as there are all kind of reasons LabVIEW calls the CLFN from a new thread.

 

I'd suggest you do some experiments if you want to know all details.

 

I usually did 'global' things in there, limiting the usefulness to the process attach\detach. AFAIK, these should only called once, and you'll always get 1 detach for 1 attach.

 

If you want to clean stuff on other VI bases events, I think you could use the callback functions (in the last tab of a CLFN), but I never used them.

0 Kudos
Message 9 of 11
(888 Views)

Yes, THREAD_ATTACH can be useful if you want to manage thread local storage (TLS) and your calling code has specific threads. As you manage threads explicitly in most text based programming (other than the main thread) you have a very good idea when which thread calls your DLL function. In LabVIEW called DLLs this makes almost never any sense. A particular function could be sometimes called from thread A, then thread B and so on. If you have multiple reentrant CLN’s for the same function it can be called from.arbitrary threads in any CLN or the same. You have no knowledge, which thread will call your function and no guarantees that it will be ever the same.

Here the Callback configuration in the last tab lets you configure a pointer sized memory space for a particular node and the special InstanceDataPointer datatype lets you pass that memory pointer to the function as an extra parameter. This way you can use a CLN local dataspace to store whatever you want. If the pointer size is to small for what you want, you can use the Callback functions to allocate a larger memory space at load of the VI (per instance of the VI if you use shared clone or independent clones for the Vi) and deallocate it when LabVIEW uninitializes (unloads) the VI instances. The third callback is called before every invocation of the CLN but I never have used that.

Also for shared clones it makes almost no sense to use, you end up with the same problem as with memory allocated on THREAD_ATTACH, there is no guarantee when the CLN is called in a particular clone instance. You can consider the InstanceDataPointer similar to an uninitialized shift register, which is also a very bad idea to use in shared clone VIs.

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 11
(841 Views)