LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Pass an error cluster in and out of a C/C++ dll?

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!

 

 

0 Kudos
Message 1 of 11
(4,316 Views)

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.

Marc Dubois
0 Kudos
Message 2 of 11
(4,307 Views)
It's possible and I have done that in the past but you need to be aware about the underlaying LabVIEW datatypes.

Your error cluster definition is totally wrong!

struct {
LVBoolean status;
int32 code;
LStrHandle error;
} LVErrorClustet;

is the proper declarations.

bool is a C++ definition only and C++ mandayes no specific size for this. While most C compiler implement it indeed as 8 bit integer there is nothing in the C++ standard that wouldn't allow it to be impented as int and I'm pretty sure there is a compiler which does that.

The error string is a LabVIEW string handle and neds to be managed accordingly. You have to use LabVIEW memory manager
functions to resize it to the necessary length.
Rolf Kalbermatter
My Blog
0 Kudos
Message 3 of 11
(4,293 Views)

I'd say just return Error code and use 'Error from error code'. 🙂

/Y

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 4 of 11
(4,291 Views)
You only simply trying to format into the string is in every possible case wrong. C requires you to worry about proper memory allocations (and deallocations) unlike what you are used to in LabVIEW.
Rolf Kalbermatter
My Blog
0 Kudos
Message 5 of 11
(4,286 Views)
You can't just format into the string anyways as you need to worry about proper memory allocation in C before you can write somewhere, unlike what you are used to in LabVIEW. But normal C string pointers are difficult to handle in a dynamic way.That is why LabVIEW uses its own handles that you have to allocate, resize and deallocate with LabVIEW memory manager functions. It reqrequires
Rolf Kalbermatter
My Blog
0 Kudos
Message 6 of 11
(4,283 Views)
It requires you to use extcode.h and link your library with labview.lib from the cintools folder. Most likely unless you want to dive deep into C, this is going to be more hassles than it is worth it and Yamaeda's suggestion is much, much better.
Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 11
(4,279 Views)

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.

 

 

 

0 Kudos
Message 8 of 11
(4,242 Views)

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.

 

LVsnippet.png

 

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);
}

Marc Dubois
0 Kudos
Message 9 of 11
(4,228 Views)
If the library needs to be independant of LabVIEW you can not use LabVIEW handles!!!!!

You can't modify handles by any other functions then the calling process' memory manager.
You have the same problem in C(++) when you use a different C runtime version in your DLL and your calling process (either by using a different C compiler for each or even, at least in Visual C, a different version of Visual C).
Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 11
(4,227 Views)