From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Measurement Studio for VC++

cancel
Showing results for 
Search instead for 
Did you mean: 

EventHandler, install/uninstall in succession or not

Sorry to bother again, but now I have an architectural question regarding Visa event handlers. I like to react to SRQs several times during the life time of my instrument object, everytime in a different manner. Should I install and uninstall an event handler for each time, or keep it installed and handle the events, which I have to handle each time in a different manner, in that one event handler, which would then call the actual event processing routines according to a state machine variable? The first approach is more elegant, but is there a hardware performance issue? I guess, software performance on a Pentium isn't one.
0 Kudos
Message 1 of 4
(3,214 Views)
Gunni:

Ah, the elegance vs. functionality tradeoff. Rest assured that either approach can work fine but each has its pros and cons.

I would definitely say the traditional approach would be to install a single handler once for a given session, then handle the events based on what you are doing at the moment.

Rather than using a global variable, 1 way to keep the information more local might be to call "sess.SetAttribute (VI_ATTR_USER_DATA,value);". I'll admit to not remembering the exact syntax but I'm pretty sure that's about right. Then in your callback you can do "sess.GetAttribute(VI_ATTR_USER_DATA,&value);" and know your session's state information. Remember that this can hold any 32-bit value, including a pointer if you cast it appropriately.

On the other hand, if you want to install/uninstall a handler appropriate for the given task, make sure you remember to call EnableEvent after installing your handler (since the previous uninstall will automatically call DisableEvent). Also, make sure you install and enable just before setting up the instrument to generate an SRQ in order to avoid any race conditions. This may make the handler more elegant but potentially clutters your other code.

My recommendation would be to use the first method (always keep it installed). If a big switch statement in the handler is unappealing, try this. Make all your actual event processing routines take the same parameter list, and just set the VI_ATTR_USER_DATA value to the function pointer of the routine. Then the handler can just invoke the function pointer (with the appropriate parameters) instead of doing a switch. This will likely require that the actual event processing routines be non-member functions, and I'm pretty sure they can't be virtual ones, since you can never get a direct pointer for these.

I hope this gives you more insight into your various options. Again, it really doesn't matter too much because any of these ought to work.

Dan Mondrik
Senior Software Engineer, NI-VISA
National Instruments
Message 2 of 4
(3,214 Views)
Thanks for the great answer. I guess I go with the first choice, better safe than beautiful. It also stays object oriented all functions involved being class members, in contrast to the third suggestion.
0 Kudos
Message 3 of 4
(3,214 Views)
Gunni:

What I suggested the other day will work, but what I did not think would work, actually will, with a little massaging. This will allow you to store a "pointer" to a member method (virtual or non-virtual is OK, static or function is not) in VI_ATTR_USER_DATA. I say "pointer" because it is a pointer when used in the correct context; it is not a direct address like a normal C function pointer. Here is some sample code. Let me say right now that this is pretty advanced C++ stuff. Well, at least it's not common.

All of your handler methods must be in the same class or derived from the same base class, and must be of the same signature. You must typedef your pointer like this. This example takes no arguments and returns a VISA st
atus value, but of course you can change that as you wish.
typedef ViStatus (CMyVisaAppClass::* mymemberptr)();

In your code where you want to specify the member function, this is the ugliest part. You do a "special" cast to pass it by value since there is not a direct version of SetAttribute that matches this exact type:
mymemberptr foo = myRealHandler;
vi.SetAttribute(VI_ATTR_USER_DATA,*(void**)&foo);

Like I said, that part is ugly but it does work. The last part is the prettiest, though. In your handler, just get the user data as a pointer and invoke it!
CNiVisaSession& rvi = event.GetSession();
mymemberptr foo;
rvi.GetAttribute(VI_ATTR_USER_DATA,&foo);
ViStatus stat = (pmyclass->*foo)();

Recall that since the initial handler callback is in a _cdecl (ie, non-member) function, you must have a pointer to your actual class in order to correctly resolve the member pointer value. That is what the "pmyclass" is about. I assume you will have already figured out how to
do that with your current solution.

Again, this is pretty advanced, and it may be more confusing than what you are already coding. But it can be done!

Dan Mondrik
0 Kudos
Message 4 of 4
(3,214 Views)