LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by Dynami » Wed, 01 Feb 2006 07:41:01


Hi Folks,
      I need to distribute some code in a (LabVIEW) DLL, but a bug in LabVIEW 6.1 prevents me from distributing the 6.1 DLL so I'm compiling it under 7.1.  It then works great when called by a 7.1 VI, but calling it from 6.1 produces the dreaded
"
Fatal Internal Error : "memory.cpp", line 638
LabVIEW version 7.1
".:smileymad:
 
Most of the applications here are in 6.1, upgrading working programs to 7.1 or 8.0 is not realistic.
Any insight - especially know incompatabilities between 6.1 and 7.1 - would be greatly appreciated - I could use a work-around.
 
Thanks! :smileyhappy:
 
(a bit more detail...)
The bug in 6.1 is that neither the "GetRows" or "GetString" ADODB.RecordSet methods correctly return "null" values.
I don't think it would be "Kosher" to post the code, but here's a bit more specific info related to DLL parameter-types:
INPUTS (Qty, Descript, Type, DataFormat
2, Clusters, AdaptToType, HandlesByValue
1, Enum, Numeric(U16),Value
1, ArrayOfClusters, AdaptToType,PointersToHandles
OUTPUTS

2, Clusters, AdaptToType, HandlesByValue

2, ArrayOfClusters, AdaptToType,PointersToHandles
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by Dynami » Wed, 01 Feb 2006 12:10:55

Follow-up in case anyone has to deal with similar issue...
Problem seemed to be with string conversions in return-clusters.  Looks like INPUTs to LV7.1 DLL are no problem.  Removed all outputs, added a cluster with bool - OK.  Added numeric to the cluster - OK.  Added (Error.Source) string - crash.:smileysurprised:
Found that passing OUTPUTS as variants, then (on 6.1 side) converting back to desired type works. :smileyhappy:
So, built/Compiled a "wrapper" VI.  The wrapper converts target outputs to ActiveX Variant.  Call Lib. Func. unpacks these as ActiveX Variant, and variants are transformed back to type on same diagram as CLF.
 
<img src=" http://www.yqcomputer.com/ "><img src=" http://www.yqcomputer.com/ "> Message Edited by Dynamik on 01-30-2006 08:53 PM


DLLWrap.GIF:
http://www.yqcomputer.com/


DLLCall.gif:
http://www.yqcomputer.com/

 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by rolf » Wed, 01 Feb 2006 21:10:39


I need to distribute some code in a (LabVIEW) DLL, but a bug in LabVIEW
6.1 prevents me from distributing the 6.1 DLL so I'm compiling it
under 7.1.  It then works great when called by a 7.1 VI,
but calling it from 6.1 produces the dreaded " Fatal Internal Error : "memory.cpp", line 638 LabVIEW version 7.1 ".:smileymad:   Most of the applications here are in 6.1, upgrading working programs to 7.1 or 8.0 is not realistic. Any
insight - especially know incompatabilities between 6.1 and
7.1 - would be greatly appreciated - I could use a work-around.   Thanks! :smileyhappy:   (a bit more detail...) The bug in 6.1 is that neither the "GetRows" or "GetString" ADODB.RecordSet methods correctly return "null" values. I don't think it would be "Kosher" to post the code, but here's a bit more specific info related to DLL parameter-types: INPUTS (Qty, Descript, Type, DataFormat 2, Clusters, AdaptToType, HandlesByValue 1, Enum, Numeric(U16),Value 1, ArrayOfClusters, AdaptToType,PointersToHandles OUTPUTS 2, Clusters, AdaptToType, HandlesByValue 2, ArrayOfClusters, AdaptToType,PointersToHandlesYou
can't use LabVIEW datatypes in the DLL interface if the DLL is to run
in a different LabVIEW process than the LabVIEW system calling it. In
your case the DLL is running in the LabVIEW 7.1 runtime system while
you call it from a LabVIEW 6.1 runtime or development system. The array
handles allocated by your LabVIEW 6.1 system are totally and utterly
meaningless to the LabVIEW 7.1 runtime system but since it is a LabVIEW
handle in the API definition the DLL code simply assumes that it is
valid to resize them at a certain point. ->>>> General
Protection Fault.

The only solution is to define your DLL API in a way that uses C
datatypes. With them it is always so that the caller allocates all the
memory necessary for parameters for the callee to be used so that the
DLL function does not have to (and it really can't) resize the
parameters.

Rolf Kalbermatter
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by Dynami » Thu, 02 Feb 2006 06:40:59

Hi Rolf,
      I'm not sure I understand your post - and the DLL seems to be working as described - correctly using inputs to assemble and pass back large arrays of clusters.  I assumed the caller was passing valid pointers to data-sources (the inputs) and the DLL was allocating memory as needed, passing back to the caller valid pointers to the results.  If I can't depend on this, I DO want to know, but your post seems to imply that it could never work, yet it has, flawlessly so far.
 
Cheers!



You can't use LabVIEW datatypes in the DLL interface if the DLL is to run in a different LabVIEW process than the LabVIEW system calling it. In your case the DLL is running in the LabVIEW 7.1 runtime system while you call it from a LabVIEW 6.1 runtime or development system. The array handles allocated by your LabVIEW 6.1 system are totally and utterly meaningless to the LabVIEW 7.1 runtime system but since it is a LabVIEW handle in the API definition the DLL code simply assumes that it is valid to resize them at a certain point. ->>>> General Protection Fault.
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by JLS » Thu, 02 Feb 2006 10:10:59

Hello,
 
Dll's called by LabVIEW using a call library function node are loaded into memory when the owning VI is loaded into memory, and subsequently unloaded when the VI is unloaded from memory.  You can control this by calling VIs which contain call library nodes by reference - when you close the VI reference, the VI will be unloaded from memory, and so will the dll it called.  Here's an example program I wrote to illustrate this:
 
Title: Controlling DLL Loading At Runtime in LabVIEW

Link: <a href=" http://www.yqcomputer.com/ ;p_node=DZ52048&p_source=External" target="_blank"> http://www.yqcomputer.com/ ;p_node=DZ52048&p_source=External</a>
I hope this helps!
Best Regards,
JLS
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by rolf » Thu, 02 Feb 2006 17:10:36


Thanks again for your post - having re-read it a few times, perhaps I
understand your warning, now.  Essentially, the DLL shouldn't
re-size data-structures that are allocated by the caller.  I
knew that! :smileywink:  But you forced me to think about memory
allocation and now I'm worried about leaks.  Will the
(LV7.1) DLL allocate different memory for results every time it's
called? No, it is worse than that. Since the DLL
really runs in a different process (your LabVIEW 7.1 runtime engine) it
has absolutely no control over the memory it gets passed from the
caller. But since you are using LabVIEW data types it assumes it can
resize them anyhow to accommodate the data it wants to put in. So it
does use it's own DSSetHandleSize fucntions and friends that allocate
memory from its own heap, but at the first occurrence of such a call
will recognize that the handle is not something it has ever allocated
and therefore cause an assert.

As long as you run the DLL in the same exact LabVIEW version runtime as
the DLL was created it calls the same runtime engine and therefore uses
the same heap and nothing bad happens. Apparently LabVIEW is even smart
enough to allow calling of a LabVIEW x version DLL in the LabVIEW x
development system eventhough that should in fact be two different
processes. Apparently at loading of the DLL LabVIEW recognizes that it
was created with the same LabVIEW version and loads it in the
development runtime environment instead of starting up a seperate
runtime system for the DLL.
Once the DLL and LabVIEW version are not the same this is unfortunatly
not possible anymore as that would cause all sorts of incompatibilities
and crashes.

Rolf Kalbermatter
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by Dynami » Fri, 03 Feb 2006 16:10:36

Hi Rolf, [and fellow App. Builders]
      I hate to confess my ignorance here, I'm new to the LabVIEW DLL.
 

This would also be true when caller is non-LabVIEW, no?
 
How does the DLL figure-out [from the data passed,] that the caller is a LabVIEW program?  
Even if the DLL [erroneously] identifies an object as something it can resize,
why would it want to "put in" any data, if the DLL only reads the [Input] datastructure?

Can one pass data in such a way that the DLL will not assume it can resize things?
 
Rolf's post(s) seem(s) to imply that LabVIEW DLL can be used safely by [practically] everything - except another version of LabVIEW!
 
If there's a good app-note on this, please share the link.
Thanks, Cheers.
 
 
 

LabVIEW 6.1 VI calling a DLL compiled in 7.1, Mem error/crash

Post by rolf » Fri, 03 Feb 2006 20:41:25

ynamik wrote:Hi Rolf, [and fellow App. Builders]       I hate to confess my ignorance here, I'm new to the LabVIEW DLL.   > ... the DLL really runs in a different process > ... has absolutely no control over the memory it gets passed This would also be true when caller is non-LabVIEW, no?   > since you are using LabVIEW data types it assumes it can resize them anyhow > to accommodate the data it wants to put in How does the DLL figure-out [from the data passed,] that the caller is a LabVIEW program?   Even if the DLL [erroneously] identifies an object as something it can resize, why would it want to "put in" any data, if the DLL only reads the [Input] datastructure? Can one pass data in such a way that the DLL will not assume it can resize things?   Rolf's
post(s) seem(s) to imply that LabVIEW DLL can be used safely
by [practically] everything - except another version of
LabVIEW!   If there's a good app-note on this, please share the link. Thanks, Cheers. First
not the DLL is recognizing anything but probably LabVIEW. Each LabVIEW
DLL exports an extra function that LabVIEW can use to query or set
certain information.

And even if the DLL needs to recognize anything it will not figure it
out in the function itself, but can do so during its intialization
routine. Something like GetModuleHandle() and GetModuleName() on that
handle are all it needs to do. But probably LabVIEW when loading a DLL
checks if it exports that specific LabVIEW function and then can use it
to tell the DLL to link to its own kernel instead of trying to load the
runtime system.

As to the safety of calling a LabVIEW DLL you make it worse than it is.
The problem lies in the fact that you are trying to pass LabVIEW data
directly to the DLL (with Adapt to Type) and that data consists at
least partly of variable sized elements such as arrays and strings.
LabVIEW then passes that data unaltered to the DLL (and all strings and
arrays are then LabVIEW handles). Those handles however can only be
manipulated inside the same process as that had created them.

Now the nice thing seems to be that when the DLL and LabVIEW are the
same version the DLL will actually use the LabVIEW functions of the
host application to manipulate those data handles and everything is
fine. If the DLL is from another LabVIEW version it obviously can't do
that as the LabVIEW system could not load and interprete the VIs
contained in the DLL, so it links with its own runtime system kernel
and crashs.

The only way to avoid this problem is to avoid passing LabVIEW handles
to the DLL. This means you will have to use C datatypes instead
(char * instead of LStrHandle, int * instead of an array of int as
LabVIEW handle, etc). Also everywhere you call these functions and
expect the DLL to return some data you will have to preallocate the
correct sized buffer and pass it to the DLL as is common practice for C
programming.

The reason you don't have these problems when not using LabVIEW as
caller, is that you will never ever use directly LabVIEW datatypes in
the caller anyhow but instead always will have to go with C datatypes
instead.

So change your DLL to export functions that do not use native LabVIEW
datatypes and then change you application to pass the data properly to
that DLL as C datatypes. This wi