09-03-2025 08:21 AM
Hi,
I am currently struggling using the CFN for a 3rd-party instrument driver DLL. This is the function of the DLL:
and this are the struct definitions:
I played around with the "AdaptToType" function and passing the according cluster without any success. In an old post I found a hint of @rolfk that it should be possible to define a parameter for each element of the struct that should be passed by value. (https://forums.ni.com/t5/LabVIEW/Interface-dll-function-with-struct-in-LabVIEW/td-p/1490848). Unfortunatelly without success, but I assume that the Response-struct pointer causes the pain...
I would be very grateful for any further tips.
It is an old driver currently used with LV2019 32-bit.
Matthias
Solved! Go to Solution.
09-03-2025 09:29 AM
Disclaimer: I never had to pass structs by value, so all of this may be wrong.
Two pitfalls are here: passing a struct by value on a 32 bit platform and having a struct with a fixed size array in it. Those come up relatively often, this is from yesterday: https://forums.ni.com/t5/LabVIEW/Passing-HPKFPI-OPENPARAM-Struct-to-DLL-via-Call-Library-Function/m-...
The first struct AASiMbRequestType is passed by value. So going by the linked thread, for each struct member you need to create one function parameter. That extends to the Data field, since it is of fixed size and will be inlined. Adding one parameter for each element, you end up with 39 parameters for the input cluster alone.
The AASiMbResponseType struct you have to pass by reference. It has a fixed size array in it, again. You can emulate that using a fixed size cluster or replace the entire cluster with one u8 array.
Either construct the cluster manually or using the Array to cluster node. In this case, it is easier to just pass a 39-element byte array instead of a cluster.
See if that works.
09-08-2025 02:19 AM
Hi,
many thanks for your reply! I tried to call the function in that way. Looks very nice 🙂
Unfortunately LV still crashes. I think there still some kind of memory leak!
09-08-2025 06:33 AM
Try adding another dummy u8 parameter between request and response.
Sorry, I suppose this has to do with stack alignment, but my knowledge about that is virtually nonexistent.
Stuff like this is also the reason why the general recommendation is to create wrapper libraries. Then you can have the compiler take care of the really low level stuff and provide a more LabVIEW-friendly interface that might also work for different bitness. This here definitely will not work for 64 bit.
09-10-2025 03:03 AM
I would try making the request and response both the 39 byte array types. I have done this for value and reference struct types and did not break it up into multiple parameters, did all the binary formatting on the LabVIEW side.
09-11-2025 03:12 AM - edited 09-11-2025 03:14 AM
That works on 64 bit Windows, because larger structs must be passed by reference, regardless of the function prototype.
__m128
types, arrays, and strings are never passed by immediate value. Instead, a pointer is passed to memory allocated by the caller. Structs and unions of size 8, 16, 32, or 64 bits, and__m64
types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller. For these aggregate types passed as a pointer, including__m128
, the caller-allocated temporary memory must be 16-byte aligned.
https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#parameter-passing
I think that implies a temporary copy is created. Otherwise the calle could modify the original data.
09-14-2025 05:32 AM - edited 09-14-2025 05:39 AM
@M-DO wrote:
Hi,
many thanks for your reply! I tried to call the function in that way. Looks very nice 🙂
Unfortunately LV still crashes. I think there still some kind of memory leak!
The principle is ok, but you are treating each char as an inidividual parameter. A structure in C is however flattened in memory. That means that a parameter can contain 4 bytes in 32-bit LabVIEW and 8 bytes in 64-bit LabVIEW.
Your structure therefore needs to be converted into a number of 32-bit or 64-bit values that are then passed as individual parameters to the function.
So for 32-bit LabVIEW you end up with 36 + 3 bytes distributed over 10 32-bit integers and in 64-bit LabVIEW it will be in 5 64-bit values. To make matters even more interesting, you have to account for endianess and possible alignment. So the DatLen goes into the LSB of the first 32-bit parameter. Then follows the Opcode and Circuit. Since the Data is byte sized, I'm fairly positive that it directly follows the 3 first bytes, so the Data[0] element would end up in the MSB of the first 32-bit parameter. But I'm not 100% positive about this, so you may have to experiment. Then continue for the remainder of the Data in the same way, filling up unused elements with 0.
ExpResLen would seem to be a shortcut for "expected response len" so might indicate the length of the last parameter but if you are positive that -1 works too, then why not.
The 39 bytes for the last parameter should be ok, but I would generally round it always up to the next multiple of 32-bit or 64-bit, so in this case 40. That's what most modern compilers nowadays do as well. It should not crash as the DLL has no business trying to access that last filler byte, but I had situations where it did for some reason and actually crashed.
And as cordm mentions, the Win64 bit calling convention specifies that parameters that do not fit in a 64-bit register are always passed by reference, even if the C code specifies by value. So there you would pass the request parameter just as you do the response parameter, as an array pointer of 39/40 bytes. Or you could create a cluster with the 3 initial values followed by a second cluster with 36 U8 and pass it as Adapt to Type. But for 32-bit you have to do the "flatten into 32-bit values" to pass individually for the first structure.
Considering the technique and syntax, it is clear that it is a rather old API, possibly originally developed in some other language than C such as Pascal or Delphi and the muling about 64-bit above is most likely useless as there is a good chance that this library was never ported to 64-bit.
09-16-2025 08:01 AM
Hi everyone
After implementing the latest hints from @rolfk everything works! The -1 for the response length was defined by the DLL-developer for "unknown".
Thanks a lot to all of you guys for the fast and good support!