LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Pass a struct type parameter to dll

Hi
 
I have a 3rd party dll, which has a function that expects a struct parameter. The struct looks like this:
 
typedef struct _FIFO_RECORDW {
    ULONG  PortAddr;
    ULONG   NumPorts;
    USHORT Buf[1];
} FIFO_RECORDW, *PFIFO_RECORDW;
So the 3rd member is an array. When I call this function normally from C, my code which works properly looks like this:
 
PFIFO_RECORDW pRead_fifo;
pRead_fifo = (PFIFO_RECORDW)malloc( 2 * sizeof(ULONG) + sizeof(USHORT)* 32768);
pRead_fifo->PortAddr = ATA_DATA;
pRead_fifo->NumPorts = (16384);
ReadPortWFIFO ( hw_ctrl, pRead_fifo); // THIS IS THE ONE WHICH I WANT TO CALL FROM LABVIEW
Basically ReadPortWFIFO reads WORDs from a port and puts them into Buf[ ]. So as I said, called from C code it works.
 
The problem is, that I want to call this function from LabView. I tried the following things, regarding the second parameter:
 
1. I created a cluster which looks the same as this C struct. Then I used a Flatten to String, and I made a CString from it. I did it as it is described in "Using external code in LabView.pdf / Using the Flatten to String function" I passed this C string as a C string from the CLFN to the function. Does not work.
 
2. Same way, but from the flattened string I created an array of U8, and passed it as an Array from the CLFN to the function. (As array data pointer). Does not work too.
 
3. Then I connected the already created cluster to the CLFN as a parameter. I set the parameter type to "Adapt to type" and the data format to "Handles by value". No success.
 
Using any of these 3 variations will call the function without crashing LabView, so I think there is no memory allocation problem happening. But it looks always that the function is not executed. For sure that is a problem with the second parameter.
 
I would appreciate your help.
 
regards
Gyula 
 
 
0 Kudos
Message 1 of 11
(4,112 Views)
hi Gyula
I would make a try with your no 3, but put in the 'swap words', and 'swap bytes'
I dont remember exactly when they are needed, but LabVIEW often produces 'bigendien' from flatten to string
and other, probably to be 'plattform independant'.

0 Kudos
Message 2 of 11
(4,093 Views)

Hi

Thanks for the quick response! But what do you mean on "swap"? What should I swap in my parameters?

I work with LabView 7.0. Maybe what you mean is something new in LV8?

Gyula

0 Kudos
Message 3 of 11
(4,089 Views)

When passing a fixed array, use the following convention as shown below.  Make your cluster with the ULONGs as U32 and the USHORT array as an array of U16 with 1 element.  You must unbundle the cluster, convert the array into a cluster (right click on array to cluster function and set cluster size to 1), then bundle it all back up.  The result is sent to the Call Library Node function.  Set the parameter as follows:

Calling Convention = stdcall (or use C if it crashes)

Parameter = whatever you name it

Type = Adapt to Type

Data Format = Pointers to Handles

This should work.  Note, only works for a definite sized array, in your case it is 1.

Note that in my example, my cluster is not the same as yours.  Change the bundling to your needs.

Message Edited by tbob on 08-15-2006 09:55 AM

- tbob

Inventor of the WORM Global
0 Kudos
Message 4 of 11
(4,087 Views)
Hi tbob,
I Tried what you wrote, but something is still not working. So I decided to call ReadPortWFIFO from C, and look how the struct look like. The first address is Buf[i-16], while I wanted to know how the two other U32 parameter are displayed, and maybe some header information about the struct. The part of the code is this:
...
ReadPortWFIFO (hw_ctrl, pRead_fifo);
    for(i=0; i<100; i++){
    ptrdataA[i]=pRead_fifo->Buf[i-16];
    }
...
 
Then I call a dummy function ParamCompare() from labview, passing the same parameter as ReadPortWFIFO() needs. I fill a similar array as before (also pre-initialized in LV), to find the difference between the two parameter passing.  
 
extern "C" __declspec(dllexport) void ParamCompare(HANDLE hw_ctrl, PFIFO_RECORDW pRead_fifo, USHORT *Array){
 ULONG i;
 for(i=0; i<100; i++){
  Array[i]=pRead_fifo->Buf[i-16];
 }
}
 
The array called ptrdataA (USHORT in HEX, note that Buf[] is USHORT type with 2048=0x0800 elements) in the first column. The one filled by the ParamCompare() is in the second column.
 
[0x0000]    [0x0000]
[0x0000]    [0x0000]
[0x0000]    [0x0000]
[0x0000]    [0x0000]
[0x0008]    [0x0000] - here...what is 0x0008? Differs.
[0x0100]    [0x0000] - differs
[0x0001]    [0x0000] - differs
[0x0000]    [0x0000]
[0x002C]    [0x0000] - differs***
[0x0000]    [0x0000]
[0xFDFD]    [0x0000] - differs
[0xFDFD]    [0x0000] - differs
[0x0170]    [0x0170] - LO word of PortAddr. OK!
[0x0000]    [0x0000] - HI word of PortAddr. OK!
[0x0800]    [0x0800] - LO word of NumBytes. OK!
[0x0000]    [0x0000] - HI word of NumBytes. OK!
[0xXXXX]    [0xXXXX] - This is already the Buf[0], also OK!
 
What are the first 12 words of the first array? Maybe these have nothing to do with the parameter, they are something else for the C code from the memory. And the value of the word which I marked with *** is incremented at each call. (?)
The fact is, when I call this func from C, it works, called from LV not. I don´t want to write a 2nd dll which calls this function. I want to use it directly from LabView.
 
Any idea? Or is it fool what I wrote? I am just curious...
0 Kudos
Message 5 of 11
(4,058 Views)
The first 12 words should usally differ since they are located before your pRead_fifo struct.
And that would be different things  in your call from C and from LabVIEW.

The 'swap words', and 'swap bytes' are on the Advanced -> Data Manipulation, function palete. But as your dump for PortAddress and NumBytes are correct, you dont need them in this case.

How about the hw_ctrl parameter, I guess it should be a handle to a windows control, if thats the case its not easy to get a value for it in LV, may be  you can pass a NULL.


0 Kudos
Message 6 of 11
(4,052 Views)

Hi all,

Well, tbob is right. The way what he proposed works. My problem was that I wanted to pass a U32 array  with 16384 (!) elements. And the array to cluster function in Labview allows only maximum 256 elements of the output cluster. Thus, my function violated the memory after writing of the 256th element...

So I have to find a way, where the struct parameter looks like as it should. But the array in the struct must have at least 16384 elements.

Now I know the rootcouse, that´s a big step. But if you have any idea, how to create this input cluster without "array to cluster" in LabView, please tell me. In the meanwhile I am trying.

Guys, you really helped a lot. Many thanks for it.

Gyula 

0 Kudos
Message 7 of 11
(4,048 Views)
well I think this one should work for you, its uggly but works, at least with a test dll I created.

0 Kudos
Message 8 of 11
(4,046 Views)
Hi gnilsson,
 
It is unbeliavable. It works, but I had to change some things in your vi.
1. I had to swap words only on PortAddr and NumPorts. Swapping bytes is not necessary, because it turns each word upside down.
2. When the input of the CLFN is an U8 array, it doesn´t work. But if I make a type casting from U8 array to U16, then works.
Unfortunately I don´t have any idea, why is it so, but nevertheless works!
 
Thanks again
0 Kudos
Message 9 of 11
(4,034 Views)
Glad to see your problem is solved.  I never tried passing large arrays, so now I'm aware of the 256 element limit.  A U8 array does not work because in your original post you mentioned USHORT data type.  This is equivalent to U16 in Labview.
- tbob

Inventor of the WORM Global
0 Kudos
Message 10 of 11
(4,024 Views)