Discussion:
Problems passing ActiveX dll refnum from VI to VI via local, global variables
(too old to reply)
snowdust
2008-08-06 18:10:08 UTC
Permalink
I have  a Visual Basic ActiveX DLL  with several functions including Init and RWReg.  Init creates a new class instance and does some initialization.  RWReg calls functions from the class to read/write some hardware registers.  I have also created Init.vi and RWReg.vi.  These are wrappers around the Init and RWReg ActiveX method calls (see attached init.pdf for example).  Here's my problem: When I call Init.vi and RWReg.vi in succession and wire the refnum output of init.vi to the refnum input of RWReg.vi directly everything works fine and I can read/write registers.  On the other hand, when I pass the refnum from Init.vi to RWReg.vi via a local variable (see attached refnum_problem.pdf), I get the following error:Code1:  Incorrect function. in cvg_RWReg.viI've tried passing the refnum using global variables and functional global variables with the same result.  It appears to me that unless the refnums are hardwired between separate VI calls, Labview clears the DLL from memory.  Is there a way to get around this?  I would like to be able to call Init.vi to initialize the class, then to be able to call RWReg.vi separately to read/write registers once the Init.vi has closed.  Can I accomplish this without hardwiring the refnums?  Would I have the same issue (DLL cleared from application memory after VI closes) if I had a standard Windows DLL instead of an ActiveX DLL? Thanks,Dan


init.pdf:
http://forums.ni.com/attachments/ni/170/347213/1/init.pdf


refnum_problem.pdf:
http://forums.ni.com/attachments/ni/170/347213/2/refnum_problem.pdf
smercurio_fc
2008-08-06 18:40:08 UTC
Permalink
You have classic race condition. The local/global variable is being read before a value is written to it. Remember, LabVIEW is a dataflow language, not a procedural language like C. Code does not necessarily execute left to right.
smercurio_fc
2008-08-06 18:40:09 UTC
Permalink
Forgot about the second part of your question: If your Init and RWReg are within the same VI there is no need to use a local variable like you're doing. In your final program are these VIs going to be in separate VIs? If so, you need to keep in mind that the refnum will only be valid while the top-level VI is still running.
snowdust
2008-08-06 20:10:06 UTC
Permalink
That's precisely right, I was hoping to use separate vi's to call
different dll functions in succession without a top-level VI running. 
Isn't one of the benefits of shared libraries/DLLs that the code can be
accessed (and data shared) in the same memory space by different
concurrent applications  (I'm new to dlls, so correct me if I am
wrong)?  Shouldn't I be able to pass a pointer to that memory space
from one VI to the next without that memory being de-allocated? 
Regarding the potential race condition, I've also tried passing the
refnum by reading/writing a global variable inside the respective VI's
(in which case there should be no race conditions since the vi calls
are wired and called in succession) with the same result.
Pakman
2008-08-08 06:10:14 UTC
Permalink
Hi snowdust, Please refer to the KnowledgeBase article titled <a href="http://digital.ni.com/public.nsf/allkb/CED0243EC0C81A98862570EC006F0EBA?OpenDocument" target="_blank">Reference Local Variable Does Not Return the Correct Value</a>.&nbsp; Basically, the (likely) problem here is that the local variable is being read before a valid reference is placed in the "refnum" indicator.&nbsp; Did adding a flat sequence structure fix the problem?
snowdust
2008-08-08 18:40:06 UTC
Permalink
Peter, I just gave a bad example initially with the potential of a race condition.&nbsp; In fact, the same problem occurs if I have the local variable read/write operations inside different frames of a sequence, if I have a global variable written/read by different vi's, etc.&nbsp;&nbsp; In short, it occurs whenever I try to pass the automation refnum in any other way than wiring it directly from vi to vi.&nbsp; This seems to be corroborated by Ian's experience (and his question is exactly the one that I have).&nbsp; Regards,Dan
Ben
2008-08-08 19:10:05 UTC
Permalink
I'm not convinced these are both the same issue.
Ian's issue may be realted to LV clean-up routine If the VI that is opening the resource goes idle, all of its allocated resource are marked as invalid. You have to make sur ethe enitity that opens a resource is active as long as the resource will be used. That issue can be handled using an <a href="http://forums.ni.com/ni/board/message?board.id=170&amp;view=by_date_ascending&amp;message.id=240328#M240328" target="_blank">Action Engine</a>.
Some screen shots will help up chase down these issues. Please post png or jpg since not all of as viewers for pdf's.
Ben
Ian Melville
2008-08-08 08:10:05 UTC
Permalink
Hi Snowdust/ Peter K.
I have been experiencing similar problems using ActiveX to access a COM Object for communication with an external hardware module. I created a Cluster in the top Level Vi to store the reference and then generated the&nbsp;refnum in a SubVi using the Automation Open function and before exiting the SubVi stored the refnum in the Top Level Cluster (via Local Variable) prior to exiting the SubVi. Although I had not closed the reference (Close Reference function) the refnum seemed to be lost.&nbsp;
Question to Peter K. Is there a way around this problem where I don't have to hardwire the Refnum as&nbsp;I&nbsp;the design is highly architectural and&nbsp;hardwiring would be very messy (and cumbersome)? Would&nbsp;creating (and storing in the cluster) the refnum in the Top Level Vi&nbsp;&nbsp;make this available for use in all&nbsp;SubVi's&nbsp;within the Hierarchy of the Top level Vi?
Regards
Ian Melville
&nbsp;&nbsp;&nbsp;
snowdust
2008-08-09 01:10:05 UTC
Permalink
Hi all, I've discovered a related issue that's even more troubling.&nbsp; I've created several VI's as wrappers for some ActiveX DLL routines.&nbsp; It appears that even if I pass refnums from VI to VI by wiring them, if I recompile the DLL I have to manually re-link the refnums in every single VI and subVI that calls the DLL (even if the calls themselves haven't changed).&nbsp; Otherwise, I get broken wires between VI's because the output refnum of one VI is linked to a different version of the DLL than the input of the next VI.&nbsp; This is extremely frustrating, especially when the DLL is frequently recompiled during debugging.&nbsp; Is there any solution to this?&nbsp; If I am not changing any of the function interfaces in the DLL, can I fool Labview/Windows/VisualBasic into believing that the DLL version hasn't changed?Finally, since there appear to be these issues with ActiveX DLL's and Labview, will my life be any easier if I recompile the DLL as a regular Windows DLL?&nbsp; I think I've found a way to coax Visual Basic into doing that (although this too is a significant investment of time).Regards,Dan
Ben
2008-08-09 13:40:05 UTC
Permalink
FIrst I would again urge you look into the <a href="http://forums.ni.com/ni/board/message?board.id=170&amp;view=by_date_ascending&amp;message.id=240328#M240328" target="_blank">Action Engine</a>. Set it up such that is has an Init method, methods for each call,.... and also a close method. Keep the ref in a shift register inside the AE&nbsp;(works like a static local) and make all of your&nbsp;calls to the dll&nbsp;using the AE. This way you just have to update the AE with you re-compile.
Another thing that could help you is to use Type-Definitions for you ref num. I wrote about those in another <a href="http://forums.ni.com/ni/board/message?board.id=170&amp;message.id=233257#M233257" target="_blank">Nugget that can be found here</a>. They let you make the change once and the change is realized everywhere the type-def is used.
THe recompiling makes sense and is correct. LabVIEW enforces all of the details associated with function call protypes etc. so as a developer you just wire and run. Burried inside you refnum is the info for the calling standard. By forcing you to redifine the refnums, LV is helping you ensure you dod not do an illegal function call that could result in very bad things happening. :smileymad:
Ben
Ian Melville
2008-08-11 09:10:16 UTC
Permalink
Hi Ben
Thanks Ben for your input. My problem is different but the same :smileyvery-happy: You are correct that my primary&nbsp;problem is that the resources relatived to the refnum (and therefore the reference to the Event handler) are released when&nbsp;this is not intended. The example I have seen for an FG/AE solution is based on creating a new refnum when the old is released. This still causes me a problem, as part of the shutdown process for the COM object is the releasing of the Event Handler that was referenced to the original refnum whose resources have already been released by a previous LV cleanup routine. This results in the COM Object trying to release a Event process (that is still running) via a non existent pointer (now a NULL pointer) causing&nbsp;the COM Object (and LabView) to crash.
In any case I will&nbsp;investigate further the possibilities of using the FG/AE&nbsp;solution.
Regards
Ian M.
&nbsp;
&nbsp;
Ben
2008-08-11 14:10:11 UTC
Permalink
Since LV is a a graphic language the images of your code would be very helpful in letting us help y'all.
&nbsp;
Please post images of your code (and or example code) and Y'all will get much better milage out of us.
&nbsp;
Ben
Ian Melville
2008-08-12 07:40:07 UTC
Permalink
Hi Ben
I've zipped up the project and attached it below. You will notice that there are a number of case statements that appear to be static. I use this method to switch off features when I'm experimenting as it saves the time of&nbsp;re-drawing deleted items.
I hope that it will be of some use.
Ian
&nbsp;


08AUG12_CMAG_v0.1_UsrGroup.zip:
http://forums.ni.com/attachments/ni/170/348519/1/08AUG12_CMAG_v0.1_UsrGroup.zip
Loading...