01-04-2015 07:21 AM
Hello Forum,
I have created a wrapper dll in C for an instrument to use it in a LabVIEW instrument driver library.
I did not really find a way how to let the dll know, that the LabVIEW Abort button was pressed. I mean the red knob in the LabVIEW toolbar.
This is important for me, because the library is going to be used by other people, who's behavior is to use the abort button.
To give an easy example, on what I need to do:
There are 3 functions in the dll.
initSession()
acquire()
closeSession()
Now a LabVIEW VI is started and initSession() and acquire() are called. When the user hits the abort button, I want the dll to call the closeSession() function.
Somehow I did not find any information on this. But I guess it must be possible somehow..
Cheers
01-04-2015 08:30 AM
01-04-2015 08:46 AM
Well, I personally almost never use the abort button. But I guess the majority of not experianced LabVIEW users does..
The LabVIEW library is for distribution with an instrument. It is based on a wrapper dll to the instrument dll.
01-04-2015 09:00 AM
01-04-2015 09:11 AM
Oh no, I don't want to reinforce that bad style 🙂
But I know, that all problems that arise, because somebody pressed the abort button will come back to me.
But anyway, I am relly really intersted, if there is a way to catch the LabVIEW abort in the dll.
The callbacks in the CLN don't work, because they are only called, when the CLN is action. The reserve and unreserve dll calls also don't work for the abort.
01-04-2015 09:35 AM
If you are supplying the Top Level code, then you certainly can follow "best practices" by (a) removing the Abort button from the top level Front Panel, (b) "trapping" the "Application Close" button (the "X" in the red rectangle at the upper right corner), discarding it, and calling your "safe shutdown routine (a trick I learned from Fabiola de la Cueva), and (c) supplying your "end-of-program" code to safely stop your device.
But if you are, instead, supplying code designed to be run by other LabVIEW programmers who might not adhere to these practices, I'm not sure that there is much you can do, other than document very carefully (and in bold, underlined, italicized type) the procedures that should be followed before the users stop or abort their programs. You have provided the CloseSession() call -- do what you can to emphasize the requirement that the users call this before they stop their programs.
And, if you think it would help, you might suggest that users of your code make sure that their Top Level window sets the Window Appearance property to "Top Level application Window" -- this has the effect of removing the Abort Button. Of course, if you have to tell them to do this, you probably should also say something like "This has the effect of removing the Abort Button, allowing you to force the user to stop your program using your Stop button, which you can code to initiate a safe shutdown."
Bob Schor
01-05-2015 04:00 AM
In your Call Library Node configuration dialog, check out the Tab "Callbacks".
You have three functions in there.
Reserve: is called when your diagram containing this Call Library Node is reserved for execution (the moment you click the run button of your top level VI)
Unreserve: is called when your diagram containing this Call Library Node is going idle (stopping execution)
Abort: is called when your user hits the abort button
Each of these functions can be provided by your DLL and has the prototype defined on that tab. It receives a Ptr that you can use to initiliaze some data structure in your reserve function to maintain state information for the particular Call Library Node. Unreserve should deallocate anything that is allocated in Reserve and/or your actual Call Library Node function inside this pointer/structure.
You can configure the Call Library Node Parameters to pass an extra pointer to this particialr Instance Data Pointer to your DLL function.
Typically you would configure a "Reserve"() function that allocates some memory structure to maintain state information. In your actual "Run"() function (the function you configure in your Function tab) you add an extra Instance Data Pointer parameter that your "Run"() function uses to store whatever information the "Abort"() function would need in order to abort the execution of your "Run"() function. Don't forget to somehow store indication in that structure just before returning from your "Run"() function, that the "Abort"() doesn't attempt to abort your code that is not running.
In the "Unreserve"() function deallocate any intermediate resources that may still be stored and/or left open in your Instance Data Pointer before deallocating the Instance Data Pointer itself.
That's about it. Definitely not trivial but asynchronous programming never is!
01-05-2015 05:04 AM
I did play around a bit with the callbacks in the CLN a few days ago. I just put a Windows Message Box in the function that was the callback and was able to trigger the popup a few times. But it seemed it was only when the CLN was in execution.
I am not sure, if I understand the behavior of the those callbacks right.
Maybe a simple example case could help.
I have three VIs INIT, ACQUIRE and CLOSE that contain a CLN. The Main.vi calls INIT once at startup an then in a while loop the ACQUIRE untill stopped and CLOSE when stopped.
What callback is called, when I hit the abort button in the main VI when the while loop is already running but in a moment the ACQUIRE VI is not executing?
Thanks
01-05-2015 05:25 AM - edited 01-05-2015 05:27 AM
I haven't really done that much with these functions so far. But basically if you press the Abort button, for EVERY CLN in the current VI hierarchy that has an Abort callback configured, the according function will be called with the specific instance data pointer (that you better have initialized in the Reserve callback if you plan to access it in any other callback or your CLN function).
Basically EVERY CLN in EVERY diagram in the reserved/running VI hierarchy has a single implicit instance data pointer that is passed to these callback functions if configured and as the optional function parameter for the CLN function itself.
ALL configured callback functions in the whole hierarchy of your top level VI are called at their respective moment. So if you want to create only one Abort function (and Reserve/Unreserve) for multiple CLNs you really would have to work with the instance data pointer to be able to distinguish the individual CLNs.
On the other hand it is possible, although not really very sane and nice, to only have a single Abort callback that ignores its instance data pointer completey and simple sets some DLL global variable that indicates abort and all your CLN functions that can take some time to do their work to regularly poll that global and then quit whatever lengthy process they are currently running in.
Basically your Abort callback needs to be able to somehow, asynchronously signal to any CLN function that might still be running, that it should immediately stop whatever it is doing and return from its function to give execution control back to the LabVIEW diagram.
This also means that you need to be careful about threading configuration of your CLN. I would suppose that a CLN that executes in the UI thread will itself block the call to the callback functions. So make sure that any CLN you intend to asynchronously abort through the callback interface will run in the Any thread configuration.
01-05-2015 05:39 AM
Thank you very much for the extensive reply.
I will investigate further on those callbacks.
My plan was just to call the close() function in the callback, that sends a stop command to the device, does cleanup and frees ports, etc. There are no threads running.
So if I understand you right, if I have three CLNs in my hirachy, the callback would be called three times.