LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LabView 6.1 crashes when function in dll is called using call library function

I am writing a LabView application to obtain data from the network using a DLL written in C.
DLL Function:
IMPORT_FUNCTION int WINAPI WvListBeds(const TCHAR *pServerName, const TCHAR *pUserName, const TCHAR *pPassword, WV_BED_LIST *pBedList, int *pNumberOfBeds) ;

typedef struct {
TCHAR PatientName [WV_PATIENT_NAME_SIZE] ;
TCHAR PatientID [WV_PATIENT_ID_SIZE] ;
TCHAR BedLabel [WV_BED_LABEL_SIZE];
TCHAR CareUnit [WV_CARE_UNIT_SIZE];
TCHAR FileName [WV_FILE_NAME_SIZE];
TCHAR IPAddress [WV_IP_ADDRESS_SIZE];
TCHAR MulticastIP [WV_MULTICAST_IP_SIZE];
TCHAR DeviceType [WV_DEVICE_TYPE_SIZE];
WV_OPERATING_MODE DeviceStatus ;
WV_CONNECT_ID ConnectID ; // 0 if not connected
} WV_BED_DESCRIPTION ;


typedef struct {
WV_BED_DESCRIPTION WvBeds[256] ;
} WV_BED_LIST ;

When I call the above function from LabView, it executes successfully but when I call any function after calling this function, LabView crashes. I have attached screen shot of the block diagram.

Any ideas on why this is happenning???

Many Thanks for your help.
Mim
0 Kudos
Message 1 of 17
(3,995 Views)
Mim,

(To go easy on the NI server and allow for faster downloading, you should save any future images as PNG or GIF files; it will result in images that are orders of magnitude smaller)

The reason for the crash is almost certainly that the DLL is attempting to write memory space beyond what LabVIEW has allocated. Right up front, I urge you to download and examine the Passing a Variety of Data Types from DLL to LabVIEW example available on the NI site. You'll see how to successfully pass strings to a DLL and modify them there.

With that example in mind, I'd say the problem lies with the string members of the Bed List array not being preallocated with enough characters to hold the values that the DLL is attempting to write into them. Without exploring the front panel, I can't tell if you've set those string members with non-empty default values, but that's what you'll need to do to make the call work. Alternatively, you can create sufficiently long U8 arrays on the block diagram and cast them to strings, then build the Bed List array using those elements.

My two cents,
John
0 Kudos
Message 2 of 17
(3,979 Views)
John,
Thanks for your response.

This was my first posting on the Forum and I didn't realize the download issue with bmp files. Thanks for the tip.

Regarding my vi, the string members of the array of clusters were empty. I implemented your suggestion of casting U8 data type to string of desired length. I am attaching my VI (APITestApp1.vi) for your review. The zip file contains other vis that this vi is linked to.

The problem definitely is with the data type for the Bed List array. But I am not being able to resolve it.

Please help!

Many Thanks,
Mim
Message 3 of 17
(3,969 Views)
Mim,

I'm not particularly experienced with using Adapt to Type, I have to admit. However, if you right-click on the Call Library node and choose Create .c File..., then you can see what sort of prototype the call will match.

Looking at the resulting file, I guess the problem here is that LabVIEW is passing the Bed cluster with LabVIEW String Handle elements instead of C-style string elements. That's not what the DLL is expecting. Perhaps a better DLL guru will come along and clear things up completely, but one idea is to create your input cluster array (Bed List) using U8 arrays instead of strings. Given sufficiently long arrays, the DLL will then have enough room to write its string values into place.

Also make sure that you're providing some extra length beyond what you think the longest expected string will be; that way, you can avoid "fencepost" problems where the DLL needs an extra byte for its string termination character, etc.

Maybe this will help, though if it does, you'll have to recast the arrays back into strings once they come back from the DLL. Maybe this is the wrong track, though.

Hope it helps,
John
0 Kudos
Message 4 of 17
(3,963 Views)
Mim,

I'm afraid my suggestions so far are absolutely no good, for a number of reasons. For one, the U8 arrays in the cluster will be "mangled" by LabVIEW in exactly the same way that the strings are when they are passed to the DLL. Furthermore, at a higher level, the array of structs itself will get the exact same treatment.

For a good discussion of the problem, refer to the thread here entitled How do I pass a pointer to an array of structs to a DLL function?

I don't really think the solution there is tenable for you, since you have the added problem of strings inside the structs that you want to pass as an array. However, since you do seem to be working with an upper limit of 256 elements in the array, I think you might be able to get this to work in a messy way that would involve reformatting the string data once it got back to LabVIEW.

The better solution (assuming the DLL can't be rewritten or implemented directly in LabVIEW) probably lies in a CIN or some sort of wrapper DLL that accepts simpler data structures and calls the target DLL inside itself.

Sorry for the bum steer,
John
0 Kudos
Message 5 of 17
(3,955 Views)
Hi John,
A similar application has been written in Test Stand. And that seems to work OK. Bed List parameter is an array of clusters of length 256.
I cannot modify the DLL. That has been validated and is used for various other products/applications.

Any ideas on what I could try next?

Many Thanks for your time and help.
Mim
0 Kudos
Message 6 of 17
(3,946 Views)
Mim,

In the second thread that you opened up, it would be a good idea to link back over here to provide more background to anyone who wants to help.

I won't touch that second thread so that other people are more inclined to take a crack at it. However, now that I've more thoroughly thought this over and reviewed some similar discussion threads involving other experts here, I think I understand the situation:

I really think you are going to have to create a wrapper DLL. Since you'll be making this new DLL, you can include extcode.h (see the example above and refer to the Using External Code In LabVIEW manual) and make use of LabVIEW's native data type definitions and memory manager functions. This wrapper DLL would accept your cluster array exactly as you originally programmed it, with no need to prepopulate the array or the strings inside the clusters. The DLL would create a temporary C-style pBedList data structure and feed that to the original WvListBeds DLL function. Then, it would take the results and copy those pieces of data into the cluster array that LabVIEW passed into the wrapper DLL, using memory manager functions to resize the array and populate the strings inside each cluster to match the data found in the temporary pBedList object.

Maybe I'm still mistaken and someone else will have a better idea, but given your data structure, I think you'll have to use a wrapper-style approach.

--John
0 Kudos
Message 7 of 17
(3,922 Views)


@Mim wrote:
I am writing a LabView application to obtain data from the network using a DLL written in C.
DLL Function:
IMPORT_FUNCTION int WINAPI WvListBeds(const TCHAR *pServerName, const TCHAR *pUserName, const TCHAR *pPassword, WV_BED_LIST *pBedList, int *pNumberOfBeds) ;

typedef struct {
TCHAR PatientName [WV_PATIENT_NAME_SIZE] ;
TCHAR PatientID [WV_PATIENT_ID_SIZE] ;
TCHAR BedLabel [WV_BED_LABEL_SIZE];
TCHAR CareUnit [WV_CARE_UNIT_SIZE];
TCHAR FileName [WV_FILE_NAME_SIZE];
TCHAR IPAddress [WV_IP_ADDRESS_SIZE];
TCHAR MulticastIP [WV_MULTICAST_IP_SIZE];
TCHAR DeviceType [WV_DEVICE_TYPE_SIZE];
WV_OPERATING_MODE DeviceStatus ;
WV_CONNECT_ID ConnectID ; // 0 if not connected
} WV_BED_DESCRIPTION ;


typedef struct {
WV_BED_DESCRIPTION WvBeds[256] ;
} WV_BED_LIST ;

When I call the above function from LabView, it executes successfully but when I call any function after calling this function, LabView crashes. I have attached screen shot of the block diagram.

Any ideas on why this is happenning???

Many Thanks for your help.
Mim




Basically you can do what you want but you need to know a little about how C structs are constructed. I can't tell you exactly what you have to do as there are to many unknown parameters in the code declaration you provide but I can tell you what you have to create.

Fixed size arrays are directly embedded into the cluster and not as a pointer. So what can you do?

Find the definitions of WV_PATIENT_NAME_SIZE, WV_BED_LABEL_SIZE, WV_CARE_UNIT_SIZE, WV_FILE_NAME_SIZE, WV_IP_ADDRESS_SIZE, WV_MULTICAST_IP_SIZE, WV_DEVICE_TYPE_SIZE,
WV_OPERATING_MODE, and WV_CONNECT_ID.

Then calculate the size of WV_BED_DESCRIPTION as:

WV_BED_DESCRIPTION_SIZE = WV_PATIENT_NAME_SIZE + WV_BED_LABEL_SIZE + WV_CARE_UNIT_SIZE + WV_FILE_NAME_SIZE + WV_IP_ADDRESS_SIZE + WV_MULTICAST_IP_SIZE + WV_DEVICE_TYPE_SIZE + sizeof(WV_OPERATING_MODE) + sizeof(WV_CONNECT_ID)

Multiply this with 256 and create an array of U8 with this number of elements. Pass this to the DLL as an Array of type Unsigned 8 bit, 1 Dimenstion and C array pointer.

Now the fun starts. You will have to index into the returned array with i * WV_BED_DESCRIPTION_SIZE and extract from there at the appropriate offset the information you want. Lets say you want to retrieve the BedLabel of record 1 considering that the first record is record number 0.

You do this by copying with the function "Array Subset" with an offset of
1 * WV_BED_DESCRIPTION_SIZE + WV_PATIENT_NAME_SIZE and a length of WV_BED_LABEL_SIZE. Then as this string is 0 terminated and most probably not as long as WV_BED_LABEL_SIZE would allow you have to search for the 0 terminator. To this in a subVI which loops through that subarray and stops when it finds either a 0 or has looped through any character in the array. Resize the array to the number of characters found up to the termination 0 and convert it into a string by using the Byte Array To String function. Et voila!

Do this for every element in a record and put this all into another subVI called something like Extract Bed Description.vi taking in the entire array and the record index and returning a cluster with all the elements you want to have. Now call this VI in a loop which executes for the number of records the function has indicated in the last parameter to have been filled in.

Attached you will find a first start, the VI which scans an incoming byte array for the terminating 0 character and returns the resulting string.

Rolf Kalbermatter
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 8 of 17
(3,745 Views)


@Mim wrote:
John,
Thanks for your response.

This was my first posting on the Forum and I didn't realize the download issue with bmp files. Thanks for the tip.

Regarding my vi, the string members of the array of clusters were empty. I implemented your suggestion of casting U8 data type to string of desired length. I am attaching my VI (APITestApp1.vi) for your review. The zip file contains other vis that this vi is linked to.

The problem definitely is with the data type for the Bed List array. But I am not being able to resolve it.

Please help!

Many Thanks,
Mim




Assuming that the sizes in your VI are correct, the VI in the attached Archive should more or less work.

Rolf Kalbermatter
Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 9 of 17
(3,915 Views)
Hi Rolf,

Many, Many Thanks for your ideas.

I implemented your suggestion of sending an Array to the DLL based on the size of all members. AND IT WORKS! The application doesn't crash and it is wonderful. I can't open your VIs because I have version 6.1. Would it be possible for you to send Extract Zero Terminated String.vi in version 6.1? If not thats fine too.. I will implement your suggestion of extracting the array subsets.. I will let you know how this goes.

Thank you so much... this has been a GREAT help.

Regards,
Mim
0 Kudos
Message 10 of 17
(3,731 Views)