LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

DLL call with a struct definition

I'm trying to get some DLL calls running for a CCD camera controller (HAMAMATSU C7557).

I've been able to get a few functions working, but I've a problem with a particular function call.

I need to be able to pass a pointer to a struct with 4 "int" values. One source of uncertainty is that, according to other DLL calls, the "int" should be U16. The U16 values are elsewhere in the DLL documentation described as WORD, not "int". Am I missing something silly here or is this simply inconsistent?

Additionally, I'm assuming I need to set the parameter type for my cluster (Assuming I can find the right data type) to "Adapt to type", and then send a pointer to a handle.....


Function according to DLL documentation:

Function name : ChecksSensor (ID, Status)

Format : WORD CheckSensor(WORD, SENSOR_STATUS*);

Arguments :
ID = SCSI ID Number
Status = Struct as follows
typedef struct tag_SENSOR_STATUS
{
int nSensorType;
int nHPixel;
int nVPixel;
int nADType;
} SENSOR_STATUS;

If anyone can give me a pointer (pun intended) I'd be very happy.


Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 1 of 11
(4,322 Views)
This sounds wrong. int used to be 16 bit under 16 bit systems but is 32 bit under 32 bit Windows. That said it may work to declare an int16 value when the DLL expects a 32 bit integer as long as your number is in the range which can be represented by an i16 value. Any paramters in WIndows are passed as 32 bit value on the stack. How an int16 is expanded to 32 bit by the caller is however not defined. So while LabVIEW might clear the entire 32 bit before storing the 16 bit number and pushing it on the stack there is no guarantee that LabVIEW or any other caller will always do this. If the higher bits are not cleared, they might contain garbage and the callee trying to interprete the full 32 bits will be completely hosed.

For a structure however, which when larger than 32 bits is always passed by reference by the way, the actual size for the int does of course matter very much. Since it is a 32 bit DLL, and LabVIEW would bark about an invalid DLL if it was 16 bit, I would strongly expect the DLL to actually use 32 bit integers here.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
Message 2 of 11
(4,313 Views)


Additionally, I'm assuming I need to set the parameter type for my cluster (Assuming I can find the right data type) to "Adapt to type", and then send a pointer to a handle.....



Yes adapt to type is fine. The specifier how to pass handles has no meaning for flat structures. It tells LabVIEW to pass references to arrays or strings as pointers to its handles or the handle itself only. A cluster is always passed as pointer to the structure in LabVIEW.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
0 Kudos
Message 3 of 11
(4,311 Views)
Thankls Rolf,

most of the parameters being passed are WORD, which, unless I'm ageing at a rate I'd rather not admit, is a 16-bit integer?

I'll try it with U32.

I also read that some C++ compilers "pad" clusters (Sorry, Structs) to a defined padding width, but I'm not sure if this only applies to mixed-data structs).

Either way, I^ll give it another go.

Thanks

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 4 of 11
(4,307 Views)
I also read that some C++ compilers "pad" clusters (Sorry, Structs) to a defined padding width, but I'm not sure if this only applies to mixed-data structs

==========

Actually just about all of them do. It only happens when the struct is not 32 bit aligned. A struct (for example) that has an odd number of 16 bit ints will be padded (silently) on the end with another 16 bit int for alignment purposes. Its main purpose is to speed up data access...
0 Kudos
Message 5 of 11
(4,297 Views)
Is the padding just at the end, or between data objects. I followed a few links in the NI forums (search DLL struct), and one link brought me to an article stating that the individual elements can be padded to 32-bit sometimes, and that inserting "dummy" values between the individual elements might help. This was with mixed structs though.

I'll try it again today (Just got into work)

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 6 of 11
(4,286 Views)
shoneill wrote:




most of the parameters being passed are WORD, which, unless I'm ageing at a rate I'd rather not admit, is a 16-bit integer?



Shane,

A WORD is in the WINAPI nomenclature indeed a 16 bit unsigned integer, and if used extensively in an API in my opinion a real sign that the API and DLL has been developed by a hardware person. For embedded designs it is an advantage to use the smallest possible representation for parameters and variables, but for modern 32/64 bit CPUs the best parameter size in terms of performance is always its native bit size.



I also read that some C++ compilers "pad" clusters (Sorry, Structs) to a defined padding width, but I'm not sure if this only applies to mixed-data structs).



Well, with all compilers you can select the byte padding in structures as one of the compiler options. This can be 1,2,4,8 and nowadays even 16 bytes. What this means is that the compiler will align each element in a cluster to the smaller of the two values, either the elements own byte size or the alignment. So a double will be made sure to align to 8 byte if you specify a structure alignment of 8 or higher but a char will always be put whereever it is, as its own size is only one byte and so no alignment is ever done. LabVIEW on x86 architecture uses throughout byte packing (1 byte alignement) which is fine as it is the most flexible, although not most performant, option. So if your DLL needs other alignment you have to care yourself about adding additional filler bytes in the cluster. Visual C defaults to 8 byte alignment nowadays, but for Pentiums, 4 byte is not worse. Accessing an int32 on a non 4 byte aligned address incurres extra CPU cycles to read and write the value to/from a register.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
Message 7 of 11
(4,286 Views)
Hi Rolf,

I automatically assumed that the padding would be interpreted as the LARGER of the two numbers, either the native data size or the padding length, but your answer suggests the opposite. This means that a cluster whose total size is less than 8 bytes (or equal to 8 bytes) will not have any padding issues? "My" cluster is 4 WORD (even though the DLL documentation describes them as int, I'm assuming they're actually WORD) in size, which is exactly the 8 bytes. So basically, I shouldn't have to worry about padding, correct?

Could someone be kind enough to send me an example of how to configure a DLL call in LabVIEW (It doesn't have to work, any old Win32 Dll will do, even with false inputs - I won't execute it, I swear 😉 )?

This would help me a bit because I've read in some places that passing clusters can sometimes be impossible with LV without writing a CIN wrapper, where I have even less experience than with DLLs (i.e. none).

Here's how I'm trying to do it..... The code won't run, but the DLL configuration is visible.

Thanks

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 8 of 11
(4,280 Views)
shoneill wrote:

I automatically assumed that the padding would be interpreted as the LARGER of the two numbers, either the native data size or the padding length, but your answer suggests the opposite. This means that a cluster whose total size is less than 8 bytes (or equal to 8 bytes) will not have any padding issues?


Not necessarily! Assume a structure like

struct {
int16 val1;
int32 val2;
} MyStruct;

A compiler set with alignment higher than two bytes will allign the val2 parameter to four bytes as it is also the size of the val2 parameter. So while this structure needs 6 bytes it really takes 8 bytes in memory.


"My" cluster is 4 WORD (even though the DLL documentation describes them as int, I'm assuming they're actually WORD) in size, which is exactly the 8 bytes. So basically, I shouldn't have to worry about padding, correct?
This would help me a bit because I've read in some places that passing clusters can sometimes be impossible with LV without writing a CIN wrapper, where I have even less experience than with DLLs (i.e. none).


This applies to clusters with embedded strings and arrays. While it is possible with a lot of woodoo to do it without wrapper DLL it is a lot of work, worrysome, cumbersome, and did I mention a lot of work? If you have several functions with such parameters or structure parameters with arrays of structures with ........ then it is definitely just simply a pain in the ass to try to work around a wrapper DLL.


Here's how I'm trying to do it..... The code won't run, but the DLL configuration is visible.

Thanks

Shane.




Well, put your reference to your DLL in there and then you go. Looks fine to me but I would first try with 32 bit integers. If you have to large parameters, the returned data will look weird. But if they are to small it will either crash immediately or corrupt some LabVIEW data which will crash sooner or later too, but maybe after a VI was saved to disk with corrupted content.

Rolf Kalbermatter
Rolf Kalbermatter
My Blog
Message 9 of 11
(4,274 Views)
Ok, sorry to draw this thread out so much, but I'm learning on the job here,

So basically, I've got my DLL interface right, but the thing keeps exiting with an error message. However, you then say that saving the VI might save a corrupt VI? Could this be why I've been unable to get it to work at all, no matter what type ofa data I've been feeding the DLL?

Should I only work from a "fresh" VI with the DLL interface every time, without saving after a DLL error? I really hadn't thought of this. I have saved many times AFTER I got error messages from LAbVIEW. I know it said something about corrupting VIs, but I'm hard of hearing in my left eye 😉 .

Thanks a lot for the excellent help

I'll report if I get it working or not

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 10 of 11
(4,268 Views)