LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Howto pass a callback function to call library function node

I need to implement a progressbar in labview that is updated by a callback routine that is passed to the hardware configuration routine.
So the routine in the DLL is something like: int configure(ptrToCallbackRoutine routine). and CallbackRoutine is defined like int callbackRoutine(int progress, const char* message);
Is this possible in LabView? I just cannot find the right documentation on this subject.
0 Kudos
Message 1 of 16
(7,586 Views)
Almar wrote:

> I need to implement a progressbar in labview that is updated by a
> callback routine that is passed to the hardware configuration routine.
> So the routine in the DLL is something like: int
> configure(ptrToCallbackRoutine routine). and CallbackRoutine is
> defined like int callbackRoutine(int progress, const char* message);
> Is this possible in LabView? I just cannot find the right
> documentation on this subject.

LabVIEW can NOT generate code to pass a callback routine pointer to a
shared library function. You will need to create an intermediate shared
library which creates that callback function and calls your function and
the callback function in that intermediate DLL then needs to somehow
post back the event to LabVIEW.

Possible ways
to do that are:

1) Passing an occurrence refnum to the callback function and invoking

MgErr Occur(LVRefnum refnum);

on that occurrence inside the callback.

2) Using a queue in the shared library have the callback function post
an event to that queue and have an exported function you call from
withing LabVIEW regularly poll that queue.

3) Undocumented and untried as of this day and only available in LabVIEW
7.0 and higher: Pass a user event refnum to the callback function. Have
that function call the LabVIEW function

MgErr PostLVUserEvent(LVRefnum userEventRefnum, UPtr data);

The data pointer supposedly is the pointer to the flattened data for the
data type the UserEvent was registered for, so make sure it matches or
you will crash.

As to how the different data types to 1) and 3) should be interpreted
you should also read throught he "Calling External Code in LabVIEW"
online documentation.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
0 Kudos
Message 2 of 16
(7,584 Views)
Thanx for your fast answer, I've looked into the options you gave me. and the thirth:
MgErr PostLVUserEvent(LVRefnum userEventRefnum, UPtr data);
way seems the most suitable for me. because MgErr Occur(LVRefnum refnum); cannot be given a progress indication.
Just one more question is, do I need to create an event loop? and if so how can I create the LVRefnum userEventRefnum so the event handler can catch that event.
0 Kudos
Message 3 of 16
(7,584 Views)
Almar wrote:

> Thanx for your fast answer, I've looked into the options you gave me.
> and the thirth:
> MgErr PostLVUserEvent(LVRefnum userEventRefnum, UPtr data);
> way seems the most suitable for me. because MgErr Occur(LVRefnum
> refnum); cannot be given a progress indication.

But be aware! I saw this function mentioned here on this forum once and
went out to check if it really existed and what its possible
parameterlist might be. I could not find any documentation anywhere
about it, both with Google nor here on the NI site. So the whole
function is there, but undocumented and the prototype above is just a
somewhat educated guess but not at all tested by me in any way. I could
probably try to get this information confirmed by someone fr
om NI but
have a the moment the time nor the drive to really pursue that.

As to for choosing a solution which is surely compatible and independant
on undocumented functions, only the solution with the queue is actually
available. Going one of the other 2 ways has a chance of breaking with
future LabVIEW versions.

> Just one more question is, do I need to create an event loop? and if
> so how can I create the LVRefnum userEventRefnum so the event handler
> can catch that event.

Yes you need to create and register an user event. Look for "User Event"
example in Help->Find Examples.

Rolf
Rolf Kalbermatter
My Blog
0 Kudos
Message 4 of 16
(7,584 Views)
I've found the PostLVUserEvent function documented in the PDF "Using external code in LabView" and I've seen the prototype in extcode.h (I am using the evaluation version of LV 7.0)
0 Kudos
Message 5 of 16
(7,584 Views)
Almar wrote:
> I've found the PostLVUserEvent function documented in the PDF "Using
> external code in LabView" and I've seen the prototype in extcode.h (I
> am using the evaluation version of LV 7.0)

Thanks for pointing this out. I use still the 6.1 version of the PDF on
my desk and haven't checked the extcode.h lately as I wrongly assumed
there hadn't been any changes. Thanks a lot for that.

Rolf
Rolf Kalbermatter
My Blog
0 Kudos
Message 6 of 16
(7,584 Views)
Well, LabVIEW can generate code to pass as a callback, but you have to use
the application builder to generate a dll...

The function in the dll can signal events to 'normal' LabVIEW code. Then you
can load the LabVIEW dll dynamically, and get it's funcion address.

Regards,

Wiebe.

"RolfK" wrote in message
news:4120c4a2@newsgroups....
> Almar wrote:
>
> > I need to implement a progressbar in labview that is updated by a
> > callback routine that is passed to the hardware configuration routine.
> > So the routine in the DLL is something like: int
> > configure(ptrToCallbackRoutine routine). and CallbackRoutine is
> > defined like int callbackRoutine(int progress, const char* message);
> > Is this possible in LabView? I just cannot find the right
> > documentation on this subject.
>
> LabVIEW can NOT generate code to pass a callback routine pointer to a
> shared library function. You will need to create an intermediate shared
> library which creates that callback function and calls your function and
> the callback function in that intermediate DLL then needs to somehow
> post back the event to LabVIEW.
>
> Possible ways to do that are:
>
> 1) Passing an occurrence refnum to the callback function and invoking
>
> MgErr Occur(LVRefnum refnum);
>
> on that occurrence inside the callback.
>
> 2) Using a queue in the shared library have the callback function post
> an event to that queue and have an exported function you call from
> withing LabVIEW regularly poll that queue.
>
> 3) Undocumented and untried as of this day and only available in LabVIEW
> 7.0 and higher: Pass a user event refnum to the callback function. Have
> that function call the LabVIEW function
>
> MgErr PostLVUserEvent(LVRefnum userEventRefnum, UPtr data);
>
> The data pointer supposedly is the pointer to the flattened data for the
> data type the UserEvent was registered for, so make sure it matches or
> you will crash.
>
> As to how the different data types to 1) and 3) should be interpreted
> you should also read throught he "Calling External Code in LabVIEW"
> online documentation.
>
> Rolf Kalbermatter
>
0 Kudos
Message 7 of 16
(7,587 Views)
Wiebe@CARYA wrote:
> Well, LabVIEW can generate code to pass as a callback, but you have to use
> the application builder to generate a dll...
>
> The function in the dll can signal events to 'normal' LabVIEW code. Then you
> can load the LabVIEW dll dynamically, and get it's funcion address.

Technically you are correct. Practically there are some nitty gritty
details which are not so easy to deal with. First the DLL is as far as I
know always executed in the context of the LabVIEW runtime engine which
is compatible to the LabVIEW version which was used to create it. So if
your main program happens to run in the LabVIEW development system or a
different built LabVIEW application version, the process memory between
the VI memory space in the
DLL and the calling LabVIEW application is
not the same and you get a few problems to actually share data.

A User Event refnum in one context has no meaning to the other context
and you will receive an error 1 (manager argument error or similar) if
you try to pass such a refnum from the calling application to the DLL to
have the DLl work on that. Sharing information through globals directly
(VI globals or LV2 style globals) is definitely not possible as each
application maintains its own VI name space. So you will have to resolve
to interapplication communication such as VI server, shared memory, or
something similar to actually share data, including signaling as
occurrences are also just LabVIEW refnums which only work in the same
process memory context.

Rolf Kalbermatter


>
Rolf Kalbermatter
My Blog
0 Kudos
Message 8 of 16
(7,587 Views)
Rolf,

"RolfK" wrote in message
news:412219de@newsgroups....
> Wiebe@CARYA wrote:
> > Well, LabVIEW can generate code to pass as a callback, but you have to
use
> > the application builder to generate a dll...
> >
> > The function in the dll can signal events to 'normal' LabVIEW code. Then
you
> > can load the LabVIEW dll dynamically, and get it's funcion address.
>
> Technically you are correct. Practically there are some nitty gritty
> details which are not so easy to deal with. First the DLL is as far as I
> know always executed in the context of the LabVIEW runtime engine which
> is compatible to the LabVIEW version which was used to create it. So if
> your main program happens to run in the LabVIEW development system or a
> different built LabVIEW application version, the process memory between
> the VI memory space in the DLL and the calling LabVIEW application is
> not the same and you get a few problems to actually share data.
>
> A User Event refnum in one context has no meaning to the other context
> and you will receive an error 1 (manager argument error or similar) if
> you try to pass such a refnum from the calling application to the DLL to
> have the DLl work on that. Sharing information through globals directly
> (VI globals or LV2 style globals) is definitely not possible as each
> application maintains its own VI name space. So you will have to resolve
> to interapplication communication such as VI server, shared memory, or
> something similar to actually share data, including signaling as
> occurrences are also just LabVIEW refnums which only work in the same
> process memory context.
>
> Rolf Kalbermatter
>
>
> >

I agree with all that. To get a callback, I sometimes create one vi to be
called as callback (this vi stores it's information in a buffer, also in the
dll, ) and another to get the values in the buffer. Then the second
vi/function can be polled.

Of course you will still need two run time versions if the dll is created in
a different LabVIEW version.

At one time, I tried to create a generic callback function (that modifies
the stack so any number of parameters could be passed to it).
Unfortunatelly, it was not that easy (and thus not finished)...

Regards,

Wiebe.
0 Kudos
Message 9 of 16
(7,587 Views)
Hi,

After lot's of crashes, I succeeded in creating a general callback dll.

The dll is configured with the number of pops and the data needed to return.
The result is a callback pointer. The data can be monitored (to see the
data, and if it is available or not), but the callback waits.

A second VI is used to stop the callback waiting, and to pass the return
value.

I succesfully called EnumObjects, and EnumResourceNames. It even works in
parallel, because each callback is a copy of modified template code.

It will be on our website soon, but I could send you a preliminairy version.

Regards,

Wiebe.

"Almar" wrote in message
news:50650000000800000086EB0000-1079395200000@exchange.ni.com...
> I need to implement a progressbar in labview that i
s updated by a
> callback routine that is passed to the hardware configuration routine.
> So the routine in the DLL is something like: int
> configure(ptrToCallbackRoutine routine). and CallbackRoutine is
> defined like int callbackRoutine(int progress, const char* message);
> Is this possible in LabView? I just cannot find the right
> documentation on this subject.
Message 10 of 16
(7,589 Views)