02-17-2014 01:22 PM
Hi all,
I'd like to know if it is possible to pass a LabVIEW error cluster to a C/C++ function from a dll. This would greatly help error handling in the different VIs.
I am able to access and modify the first two members of the error cluster; the error status and the error code, which are, respectively, boolean and integer. But I cannot modify the string. LabVIEW crashes completely doing so.
I first define a structure in C++ like this:
const int N = 512; #pragma pack(push,1) typedef struct lvcluster { bool status; int code; char source[N]; } lvcluster; #pragma pack(pop)
Then, I define a function that will access the members status, code and source:
int TestCluster(lvcluster *err) { err->code = 1; err->status = false; sprintf(err->source, 'Test'); }
I then use LabVIEW's "Call Library Function" to call this dll's function. I have set the parameter "err" to "Adapt to Type" and "Handles by Value". Trying to write characters to the source array crashes LabVIEW.
Is this possible at all? How should it be done?
Thanks!
02-17-2014 01:51 PM
Trying to return directly an error cluster from a DLL into Labview is probably risky if even possible. The difference between the C string and the Labview string is probably what makes it crash. I think that you should just return three separate elements, char (status), int (code), and string (text) and use a wrappping VI that would convert the output of the DLL into a nice error cluster.
02-17-2014 03:36 PM
02-17-2014 03:36 PM
I'd say just return Error code and use 'Error from error code'. 🙂
/Y
02-17-2014 03:40 PM
02-17-2014 03:45 PM
02-17-2014 03:49 PM
02-18-2014 08:49 AM
Thanks all for the comments.
I've been looking at extcode.h where I saw the defeninition of a LStrHandle. It seems to be a pointer to pointer to "character array":
typedef struct { int cnt; /* number of bytes that follow */ unsigned char str[1]; /* cnt bytes */ } LStr, *LStrPtr, **LStrHandle;
The "character array" is different than a C character array, see http://www.ni.com/white-paper/4877/en/#toc4
The first 4 bytes contain a signed 32 bit integer representing the number of characters. There is no NULL-termination character.
So the error structure should be something like this (modulo the size of boolean, thanks rolfk):
const int N = 512; #pragma pack(push,1) typedef struct lvcluster { bool status; int32 code; LStrHandle source; } lvcluster; #pragma pack(pop)
From there, I was able to access a LabVIEW string from C. But I am unable to modify any of it. I might be able to change the characters from an alreay allocated string, but resizing or even creating a new string crashes LabVIEW. As reported by others, manipulating these strings would require linking against labview's library to access the string manipulation functions, but this is not possible as the library must be independant of LabVIEW.
The only last possible way I can think of is to allocate a new cluster inside the DLL. Then I might be able to change the string in it, and hopefully LabVIEW would pick it up. I don't know how LabVIEW manages its memory; would it garbage collect the input cluster that is not used anymore?
Thanks for all the feedback.
02-18-2014 11:46 AM
I'm not sure I understand why you want to absolutely use an error cluster. Using 3 separate variables would definitely work. The only issue is with the string. You need to allocate the space in Labview prior to calling the DLL, and copy the string (not the pointer) into the Labview string, using strcpy() for example. You allocate the memory in Labview by creating a string with the number of characters corresponding to your length limit.
The code in the DLL would look like:
int TestCluster(char status, int code, char *source)
{
code = 1;
status = 0;
strcpy(source, 'Test');
return (1);
}
02-18-2014 11:49 AM