Before I get in to this post I want to put just a bit of a disclaimer up front. Some of the topics I want to write about, including this one, fall outside the realm of NI support. These will be use at your own risk tools. That being said, everything in this post is in the shipping version of LabVIEW and does not require any knowledge not available online. Because a lot of this information is found through trial and error though, some things in this or future posts may not be completely correct so I encourage anyone reading to explore these topics more and let me know if I'm wrong.
The Event Inspector Window
Even though the title of this post is "Programmatically Inspect Event Queues" I want to spend a bit of time exploring our current options in LabVIEW. There are a couple reasons why I want to do this. First, the tools that ship with LabVIEW are probably going to be easier to use and are all you will need for most troubleshooting purposes. The other reason is that the API we will use has very little documentation so understanding the information provided by the built in tools will help us figure out how this API works.
So, what is already available to us in LabVIEW? Well, as of LabVIEW 2013, you can open up the Event Inspector Window by either selecting View > Event Inspector Window or by choosing the same option when right clicking an Event Structure in a running VI. Something to note is that we can only see events that occurred after launching this window. As an example I ran "Test My Cloneable Module API.vi" which is a test VI for the Delacor Queued Message Handler sample project (which you can download off of VIPM).
Starting from the top, the first option is to select a VI from the list of all active VIs with event structures. Selecting a new VI will update the table of Unhandled Events of Event Queues in that VI and the Event Log which shows a list of all events handled since the event inspector window was launched. The table of Unhandled Events in Event Queue(s) and Evelt log show the same information for each event, just with different formatting. The information we have for each event is:
Sequence # - Specifies the monotonically increasing event sequence number. The sequence number starts from 0 when the LabVIEW application launches and shows the order at which the events occurred. This means that if a single event is registered in multiple VIs, this will show the same event with the same sequence number.
Queue ID - Specifies the ID for the event queue.
Time - Specifies the timestemp, in milliseconds, of the event when the event occurred. This is the same value returned by the tick count primitive.
Reference - Specifies the refnum to the event.
Event Type - Specifies the type of the event such as Mouse Move, Value Change, or User Event.
Source Name - Specifies the name of the object associated with the event. For most front panel events this is the name of the control or indicator.
Other Data - Specifies user event data
Other options we have are to filter timeout events and any events within vi.lib VIs as well as saving the contents of the Event Log window to a text file.
Accessing This Data Programmatically
Now that we know what LabVIEW can already do, what other functionality do we even need? Like I said in the beginning of this post, most of what you will want to do is covered by the Event Inspector Window. However, one thing you might want to do is compile a global list of all events that occurred in your application. LabVIEW does not give you a way to do this currently and even if you wanted a list after the application had finished execution, you would need to save each Event Log to an individual text file and write a program to get that into one master list. An even simpler reason for wanting access to this data is to be able to automate the process of launching this window and saving logs for troubleshooting purposes.
So not even knowing whether our goal of programmatically inspecting event queues is possible, where would we start to look? If you have been programming in LabVIEW for some time you may notice that a lot of dialog boxes in LabVIEW look like typical VI front panels, and if you have ever spent some time looking through the LabVIEW folder (which I recommend doing) you may have noticed the <LabVIEW>\resource\dialog folder where most of these dialog boxes reside. In the dialog folder for LabVIEW 2016 you will find a folder named Event Inspector with the following 3 VIs.
All of these VIs are locked and none have context help so we will have to make a few educated guesses as to what they do. We don't know for sure, but it is probably safe to say that Event Inspector Launcher.vi will simply launch Event Inspector.vi which is the window we were previously looking at. The final VI, EI Get Event Queue Data.vi looks a bit more promising for what we want to be doing.
There may not be context help but there is a note on the front panel which give us an idea of how to use this VI. Part of the note isn't visible, so I had to do some scripting to get the whole message. I copied down the full message below and bolded a section everyone who wants to use this VI needs to be aware of.
This VI returns a snapshot of LabVIEW's internal event system for debugging purposes. This is not a formal public API and is subject to change without notice.
Passing in an occurrence causes LabVIEW to save a copy of future event data as it occurs. Subsequent call to this VI return new events data since the last call. IMPORTANT : Call the VI one last time with a null occurrence in order turn off event logging when done, otherwise the data will be kept indefinitely and may eventually run out of memory.
Calling this VI may disrupt the operation of the built-in Event Inspector Window and cause it to drop events.
There are a few things we learn from this label. First, we are going to use occurrences to turn logging on and off. A valid occurrence will start logging and a null occurrence will stop it. Every call made to this VI will return event data since the previous call and if calling this VI may disrupt the operation of the built-in Event Inspector Window, we will make the assumption that this VI should only be used in one location.
The output Active VIs/QUID Groups give us an array of strings which returns the name of all currently active VIs with event structures. Each element of the Active VIs array matches to the same index of the Event Data output array. To say this another way let's take the first event inspector window in this post, which shows the running VI "Test My Cloneable Module API.vi", as an example. In general "Test My Cloneable Module API.vi" would be at some index N of the Active VIs output. The relevant data for that VI would also be the Nth item of the Event Data array which contains a cluster of the items Event Past Log and Event Current Queue. The Event Past Log is a 1D array of strings where each string is a single line of the event log for all events since the last call of EI Get Event Queue Data. Event Current Queue is a 2D array of events that have occurred but not yet been processed. Each row is a single event and the columns are the same as those in the Event Inspector Window table (Sequence #, Queue ID, etc.).
Now that we have access to this information we can format and do with it as we please. For instance, if we want to see the events for every VI which had an active event structure during execution, we could do something similar to what is shown below. And if you have some other clever ideas of how you can use the EI Get Event Queue Data, let me know in a comment.