LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Running a DLL function with a structure pointer parameter

Solved!
Go to solution

The structure 'InitData' only has long data types. The structure MeasData has a mix of different data types as shown below.

 

struct MeasData
{
unsigned char mdNo;
unsigned char chNo;
unsigned char chState;
unsigned char chStepType;
unsigned char chMode;
unsigned char chStepNo;
long lVoltage;
long lCurrent;
long lCapacity;
long lWatt;
long lWattHour;
unsigned long ulStepTime;
unsigned long ulTotalTime;
long lImpedance;
unsigned long ulTotalCycleNum;
unsigned long ulCurrentCycleNum;
long lAvgVoltage;
long lAvgCurrent;
long lSaveSequence;
long lChargeCapacity;
long lChargeWattHour;
long lDischargeCapacity;
long lDischargeWattHour;
unsigned long ulCVEndTime;
unsigned short wCycleNum;
long lChargeCCCapacity;
long lChargeCVCapacity;
long lDischargeCCCapacity;
long lDischargeCVCapacity;
unsigned short wChCode;
unsigned long ulRealDate;
unsigned long ulRealClock;
long lChamberTemperature;
long lSubChannelCode1;
long lSubChannelCode2;
long lSubChannelCode3;
long lSubChannelCode4;
long Reserved1;
long Reserved2;
long Reserved3;
long Reserved4;
unsigned char chControl;
unsigned char chPause;
unsigned char chCV;
unsigned char chStepEnd;
long lAuxValue[MAX_AUX_COUNT_SIZE];
float lCanValue[MAX_CAN_COUNT_SIZE];
};

 

NI Forums MeasData.png

The method for Init() with InitData doesn't work for Run() with MeasData. Only the first six parameters are passed correctly. What else can I try?

0 Kudos
Message 11 of 19
(300 Views)

The cluster needs two dummy bytes (or one int16) after chStepNo so that the next member is properly aligned.

 

Padding and Alignment of Structure Members

x64 structure alignment examples

 

Message 12 of 19
(289 Views)

Your next problem is called memory alignment!

 

C compilers align elements inside a structure to the natural alignment of that element or the currently set alignment size, whichever is smaller.

 

Natural alignment of a structure element is the multiple of the element size. currently set alignment is either the compiler default alignment, the project specific alignment when the code was compiled or any alignment explicitly set in the according source code through #praga pack() statement and in that order with the pragma overwriting the project setting and the project setting if available overwriting the compiler default setting.

 

Most compiler platforms nowadays use 8 byte default alignment, a possible project alignment setting is impossible to see in the compiled product, and pragma settings are usually visible in the header file where the structure is defined. However for most DLLs you can assume that they use 8 byte default alignment.

 

LabVIEW 32-bit however uses byte packed alignment since its foundation was created in 1992 with LabVIEW 2.5 for Windows, at a time where people were demanding that a LabVIEW application could run on computers with a staggering 4MB of physical memory (yes that is right MegaBytes, it's not a typo). Using byte packing throughout allowed it to shave off quite a few bytes of runtime size that could sometimes make the difference between a LabVIEW application loading and running or popping up an out of memory dialog.

 

So since you are using 32-bit LabVIEW. the data elements in the cluster are byte packed. But your Windows DLL uses 8 byte alignment, so the lVoltage element, being a int32 is aligned on a multiple of 4 bytes, in this case this is 8, since the previous 6 1 byte char elements occupy 6 bytes, and the next multiple of 4 is 8. So you have to add a dummy int16 (or two dummy int8) elements between chStepNo and lVoltage.

 

Next problem is between wChCode and ulRealDate. wChCode is a 16-bit value, ulRealDate is a 32-bit value and will be aligned on a 4 byte address, so there needs to be another 16-bit filler value between these.

 

The rest ligns up.

 

 

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 13 of 19
(281 Views)

Thank you for the detailed explanation. In the meantime, the DLL developer kindly updated his code for me to try. He added #pragma pack(push,1) before the structure and #pragma pack(pop) after it. This made it work beautifully without any padding on my LabVIEW side. However, that means he will have to maintain a separate version of DLL for me, and I would still like to find a solution that does not involve this trick. So I tried the padding method you explained as shown below. In the memory table, I just assumed how the two arrays might be handled. (Correction for one of my earlier comments: Elements of both arrays at the end are 'float'. The first array elements are not 'long'.)

 

NI Forum Paddings.png

Now, all elements are passed correctly except the arrays. I don't care about the last array since it is unused, but the first array is essential. 21900, 3729630 and 24907 are logged as 1185620000, 1248040000 and 1187160000. When I used the DLL version that included #pragma pack directive, this part worked correctly. Is there anything I can try to pass the array values correctly?

 

 

 

 

0 Kudos
Message 14 of 19
(238 Views)

Ahh, your developer saved your day and lay a trap for the future for you when you move to LabVIEW 64-bit.😁

 

Because in LabVIEW 32-bit for Windows clusters are byte packed, so his se of #pragm pack(1) the structures saves you from adding filler bytes in the LabVIEW cluster.

 

But LabVIEW 64-bit uses default 8 byte alignment in clusters and the according DLL API should be compiled with default alignment too. So tell your developer to make an additional "fix" to his code to only use packing for the structures when he compiles for 32-bit Windows!

 

Or you let him keep the default alignment as before, add the filler bytes in your clusters and it will work for 32-bit and 64-bit too. 😁

 

Are you sure you are using single floats in the clusters to typecast your data into? 

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 15 of 19
(212 Views)

Yes, the array elements are single-precision floats (SGL).

 

NI Forum Aux Array Cluster 2.png

I tried some other input values.

 

0 is 0.

1 becomes 1065350000.

2 becomes 1073740000.

3 becomes 1077940000.

4 becomes 1082130000.

5 becomes 1084230000.

6 becomes 1086320000.

7 becomes 1088420000.

8 becomes 1090520000.

9 becomes 1091570000.

10 becomes 1092620000.

0 Kudos
Message 16 of 19
(187 Views)

Are those the exact numbers? They are larger than 16777216 and thus not exactly representable by floats. If you typecast a float 1 to u32, you get 1065353216, pretty close to 1065350000. So it looks like you are using a DLL where the AuxValues are still longs.

 

Message 17 of 19
(176 Views)

Those four 0000 at the end of each number look very suspicious. Most likely some sort of resolution limitation in the way those numbers are displayed in your debugger window. And then it gets indeed suspiciously close to an integer value:

 

1.0 -> 1065353216

2.0 -> 1073741824

3.0 -> 1077936128

4.0 -> 1082130432

Typecast.png

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 18 of 19
(164 Views)

Thank you, folks. That was it. There was a bit of DLL version confusion because the array data type was changed back and forth recently. Now the DLL logs every value correctly. Thank you, Knight rolfk, for all these detailed comments along this journey!

0 Kudos
Message 19 of 19
(117 Views)