What Are UI Messages?
TestStand uses UI Message objects to pass information about the state of the Engine and current executions to the Operator Interface or Sequence Editor. For example, the TestStand Engine posts a UI message to notify the Operator Interface when a step completes. The Operator Interface can then perform actions in response, such as refreshing the Execution View control to display updated step results.
Each UI message contains the following data related to an execution event:
- Message ID, which indicates the type of message being sent.
- Numeric data.
- String data.
- Object reference data.
The Default TestStand UI Messages section later in this article provides additional details about the UI messages that the TestStand Engine posts automatically.
In some situations, you may need to notify the Operator Interface about additional execution events or pass custom data to the User Interface. To accomplish this, post custom UI messages by using the TestStand API. Custom UI messages must use a Message ID greater than the UIMsg_UserMessageBase constant (10000 by default).
Possible applications of custom UI messages include:
- Passing information about the total number of units tested to the User Interface after a test completes.
- Passing specific numeric results from a test and appending them to a graph in the User Interface.
This article discusses how to post UI messages using the TestStand API and how to configure a custom Operator Interface to receive and process them.
Why Use UI Messages?
UI messages provide the preferred mechanism for communication between TestStand sequence files and User Interfaces. An alternative approach, such as updating a sequence file property or User Interface variable, introduces unnecessary dependencies between the sequence file and the User Interface.
UI messages are preferred for the following reasons:
Independence Between the User Interface and Sequence Files
A User Interface should be capable of running with any compatible sequence file, and a sequence file should be capable of running in any compatible User Interface.
By using UI messages:
- The User Interface can execute sequences that do not implement specific messages.
- Sequences that post custom messages can execute in User Interfaces that do not handle those messages.
If a custom message is not handled, the User Interface simply ignores it.
Maintainability
UI messages eliminate dependencies on sequence file properties and User Interface variables, reducing maintenance requirements for both sequence developers and User Interface developers.
Default TestStand UI Messages
The TestStand Engine automatically posts UI messages throughout execution to announce Engine and execution events. These messages allow the User Interface to obtain information about the current execution state.
The Engine defines multiple message types through Message IDs and automatically posts these messages when specific events occur.
For a complete list of default UI messages, refer to the UIMessageCodes article from the TestStand user manual. This documentation describes:
- When each message is posted.
- What data the message contains.
- How the User Interface can use the message.
Many default UI messages trigger behavior within the User Interface but are never automatically posted by the Engine. You can manually post these messages by using the API methods described in the Posting UI Messages section.
You can also configure the User Interface to execute custom code when specific UI messages are received. This process is described in the Receiving and Handling UI Messages section.
Custom UI Messages
You can define custom UI messages by assigning a Message ID greater than or equal to UIMsg_UserMessageBase (10000).
Custom UI messages work similarly to default UI messages; however, the developer must implement all functionality associated with them.
This includes:
- Posting the message in the sequence file or code module.
- Handling the message in the User Interface.
Unlike default messages, custom messages are not posted automatically by the Engine, and TestStand User Interface controls do not provide default handling behavior.
Posting UI Messages
To post a UI message, use one of the following TestStand API methods:
Engine.PostUIMessage Method
Use the Engine.PostUIMessage method when posting a UI message from code outside a sequence execution. When using this method, you must explicitly specify the Execution and Thread references. Refer to article Engine.PostUIMessage from the TestStand user manual for more information.
Thread.PostUIMessageEx Method (Typical)
Use the Thread.PostUIMessageEx method when posting a UI message from a sequence file. This method uses the current Thread and Execution references automatically. You can see the page Thread.PostUIMessageEx from the TestStand user manual for more information.
The parameters of the PostUIMessageEx method are shown below: PostUIMessageEx (eventCode, numericDataParam, stringDataParam, activeXDataParam, synchronous)
Note: The synchronous parameter determines whether the method waits until the User Interface acknowledges the message. In most applications, set this parameter to True to prevent UI message queue overflows that can occur when messages are posted faster than they can be processed.
You can invoke these methods in several ways, as described in the following sub-sections.
Statement Step (TestStand 4.0 and Later)
A Statement Step can directly invoke PostUIMessageEx through an expression.
This is generally the preferred option because it minimizes implementation complexity and avoids unnecessary ActiveX integration.
In this example, the current sequence error message stored in RunState.SequenceError.Msg is passed through the string data parameter of the UI message. Notice the use of UIMsg_UserMessageBase + 1 as the event code. Adding the value of UIMsg_UserMessageBase ensures that the custom message does not conflict with any predefined TestStand UI message IDs.
Whenever this Statement Step executes, the thread posts a custom UI message with ID 10001. The string data associated with the message contains the value of RunState.SequenceError.Msg, which can then be processed by the User Interface.
LabVIEW

LabWindows™/CVI™
// Get a reference to the current thread from Sequence Context
tsErrChk(TS_SeqContextGetThread(
seqContext,
&errorInfo,
&threadRef));
// Get the RunState.SequenceError.Msg property value
tsErrChk(TS_SeqContextGetRunTimeErrorMessageEx(
seqContext,
&errorInfo,
&errorMessage,
NULL,
NULL));
// Post the UI message
tsErrChk(TS_ThreadPostUIMessageEx(
threadRef,
&errorInfo,
TS_UIMsg_UserMessageBase + 1,
0,
errorMessage,
NULL,
TRUE));
TestStand ActiveX Step
Receiving and Handling UI Messages
Within the Sequence Editor or a TestStand Operator Interface, the Application Manager automatically acknowledges UI messages and handles default UI message events.
You can configure the User Interface to execute custom code by creating callbacks for one of the following Application Manager events:
- UIMessage Event - This event occurs whenever the Application Manager processes any UI message. The callback executes before default processing occurs. You can set the
Cancel output parameter to True to override the default behavior. - UserMessage Event - This event occurs only for custom UI messages whose Message ID is greater than or equal to
10000.
The following sections describe how to implement custom UI message handling in LabVIEW and LabWindows™/CVI™.
LabVIEW Implementation
In this example, you can modify the Simple Operator Interface to handle the custom UI message described earlier.
The Simple Operator Interface is located at:
<TestStand Public>\UserInterfaces\Simple\LabVIEW\Source Code\TestExec.llb
In the simple Operator Interface, the TestStand events are registered in the Top Level.vi. Specifically, in the Register Event Callbacks Case. In this VI, we set what action to take when an event occurs by specifying a callback VI to run when the event occurs. Configuring the event handling callbacks is accomplished using the Register Event Callback Node .
To implement code to execute when a custom UI message is received, we first need to implement a callback VI for the UserMessage Event:
- Expand the Register event node to contain an additional event. You should see three additional inputs
- Wire the Application manager reference to the first new input. This specifies that we are handling an event of the Application Manager
- Left click the first input to select the User Message event from the list of Application Manager events
- Right-click the node of the second input (VI Ref), and select Create Callback VI from the context menu. This creates a new callback VI which runs whenever a custom UI message is received
- Pass any additional data to be used by the callback into the User Parameter node (in this case, no additional data is needed)
The Top Level.vi with these modifications is shown below.

We now need to implement the code within the callback VI that should execute when the custom UI message is received:
- Open the callback VI created in step 4 above by double clicking it. Note that the parameters of the VI are created for you based on the event
- To access the UI message data, unbundle the Event Data parameter to access the uiMsg object, then create a property node from this object. This object represents the data of the UI message that fired the UserMessage event
- Since this event callback will run for any custom UI message, we first need to check the ID of the message. To do this, use the Event property as the selector data for a case structure. Add a case for the ID of the custom event (10001)
- Within the case structure, create the code to execute. In this case, we launch a dialog to display the error information sent within the UI message.
The completed callback VI is shown below.
The modification is now complete, and the UI will now handle the custom UI message. To handle additional custom messages, simply add an additional case in the callback VI for each new UI Message ID.
LabWindows™/CVI™
In this section, we will modify the Simple Operator Interface to handle the Custom UI message in the example above. The simple Operator Interface is located in the following directory:
<TestStand Public>\UserInterfaces\Simple\CVI\TestExec.cws
In the simple Operator Interface, the TestStand events are registered in the SetupActiveXControls() function. In this function, we set what action to take when various events occur by calling event registration functions. Each event type has a separate function associated with it; to handle the User message event, we use the following function:
errChk( TSUI__ApplicationMgrEventsRegOnUserMessage(gMainWindow.applicationMgr, ApplicationMgr_OnUserMessage, NULL, 1, NULL));
This function configures a callback function to execute when a user message is received. It requires five parameters:
- The object that handles the event - in this case, the application manager
- The callback function to execute when the event occurs - we need to create the function specified here (ApplicationMgr_OnUserMessage)
- Callback data - any additional data needed in the callback function - in this case, nothing is needed
- Enable callbacks - sets whether to link the callback to the event immediately. In most cases, this should be set to 1, or true
- (return parameter) callback ID - use this parameter to access the unique ID of the callback. This data is not needed for this tutorial
This function should be inserted with the other event registration functions (lines 277-281). Documentation for this and other TestStand API functions is provided in the CVI function panel.
We now need to implement the code within the callback function that should execute when the custom UI message is received. The prototype of this function is provided in the documentation for the registration function above.

The completed callback function is written below. The comments provide more detail on each call.
HRESULT CVICALLBACK ApplicationMgr_OnUserMessage (
CAObjHandle caServerObjHandle,
void *caCallbackData,
TSUIObj_UIMessage uiMsg)
{
char *stringData;
enum TSEnum_UIMessageCodes messageID;
int error = 0;
//obtain message ID from UI message object
tsErrChk(TS_UIMessageGetEvent(
uiMsg,
&errorInfo,
&messageID));
switch (messageID)
{
case 10001:
//run only for this message type (ID 10001)
//get the UI message string data
tsErrChk(TS_UIMessageGetStringData(
uiMsg,
&errorInfo,
&stringData));
//display the string data to the user
MessagePopup("Sequence Error",stringData);
break;
}
Error: //handle errors (same as other callbacks)
DisplayError(error);
return error < 0 ? E_FAIL : S_OK;
}
The modification is now complete, and the UI will now handle the custom UI message. To handle additional custom messages, simply add an additional case in the callback function for each new UI Message ID.
The modified TestExec.c file can be found in the attachments.