Recently I have been exploring how to best expose actor-oriented LV code to .Net developers. I created a simple Metronome actor (not AF) in Labview and built an interop assembly. I also have created a simple c# client app to call the assembly. However, I'm getting an exception when I call the assembly method that invokes LV code initializing the actor.
The exception message is:
Failed to convert the LV Class to the .NET class because LV cannot get the LV Class Instance.
For reference, here's the C# code that generates the error. (Attached zip file contains entire LV and VS projects as well as the built assembly.)
// Create the message queues MessageQueue metQ; // Queue to send messages to the metronome MessageQueue myQ; // Queue to receive messages from the metronome MessageQueue.Init(out myQ); // Create the metronome and launch it under a Labview logical thread Metronome met; Metronome.Init(myQ, out met, out metQ); // Raises Exception
And here's the equivalent LV code using the same vis the .Net assembly delegates to, which works just fine.
The MessageQueue.Init method isn't doing anything particularly complicated. It accepts and stores myQ so the Metronome can send messages out, creates, stores, and returns metQ so it can receive messages, and returns a newly created Metronome object. That's it. There are several layers of abstraction between the exposed MessageQueue object and the native LV queue, but I don't think that's related to the error I'm seeing.
Does anyone know what might be causing this error?
[Closely related cross-post on LAVA.]
First of all can you elaborate a little more on what the Visual Studio code, is that the Metronome or is the Metronome in LabVIEW. So you are calling the Metronome through LabVIEW correct? Is there an error code/number that you get with your error?
Thanks for taking a look at this Basil. Actually, you have it backwards. I've attached another zip. Functionally I think it's identical to the earlier one, but I've added more icons to the vis and comments to SimpleTest.vi. Hopefully it will help.
The Metronome is implemented in Labview. LapDog.Metronome.lvlib contains the Metronome class and the message classes for interacting with a running metronome. The core metronome functionality is implemented in ExecutionLoop.vi. SimpleTest.vi is an example of how the Metronome is used in Labview. This verifies the metronome is working as expected.
The Interop Layer folder contains simple wrappers around the classes in the LapDog.Metronome library. The MetronomeInterop build spec only references the vis in the Interop Layer folder. InteropLayerTest.vi does the exact same thing as SimpleTest.vi, except it uses the Interop Layer vis instead of the LapDog.Metronome library. This vi verifies the interop layer vis work as expected.
Ultimately what I'm trying to do with this prototype is write c# code that uses the metronome in the same way SimpleTest and InteropLayerTest do. The c# code isn't complete yet, but I've run into this error and it is blocking further progress. The exception is occurring when I run the c# code. The only information visual studio is giving me is,
Exception Type: NationalInstruments.LabVIEW.Interop.VIAssemblyException
Exception Message: Failed to convert the LV Class to the .NET class because LV cannot get the LV Class Instance.
If I recall correctly the exception only occurs on methods that have both input and output parameters. So,
MessageQueue.Init(out myQ); and
do not raise an exception, but
Metronome.Init(myQ, out met, out metQ);
I don't know if there's something wrong with my interop build spec, if there's an error somewhere inside Labview, or if I'm just trying to do something that isn't possible.
(If the LapDog.Messaging library is confusing you, it's easiest to think about it as an OO implementation of string/variant messages.)
I should also explain what the metronome is intended to do...
The purpose of the metronome is to send a specific message at regular intervals. It runs as a parallel logical thread, and sending a message at regular intervals is all it does. I use them to send messages to message handling loops when some action needs to be done regularly and I don't want to rely on the Dequeue timeout.
I'm working on playing around with your code to see if I can get anything figured out. I'll post back when I make any headway.
Have you made any progress on this? Do you understand what I'm trying to do, or do I need to explain it further?