Exception Handling
By using the VISA event VI_EVENT_EXCEPTION, you can have one point in your code that traps all errors and handles them appropriately. This means that after you install and enable your VISA exception handler, you do not have to check the return status from each operation, which makes the code easier to read and maintain. How an application handles error codes is specific to both the device and the application. For one application, an error could mean different things from different devices, and might even be ignored under certain circumstances; for another, any error could always be fatal.
For an application that needs to treat all errors as fatal, one possible use for this event type would be to print out a debug message and then exit the application. Because the method of installing the handler and then enabling the event has already been covered, the following code segment shows only the handler itself:
ViStatus _VI_FUNCH myEventHandler (ViSession vi, ViEventType etype,
ViEvent eventContext, ViAddr uHandle)
{
ViChar rsrcName[256], operName[256];
ViStatus stat;
ViSession rm;
if (etype == VI_EVENT_EXCEPTION) {
viGetAttribute(vi,VI_ATTR_RSRC_NAME,rsrcName);
viGetAttribute(eventContext,VI_ATTR_OPER_NAME,operName);
viGetAttribute(eventContext,VI_ATTR_STATUS,&stat);
printf(
"Session 0x%08lX to resource %s caused error 0x%08lX in operation %s.\n",
vi,rsrcName,stat,operName);
/* Use this code only if you will not return control to VISA */
viGetAttribute(vi,VI_ATTR_RM_SESSION,&rm);
viClose(eventContext);
viClose(vi);
viClose(rm);
exit(-1); /* exit the application immediately */
}
/* code for other event types */
return VI_SUCCESS;
}
If you wanted just to print a message, you would leave out the code that closes the objects and exits. Notice that in this code segment, the event object is closed inside of the callback, even though we just recommended in the previous section that you not do this! The reason that we do it here is that the code will never return control to VISA—calling exit() will return control to the operation system instead. This is the only case where you should ever invoke viClose() within a callback.
Another (more advanced) use of this event type is for throwing C++ exceptions. Because VISA exception event handlers are invoked in the context of the same thread in which the error condition occurs, you can safely throw a C++ exception from the VISA handler. Like the example above, you would invoke viClose() on the exception event (but you would probably not close the actual session or its resource manager session). You would also need to include the information about the VISA exception (for example, the status code) in your own exception class (of the type that you throw), since this will not be available once the VISA event is closed.
Throwing C++ exceptions introduces several issues to consider. First, if you have mixed C and C++ code in your application, this could introduce memory leaks in cases where C functions allocate local memory on the heap rather than the stack. Second, if you use asynchronous operations, an exception is thrown only if the error occurs before the operation is posted (for example, if the error generated is VI_ERROR_QUEUE_ERROR). If the error occurs during the operation itself, the status is returned as part of the VI_EVENT_IO_COMPLETION event. This is important because that event may occur in a separate thread, due to the nature of asynchronous I/O. Therefore, you should not use asynchronous operations if you want to throw C++ exceptions from your handler.