LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

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

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
".Smiley Mad
 
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! Smiley Happy
 
(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
When they give imbeciles handicap-parking, I won't have so far to walk!
0 Kudos
Message 1 of 10
(4,024 Views)

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.Smiley Surprised

Found that passing OUTPUTS as variants, then (on 6.1 side) converting back to desired type works. Smiley Happy

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.

 

Message Edited by Dynamik on 01-30-2006 08:53 PM

When they give imbeciles handicap-parking, I won't have so far to walk!
Download All
0 Kudos
Message 2 of 10
(4,015 Views)


@Dynamik wrote:
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
".Smiley Mad
 
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! Smiley Happy
 
(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


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.

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
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 3 of 10
(4,007 Views)
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!

@rolfk wrote:
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.



When they give imbeciles handicap-parking, I won't have so far to walk!
0 Kudos
Message 4 of 10
(3,993 Views)

Hi (again) Rolf,

      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! Smiley Wink  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?

cheers.

When they give imbeciles handicap-parking, I won't have so far to walk!
0 Kudos
Message 5 of 10
(3,984 Views)
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
Best,
JLS
Sixclear
0 Kudos
Message 6 of 10
(3,975 Views)


@Dynamik wrote:

Hi (again) Rolf,

      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! Smiley Wink  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
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 7 of 10
(3,970 Views)
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.
When they give imbeciles handicap-parking, I won't have so far to walk!
0 Kudos
Message 8 of 10
(3,961 Views)


@Dynamik 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 will be a major pain in the ass from viewing your diagram earlier on, since it won't be really possible to pass anything but single arrays and strings to the DLL (definitely no clusters of strings and arrays or even more complex data).

To conclude with this and if you have more than one single function in the DLL with such complicated data types, it might be actually easier to try to find a workaround for your problem with LabVIEW 6.1 to do the whole thing in LabVIEW 6.1 anyhow instead of trying to convert your DLL interface and trying to figure out how to call your DLL correctly.

Rolf Kalbermatter




Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 9 of 10
(3,957 Views)

Hi Rolf,

      You warnings have me worried, but pre-allocating the [arbitrary amount of] memory required for a database query result is not feasible.  Besides if, as you say, the 7.1 DLL runs in it's own process perhaps it's perfectly OK to let the DLL allocate the memory it needs for results.  Anyway the strategy seems to be working as is (Lv6.1 calling 7.1) so I'll share what I have and search for a work-around to the 6.1 ADODB.Recordset problems so to keep it all in 6.1 per your advice. Smiley Happy

Cheers.

When they give imbeciles handicap-parking, I won't have so far to walk!
0 Kudos
Message 10 of 10
(3,943 Views)