Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Calling LabVIEW dll with LVRefNum * parameters from .Net

I created a .vi which has input and output terminals defined as .Net object (by creating controls and indicators against the .net terminals of To Object.vi and To Variant.vi)  When I build my vi as a dll and add these paramters to the method signature they are defined as LVRefNum *.  What do I need to do with my objects (in this case CWIMAQPoints and CWIMAQLine) in order to pass them properly to the method?  How should my method signature after DllImport be defined?
 
-Matthew
0 Kudos
Message 1 of 10
(6,209 Views)

Hi Matthew,

I am not too familiar with IMAQ stuff, but just as a note LVRefNum is a simple 32 bit pointer. Depending on the IMAQ object, you probably can just typecast them to get the actual value.

Will it be possible for you to post a sample code, so I can look further in the use of IMAQ objects?
 
The example I was referring to earlier does not make too much sense here. Sorry for the broken link.
 
Regards,
Ankita
0 Kudos
Message 2 of 10
(6,183 Views)
Attached is a simple example of LabVIEW code that uses the .net object to variant and variant to .net object VIs  This example simply takes two floats and multiplies them together to return a result.
0 Kudos
Message 3 of 10
(6,174 Views)
And here is an example console application that tries to call the LabVIEW multiply code.
0 Kudos
Message 4 of 10
(6,177 Views)
HI Matthew,
 
I am working on your VIs and need a  little more time before I can get back to you.
 
Ankita 
0 Kudos
Message 5 of 10
(6,150 Views)

Hi Matthew,

After trying your aplpication I have found that the "to .NET object" and "from .NET object" in LabVIEW are used when calling the .NET assembly in LabVIEW. At this time they do not support exchanging values with other .NET environment from inside LabVIEW DLL.

The best way to use a LabVIEW DLL in .NET environment would be by creating a simple C style DLL and calling it like any other un-managed DLL. Some good resources to call LabVIEW DLL in .NET would be as follows:
Bilal's Response on http://forums.ni.com/ni/board/message?board.id=232&message.id=1881
How Do I Import a DLL in Microsoft Visual Studio.NET?

Please let me know you have any more questions.

Regards,
Ankita Agarwal

0 Kudos
Message 6 of 10
(6,136 Views)

Ankita,

Thank you for taking a look at it.  Yes, I have used the to .Net and from .Net when calling C# dlls from within LabVIEW.  Was hopefult that this was a route around the process switching overhead that I am suffering going the COM interop route.  I'll head over to your recommended thread and see what I can find.

Thanks,

Matthew B.

0 Kudos
Message 7 of 10
(6,132 Views)
Matthew,
 
Ankita is correct - you can't pass in a .NET handle to a LabVIEW DLL. While we support .NET integration within LV, it is from starting in LV and calling into .NET. Remember - LV itself isn't managed code (its unmanaged C++) and so can't take a direct .NET handle. No matter what, calling LV from .NET means going from managed to unmanaged code. For this reason, I wouldn't worry about using the P/Invoke scheme to call the LV DLLs.
 
In case you're curious, the .NET refnum is a couple levels of indirection from .NET. The first level is what is known as a GCHandle. Because .NET's garabage collector can reassign the address of any managed pointer at any time, you can't take a managed pointer outside of .NET (such as into LV). Instead, you have to get a "ticket" for the pointer - a GCHandle.
 
However, a GCHandle tells the GC that it can't reclaim the object because someone "out there" is using it. If you never destroy the GCHandle, you'll end up with a memory leak in .NET. Therefore, LabVIEW has an internal tracking mechanism for the GCHandle so that even if forget to close the reference to the refnum, we will clean it up for you when the top level VI stops. So we have our own "ticket" for the GCHandle. That second ticket is what you actually have when you have a refnum. All of this is internal implementation, subject to change, not documented, not exposed, yada yada yada.
 
P.S - If the refnum was created by LabVIEW (in other words, you create the .NET object from within a VI) and returned to you in .NET-land, then you can pass it back to us (via the P/Invoke) and another VI can use it.
0 Kudos
Message 8 of 10
(6,110 Views)
Slick!  Can you point me to any more reading (either NI or Microsoft) on this route for interacting with .Net?  Sounds like this is a faster route than all of the COM calls I am making currently and (maybe?) avoids flattening to a string or array that then needs to be reconstituted.  I'll run a few experiments and reply again soon.  One follow up question for you...  Sounds like you are hanging on to the GCHandle for the life of the LV server and not the lifespan of an individual VI execution, correct?  Or does it live on specifically if the GCHandle is passed back to the caller?  Do I need to call anything special to have LV hold/release the GCHandle?  Implementation disclaimer received...  just hope I'm not the lone voice pushing for increasing .Net support and that things continue to improve even if I need to do some rework to get to the "supported" version.

Thanks,
Matthew
 
0 Kudos
Message 9 of 10
(6,107 Views)
If you're doing a lot of interop, the absolute and final bible is the book by Adam Nathan - .NET and COM, The Complete Interoperability Guide. Warning - it is very large - it covers EVERYTHING about interop. I would also recommend checking out pinvoke.net on the internet. It is a wiki setup by Adam to keep a list of P/Invoke signatures for the Win32 API. Good place to get examples.
 
The key difference between COM inteorp and P/Invoke really comes down to what you are calling. If you have a COM interface, then COM interop is the only way to call it. Same for C API calls - P/Invoke is your only option (well, there is IJW in managed C++ - very good option if you are going to do a lot of managed/unmanaged interop). In the end, they do share a lot of common code - ie calls to the .NET marshaller. Whether you can avoid flattening strings and arrays and such depend really on what is on each side of the call.
 
As far as the GCHandle, it's held only as long as the top level VI is running. My blog goes into a lot more detail, but in summary - we create a .NET AppDomain for each top level VI that executes. When that VI stops running, the AppDomain is torn down. Before we tear it down, we go through all of our "tickets" (okay okay, we call them cookies internally so I'll switch to that...too confusing to keep two terms in my head)..huhhmm...cookies and release them - thus releasing the GCHandles. Note that any subVI called by the top level VI can start and stop 100 times and we won't destroy the cookies - only when the top one stops.
 
This is actually where the problem can come in. If you don't manually close a .NET refnum and leave it up to LV, you can leak memory. Consider a subVI that creates a .NET object but doesn't close the refnum. Now call that in a while loop from another VI. Leave it running and you are going to run out of memory. So, remember to use the Close Reference VI when you are finished with an object.
 
Whew...let me take a breather...
 
okay, final q/a...
 
As far as I am concerned, there is a lot more support for .NET that I would like to see added. Obviously I can't say what is and isn't going into future releases but I am very interested in hearing from the community about what is missing. Feel free to ping me at my blog if you have anything to say on that topic.
 
Also - do let me know what you are doing with .NET. I want to get a sense of what people are doing with the feature. It helps to shape the future support we add.
 
0 Kudos
Message 10 of 10
(6,099 Views)