Lessons learned from plugins
When launching LabVIEW VIs using VI Server, the intrepid programmer may run across some stumbling blocks. Below is a collection of issues that Jova Solutions documented while implementing a method to allow users of a built LabVIEW executable to have their own LabVIEW code run by the executable. This information was collected while working in LabVIEW 6.1 and 7.0, and is valid for 7.1 as well, according to NI Developers. We welcome input from groups working in 8.0 or higher.
Contents
Facts about App, VI, and Control References
- You cannot test an Application Refnum using Not-A-Refnum; you must try using it, e.g. read the Name property and test the error returned. This is time-consuming (?).
- Opening Application Ref with default empty string (local machine) uses ActiveX for VI Server functions (ActiveX must be enabled in Options -> VI Server: Configuration, Protocols). Opening Application Ref with any string input, including local machine name instead of default empty string uses TCPIP for VI Server functions (TCPIP must be enabled in Options -> VI Server: Configuration, Protocols). Using TCPIP VI Server functions is slower than using ActiveX; so always use empty string instead of local machine name.
- Opening VI Refs - benchmarks (non-reentrant faster to open than reentrant, untyped faster than typed, ...)
- VI Reference will become invalid (disposed by LV) when call chain of VI that opened the reference finishes running. The VI that opened the reference might still be in memory and reserved by a different caller, but that doesn't keep original caller's references valid.
- Closing a reentrant reference, or the only open non-reentrant reference, to a running VI will abort that VI because the VI's code drops out of memory. You cannot close a reference to a running VI that is being Called by Reference (acts like a reserved subVI), so the VI would have to be started by the Run method.
- Control references only stay valid as long as the application reference, VI reference, panel reference, and parent control reference (if any) from which they came stay valid.
- Control references cannot be used with reentrant VIs, because, although a reentrant VI has multiple dataspaces (one for each instance), it only has one front panel with one set of controls. You can use Get/SetControlValue methods to access the front panel data, but you cannot use the Value property. (According to LV developer Stephen R. Mercer with a 26 Oct 2007 statement on info-LabVIEW this is false for LV versions >8.0. Clones of reentrant VIs now have their own panel and diagram, enabling independent VI Server work and independent probes for debugging).
To avoid problems with references
- Test AppRef by reading application property, such as name. This is expensive.
- Always use empty string to open an AppRef to the local LV, instead of the local machine name.
- Open and manage VI refs in independent VI that stays running for the life of the application.
- Preload VIs using PATH as early as possible and keep that initial reference open so VI stays in memory (non-reentrant because faster to open; won't be used to call VI), then any subsequent Open of untyped reentrant VI refs can use STRING name input.
- Use Get/SetControlValue instead of Value property for controls on reentrant VI.
Facts about LV Execution: the [b]Root Loop[/b]
- The LV execution system processes certain user interface activity in sequential order in "root loop."
- User activity can block the root loop for long periods, such as a LV dialog box and menu navigation. Whenever our application uses LV functions that go through the root loop, it will be blocked (hang) until the user activity completes. If a user leaves a menu open and then goes home for the weekend, it's possible to hang every station on the network.
- Opening untyped VI ref with PATH input type goes through root loop; opening untyped VI ref with STRING input type does not go through root loop.
- Open TYPED VI reference always goes through root loop (regardless of path or string input).
- Invoking the Run method on a VI goes through the root loop (think of this as programmatically pressing the Run button).
- Invoking the Abort method on a VI goes through the root loop (think of this as programmatically pressing the Abort button). When you close the last reference to a VI so it drops out of memory, it will also abort, but this does not involve the root loop.
To avoid problems with the root loop
- Do not use LV built-in dialogs; use dialog-mode subVI.
- Open TYPED VI reference as early as possible.
- Use call by reference instead of using Run method whenever possible. Not possible if caller should not wait for other VI to finish (Wait until Done option only on Run method).
- To use call by reference for Vis with different, unknown connector panes, use Get/SetControlValue methods to set inputs & outputs instead of wiring to connector pane in Call by Ref; and force Vis to conform to "blank" connector pane (this can be set programmatically).
- To keep VI Refs valid for as long as possible, we launch a looping VI that takes requests off a queue and opens ALL the VI refs for our application (both local and remote refs).
- We need to know if a VI that we have started running in the background (not waiting until done) has finished. We have the reentrant reference to the VI; but the property "VI state" does not distinguish between running and reserved. We considered closing this reentrant reference as the last thing in the running VI itself (which would abort it) so that we could know the VI was complete if the reference was invalid. However, if a VI (or one of its subVIs) closes its own reentrant reference, LV 6.1 will crash. So we had to set a Boolean control on the Vi's front panel to True as the first thing in the VI's code and to False as the last thing. The application can read this Boolean (must use GetControlValue method, not Value property) to find out if the VI is running.
- Catch 22: VI Refs Fact (d) vs. Root Loop Facts (e & f). If we might need to abort a VI that we have started running in the background, we have to use the Run method to start it, so we can't avoid going through the root loop then. But we can close its (reentrant) reference instead of using the Abort method to avoid the root loop there.
[b]Meg Kay[/b] and [b]Veda Murthy[/b] of Jova Solutions, Inc.
June 26, 2002