The very essence of event-driven programming in LabVIEW is the ability to handle occurrences in the application that are not directly related to, or synchronized with, other things happening in the system. As we have seen in previous posts, the proper handling of these asynchronous events is critical to an application’s success. So far we have covered events arising from such things as the user changing a control value, one part of an application using an event to signal another process to do something, and time-based events that fire periodically.
However there are other sources for events that you need to be aware of, not the least of which are other parts of LabVIEW and even Windows itself.
Incoming Windows Events
Starting with Windows, this event source shouldn’t be too surprising. After all every modern operating system incorporates some type of messaging scheme for communicating with the applications that they are running. Now to tell the truth, most of the messaging that Windows does is not very useful for what we do, but there is one very large exception. When a user tells Windows to shut down or restart, one of the first things that Windows does is broadcast a message that tells all applications currently running that they need to quit. This message (which, by the way, also fires when the task manager tells a program to stop) is important because it allows programs to come to a controlled, graceful stop. When all you’re doing is calculating a spreadsheet, a “controlled, graceful stop” is a convenience. However if your application is controlling the operation of potentially dangerous equipment, an orderly shutdown is an absolute necessity.
Because LabVIEW applications tend to be doing this sort of thing on a regular basis, the language designers have chosen to expose this message to us in the form of the Application Close? filter event. Basically what happens is that when Windows generates the shutdown message, LabVIEW, or the LabVIEW runtime engine, catches the message and passes it on to any user-program that has registered to receive the associated event. From this point on, the event is handled however that code sees fit. If no program has registered for the event, LabVIEW performs an abort to stop all running code. The thing to remember is that using abort to stop a program is like stopping your car by running it into a tree: It works, but there can be negative consequences.
To prevent these “consequences”, every application should have a process that is registered to catch the Application Close? event. The good news is that this logic is very easy to implement — assuming of course that you have written your program such that it is easy to stop. The only other thing you really have to decide is where to put the code. There are arguments that can be made for putting this event handler in a variety of places, but the spot I prefer is in the Exception Handler process. It is after all, the centralized spot for handling things that would interfere with what the program is normally doing. You know, things like errors or shutdown commands from the OS.
This is what the event handler looks like added to Exception Handler.vi in our testbed application.
As you should expect, there isn’t a whole lot to look at: When Windows sends a shutdown message, the error handler fires the internal Stop Application UDE to shut down our application. In addition, it discards the original Application Close? event to prevent it from having any further effect in the LabVIEW world.
Closing the GUI
The other shutdown situation that you should always handle is the case where the user tries to stop the application by clicking on the close box in the upper right-hand corner of the screen. Conceptually, the case is very similar to the previous one, but with one big exception: When the operator tries top close the window, actually stopping is optional. When Windows starts closing, your application will be shutting down. The only question is the circumstances: will it be a systematic shutdown or an abort.
Due to this difference, it is not uncommon for the logic that handles this event include a prompt to the user asking them if they are sure that they want to quit. If you do decide to include a dialog box, make the prompt short and easy to understand. I once saw a dialog that gave stated:
“Are you sure you don’t want to not abort?”
In any case, here is the code for implementing a handler for the Panel Close? event. It is, of course located in the GUI process — the only place it would make sense, right?
You will notice, however, that there is a slight problem here. Namely, as soon as the dialog box opens the screen updates stop. You might not think that this is much of a problem because you are, after all, stopping the application. But what if the user realizes their mistake and decides to continue? Now you have lost (or at the very least, distorted the timing of) perhaps several seconds of data. Moreover, what happens if during that time something important happens to which the software needs to respond? Well, that doesn’t happen either. The problem is that the dialog box is “blocking”. In other words, until the user responds to the dialog, further execution of the loop is blocked.
Never fear though, there are ways around this problem that retains both your ability to prompt users for input, and prevents the blocking of your program’s execution. And we’ll start looking at those solutions in the next post. Once said fix is implemented I’ll update SVN.
Until next time…