viSci Posted March 15, 2018 Report Share Posted March 15, 2018 (edited) Was hoping someone might be able to give me a tip on this one... Trying to call the function below: typedef struct { unsigned int Length; unsigned int Id; unsigned int TimeTag; char Data[1024]; }DATA_FRAME; int __stdcall SRVIVR_API_StoreData(void* handle, int partition, int totalFrames, DATA_FRAME frameData[]); Here is what the import dll tool produces: This does not look correct to me and produces the dreaded 1097 exception error. I modified the call to be: Which I believe is closer to the intent of the original C function, but still gives me a 1097 error. I suspect that somehow the array pointer that the function is expecting is not correct. The frameData parameter is being passed into the function as a 'Adapt to Type', Array Pointer. I also tried flattening to a single U32 array and passing that in as an array data type but still no joy. Any ideas? BTW, I have had success calling many other functions from the dll of the form: int __stdcall func(void* handle, int param1, int param2, etc); Edited March 15, 2018 by viSci Quote Link to comment
Yair Posted March 15, 2018 Report Share Posted March 15, 2018 Whether you have separate elements or a cluster or a 1D array of clusters with a single element should probably not matter, as they are all the same in memory. I'm pretty sure the part you're missing is the char Data[1024] line - this means an array of 1024 bytes is expected (possibly so that it can be written into) and you're not allocating that memory. Try initializing the array to a size of 1024 bytes. Quote Link to comment
viSci Posted March 15, 2018 Author Report Share Posted March 15, 2018 Ok, that comment prompted me to dig some more into the IDD for the device and found that Length parameter, which I thought was the number of bytes in the data array is really the number of bytes in the data array plus 12 for the 3 long int parameters in the cluster. Once I made that change it all started working. Thanks for your help! Quote Link to comment
Rolf Kalbermatter Posted March 16, 2018 Report Share Posted March 16, 2018 (edited) Yes, Yair's idea won't work. The array inside the cluster is fixed size and therefore inlined. Putting a LabVIEW array in there is not only once wrong but even twice. First a LabVIEW array is not just a C array pointer but really a pointer to a pointer to a long pascal byte array, second there is not an array pointer but an inlined fixed size array in the structure. So the correct thing to pass is a byte array of 1024 + 12 bytes as you have already figured out. And more correctly it might be actually totalFrames * (12 + 1024) bytes. Also eventhough you may not plan to ever use this in 64-bit LabVIEW it still would be useful to configure the handle parameter as pointer sized integer instead (and use a 64 bit integer control on the front panel to pass that handle around in the LabVIEW diagrams). Edited March 16, 2018 by rolfk Quote Link to comment
viSci Posted March 16, 2018 Author Report Share Posted March 16, 2018 (edited) So does every *struct passed into a dll need to be flattened to a byte array? I guess in the previous case it only worked because I was passing a empty array in the cluster. So for something like this: // Structure to pass reconstruction parameters struct RECON_INFO_STRUCT { unsigned int cpmBlkSize; unsigned int sepTimeDelta; unsigned int sepByChannelFlag; //0=no, 1=yes unsigned int wavFormat; //0=mulaw, 1=pcm unsigned int decryptFlag; //0=no, 1=yes unsigned int AESKeySize; //0=128,1=192,2=256 char AESKey[CRYPTO_KEY_MAX_LENGTH_BYTES]; unsigned int makeReadableAfterReconFlag; char reconFile[MAX_PATH]; }; STATUS __stdcall SRVIVR_API_ReconFile(void* handle, char* partDataFileName, RECON_INFO_STRUCT* pReconInfo, void* pNotifyCB, void* pCBArg); Do I need to manually flatten everything to a single byte array or is there some way to use this? Edited March 16, 2018 by viSci Quote Link to comment
Rolf Kalbermatter Posted March 16, 2018 Report Share Posted March 16, 2018 (edited) Well every structure can be of course represented by a byte array. But you don't always have to go through those trouble. Fixed arrays inside a structure are in fact best implemented as an extra cluster in LabVIEW inside the main cluster with the number of elements indicated between the square brackets and of the type of the array. BUT: if the number of elements get huge this is not practical anymore as you end up with mega pronto saurus clusters in LabVIEW. Then you have two options: 1) flatten the entire cluster into a byte array and before the call insert into (for input values) and after the call retrieve the elements by indexing into that array at the right offset. Tedious? Yes you bet! And to make everything even more fun you also have to account for memory alignment of elements inside the cluster! 2) Create a wrapper DLL in C that translates between LabVIEW friendly parameters and the actual C structures. Yes it is some work, and requires you to know some C programming but in fact less low level knowledge about how a C compiler wants to put the data into memory than the first approach. Edited March 16, 2018 by rolfk Quote Link to comment
viSci Posted March 16, 2018 Author Report Share Posted March 16, 2018 I like the idea of a cluster within a cluster. Is it then possible to just use an array to cluster going into a cluster bundle to add in the fixed arrays? Quote Link to comment
Aristos Queue Posted March 16, 2018 Report Share Posted March 16, 2018 The other option is to create a cluster of 1024 int8 values and use that for the inlined char array. Quote Link to comment
Rolf Kalbermatter Posted March 16, 2018 Report Share Posted March 16, 2018 (edited) 52 minutes ago, viSci said: I like the idea of a cluster within a cluster. Is it then possible to just use an array to cluster going into a cluster bundle to add in the fixed arrays? Nope! Array to Cluster is limited to 256 elements in its Right click popup menu. Of course you could add 4 clusters of 256 bytes each directly after each other. Edited March 16, 2018 by rolfk Quote Link to comment
Rolf Kalbermatter Posted March 16, 2018 Report Share Posted March 16, 2018 (edited) 49 minutes ago, Aristos Queue said: The other option is to create a cluster of 1024 int8 values and use that for the inlined char array. You like mega pronto saurus clusters, don't you! Edited March 16, 2018 by rolfk Quote Link to comment
viSci Posted March 16, 2018 Author Report Share Posted March 16, 2018 Not sure were the 1024 comes in as AES key here is 32 bytes and the ReconFile path is 260 characters. As you said to get 260 I would have to append two clusters. Here is my latest clusterasaurus... Unfortunately this still is not satisfying the DLL. It is not blowing up but returning an error indicating an invalid parameter so I might not be too far off... Quote Link to comment
viSci Posted March 16, 2018 Author Report Share Posted March 16, 2018 Finally, It works! Sometimes a clusterasaurus is just what you need. The cluster within cluster idea is a neat trick, thanks Rolf. Quote Link to comment
Yair Posted March 18, 2018 Report Share Posted March 18, 2018 On 3/16/2018 at 3:05 PM, rolfk said: Yes, Yair's idea won't work. The funny thing is that I actually ran into this myself more than once, but I keep forgetting that it's not like flattening the array using the LV flattening functions and that you need to inline the bytes yourself using a cluster. I seem to recall making that mistake more than once and then having to fix it after testing. Quote Link to comment
Aristos Queue Posted March 20, 2018 Report Share Posted March 20, 2018 On 3/16/2018 at 11:13 AM, rolfk said: You like mega pronto saurus clusters, don't you! No, but it is an option, and sometimes when talking to a foreign language, it is better to bow to the grammar of the foreign language than to cleave to the proper grammar you might normally use. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.