Jump to content

Events from within .Net Interop Assemblies?


Recommended Posts

I know how to call and use .Net from within Labview, and I have on a few occasions compiled LV code into dlls and called them from other languages.  What I'd like to do is compile Labview actor-oriented code (not necessarily based on the Actor Framework) into an interop assembly and be able to exchange messages with it from .Net languages.  The idea is to have the Labview code and .Net code running concurrently.  The problem is I don't have much any experience building actor-oriented apps in .Net, or trying to use a message-based interface between LV and .Net.

 

The simplest way to do it would be to expose the actor, queue, and messages as objects through the assembly.  I'd let the .Net code interact with the actor in much the same way parallel loops interact with each other in Labview.  This puts some burden on the .Net developer to write their message handler so it runs concurrently with the rest of their code.

 

A more complex alternative is to write the Labview code so the .Net code registers callbacks with it.  It would be similar to how Labview developers can register for events in .Net components, except the other way around.  To be honest I have no idea how this would be implemented, or if it is even possible.  Would I have to create a .Net class named "Labview Event Handler" and call that from my LV code, while having the .Net developer subclass it for each callback they want to register?

 

Have any of you tried these kinds of things?  Can you share what worked well and what kind of technical obstacles you ran into?  Any inputs or suggestions are appreciated.

Link to comment

I created a simple Metronome actor, built a .Net Interop Assembly, and used dotPeek to poke around in it. 

 

post-7603-0-90286700-1363069383_thumb.pn

 

I'm a little unclear on exactly how one would go about using these objects in .Net code.  For example, Labview doesn't have constructors, so we often manually create our own creators and call them directly.  (i.e. Metronome.CreateMetronome)  However, the .Net Metronome object exposed by the assembly *does* have a constructor... three of them in fact.  So, is the C# code...

 

Metronome m = new Metronome();

 

the .Net equivalent of dropping a class cube on a block diagram?  And I assume I'd have to follow it up with...

 

m = CreateMetronome(OutputQ, InputQ);

 

If so and there's no way to automatically bind the .Net constructor to the CreateMetronome method, then my naming convention sucks and I'll have to redo it a bit.

 

 

  • Like 1
Link to comment
One method to test this is using the .net object in LabVIEW. You might even be capable to debug the .net dll.

 

I have been doing that (see attached zip); I was just hoping somebody else had been down this road and could provide some hints and tips. 

 

For instance, I discovered the .Net methods generated by Labview's interop assembly builder are all static.  I also discovered it mangles my namespaces in ways I don't particularly like.  (Replacing invalid characters with _charcode.)  I ended up adding an interop layer in my LV code for the sole purpose of simplifying the assembly's API.

 

post-7603-0-14368700-1363279041_thumb.pn

 

Another tip I learned:  If you're using LVOOP don't use the new keyword to construct objects exposed by the interop assembly.  You get a search dialog asking for the location of the .lvclass file, which obviously an end user wouldn't have.  Even if I did link to the .lvclass file stuff crashed later on so I'm thinking it's better to avoid doing it completely.

 

My totally awesome and uber-cool sister (who wrote documentation for .Net and WPF for years and might be reading this thread) clued me in.  Instead of...

 

Metronome met = new Metronome(); <--- Triggers a LV find dialog

 

...the code should read.

 

Metronome met;

 

In her words:

 

...when you use an out parameter, the C# specification says that the caller doesn't have to initialize the variable before making the call, but the method guarantees that the variable is assigned when it returns.  Hopefully LV assemblies honors those rules.

 

--------------------------------------

 

Unfortunately I'm still getting errors with any calls into the assembly that have both in and out parameters.  For example, this code works fine:

 

MessageQueue myQ;

MessageQueue.Init(out myQ);

 

...but this code does not:

 

MessageQueue metQ;

MessageQueue myQ;

MessageQueue.Init(out myQ);

 

Metronome met;

Metronome.Init(myQ, out met, out metQ);  <--- Raises error

 

The error is generic and unhelpful.  "MyProj.vshost.exe has encountered a problem and needs to close."  I have no idea why it is occurring or how to fix it.  Any insight is appreciated.

 

(The attached zip file includes Labview source, built assembly, and a C# project that uses the assembly.  It should work out of the box as long as you have the LV2012 runtime installed.)

.Net Interop.zip

Link to comment
  • 1 year later...

Daklu,

 

Were you ever able to get to the bottom of this error?  I'm having the same issue.  I've simplified my code down to a very basic lvclass and still get an exception thrown anytime there's both an input and output of a class as you've shown.

 

Using LV2013, VS2013, .NET 4.0.

 

I've created the lvclass Vehicle, which has 3 methods:

  1. initializeVehicle -- Returns a LV class object.
  2. setMakeModel -- Inputs strings for make and model and stores in class private data.
  3. getVehicleFullName -- Concatenates the make and model strings from the object and outputs the concatenated string.

lvproject.png

 

 

I call this from a simple C# console application:

 

VIE.LVClassTest.Vehicle testVehicle;VIE.LVClassTest.Vehicle.initializeVehicle(out testVehicle);VIE.LVClassTest.Vehicle.setMakeModel(testVehicle, "VW", "Golf", out testVehicle);            string vehicleName = "";VIE.LVClassTest.Vehicle.getVehicleFullName(testVehicle, out vehicleName, out testVehicle);Console.WriteLine(vehicleName);

 

I get a VIAssemblyException at the setMakeModel function saying: "Failed to convert the LV Class to the .NET class because LV cannot get the LV Class Instance."  The function initializeVehicle works fine.

 

 

As a test, I also tried calling the .NET assembly in LabVIEW:

 

lv_vehicletest.png

 

I also get the same exception thrown at the setMakeModel invoke node.  Probing the outputs for the functions, initializeVehicle returns a valid refnum, however setMakeModel returns a null refnum.

 

 

Any thoughts?  Thanks!

 

(Also cross-posted as a reply on NI forums here: http://forums.ni.com/t5/LabVIEW/Problems-exporting-a-LVOOP-class-to-a-NET-interop-assembly/m-p/2801694#M821666 )

Link to comment
I gave NI my test code and they confirmed it was an existing CAR.  It is reportedly fixed in 2013 SP1, but I have not confirmed it yet.

 

Thanks.  Talked with NI and it turns out that this issue (CAR 447058) is fixed in the 2013 SP1 f1 patch.  I've installed the f1 patch and my assembly works fine now.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.