LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Error Code 1097 Calling DLL After Block Diagram Modified

Ok, so I have a DLL file I am calling that works great using the call library function node until the block diagram is modified. The node returns the infamous error 1097. Restarting LabVIEW is the only way to get the VI operational again.

 

I believe this is a memory management problem. When the block diagram is modified, i.e. placing a control or indicator, maybe LabVIEW overwrites something in memory that my DLL claimed.

 

Anybody experience this issue before?

0 Kudos
Message 1 of 15
(4,813 Views)

@abeaver wrote:

Ok, so I have a DLL file I am calling that works great using the call library function node until the block diagram is modified. The node returns the infamous error 1097. Restarting LabVIEW is the only way to get the VI operational again.

 

I believe this is a memory management problem. When the block diagram is modified, i.e. placing a control or indicator, maybe LabVIEW overwrites something in memory that my DLL claimed.

 

Anybody experience this issue before?


No, no, it's exactly the opposite! Your DLL overwrites something that belongs to LabVIEW and as soon as you edit your VI, LabVIEW trips over the destroyed data.

Most likely it's a wrong data type configuration for the DLL. There are two common errors most people do when starting with the Call Library Node. The first and usually most common is to not provide (enough) memory for an output buffer the DLL wants to write into. In C you have to properly allocate a buffer for an array or string parameter that the DLL wants to write into to return data. Since the Call Library Node is simply a C interface in reality, you have to do that also in LabVIEW and LabVIEW can't even guess if a parameter is an input or output parameter and even less how big such a buffer might need to be. So you have to either use Initialize Array to allocate a big enough array or you can use the Minimum Size setting in the parameter setup to tell LabVIEW how large the buffer needs to be made before calling the function.

The other common error is a wrong datatype. If none of these is going to help, there is a chance that the DLL itself does illegal things, but for a released DLL that is not so likely.

I have used the Call Library Node very extensively in the last 20 years and never was LabVIEW the culprit for crashes with them, but always oversights or misunderstandings on my part about how to configure the Call Library Node parameters correctly, or for self developed DLLs simply bugs in the DLL itself!

 

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 2 of 15
(4,795 Views)

Ah - great information! I know the exact size of my input parameters and the output's memory management is managed in the DLL itself.

 

Are there only two ways of setting the size of the inputs? Either using an already existing function input as the size or type a constant in the Minimum size box. It would be nice to set that size at the block diagram level.

0 Kudos
Message 3 of 15
(4,775 Views)

Then use an Initialize Array node! It's as simple as that and before LabVIEW 8 or so it was the only way to allocate such buffers! I still prefer it that way since it is also explicitly visible on the diagram. I sometimes make exceptions for functions which take an extra parameter to indicate to the function the size of a buffer, but not very often.

 

When reviewing such VIs for correct configuration, an Initialize Array Node on the diagram is easily visible and can be checked immediately. For size configurations of the parameters itself you always have to open the configuration dialog and move to the parameter tab and then locate the correct parameter to be able to verify it.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 4 of 15
(4,771 Views)

Awesome, thanks. I am almost there but need a few clarifications.

 

So the idea is to clear a space in memory the DLL can use by initializing an array that goes no where in LabVIEW?

 

What about character arrays? Do we assume its an 8-bit character and just initialize a U8 array + 1 for null /0?

0 Kudos
Message 5 of 15
(4,732 Views)

@abeaver wrote:

Awesome, thanks. I am almost there but need a few clarifications.

 

So the idea is to clear a space in memory the DLL can use by initializing an array that goes no where in LabVIEW?


I find your way of describing this rather strange. You intialize an array of bytes (or something else, wire it to the parameter input on the left side of the CLN and then wire it out on the right side to be used in LabVIEW someway after the DLL has written the information into that buffer!

What about character arrays? Do we assume its an 8-bit character and just initialize a U8 array + 1 for null /0?


That would be one way. And if you then use a Byte Array to String node before connecting the wire to the left side terminal and configure the parameter as a String Pointer, LabVIEW will even search the returned string for a null character and only pass on the string up to this point further.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 6 of 15
(4,728 Views)

Now I'm confused. The left side of the CLN in my case is a string pointer given to the input of my DLL function. For example a file path. This information is provided by the user in the FP and length can vary. Do I need to preallocate memory in that case?

 

Isn't the left side of the CLN is always of identical value as the right? Excluding the function's return.

0 Kudos
Message 7 of 15
(4,722 Views)

Well, you have input parameters to a function and output parameters. Input parameters are meant to be read by the function and nothing else. They are not the problem here. Your path is an input parameter to the function, obviously you would have to convert a LabVIEW path to a string and pass it as C String Pointer to the DLL function. The nice thing here is that if you configure the parameter as C String Pointer in the CLN, LabVIEW will take care about appending a NULL character to the string (LabVIEW itself doesn't need a termination character since the native string handle contains an explicit length information).

The problem is with output parameters of string and array types. Here you have either an extra (integer) parameter to the function, which tells the function how big the available buffer is for it to fill in something or the documentation of the function states how big the function will maximally try to fill in something. If neither of these two is true you need to hit the original programmer on his head with a stick :-).

 

Many LabVIEW programmers go wrong with these output parameters, since they are used that LabVIEW functions always allocate a buffer automatically whenever they return some data. For a C function called by the Call Library Node, this is not true, since LabVIEW can not guess what the C function will do with the buffer. And there is no common standard for a C function how to allocate memory automatically so it can be "managed" by other parts of the calling application.

Modern environments like .Net have such explicit contracts so there it is easier, but the DLL interface was conceived with C compiler capabilities in mind, and therefore there isn't such a standard and even if someone would add it now it would be pretty useless as you have to deal with lots of software that has been written in the past and doesn't provide that mechanisme.

The only universally applicable mechanisme is to have the caller (here our LabVIEW diagram) allocate all the buffers that are passed to the function, including the buffers that the function wants to write into. And the programmer has to do that himself explicitly, also when calling the DLL function from any other programming environment including C. For most C programmers this is obvious, for many LabVIEW programmers however not, since they don't have to deal with that in other parts of LabVIEW.

So for these output parameters you allocate a buffer, either on the diagram and wiring it to the left side of the parameter or by specifying a minimum size for that parameter, and then wire the returned data from the right side to whatever you want to do on the LabVIEW diagram with it.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 8 of 15
(4,712 Views)

abeaver wrote:

Isn't the left side of the CLN is always of identical value as the right? Excluding the function's return.


No. For any data passed by reference (pointer or handle), the DLL function can modify the data being pointed at, and on the right side you get the modified data. For example, you could have a DLL function that adds one to each element of an array, or does a ROT13 on a string. The left side input is the original array or string, and the right side output is the modified array or string. Where possible this happens in-place - the DLL gets a pointer to the same memory location that LabVIEW uses.

0 Kudos
Message 9 of 15
(4,685 Views)

Right, I understand that. Thanks rolfk and nathand.

 

But! I was doing the memory management correctly. Turns out it is how I specified the link to the DLL. And maybe one of you can shed some light on why one method works and the others don't.

 

Method 1 (does not work):

Configuring the CLN to "Specify path on diagram" for DLL file and wiring the absolute or relative path of the DLL to the CLN requires LabVIEW to be restarted every time the VI is recompiled. This was passing the DLL path through each CLN similar to a VISA handle or something.

 

Method 2 (does not work):

Disabling the "Specify path on diagram" and entering the absolute path of the DLL in the CLN.

 

Method 3 (does work):

Disabling the "Specify path on diagram" and entering the relative path of the DLL in the CLN. I think this method works because the PATH environment variable in Windows has the path to my DLL and by specifying an absolute path LabVIEW is trying to load it again, update the link, or something like that.

 

What I don't understand is why

1) Method 1 will not work when specifying a relative path

2) Method 1 and 2 work just fine until the VI is recompiled

 

Reading the below documentation I think my DLL qualifies as a system DLL because it exists in PATH and LabVIEW automatically includes it but still that doesn't explain why both methods work until the VI is recompiled.

 

https://www.ni.com/docs/en-US/bundle/labview/page/specifying-the-location-of-shared-libraries-on-dis...

 

labview.png

0 Kudos
Message 10 of 15
(4,667 Views)