LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LabView user-event from external dll source

If you want to do simple IO operations, why do you think you will need LVPostUserEvent()? That only makes sense if you want to call APIs that need a callback function. Otherwise you would need to create a thread in your C code that does synchronous DAQmx API calls and then translate the end of certain calls into LabVIEW user events, but that would be definitely advanced C programming and I think you shouldn't attempt to do that considering the C expertise you said to have and the time constraints of your project.

 

As long as you call only synchronous APIs, and DAQmx consists mainly from synchronous APIs, there is no reason to try to call LVPostUserEvent() from your C DLL.

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
0 Kudos
Message 41 of 56
(967 Views)

Ok, it seems complicated. So what do yo suugest, besides upgrading the software?

 

I mentioned LVPostUserEvent because the examples I was reading use the hardware internal clock. They use callbacks to post the data.

 

Could I write a C program and implement another mechanism for writing and reading to/from LV7.1 like TCP/IP or something like that?

 

Regards,

 

Roberto.

0 Kudos
Message 42 of 56
(959 Views)
and then use it in LabVIEW like this:
 
...           ...             ...                       ...                   ...
 
Is there a way to do this in C#?
0 Kudos
Message 43 of 56
(736 Views)

@Lexilighty wrote:
and then use it in LabVIEW like this:
 
...           ...             ...                       ...                   ...
 
Is there a way to do this in C#?

Please give a bit more background information! Generally there is no easy way to do that. PostLVUserEvent() is as far as C# is concerned an unmanaged API. You can't link in the labviewv.lib import library to access that API so have to define your own interface definition in C# that handles the managed<->unmanaged interface. In addition the location of that API is not static since it is either located in labview.exe when you run in the development system and in lvrt.dll when you run it in a build application (und under some rare circumstances even in other DLLs).

 

Generally it is much easier to create a .Net assembly in C# that exposes an according event  and then interface to that .Net assembly through the LabVIEW .Net interface. There you can directly create LabVIEW callback VIs that get invoked when your .Net event is triggered from inside your assembly.

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
0 Kudos
Message 44 of 56
(727 Views)

Hi.

 

I am trying to implement a small test using PostLVUserEvent in a DLL, and need to set the LVUserEventRef. I use the Import Share Library wizard, and everything seems ok, but when I try to connect "user event out" to the approprialte input of my function, I get following error:

 

These cannot be wired together because their data types (numeric, string, array, cluster, etc.) do not match. Show the Context Help window to see what data type is required.
The type of the source is User Event Refnum.
The type of the sink is unsigned long [32-bit integer (0 to 4,294,967,295)]. 

 

My function is defined like  this: 

 

DLLIMPORT void setEventRef(LVUserEventRef *rwer);

 

 

--

Dag Magne

0 Kudos
Message 45 of 56
(608 Views)

The import library wizard is not meant to be used for such custom DLLs. You have to change the parameter yourself to "Adapt To Type" and then wire your user even refnum to that parameter.

 

If you work with LabVIEW specific datatypes, the normal workflow is rather the opposite. You create the VI with the Call Library Node and then select "Create C Code" from the popup menu of the Call Library Node to let you create a C source file with a compatible empty function body.

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
Message 46 of 56
(597 Views)

Hi, and thanks for the swift answer.

 

 

This is a little confusing, as even the "configure" dialog of the "Call Library Function" node advertises "Consider using a wizard instead..."  :-)

 

I created a new  "Call Library Function" node, and configured a single argument of type: "Adapt to type". 

the "Create C file" option then produced this code:

 

/* Call Library source file */

#include "extcode.h"

void SetUserEventRef(void *arg1);

void SetUserEventRef(void *arg1)
{

/* Insert code here */

}

 

Changing my DLL code to match the generated C-kode and using "Call Library Function" nodes ( instead of nodes generated by the wizard) seems to work, and I now have a node that generates user events.

 

I also tried to change the calls in my header into "DLLIMPORT void setEventRef(void *userEventRef)" and re-run the import wizard, using control type "Cluster" in the "Configure VIs and controls" tab, as this seems to use "void *" for the argument, but this failed in the last step of the wizard, and no node was generated.

 

I guess I'll stick to using the  "Call Library Function" nodes then.

 

--

Dag Magne

 

 

0 Kudos
Message 47 of 56
(565 Views)

      This is a little confusing, as even the "configure" dialog of the "Call Library Function" node advertises "Consider using a wizard instead..."  :-)


 

Well, 98% of the people wanting to use the Call Library Node do want to interface to an existing DLL from another source that knows absolutely nothing about LabVIEW datatypes. Your use case is the absolute exception outside of NI. NI uses these features all the time for their own drivers and libraries, which supposedly is the main raeason they even exist!

 


     I created a new  "Call Library Function" node, and configured a single argument of type: "Adapt to type". 

     the "Create C file" option then produced this code:

 

    /* Call Library source file */

    #include "extcode.h"

    void SetUserEventRef(void *arg1);

    void SetUserEventRef(void *arg1)
    {

          /* Insert code here */

    }


 

You should wire the correct datatype to the Call Library Node before creating the C source code. LabVIEW then can often infer a more suitable datatype in the parameter list.

 


     I also tried to change the calls in my header into "DLLIMPORT void setEventRef(void *userEventRef)" and re-run the import wizard, using control type "Cluster" in the "Configure VIs and

     controls" tab, as this seems to use "void *" for the argument, but this failed in the last step of the wizard, and no node was generated.


The void * datatype gives the wizard ABSOLUTELY no information, other than that it is SOMETHING! Because that is what a void * pointer means. LabVIEW does not know a datatype ANYTHING YOU WANT and conceptually can't, so the wizard has to take a deep sigh, throw its hand in the air and stop in despair at its task.

 

The Call Library Node interfaces on a much deeper level to external code than what you as LabVIEW user are normally used to work with. That is because the DLL interface is designed to work with all compiler types including C which is really just a tiny bit above assembly level in terms of automatic handholding during programming and debugging. The import library wizard is an attempt to ease that process, but the whole task is conceptually absolutely impossible to fully automize, since the C syntax in the header only provides the tiniest of the necessary information for such an automatic task. Once you have run the wizard most of the tedious manual work of creating VIs has been done, but the difficult task only begins! You have to go into each VI, open and control and quite often adjust the settings that the Call Library Node has made for you, with a very good understanding of the DLL interface just as if you would use it in a C program. Anything else is roulette play! It may work or may not, and it may crash, eat your harddisk or burn a hole in your monitor! Smiley LOL And it may do these things only after you deployed the application to the other side of the world.. A misconfigured Call Library parameter or to small allocated array or string buffer will always cause corrurption, but such corruption may go undetected for a while.

 

If you ever work with the Call Library Node and suddenly notiice rare crashes, even long after you run through your Call Library Node, you know for 99% sure that your Call Library Node has a problem. But if it doesn't crash, not even when you close LabVIEW at the end, you still don't know that you have NO problem with them.

 

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
Message 48 of 56
(546 Views)

Hi!

This examples work fine for my driver application, but does not fullfill my needs.

In my case the number of user event registration is variable, so i made a for loop around the dynamic registration event and test it with 2 registrations. The odd thing is the registration in the dll library (with call library node) is done twice with the same LVUserEventRef pointer as the reference to register event is different.

 

So triggering different user events are handled by the same (last registered) event. 

Also one dll user event is handled twice in the event loop.

For call Library node is configured Type= "adapt to type" Data Format= "Handles by Value".

 

The entry point looks like this:

MgErr err = PostLVUserEvent(*((LVUserEventRef*)notification_), (void*)&data);

 

Is there proper manner to register mulple user events to an external dll library?

 

 

 

 

0 Kudos
Message 49 of 56
(336 Views)

Your external DLL needs to maintain somehow a reference for each user event refnum. How to do that is a complicated exercise that very much depends on your use case.

Personally in my libraries I usually have something like a device refnum that is passed to all functions. That device refnum is a pointer to a dynamically allocated DLL internal structure that stores all kind of information that the various functions require to work with for this device. Because the information is all stored inside this device refnum rather than a DLL gobal variable, I can instantiate multiple devices in parallel, each with its own device refnum. Inside that device refnum one can then store the event refnum. If you have multiple possible events per device you somehow need to store each of these event refnums in a seperate location.

The example here is not meant to teach you how to write a proper resource managed device driver but only how the PostLVUserEvent() needs to be called. It is also not meant to be a teaching class in proper C programming either. That is why it uses a DLL global variable to store the event refnum in and the nature of a global variable is that it can only be used for one thing at the same time. If your needs are bigger, then that you will have to setup a proper infrastructure handling in your DLL. You can't expect a LabVIEW specific example to be a proper example of doing such a complex infrastructure.

 

Using global variables for simple C code examples is a common technique since it is quick and doesn't complicate the code with additional resource management tasks. It is however almost always the wrong thing to do for real code!

Rolf Kalbermatter
Averna BV
LabVIEW ArchitectLabVIEW ChampionLabVIEW Instructor
0 Kudos
Message 50 of 56
(327 Views)