LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

XControls: Dynamic loading & polymorphism

This is for XControl freaks (if there are any).  It's long, and I don't know how to make it shorter; sorry about that. So gather 'round and enjoy.

We want to dynamically load and manipulate XControls -- that is, we want to dynamically load an XControl and invoke properties and methods on it.

Not only that, we want to be able to dynamically load one of several XControls, all sharing an interface, just as one might dynamically load different VIs that have the same connectors.

(Why? So we can make an app that loads "plugins" that can have independent event loops, properties, and state -- in other words, we want objects -- which is why we want XControls as plugins.)

No
w, we're certain that we can't dynamically load XControls, just as we can't dynamically load built-in controls.  So we don't.  Instead, we dynamically load a VI that has our XControl in it.  This "wrapper VI" has one output connector, which is a refnum for the XControl inside it.  We downcast the refnum to the XControl's class and use it to get property and invoke nodes for the XControl.

A big problem is that LabView has its own way of locating the XControls themselves, and we're not sure what that is.  So we have to trick LabView into loading the XControl we want, observing the following rules, which we have found out by experiment (and may be incorrect):

1. LabView locates XControls by name only, even though it stores paths in calling VIs anyway. (The same applies for subVIs.)

2. LabView seems to load the nearest XControl to the VI that loads it.  For example, if a VI loads XControl "foo.xctl", and foo.xctl is in the same directory, it will always load that one.  It will not load a foo.xctl in a different directory, because it uses a nearest-neighbor search.  (Or so we hope.)

2a. When an XControl is loaded, you cannot load another XControl with the same name.  (This is also the same as with subVIs.)

2b. If an XControl called "foo" is in memory, and you try to load a different XControl also called "foo", LabView won't do it.  It will use the "foo" already in memory.

3. To load a different XControl that has the same name, you have to unload all instances of XControls first, which you do by unloading all VIs that reference that XControl.

We're not completely sure about Rule 4 yet, but we're 90%:

4. SubVIs aren't the only things that can cause XControls to be loaded.  Class constants, invoke nodes, property nodes, and possibly reference wires also cause XControls to be loaded.

So, if I make a VI "bar" that has a property node for XControl "foo", but I don't actually place "foo" in VI "bar", "bar" will still load "foo", even though "bar" doesn't actually have "foo" in it.  It's enough that "bar" has a property node for "foo".**

Rule 4 is what makes our lives miserable.  To work around it, we will make subVIs which contain property nodes for "foo", and dynamically load these subVIs. This way, we can keep all references to "foo" out of our shell VI, and force (well, convince really) LabView to unload an XControl so we can load a different one when we want.

I'll post some actual code in a bit, but I'm hoping that somebody understands and knows of a magic brick in LabView that will take us to the Warp Zone and solve all our problems* -- either that, or maybe 8.1 will make us happy.

best -- Michael Ashton, Texas Instruments

* apologies for Super Mario Bros. reference

** Further evidence in support of Rule 4: I made such a VI and looked at the VI file in a text editor. I found my XControl's base name embedded in the binary rubble. I think it's a sign.

0 Kudos
Message 1 of 6
(3,365 Views)
The code promised in my last post is attached in "foofun.zip". It has the following things:

- Two XControls, each named "foo". One is in folder "foo1", the other in folder "foo2". Although named the same to LabView, we will call them foo1 and foo2.

- Each XControl directory has a wrapper VI called "foo.vi" which puts out a reference to the XControl it contains. - A VI called "samefoo.vi", explained below.

- A VI called "anyfoo.vi", explained below.

- A property wrapper VI called "prop_whoareyou.vi". This is used by anyfoo.vi and is explained below.

The XControls


The XControls called "foo" each have a label. In foo1, the label reads "This is foo1"; in foo2, the label reads "This is foo2".

Each "foo" also has a property called "whoareyou". This property is read-only and returns a string. In foo1, the string is "foo1"; in foo2, the string is "foo2".

samefoo.vi


samefoo.vi loads the wrapper VI of your choice into a subpanel. The wrapper VI contains the XControl and outputs a reference to it. We downcast this reference to the type of the "foo" XControl.  Normally we would use this reference to invoke properties etc., but here we don't do anything with it, so that we can demonstrate the evil side-effect of a class type specifier. More on that in a bit.

When you run samefoo.vi, it presents a file dialog. Select one of the wrapper VIs -- either foo1\foo.vi or foo2\foo.vi. (If you choose a different one, you will get a type mismatch error.)

Now, we would like foo1\foo.vi to load foo1, and foo2\foo.vi to load foo2, but that's not what happens. Instead, both wrapper VIs give us foo1. It doesn't matter which one we load first: we always get foo1.

Why? We're not positive, but we're pretty sure that the culprit is the class type constant. This causes LabView to store some kind of reference to an actual XControl (rather like a static VI reference). In this case, I used foo1 to get the class name, so that's the one that samefoo.vi is eternally stuck with.

anyfoo.vi

As the name implies, "anyfoo.vi" is our solution to the "samefoo.vi" problem. Like samefoo.vi, it has a subpanel and loads a wrapper VI into it. Unlike samefoo.vi, it will load either foo1 or foo2, depending on the wrapper you choose. It can also call the "whoareyou" property on either foo1 or foo2 and get the correct result.

anyfoo.vi does this by not including a class type constant or a property node (the latter has the same pernicious effect). Instead, it uses the class type constant and property node in prop_whoareyou.vi. That VI's purpose is to call a property on an XControl in a wrapper VI. It takes as input a reference to the wrapper VI, calls the promised property, and outputs the result.

Note that the prop_whoareyou.vi is dynamically loaded. We can't use the VI itself, because that would cause anyfoo.vi to be stuck with a reference to foo1 or foo2. We can't use a static reference for the same reason.

The key is load order. anyfoo.vi loads first, when we open it. It has no references to XControls, so no XControls get loaded. When we run anyfoo.vi, it loads one of the wrapper VIs first. This loads the XControl we want. After that, we load the property wrapper VI. There only needs to be one of these, because even though the property wrapper VI has references to one of the foo XControls, it will always use the foo that's already in memory.

Therefore, it's critical to load the wrapper VI before the property wrapper VI. Otherwise, either of the foos will load, we won't be able to choose which one, and it will be stuck in memory until the property wrapper VI is unloaded.

The verdict

Apparently we can get the effect we want, but we have to resort to evil chicken-wire-and-chewing-gum trickses, and the process is very inefficient. But it's the best we can think of. If anybody knows of a better or more efficient method, we'd love to hear about it.

And NI -- if you were to add some streamlined method for this to LabView 8.1, you would hear not a peep of complaint from us ...

0 Kudos
Message 2 of 6
(3,354 Views)
Hi mpa,

Thank you for your feedback on your XControls project. It sounds very interesting! Unfortunately, I can't see the logic in having multiple XControls named the same thing (foo.xctl). If you want to dynamically load separate XControls into memory using your wrapper VI, you will have to name the XControls themselves separate things.

You are correct about number 4. For your information, you can view exactly when LabVIEW loads a certain XControl into memory, because it locks the XControl VIs themselves. So if you are developing in a Project, then you will see a red padlock icon appear over your XControl file whenever you open a VI that contains the XControl, a reference to it, a class specifier constant, or a property node.

There really isn't any workaround except for dynamically loading everything along the way to avoid these naming collisions, but again, I don't see why there should be a workaround. Can you clarify what you're trying to accomplish by having XControls with the exact same names? I'd love to help!
Jarrod S.
National Instruments
0 Kudos
Message 3 of 6
(3,326 Views)
"Thank you for your feedback on your XControls project. It sounds very interesting! Unfortunately, I can't see the logic in having multiple XControls named the same thing (foo.xctl). If you want to dynamically load separate XControls into memory using your wrapper VI, you will have to name the XControls themselves separate things."

* If you can suggest a better method of calling different XControls having the same methods and properties with the same code, I'm all ears. I think I explained what we want to do in my post; was it unclear? My examples demonstrate the essence of what we're trying to do. Are you familiar with polymorphism, as used in C++, Ada, Python, etc. (not as used in LabView -- that's overloading)? That's what we're going for.

* We don't want to load them all at the same time, so it doesn't matter if they have the same names.

* Yes, I know that naming them all the same is an ugly hack (and I already said as much). Once again, if you can suggest anything better, fire ahead.

0 Kudos
Message 4 of 6
(3,320 Views)
Hi again,

I got an example working that effectively abstracts the dynamic calls from the user and instead exposes only a common interface. It does this using a root XControl that dynamically instantiates the foo VI wrappers. The root XControl then has its own property nodes which would in turn call the foo property nodes dynamically. It appears to work, and it certainly looks a lot cleaner. Have a look.

Unzip the VIs, then open the foofun_project file. The example in question is called Example_with_root_foo.vi. Let me know if you have any questions. You can also contact me by calling in on your service request number. I've taken ownership, so you'll get routed directly to me.
Jarrod S.
National Instruments
0 Kudos
Message 5 of 6
(3,315 Views)
Hi Jarrod -- now that's a clever idea! It certainly would turn the interface back into something more like we'd hoped at the beginning.

Thanks for setting this up -- we'll look at it.

best --mpa
0 Kudos
Message 6 of 6
(3,304 Views)