LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I pass a pointer to an array of structs to a DLL function?

Thank you!

Ben
Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 11 of 22
(2,077 Views)

Hello folks,

 

Sorry for reviving this post, but WHAT IF the array of structs is of a fixed size, say '3'?

 

Ex:

 

struct myStruct

{

   int x;

   int y;

};

 

myStruct mS[3]; //I need 3 of these structures

 

void myFunc(myStruct *input)

{

   input[0].x = 10;

   input[1].y = 5;

   input[2].x = 13; //just random assignments to test the functionality

}

 

Would this work in LabVIEW?

 

Thanks

Erick

0 Kudos
Message 12 of 22
(1,869 Views)

Non related: Holy smokes just realized this post was ~12 years old!

 

0 Kudos
Message 13 of 22
(1,859 Views)

@erickschmidt wrote:

 

Sorry for reviving this post, but WHAT IF the array of structs is of a fixed size, say '3'?

 

struct myStruct

{

   int x;

   int y;

};

 

myStruct mS[3]; //I need 3 of these structures

 

void myFunc(myStruct *input)

{

   input[0].x = 10;

   input[1].y = 5;

   input[2].x = 13; //just random assignments to test the functionality

}


Basically, you need to allocate enough RAM for the data and let the function know where that is, which you do by generating the relevant data structure. I believe this can simply be a string of length N, or it can be an array of clusters of two I32s of size 3 or it can be a cluster with three sub-clusters. All are equivelent from the LV side, since they're all just a sequence of bytes. I believe that the correct number of bytes depends on the alignment on the C side, but I don't think there are any alignment issues with ints. If there are, I'm sure you'll find a post by Rolf or Nathan below this one in not too long.

 

The short version of that: yes, but you need to allocate the RAM. Just test it.


___________________
Try to take over the world!
Message 14 of 22
(1,838 Views)

Basically what tst already said. A fixed size array of scalars or structs of scalars is always inlined and the LabVIEW equavalent is to place the element as many times into a cluster. This specific case, since all elements in the inner struct are of the same type you can also simply create an array of 3 * 2 int32 values and get the same memory wise.

Rolf Kalbermatter
My Blog
Message 15 of 22
(1,826 Views)

Thank you both for your suggestions. (rolfk and tst (Knight of NI))

 

I was able to pass an array of clusters per your suggestions. I created the array before so that it resides in memory in LV, and then passed it as a Pointer to an Array to my DLL and modified the inputs by using input[0].x and input[2].y, etc for each different cluster in the array.

 

This guide here helped me quite a lot too:

 

https://decibel.ni.com/content/docs/DOC-9079

 

Cheers

0 Kudos
Message 16 of 22
(1,801 Views)

Hello again,

 

I wanted to see if anyone can help me out. I have been reading extensively in the forum and on the documentation. I even thought I had it resolved but now I face another issue:

 

It seems the data cluster values are reversed or something's going on with the data type compatibility after passing through the DLL (through the Call Library Function Node).

 

I'd like to start by showing exactly what my code is for the DLL file:

 

#include "extcode.h"

static int example; //just testing a global variable

 

struct channel2
{
    int32 a;
    int32 b;
};

 

struct channel
{
    double x;
    int32 d;
    double y;
    int32 c;

    struct channel2 z;
};

 

_declspec(dllexport) void CLUSTERSimple(struct channel *input);
_declspec(dllexport) void CLUSTERSimple2(struct channel *input);

_declspec(dllexport) void CLUSTERSimple(struct channel *input)
{
    input->x += 1;
    input->y += 2;
    example = input->z.a;
}

_declspec(dllexport) void CLUSTERSimple2(struct channel *input)
{
    input->z.b = example;
    input->z.a = 100;
    input->c = 33;
    input->d = 44;
}

 

Specifically when I insert an int32 data type between the two doubles x & y in my struct, or if I place the int32 as the first value in the main structure, it kind of shows weird results. So as long as the int32 is after the doubles (i.e. double x, double y and THEN int32 c), it works. I don't know what's going on or if I'm missing something.

 

LabVIEW VI:

 

ScreenHunter_233 Feb. 16 02.19.jpg

 

ScreenHunter_234 Feb. 16 02.19.jpg

 

I used 'Adapt to Type' and 'Handles by Value' for both DLL Calls. I am currently using LabView 2013 (32-bit) on Windows 8.1 (64-bit).

 

I also verified that the order of the variables in the structure and sub-structure were correct, by using the "Reorder Controls in Cluster" option in LabVIEW. And I also set the variables data type as I32 for int32 and DBL for double, respectively (LV -> C).

 

As I mentioned before, If I remove the int32 d variable which is between the doubles, on both the DLL and the cluster, it works. Only when there's an int32 between the doubles or at the beginning of the structure, this happens. It seems the int32 is corrupting the next values?

 

Do I need to do something related to byte swapping or something like that that I might not be aware of (i.e. endianness compatibility issues)?

 

By the way, I can't afford a Wrapper or other sort of manual processing (such as "flattening" the structure to bytes or so) because this is just a sample program, but my actual application under development has a bunch of data types in the structure (around 55 variables) and I can't afford post-processing them since it translates to overhead.

 

Thanks Cheers!

0 Kudos
Message 17 of 22
(1,775 Views)

You can see the c value to be a HUGE number so it seems its not detecting the appropriate data type or something. Also y is zero, and it shouldn't be. 

 

Expected outputs:

 

Intermediate

x = 1 + 1 = 2

d = 2

y = 3 + 2 = 5

c = 4

z.a = 5

z.b = 6

 

(example = 5)

 

Final

x = 2

d = 44

y = 5

c = 33

z.a = 100

z.b = 5 (example)

 

Cheers

0 Kudos
Message 18 of 22
(1,769 Views)

x and d are working fine, but AFTER d (which is the int32 in between the doubles) the results are all swapped or just strange.

 

Any clues?

 

 

0 Kudos
Message 19 of 22
(1,767 Views)

I suppose this is 32 bit LabVIEW. Read about structure element alignment in C!

 

LabVIEW 32 bit uses single byte aligned clusters. Microsoft Visual C and most other C compilers use 8 byte default alignment.

 

You need to put #pragma pack(1) and #pragma pack() around your structure definitions in your C file. However LabVIEW 64 bit switched to default byte alignment so doing it like this would cause trouble if you ever want to compile the code for both LabVIEW bitnesses.

 

Luckily NI provides two header files together with extcode.h called lv_prolog.h and lv_epilog.h. Put them around your struct declarations that you intend to interface on the diagram directly and you are ready, set and fine.

 

If you need to interface to existing code you have to decide if you ever might need to port the code to 64 bit LabVIEW or not. It's fairly easy to add dummy filler elements in your cluster to make it match the C compiler aligned struct. You simply have to make sure that every element starts at a multiple of the smaller of it's own size or the default alignment of the C compiler (8 bytes for Visual C). And it should not even make a difference between 32 bit and 64 bit DLLs unless a struct contains pointers of any kind.

 

A wrapper is the cleanest way but requires extra work to create and maintain, and unless there are other issues to crush like embedded pointers in structs or callback functions etc in your API it may be overkill.

Rolf Kalbermatter
My Blog
Message 20 of 22
(1,752 Views)