10-26-2023 12:38 PM
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?
10-27-2023 01:44 AM
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).
10-27-2023 02:32 AM
Can you show us a some sample code? This sounds very interesting but so far I didn't find something similiar on this forum.
10-27-2023 03:35 AM
@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.
10-27-2023 04:45 AM - edited 10-27-2023 04:47 AM
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.
10-27-2023 05:45 AM
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().
10-27-2023 07:14 AM
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.
10-27-2023 08:22 AM
@rolfk wrote:
But watch out what you do in DLLMain.
good point ... lot of functions cannot be used in DLLMain even some kernel calls.
10-27-2023 10:17 AM
@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.
10-28-2023 03:45 AM - edited 10-28-2023 03:48 AM
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.