09-01-2025 11:04 PM
Hello,
I'm working on integrating the MEMS-FPI spectrum module from Hamamatsu into my LabVIEW application. The official DLL provided by Hamamatsu includes a function:
HRESULT hpkfpi_getdevcount(HPKFPI_INITPARAM* initparam);
The HPKFPI_INITPARAM structure is defined as:
#define HPKFPI_INITARY_NUMBER 255
#define HPKFPI_INITARY_STRLEN 32
typedef struct {
int32_t sizeof_parameter;
int32_t devicecount;
char buf_VID[HPKFPI_INITARY_NUMBER][HPKFPI_INITARY_STRLEN];
char buf_PID[HPKFPI_INITARY_NUMBER][HPKFPI_INITARY_STRLEN];
char buf_SERIAL[HPKFPI_INITARY_NUMBER][HPKFPI_INITARY_STRLEN];
} HPKFPI_INITPARAM;
Where:
sizeof_parameter: Size of the structure (24488 bytes)
devicecount: Number of connected devices (0 to 😎
buf_VID, buf_PID, buf_SERIAL: Buffers for receiving vendor IDs, product IDs, and serial numbers, respectively.
I'm encountering difficulties when attempting to pass this structure to the DLL using LabVIEW's Call Library Function Node (CLFN). Specifically, I'm unsure how to correctly pass the HPKFPI_INITPARAM cluster. Below is what I had but I kept getting the invalid parameter error code. Any insights or examples would be greatly appreciated.
Solved! Go to Solution.
09-02-2025 02:22 AM
LabVIEW arrays are not the same as C array pointers and what you have in that structure is again a different thing than a C array pointer. Fixed size arrays in a structure are inlined by the C compiler. You got that basically already right by calculating the sizeof_parameter correctly.
So you need to create an array of bytes with 24488 bytes and pass that to the Call Library Node (CLN) after you filled in the 24488 in the sizeof_parameter 32-bit integer in the front.
Easiest to do that is by using the Flatten to String function to add the sizeof_parameter into the array, then pass the whole to your CLN and afterwards get the relevant data out.
I leave the exercise of getting the 255 potential strings with up to 32 characters each for you to tackle. Most likely those strings are padded with zero bytes at the end to fill up the 32 characters each, so it would probably be useful to scan for that and limit the actual strings accordingly.
09-03-2025 03:11 AM
Thank you very much for the input. I've gotten basic functions working, but I'm stuck on a more complex function and would appreciate some guidance. The function HRESULT hpkfpi_getinfo(HFPI hfpi, HPKFPI_INFO* info);
hfpi is device handle (U64) from another function and info is
typedef struct {
int32_t sizeof_parameter;
uint32_t idInfo;
char* buf;
int32_t bufsize;
} HPKFPI_INFO;
Where:
I initialized a 24 byte array of 0, initialize sizeof_parameter to 24, idInfo to 3 and bufsize to 32. How do I properly tell the DLL the address of my 32-byte string buffer? I assume I cannot just calculate a memory address myself. Is there a way to configure the CLFN so it automatically handles the pointer or do I need to use a different method to pass the address of my buffer into the buf of the array? Would greatly appreciate any hints on this issue.
09-04-2025 12:39 AM
Did more testing and I guess the way to do it is to create an empty contiguous block and add the pointer to that address to the 'info' input? I have been trying to dereference the value written at that address but not sure why I can't get the correct value. i tried creating an array with size 32 as destination for the MoveBlock but it immediately crash LabVIEW. Then I tried creating another address and pass as pointer but I am unable to extract the value I wanted. Is this because I am reading just the first 8 bytes of the block? Below is what I tried. Any help would be greatly appreciated.
09-04-2025 01:59 AM
You have the right idea, but in order to use the data in LabVIEW, you need it in a block diagram array.
Get rid of the second DSNewPtr, you need Initialize Array instead.
MoveBlock is not configured correctly
- fIrst argument (source) is pointer sized integer by value
- second argument (destination) is array of u8, array data pointer
- third argument is size_t, so u64 on 64 bit
DSNewPtr, MoveBlock, DSDisposePtr, 64 bit
Why is sizeof the struct 24? I would have guessed 20. Where is the padding if it is 24?
09-04-2025 03:10 AM
Thank you for your previous help. With your guidance, I have made progress and am now able to retrieve strings using the code. However, I am encountering an issue with non-printable characters in the results. While this is acceptable for some idInfo values, it causes problems for others.
I have experimented with changing both the original array size and the size parameter used for extraction, but these changes have not resolved the issue. I also share the suspicion that the input array might only need to be 20 bytes. However, the manual explicitly states that the sizeof_parameter is 24 bytes. My current approach is to: Initialize a U8 array of size 24. Modify the various bytes according to the suggestions by @rolfk. So essentially 4 bytes of zeros are padded to the actual 20 bytes data.
Using this method, the expected output string for my sensor should be C17342 but I got
I have tried adjusting the allocated array size for the function and the info array size, but nothing has yielded the correct string so far. Any advice would be greatly appreciated. Thank you
09-04-2025 06:37 AM
Odd, does the library need to be initialized? Check if hpkfpi_getinfo succeeds. You can use DSNewPClr to ensure you use clean memory and don't get random data if it fails.
Cut of the string at the first zero byte to drop the rest of the buffer that does not belong to the string.
Do not forget to call DSDisposePtr to free the pointer.
Normally I would use a cluster in this case, but the struct size is odd. Does the documentation mention alignment or padding rules?
09-04-2025 09:44 AM - edited 09-04-2025 10:25 AM
@jaywai88 wrote:
I have experimented with changing both the original array size and the size parameter used for extraction, but these changes have not resolved the issue. I also share the suspicion that the input array might only need to be 20 bytes. However, the manual explicitly states that the sizeof_parameter is 24 bytes.
Well, it is indeed only using 20 bytes but there is an additional alignment requirement which states that a structure size is also determined by the size needed to align the following structure element if it was used in an array of structure elements. Since your structure contains a pointer, which is an 8-byte entity in 64-bit code, this means that the whole structure needs to also be aligned on an 8-byte memory boundary, so that the structure "can" be padded with bytes at the end to fill up for that. sizeof() normally accounts for that in modern C compilers (but didn't always do that in all cases in the past with certain C compilers). Most likely the programmer of the DLL simply makes a check that sizeof_parameter == sizeof(HPKFPI_INFO) and errors out if it doesn't, so filling in 24 here, if you are on LabVIEW 64-byte, on LabVIEW 32-bit it would be 16, is likely required. Technically, a memory block of 20 bytes should work too, without crash as the underlaying DLL code technically should never try to access beyond the bufsize element.
My current approach is to: Initialize a U8 array of size 24. Modify the various bytes according to the suggestions by @rolfk. So essentially 4 bytes of zeros are padded to the actual 20 bytes data.
Using this method, the expected output string for my sensor should be C17342 but I got
I have tried adjusting the allocated array size for the function and the info array size, but nothing has yielded the correct string so far. Any advice would be greatly appreciated. Thank you
That is expected since you copy the full 32-bytes in the MoveBlock, but these are really zero terminated strings with the remainder of the 32-bytes just random gibberage of whatever was in memory when the whole block was allocated.
There is a little trick that LabVIEW holds for you to avoid having to scan for the NULL byte yourself. If you place the Bytes To String function before the MoveBlock call, and configure the second parameter as a LabVIEW String, Pass a C Data Pointer, the LabVIEW Call Library Node will do the NULL byte scanning for you and terminate the string at the first occurrence of such a NULL byte.
Basically, if you have a byte array that can legitimately contain NULL bytes that you want to return to your diagram, you have to configure the Call Library Node parameter as Byte Array, Pass as C Data Pointer. If said byte array is however actually a zero terminated string, configure the according CLN parameter as String, Passed as String Data Pointer.
My approach would be for this function rather this:
Points to consider:
- No need to flatten this specific structure to a byte array to pass to the DLL. I only did it in the previous case since it is very tedious and complicated to build a cluster with the large inlined arrays, since an inlined array is in fact in LabVIEW another cluster with the specific amount of elements in it, so each of your inlined string array buffers would be a cluster of 255 clusters of 32 u8 elements.
- This is specifically only for the 64-bit version of the DLL. A 32-bit version would require a different cluster architecture with the buf pointer being a u32 and the value passed to the sizeof element being 16.
- The MoveBlock node has the second parameter specifically configured to allocate a minimum size equal to the third paramater. Saves you an Initialize Array and Byte Array to String node on the diagram.
- You really should deallocate any pointer allocated with DSNewPtr after use as you otherwise create a memory leak.
09-05-2025 12:59 AM - edited 09-05-2025 12:59 AM
@rolfk the solution you suggested fixed the non-printable character issue I was running into. I really appreciate your guidance. Thanks to the rest of the community as well, your insights helped me understand things much better. I should be able to move forward from here!