LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

How can I call CVI DLL w/UIR from LabVIEW 8.x in 2 modes: as "slave" and as "application"?

Fellow CVI mavens,
 
I have a challenging requirement for you to think about.  If it were easily solved, it would really help bridge the gap between the CVI GUI DLL world and the LabVIEW "VI" world.  That is, until the day comes that CVI panels can be "docked" inside a LabVIEW GUI (like ActiveX controls and .NET Windows Forms controls can already do), then this might be the next best solution.
 
(And, if after reading all of this, it ends up looking like I'm essentially asking for a "cheap and dirty" way of making a CVI GUI DLL look and play as if it were an ActiveX Automation server being controlled by LabVIEW , then that just about sums it up.  However, there seems to be little guidance anywhere on how to go about doing it that way in a professional manner, unless I'm not looking in the right places...)
 
Some background on why this is needed, and a description of a previous success doing this using Agilent VEE...
 
At a previous place of employment, we produced thousands of complex hybrid-chip-and-wire RF/microwave assemblies that incorporated "digital tuning" techniques (instead of conventional and costly RF bond-wire tuning techniques) to get the product cost down.  These particular DUT's needed to be preloaded with compiled VHDL code, offline from the testing area, to get them ready for their initial functional testing.  I created a CVI DLL/EXE application that had a UIR, and had a "main" and a "DLLmain" in it so that it could be built and executed two ways: as either a standalone EXE (for offline use), or as a GUI DLL "slave" to another test application (which happened to be someone's custom-built Agilent VEE test executive).
 
I was able to do this by utilizing a hint from a CVI forum member here back in 2004.  His forum name was "Al S." and his original posting is here:  http://forums.ni.com/ni/board/message?board.id=180&message.id=13266&query.id=29627#M13266
 
When the EXE was used "offline" from the VEE test executive, it created VHDL code inside of a CVI text box control based upon the most-recent "typical" performance characteristics of previous DUT's that came before it (based upon lot-to-lot testing).  Then it would compile that code to JEDEC (via a command-line digital synthesis tool), then download that JEDEC code to a Programmable Array Logic device inside the DUT.  Once this programming step was completed, the DUT was now configured for its initial functional testing, and could later go for its "digital fine-tuning under test" process using the *same* CVI EXE application, but this time using its DLL version (executed as a "slave" to a master test application).
 
In my GUI DLL's "slave" mode, the application would do the same job it did as an EXE, but it did it upon command from VEE.  It would basically fine-tune the VHDL code previously loaded into the DUT, but this time based upon actual performance data as it was in a loop being tested and aligned.  The GUI DLL would always load its UIR panels, etc., and the VEE programmer using this GUI DLL could opt to hide or display the UIR panels at startup or at any time during VEE execution.  Most of the time the GUI DLL was hidden and did its job quietly in the background, with only its system tray icon in view to reveal it was loaded and ready for use, or was discarded properly at "exit".
 
The best part of this design was that the VEE programmer could pop the GUI DLL's main panel into view if there was a situation during testing that needed its GUI to be watched as it was running.  For example, if the PAL device wasn't being programmed, an operator could watch that DUT get re-programmed while the GUI DLL was displying itself, and observe any error messages.  However, the user could not operate the GUI in this mode.
 
It worked like a CHAMP, and I still have the source code to refer to for a new requirement that is VERY similar to what I did before (building a single application as both an EXE and as a "slave" GUI DLL).  This time it needs to run from a LabVIEW 8.x VI, and the GUI DLL needs to run in two modes (desribed below), and to be able to switch between those modes without closing and restarting the LabVIEW program.  However, it is acceptable to unload/reload the GUI DLL on-the-fly from LabVIEW if that's not possible.
 
I'm guessing that there should be nothing special about LabVIEW being able to do this, but my experience with it is that once it has a hold of a DLL (at either design-time or run-time, which seem to be the same thing) that you can't unload/load it like you can do with the Win32 SDK "FreeLibrary" and its twin, "LoadLibrary".
 
Here are the two modes that it needs to switch between (these modes are as a DLL, not built as an EXE):  
 
 1.) Call this "slave" mode, like I just described, optionally hidden or in view via a GUI control from LabVIEW, and doing its job as commanded by LabVIEW's block diagram during some sort of looping test process.  Of course, this mode is without the CVI DLL handling any "RunUserInterface" events, because the LabVIEW program would be stuck waiting for the DLL to return from a QuitUserInterface if it was.  Therefore, it only displays its GUI operation as it runs, until is told to clean-up and exit from a VI.
 
2.) Call this "appllication" mode, where it would be put into view from a VI and told to run (using CVI's event handling as it normally would in an EXE).  This allows a user to make changes in the CVI DLL's GUI via mouse and keyboard.  Then s/he would click on something that turns off the event handling mode and would simultaneously let the LabVIEW application to know that the user is done over there in the CVI app, so that the LabVIEw app can be set up to re-run itself using the new settings from the CVI GUI DLL.  However, the CVI DLL application is not discarded.  The LabVIEW VI would then optionally hide it via one of its GUI controls or block diagram operation.
 
And of course, this same CVI GUI DLL code would also be set up to have a "main" so that it could also run offline as an EXE.  I already know how to do that.  But I mention it so that this design requirement is taken into consideration when a solution is proposed.
 
I would love to have someone's help building a very simple, stripped-down "demo" CVI project of how to do this, and then have it posted as a template for others to follow.  Perhaps this could be a simple UIR with a graph, a multi-state control (ring control?) and a command button to quit (when it's an EXE) that does double-duty as a "dismiss" button (when it is a DLL and needs to get out of "application" event handling mode and become a "slave" running in the background).
 
Thanks for reading all of this...
 
JB
--
To whom it may concern: My alias is also my nickname, I've had it since I was a (very) skinny basketball-playing teen. OK, so I've got a 38 inch waist now, but my hometown friends haven't shaken that appellation for me. I trust that you will someday be OK with that alias, as I have been with that nickname.
Message 1 of 7
(4,899 Views)
Why are you wanting to display the panel from CVI on top of LabVIEW and have LabVIEW handle events? It seems all of this could be done with LabVIEW itself and CVI would not need to be in the picture at all. There is not a way I am aware of the embed a CVI UIR GUI into LabVIEW as a control, but you could always make your own ActiveX server in CVI to do this as well. It just seems your adding complexity that is not needed.

Brandon Vasquez | Software Engineer | Integration Services | National Instruments
0 Kudos
Message 2 of 7
(4,877 Views)

Brandon, let me explain that I am not tying to "embed" my CVI GUI DLL into LabVIEW, they are separate applications, separate windows.  They simply communicate with each other in a more elegant manner.  ...more elegant that what I once achieved whenI had a CVI app communicating with a VEE application, as I described above.  And hey, I'm almost already there because of that previous success...!

I was expecting replies from this CVI forum that would help me over this hurdle, related to tricks I may not know about that relate to the event-handling aspects of CVI.  As one case in point, on the former (unofficial) CVI mailing list that ran for years before this forum existed, Guillaume Dargaud once built on some advice from Martin Saxon (both are long-time CVI users) on how to "nest" multiple RunUserInterface and QuitUserInterface functions within a succession of modal dialog boxes or pop-up panels to do some interesting things in their applications.  Learning from Mr. Darguad's source code (still on his web site, I believe) I once took it that idea a step further in one of my ATE applications some years ago.  That's the kind of stuff I'm hoping to learn about from others here in this forum.

But I agree with you in principal, yours is a very good question, because in an ideal world, it makes sense that we should integrate all these tasks in one development environment.  But in the real world, there are decisions made by others who want it to be done differently, for various reasons.  Reasons such as: the number of available licenses of Visual Studio, CVI, LabVIEW, etc. (which is related to cost for procuring and supporting them, including staffing developers behind them, etc.).  The other aspect has to do with the available skill-set of the current staff on hand for these development tools (limited, because we are a start-up) and the time-frame to get things done right away using this staff (again, being a startup, it is vital for our organization that this is to be delivered ASAP).  Then there is direction that came from "on high" to go down this route, even against my advice to the contrary, which I'll try to explain...

This CVI application must also gather its data from a VB & VC++ based .NET application that drives an FPGA interface board that drives our highly-reprogrammable RFIC DUT (a topic I left out in my posting since it was already into it for several paragraphs).  So from the beginnning, my personal conviction was that the task I am facing should really be created in VC++ .NET, and integrated directly into our existing .NET application.  That app. has already been developed/proven, that oh-by-the-way will be "shipped" with our product, so it will live a reasonably long life-cycle.  But the direction given was to make it work within our various working/proven/transient LabVIEW test programs created by many of our RFIC designers for driving equipment in our test lab, which would allow it to enjoy broader use, so the thinking was.

So the need is still there to interface a CVI app to a LabVIEW app in an elegant manner.  Interfacing my CVI app with our .NET app was the easy part, I got that done already, working/proven.  Hard for me to believe that bridging the unmanaged Win32 world to the managed .NET world was so much easier than bridging the gap between two environments (CVI and LabVIEW) that have been developed by the same company in the same facility for over 20 years, and yet they don't have a more elegant way of interoperating, and apparently never did.

JB

--
To whom it may concern: My alias is also my nickname, I've had it since I was a (very) skinny basketball-playing teen. OK, so I've got a 38 inch waist now, but my hometown friends haven't shaken that appellation for me. I trust that you will someday be OK with that alias, as I have been with that nickname.
0 Kudos
Message 3 of 7
(4,869 Views)
Brandon, you replied "you could always make your own ActiveX server in CVI to do this as well".  If you feel that this is the way towards a solution, could I get some direction on how to go about this?  And will this technique accomplish what I described in detail above having LabVIEW in control?
 
Looking at the examples via the "NI Example Finder" I see a pair of projects called "SimpleEventsServer" and "SimpleEventsClient".  Are these the best places to start?  Should I be calling on my local NI sales/support staff for help with this instead?
 
JB
--
To whom it may concern: My alias is also my nickname, I've had it since I was a (very) skinny basketball-playing teen. OK, so I've got a 38 inch waist now, but my hometown friends haven't shaken that appellation for me. I trust that you will someday be OK with that alias, as I have been with that nickname.
0 Kudos
Message 4 of 7
(4,864 Views)
Jumper,

Its not that you can't integrate them, you can with a DLL, but from your description it sounds like you want LabVIEW to handle a lot of the events, which defeats the purpose of CVI in the first place which is what confuses me and makes it seem like more work than you should be doing (especially since you can use .NET in LabVIEW). If you just dont want LabVIEW to wait for QuitUserInterface function, you can use two seperate while loops since LabVIEW will automatically multithread these. Like I said, its easy to integrate CVI and LabVIEW, but it just doesn't make sense with the way you are doing it.

Also, for creating ActiveX Servers in CVI, check out this link. Creating an ActiveX server would do everything you needed for the "slave" aspect that you described.

Brandon Vasquez | Software Engineer | Integration Services | National Instruments
0 Kudos
Message 5 of 7
(4,823 Views)
JB,

I'm not LV expert, but I'll try to provide some insight and maybe prompt you to give some more information that would be helpful.

First, can you provide some additional description of how the CVI and LV parts of the application interact in 'slave' and 'application' modes?  In 'slave' mode I get the impression that both the LV and CVI GUI windows can be visible and the user can switch between them.  The CVI GUI seems to be in a display only mode where it updates with the current values of the operation, but does not seem to be accepting input from the user and does not allow the user to directly close/hide it.  The LV GUI seems to be alive, accept user input, and has buttons to show/hide the CVI GUI part.  In 'application' mode, I get the impression that the CVI GUI is always visible and can accept input from the user, but I'm not sure what is going on in the LV GUI.  Can the user switch to the LV GUI window?  Can they interact with it?  Is the CVI GUI like a modal dialog (think file dialog) that blocks interacting with the LV GUI window?  I assume you still want the LV GUI to repaint if windows are moved around on top of it, but does it actually need to update displayed values or accept input?

Assuming my impressions are correct, it seems like the main issue here is how to make the CVI GUI run in 'slave' mode without freezing the LV GUI and then how to transition back and forth between this mode and the 'application' mode of the DLL.  Let's focus on the not-freezing-the-LV-GUI issue first...

To me, the biggest question here is how to handle threading interactions between CVI and LV.  So far, the presumption is that you would create your CVI code in a C DLL and call that from a LV call library node.  My understanding of the call library node is that by default it will be called in the single LV UI thread.  While that thread is calling the C DLL, the LV GUI will be hung, which is not what you want.  So I see two options...

The first option is to move the call library node into another LV thread.  From looking at the call library node documentation, it seems that if you mark the call library node call as "reentrant", that LV will move the execution of the call library node out of the LV UI thread and into another execution system thread.  This would mean that the call library node would no longer block the LV UI thread and give you behavior you want.  Now the LV definition of "reentrant" in this context seems to be that the C DLL function can be called simultaneously from multiple threads.  This isn't really true of your CVI GUI DLL.  So you would need to write the LV calling code such that this call library node is only called by one thread at any point in time.  I'm not positive, but I think that this would be relatively straightforward.  You also need to realize that your CVI GUI has thread affinity and requires that the thread that loads a panel must be the same thread to run the event loop for that panel (RunUserInterface, ProcessSystemEvents, etc).  This means that you must guarantee that the LV thread that loads your panels is the only thread to make calls that run the event loop.  I'm not sure how to do this, but you might be able to assign the VI running this call library node to a separate execution system and configure that execution system to only have a single thread.  Since I'm not sure this is possible, here's another idea...  You could say that any LV thread that calls into your CVI GUI DLL should load the panels, run the panels, and always discard the panels before leaving the DLL.  If a different LV thread later needs to call the CVI GUI DLL, it should be able to reconstruct the GUI by loading the panels again, running the panels again, and discarding the panels again.  I'm not 100% positive that either of these mechanisms will work, but it's worth some investigation.

The second option is to leave the call library node calls in the LV UI thread, but minimize the amount of time each call takes so that the LV UI thread can return from the call library node and take care of keeping the LV GUI responsive.  In simple form, I would envision doing this by creating three entry points in your CVI GUI DLL:  CreateGUI, RunSingleGUIEventLoopIteration, and DiscardGUI.  You could create LV code that calls CreateGUI, then calls RunSingleGUIEventLoopIteration in a LV loop, and after the loop calls DiscardGUI.  The simplest implementation of the RunSingleGUIEventLoopIteration would be a single call to the CVI ProcessSystemEvents function.  Hopefully these calls would be short enough to not induce long delays in the LV GUI.  In reality, there are likely to be some longer operations in your CVI GUI code that would induce delays.  You could handle these by spawning off other threads in your CVI code to handle the longer operations and let the LV UI thread return immediately.  Of course, now that you have multiple threads in the CVI code, you'll have to handle synchronizing these threads when they interact.

If you can get this part working, then I think the issue of how to hide/show the CVI GUI in 'slave' mode and how to switch between this mode and 'application' DLL mode will be solvable.  I won't waste a lot of time discussing it here since I'm not sure what you'll think of the above ideas.  With either option above, I think most of the logic would go in your LV code to manage how the LV GUI behaves while running the CVI GUI DLL in 'application' mode.  You will also need some way to communicate to the CVI GUI DLL that it should start accepting user input.  With the first option above, it seems this could be done by exposing additional entry points from your CVI GUI DLL that set global variables that are being monitored by your CVI event loop or by a timer callback if you are using RunUserInterface.  In the second option above, you could probably do the same thing or you could just modify the RunSingleGUIEventLoopIteration function to accept additional parameters through which you would pass this additional state information.

I think you are right that there could be issues in fully unloading and reloading the CVI GUI DLL from a running LV VI.  I'm not sure that's possible, but I also don't think it will be necessary.

I hope this helps.  My impression is that a good solution will depend as much on finding the right technique on the LV side of the application as the CVI side of the application.  You might want to post the LV forum as well since someone over there probably knows the LV execution system better and might have an even more elegant solution for you.  Let us know how things work out.

-Jeff

Message 6 of 7
(4,724 Views)
I am so looking forward to answer your post, but I need another day or two. This week has been all-consuming for me so far. I just wanted to let you know I saw your reply and I very much plan to answer it and try out some experiments based on your advice.

JB
--
To whom it may concern: My alias is also my nickname, I've had it since I was a (very) skinny basketball-playing teen. OK, so I've got a 38 inch waist now, but my hometown friends haven't shaken that appellation for me. I trust that you will someday be OK with that alias, as I have been with that nickname.
0 Kudos
Message 7 of 7
(4,697 Views)