LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Call By Reference Node + Call library function node

Hello,
 
I have multiple subVI's that load a DLL with a Call library function node. Each of these subVI's use a different function of the dll. I only wish to load them when i actually need them. To do so Im using a Call By Reference Node. This works for all of them except one. For some reason it only works if I actually have the SubVI opened in labview.
Im not getting any usefull errorcodes. And i can't see what is going wrong in the subVI as it does work when it is open.
The dll im using is for a TCR511PCI and im using Labview 8.5.
 
Does anyone have an idea what is causing this?
 
0 Kudos
Message 1 of 12
(4,511 Views)
What is not working when the subVI is not open? Does it crash? Or does it
produce wrong results?

Do you call an init function before you use the dll? Because if you do, the
VI might disapear from memory when no references are open. If you do the
init with a Call By Reference Node, the init will succeed. Then the CBRN is
done, and the sub VI will disappear from memory, as will the dll. The next
time you use a CBRN, the init is not done. If this is your problem, we can
talk about the solution.

Regards,

Wiebe.


0 Kudos
Message 2 of 12
(4,479 Views)

Sorry for my late response.

This SubVI is supposed to open the device and return a handle to it. There also is a Close Device SubVI, so I believe it will stay open until the close SubVI is used.

This part is in a sequence that is used as the init for the VI. It is only to open the device if there is one. (theres is a subVI that returns the number of devices found, 1st device being Nr 0). The Open SubVI just returns -1 as handle when it isn't opened in labview. When it is opened it returns the handle as it should.

The SubVI not working when it isn't loaded in labview does seem like some kind of memory problem. But I don't see it return the handle for a short moment, which it might just show after executing and before removing it from memory again.

0 Kudos
Message 3 of 12
(4,460 Views)

"Barkey" <x@no.email> wrote in message
news:1208952609042-694568@exchange.ni.com...
> Sorry for my late response.
> This SubVI is supposed to open the device and return a handle to it. There
also is a Close Device SubVI, so I believe it will stay open until the close
SubVI is used.

It will stay open, but only if the dll stays in memory. If both the open and
the close VI are called dynamically, the DLL will be gone from memory, and
the handle will be lost. That doesn't seem to be your problem though.

> This part is in a sequence that is used as the init for the VI. It is only
to open the device if there is one. (theres is a subVI that returns the
number of devices found, 1st device being Nr 0). The Open SubVI&nbsp;just
returns -1 as handle when&nbsp;it isn't opened in labview. When it is opened
it returns the handle as it should.

Perhaps the handle is related to the VI's window handle. That would be a
dirty trick, and I can't imagine why someone whould use it. Does the DLL do
any graphical stuff?

> The SubVI not working when it isn't loaded in labview does&nbsp;seem like
some kind of memory problem. But I don't see it return the handle for a
short moment, which it might just show after executing and before removing
it from memory again.

If it isn't loaded in LabVIEW how do you run it? Or do you mean you start it
in LabVIEW, but without opening the front panel? In that case, it is still
loaded...

Regards,

Wiebe.



0 Kudos
Message 4 of 12
(4,438 Views)

The DLL is only for communicating with the PCI card, so not graphical things.

I've added a screeny to make it more easy to see.

The third picture is the part that loads the DLL. Whenever the frontpanel of this VI is opened (or a VI where it is called directly), it works fine.

When i would close it it basically is out of memory because of the Call By Reference Node. At least until i want to use the DLL, which is what I intended. Now when it is closed, labview still runs the Called VI that opens the dll, but the result is an error.

0 Kudos
Message 5 of 12
(4,424 Views)
Does the VI work when you call it as a normal sub VI? Have you tested the
dynamic VI construction with a dummy VI?

Your attached picture isn't exactly the simples way to test the dll...

Regards,

Wiebe.


0 Kudos
Message 6 of 12
(4,368 Views)


@Barkey wrote:

The DLL is only for communicating with the PCI card, so not graphical things.

I've added a screeny to make it more easy to see.

The third picture is the part that loads the DLL. Whenever the frontpanel of this VI is opened (or a VI where it is called directly), it works fine.

When i would close it it basically is out of memory because of the Call By Reference Node. At least until i want to use the DLL, which is what I intended. Now when it is closed, labview still runs the Called VI that opens the dll, but the result is an error.



As long as the VI which calls the DLL has its front panel open it will stay in memory and as long as it stays in memory it will keep a reference to the DLL. So if you call your VI dynamically LabVIEW will generate a VI reference to the VI in memory in Open VI Reference and will execute the VI and then Close that VI Reference but the VI and with it the DLL will not be unloaded. If you do not have a front panel open the VI is not in memory but will be loaded by the Open VI Reference. This will load the DLL into memory too then Call By Reference calls the VI that executes the DLL call and when closing the VI Reference the VI leaves memory and with that will close the DLL reference too. If no other VI in LabVIEW has a reference to that same DLL the DLL will be unloaded.

Possibly the DLLs DETACH_PROCESS handler contains code that will deallocate all currently open handles which would at least avoid memory leaks. But even if it doesn't, for the next load of the DLL the handle created from the previous invocation will be completely meaningless to the newly loaded instance of the DLL.

Trying to dynamically call individual functions that use resources like handles across calls is not a very good idea. You could make sure that the DLL stays loaded during the entire runtime of your application by adding a VI that references a function to said DLL in a part of your program that is not dynamically loaded and executed. You can make that function call even never called. The fact that it is there makes sure that the DLL stays loaded. However be aware that if you put that DLL node into a case structure that you wire the case selector to a front panel control and not just a boolean constant since LabVIEW since 8.0 will optimize constant wired case structures away when building an executable.

Why you try to make all calls to the DLL dynamic is rather unclear to me. It would seem to make those calls a lot slower for sure  and memory savings will be minimal if at all.

Rolf Kalbermatter
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 7 of 12
(4,336 Views)
The reason why i wanted to do it this way was to make it work even if the dll would not be on the PC. If the card wasn't installed, the dll wouldn't be needed either.
So I guess this isn't going to work the way i wanted it to. Is there any way of only opening the dll if the card is detected and then keep it open?
Although I might as well just not use the Call by reference as it would only slow things down like you said. The VI being faster when the clock is less accurate wouldn't make much difference anyway.
 
 
0 Kudos
Message 8 of 12
(4,304 Views)


@Barkey wrote:
The reason why i wanted to do it this way was to make it work even if the dll would not be on the PC. If the card wasn't installed, the dll wouldn't be needed either.
So I guess this isn't going to work the way i wanted it to. Is there any way of only opening the dll if the card is detected and then keep it open?
Although I might as well just not use the Call by reference as it would only slow things down like you said. The VI being faster when the clock is less accurate wouldn't make much difference anyway.

Of course there is a way but you do need to make it smarter.
Bascally you want to write  a smart VI that can manage your DLL calls. I would do this as a LabVIEW 2 style global or as I like to call them intelligent action buffers. They are VIs with a loop with one or more unitialized shift registers and a case structure inside the loop. The case selector is wired to an operation enum with enum values like init, get ref, and close.

First you write the actual DLL wrapper with an enum as operation selector and a case structure wired to that enum and the according DLL calls inside the various cases. Obviously you also need to have some common parameters somehow.

Then write a wrapper VI with the same type of operator enum and also the same parameters. On init you try to dynamically load the subVI that access the DLL. If that fails the DLL is not there or could somehow not be loaded. Then you execute the intialization function. Now do NOT close the VI reference to the subVI if this succeeded so far but store that reference in an uninitilized shift register. Then on subsequent calls to the wrapper VI call the subVI dynamically with the same parameters and operation enum until you do not need it anymore at which time you call the close method which first dynamically calls the close method of the lower level VI and then closes the VI reference itself.

This makes sure that your DLL stays in memory for the entire time between your init and close call, so that resource identifiers that the DLL returns stay valid between calls. Obviously if the DLL is more complicated it may be hard to combine all methods into one single VI interface and you would have to devise a somewhat more involved variant of this but it will nevertheless work.

The poor mans method as I have already mentioned earlier would be to keep a reference to a VI calling that DLL somewhere as long as needed and just do the rest as you do know. Since that reference will keep the DLL in memory it won't matter if the actual calls come into memory and go again as they will simply attach to the already loaded DLL. Of course if loading that reference VI wouldn't succeed you would somehow have to make sure to not try to load the actual functions either each time as that would be useless.

Rolf Kalbermatter
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 9 of 12
(4,289 Views)
In LV 8, you can load dlls by setting the path to the dll (right click it,
and you should be able to set a path). There is also runtime error handling,
that should enable you to do the same without loading dynamic VI's. Simply
calling the dll like you would do normally, but you'll receive an error if
it's not there. Handle that error properly, and you're done.

Regards,

Wiebe.


0 Kudos
Message 10 of 12
(4,267 Views)