LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

.NET ArrayList into LabVIEW

Joe, I apologize. I sent an e-mail at about the time you started this thread that may have helped, but apparently I did something silly on my end and it never actually got to you. From your description it sounds like you have actually written a wrapper for your .NET control using VB6 so that you can get LabVIEW's ActiveX Container to host it. You actually don't need to do this; there are just some extra registry keys that LabVIEW expects that regasm doesn't set up. I'm reading from handwritten notes I wrote some time ago here, so try this and if it doesn't work, I'll poke around and look for my prototype.

You need to have regasm generate a separate .TLB file (I think that's the regasm /tlb flag).
Then add these registry keys:
HKCU\CLSID\{clsid}\Control
[No value under this key]
HKCU\CLSID\{clsid}\TypeLib
(Default) value (string) = {typelibid}
HKCU\TypeLib\{typelibid}\1.0\0\win32
(Default) value (string) =

{clsid} and {typelibid} are the GUIDs of the COM CoClass and TypeLib, respectively.

Maybe with one less level of indirection you'll have better luck with your ArrayList problem. Definitely, your "non-optimal workaround" is dicey at best--I don't think the container has full knowledge of the control, so some of the interaction it manages, like various Windows messages, probably won't work right.

Let me know how this goes and if it helps.

George Erwin-Grotsky
National Instruments
George Erwin-Grotsky
National Instruments
LabVIEW Research & Development
Message 11 of 21
(3,049 Views)
George:

You are correct about what we are doing. We have written a VB6 wrapper around a .NET control so that we can host the .NET control in a LabVIEW ActiveX container.

You will need to excuse me for my lack of understanding of .NET/C# and the finer differences between .NET controls and ActiveX controls, but what do the registry modifications you propose do? Will this let me use a .NET conrol directly in the LabVIEW ActiveX container?


Joe
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 12 of 21
(3,045 Views)
Brian:

RE: problems emailing the LV/VB/.NET example program, code is attached to this email.

Instructions for code use:
1) Run setup.exe to put the VB OCX and VB engine onto your computer (you will get an uninstall option in your Add/Remove programs Control Panel).
2) from the VS .NET command prompt, go to the directory where you installed the OCX, and type "regasm DotnetCtrl.dll /codebase" to register the assembly.
3) In LabVIEW, add the DotnetCtrl.dll assembly to the .NET Assembly References.
4) In LabVIEW, add c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll to the .NET Assembly References (this contains the ArrayList).
5) Open Untitled.vi (the VI should be in the same directory as the OCX in order to load the .NET control).

If everything is all right, the front panel should come up with a .NET control in an ActiveX container (the control should have the current date and time, along with a functional "click me" button). On the block diagram, we take the OCX reference and get the .NET reference (property "CtrlFromDotNet"). The .NET reference can pass out an ArrayList reference with the "getArrayListData" method.

LabVIEW knows that this is an ArrayList, but there are no properties or methods available with it. If I create an ArrayList assembly reference in LabVIEW, and try to type-cast the .NET-provided one to this, I can see the properties and methods it should have, but get an error when I try to use them (it appears the type-cast reference is a null reference).
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 13 of 21
(3,040 Views)
I assume that you are "exposing" your .NET control as a COM object so that VB6 actually sees it as an ActiveX control. At minimum this involves setting some System.Runtime.InteropServices.GuidAttribute attributes and running regasm to register it in the assembly. For best results, you want to not use the default "Class Interface" that .NET will construct, but define your own interface for COM access. Search around MSDN and you'll find the stuff if you haven't already.

The keys I listed are probably older COM/ActiveX registry keys that often aren't needed by newer COM/ActiveX hosting programs, but that LabVIEW still looks for. I know that the "Control" key falls into that category for sure. So, basically, this just has to do with making the .NET control appear to be an ActiveX control so that it can drive it as one.

The magic that makes this work is in the System.Windows.Forms.Control base class. Microsoft tuned it to work with Internet Explorer, and they have disclaimed any support for other use of it -- so this is use-at-your-own-risk. See http://msdn.microsoft.com/msdnmag/issues/01/08/interop/ for more about it. That article now has a disclaimer saying that you cannot create .NET Controls using CoCreateInstance (as LabVIEW's ActiveX Container would do), but I know I've gotten it to work.

That said, before you spend time monkeying around with this, realize that this will only remove the extra indirection of the VB6 wrapper. LabVIEW will still see the .NET Control as an ActiveX control, and I don't know that there is any way to trick it so that you can access properties and methods that use other than the basic data types.

George Erwin-Grotsky
National Instruments
George Erwin-Grotsky
National Instruments
LabVIEW Research & Development
0 Kudos
Message 14 of 21
(3,037 Views)
George:

I talked with my .NET counterpart, and yes, we are exposing the .NET control as a COM object for VB6. Unfortunately, we have several hundred .NET controls we would like to provide to LabVIEW eventually (I would be happy to get one to work well right now), so we are looking for a more generic approach to this problem than having to map each property and method for each control explicitly through VB. LV8 is one solution, but we are on a release deadline (for at least alpha/beta) before LV 8 will be available (or so I have been told).

The "non-optimal" solution I mentioned a few posts back seems to have a few advantages over your proposal. The largest one is that I have the reference for the .NET control, so I have access to all the .NET property/methods, using a LV-approved method to get there (e.g., the reference was created with a .NET assembly Contructor Node). This allows me proper access to complex data types such as arrayList. The biggest drawbacks with my non-optimal method at this time are 1) the backwards way of getting the control to display on the ActiveX container (including inability to size the control in Edit mode); and 2) no support for events from the .NET control (another LV 8 feature!).

Please let me know if I have misunderstood what you have proposed or any advantages of your method.
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 15 of 21
(3,032 Views)
Okay, I've got some answers for you.

Short Answer: Change your .NET class to expose an IList rather than an ArrayList.

Long Answer: You've never had a .NET refnum out of your ActiveX control. It has always been an ActiveX refnum and therefore is restricted to what is defined in the type libraries. So the goal is to use the right .NET interfaces that have a rich COM image.

Here are the details of what is going on.

When you embed your .NET class into VB6, it creates a COM Wrapper around the .NET class (aka CCW). When this happens, it needs to expose all the various .NET thingies as COM interfaces and this is what it does. For example, here's a snippet from the TypeLib for mscorlib - the fundamental .NET assembly:


[
uuid(BED7F4EA-1A96-11D2-8F08-00A0C9A6186D),
version(1.10),
helpstring("Common Language Runtime Library")
]
library mscorlib
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");

// Forward declare all types defined in this typelib
interface ICloneable;
interface IEnumerable;
interface ICollection;
...


Unfortunately, if you take a look at \Microsoft.NET\Framework\v1.1.4322\mscorlib.tlb with something like OleView, you'll see that the interface you're exposing (_ArrayList) is nothing but an IDispatch. Thus there are no methods or properties for LV to get ahold of.


[
odl,
uuid(401F89CB-C127-3041-82FD-B67035395C56),
hidden,
dual,
oleautomation,
custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "System.Collections.ArrayList")
]
interface _ArrayList : IDispatch {};


Bit scanning down a bit further you'll see that there is a CoClass for ArrayList:


[
uuid(6896B49D-7AFB-34DC-934E-5ADD38EEEE39),
version(1.0),
custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "System.Collections.ArrayList")
]
coclass ArrayList {
[default] interface _ArrayList;
interface _Object;
interface IList;
interface ICollection;
interface IEnumerable;
interface ICloneable;
};


This shows you all the other possible interfaces to consider. ArrayList is simply an implementation of the .NET IList interface, so you can expose that from your class instead. If you look for the definition of IList in the TypeLib, you'll see that it does expose all the methods you want.


[
odl,
uuid(7BCFA00F-F764-3113-9140-3BBD127A96BB),
version(1.0),
dual,
oleautomation,
custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "System.Collections.IList")
]
interface IList : IDispatch {
[id(00000000), propget]
HRESULT Item(
[in] long index,
[out, retval] VARIANT* pRetVal);
[id(00000000), propputref]
HRESULT Item(
[in] long index,
[in] VARIANT pRetVal);
[id(0x60020002)]
HRESULT Add(
[in] VARIANT value,
[out, retval] long* pRetVal);
[id(0x60020003)]
HRESULT Contains(
[in] VARIANT value,
[out, retval] VARIANT_BOOL* pRetVal);
[id(0x60020004)]
HRESULT Clear();
[id(0x60020005), propget]
HRESULT IsReadOnly([out, retval] VARIANT_BOOL* pRetVal);
[id(0x60020006), propget]
HRESULT IsFixedSize([out, retval] VARIANT_BOOL* pRetVal);
[id(0x60020007)]
HRESULT IndexOf(
[in] VARIANT value,
[out, retval] long* pRetVal);
[id(0x60020008)]
HRESULT Insert(
[in] long index,
[in] VARIANT value);
[id(0x60020009)]
HRESULT Remove([in] VARIANT value);
[id(0x6002000a)]
HRESULT RemoveAt([in] long index);
};


Moral of the story - keep to the ActiveX palette if you have wrapped a .NET class in a COM wrapper and choose your exposed interfaces wisely.

Let me know if (a) this works for you and (b) I can be of any more help.
Message 16 of 21
(3,029 Views)
Joe,
I think you have a good understanding of the tradeoffs. There is no nice answer in LV7.1.
George Erwin-Grotsky
National Instruments
LabVIEW Research & Development
Message 17 of 21
(3,023 Views)
Brian:

Tried what you suggested, but I end up with an invalid reference for the IList. All the properties/methods show up in the Property/Invoke nodes, but I get Error 1 when accessing them. We had tried the same thing earlier in type-casting the VB-supplied reference to an arrayList: you can see all the properties/methods, but the reference is invalid so you cannot use them.


J
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 18 of 21
(3,020 Views)
One other item I will add for the completeness of this topic. In order for the .NET control to be fully functional when painted on the ActiveX container, we needed to set the thread (Execution System) for the VI containing the .NET/ActiveX control to "User Interface". If we do not, events that are generated in the .NET control are lost as the .NET control is in a different thread than the ActiveX container (the .NET reference being on the block diagram in the "Standard" thread, and the ActiveX container being on the front panel in the "User Interface" thread). This is not a problem for simple .NET controls, but more complex ones may experience it!


Joe
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 19 of 21
(2,756 Views)
Brian:

Attached is the VB project we used to transfer the handle from .NET to LabVIEW.
Joe Gerhardstein
Viasat
Certified LabVIEW Architect
Certified TestStand Developer
Certified Professional Instructor
http://www.viasat.com
0 Kudos
Message 20 of 21
(2,906 Views)