UserXXX Posted February 7, 2007 Report Share Posted February 7, 2007 Hello, this must be very common problem when calling DLL:s, but still I haven't found clear and usable solution for it. I'm using LV 8.2 with DLL import wizard, but when I call a DLL, where are functions with parameters which are pointer to structures the wizard says "The function(s) are not declared in your header file." For example, structure "Example_name" in my header-file (64 bytes): struct Example_name { char one[32]; short two; long three; char four[3]; }; and my function "Example_function" in DLL: extern "C" CCONV Example_function (short something, Example_name *about); How can these structures be used when calling DLL with LabVIEW? Is it so that I can't solve this problem with DLL-wizard (by modifying the header-file, but I can't modify the DLL) and I must use normal calling node? I already tried to make a cluster and flatten it to a string, but after calling I get result only the first element value ("one"). (or only part of it; the first two bytes are "0" after calling). I made char one[32] -array to a 32-element cluster before flattening but it doesn't work anyway. I also tried to unflatten the string returned from DLL after calling but i get "generic error". (tried with different "endian" & "prepend array or string size" with LV flatten to string -function). Any good examples? Waiting for help & hoping for the best... Quote Link to comment
Tomi Maila Posted February 7, 2007 Report Share Posted February 7, 2007 How can these structures be used when calling DLL with LabVIEW? It seems that the DLL import wizard cannot manage the case. Create cluster in LabVIEW that consumes exactly the same amount of memomry as the C structure. Pass this cluster as a parameter to the library and use Adapt to type for the input type. I think for value strucures use Handles by Value specifier and for pointer structures use Pointers to Handles specifier. When creating the cluster note that strings and arrays are stored differently in LabVIEW and in C so don't use strings and arrays in your cluster. You may try to use the following conversions: C -> LabVIEW int, long -> I32 unsigned int, unsigned long -> u32 short -> I16 unsigned short -> U16 char -> i8 unsigned char -> u8 long long -> i64 unsigned long long -> u64 char[N] -> a cluster with N times U8 constants So for your example struct create a cluster with the following elements cluster of 32 times U8 or a cluster of 4 times U64 I16 I32 a cluster of three U8 Tomi Quote Link to comment
Dirk J. Posted February 7, 2007 Report Share Posted February 7, 2007 I have a similar question... how to handle functions from a dll that pass a pointer? I'm trying to use the FFTW routines, a code mockup looks like this: 'plan' is of type pointer plan = fftw_plan_dft(datalenght, inputarray outputarray, direction, method) .. fftw_execute(plan) .. fftw_destroy(plan) how is 'plan' represented in LV, and how do I configure the library node in this case? Quote Link to comment
Tomi Maila Posted February 7, 2007 Report Share Posted February 7, 2007 You can use U32 for any kind of pointer in a 32 bit operating system. U32 value 0 means NULL pointer. However you cannot preallocate memory to the location your pointer refers (unless you call memory manager functions in LabVIEW.exe). So pretend your function interface was: unsigned long fftw_plan_dft(...) // allocates memory block .. fftw_execute(unsigned long p) // uses memory block .. fftw_destroy(unsigned long p) // destroys memory block Quote Link to comment
James N Posted February 7, 2007 Report Share Posted February 7, 2007 Tomi, I've always had problems with this as well. Luckily all were in-house created DLLs and I could ask the programmer to not use a structure. So you're saying create a cluster like in the picture and pass this into the Call Library Function? ..with the input type as Adapt to Type. I assume cluster order is important too. -James Quote Link to comment
Tomi Maila Posted February 7, 2007 Report Share Posted February 7, 2007 So you're saying create a cluster like in the picture and pass this into the Call Library Function? ..with the input type as Adapt to Type.I assume cluster order is important too. Yes, I think it should work that way. Clusters are passed as values or pointers depending on if you use "handles by value" or "pointers to handles". You need to do some typecasting within LabVIEW to transform between the inner clusters of U8 and some LabVIEW type before and after the library call. Tomi Quote Link to comment
Rolf Kalbermatter Posted February 7, 2007 Report Share Posted February 7, 2007 Yes, I think it should work that way. Clusters are passed as values or pointers depending on if you use "handles by value" or "pointers to handles". You need to do some typecasting within LabVIEW to transform between the inner clusters of U8 and some LabVIEW type before and after the library call. Tomi Actually clusters are always passed as pointers. The "pointers to handles" and "handles by value" only refer to LabVIEW datatypes that are represented with handles such as arrays and strings and also only for the main datatype if it is such a handle, not for embedded handles in clusters, etc. And yes James what you show in your screen shot should work if you do it exactly that way. Rolf Kalbermatter Quote Link to comment
Tomi Maila Posted February 7, 2007 Report Share Posted February 7, 2007 Actually clusters are always passed as pointers. The "pointers to handles" and "handles by value" only refer to LabVIEW datatypes that are represented with handles such as arrays and strings and also only for the main datatype if it is such a handle, not for embedded handles in clusters, etc. Thanks for the correction By the way, Cluster to Array and Array to Cluster primitives may be handy when you need to build the inner cluster of 32 elements. Quote Link to comment
UserXXX Posted February 8, 2007 Author Report Share Posted February 8, 2007 Thanks for everybody so much! :worship: Everything works ok now, my problem was with memory allocation because of arrays inside clusters. LabVIEW rules... Quote Link to comment
UserXXX Posted February 8, 2007 Author Report Share Posted February 8, 2007 One more question about structures: How do I make it with LabVIEW, if there are sequences(structure name inside structure?), for example: struct First_coadd { double... long... short... char... ... } struct Second_status { First_coadd coadd; First_coadd coaddf; ... } Can you still help me with this...? Quote Link to comment
Rolf Kalbermatter Posted February 8, 2007 Report Share Posted February 8, 2007 One more question about structures:How do I make it with LabVIEW, if there are sequences(structure name inside structure?), for example: struct First_coadd { double... long... short... char... ... } struct Second_status { First_coadd coadd; First_coadd coaddf; ... } Can you still help me with this...? As long as those clusters to not contain variable sized elements (pointers, arrays with [] instead of [x]) you simply inline them into one big continous memory area. Actually you can keep the clusters in the clusters for better readability as LabVIEW does this same inlining too. The only problem you need to watch out here is possible byte padding. LabVIEW always uses byte packing without any padding but most external libraries nowadays use 8 byte padding. That means the offset of an element is always aligned to the smaller of the two values: 1) a multiple of the data type size 2) the alignment (here 8 byte) by adding extra filler bytes before that element to make it aligned. You can actually adjust for that too by simply adding the necessary amounts of uInt8 and uInt16 dummy elements before the aligned element since adapting to alignment with a packing compiler is possible but not otherwise. Rolf Kalbermatter Quote Link to comment
MHn Posted February 8, 2007 Report Share Posted February 8, 2007 Some time ago I had a similar problem - i need to call dll-functions with structs containing pointers to strings or other structs. I solved the problem using strcpy-API-functions, which can be used to copy strings to another memory location and then return a pointer to the new memory location. This pointer can be used afterwards as an I32-value within the struct. Please mention, that you will have to control memory-allocation for this manually (allocating and freeing). Martin Quote Link to comment
Rolf Kalbermatter Posted February 9, 2007 Report Share Posted February 9, 2007 Some time ago I had a similar problem - i need to call dll-functions with structs containing pointers to strings or other structs.I solved the problem using strcpy-API-functions, which can be used to copy strings to another memory location and then return a pointer to the new memory location. This pointer can be used afterwards as an I32-value within the struct. Please mention, that you will have to control memory-allocation for this manually (allocating and freeing). I know about this technique and have used it infrequently in the past. But basically in order to be able to do that you need to know a lot about how you would do that in C and then it gets almost always as easy or even easier to just write a wrapper DLL that does the correct translation. It's definitely not for anyone that has trouble to understand pointers and references. So instead of mentioning that this can be done and have people ask me to do it for them I just say it can't really be done. The people that know how to do it or at least know enough to be able to figure it out can easily find it themselves and usually agree after the first trial that it's very frustrating work to do. Doing alloc(), memcpy(), free() through LabVIEW CLNs is while possible, a bitch to do and the diagram basically looks very soon like someone had a very bad programming day. Rolf Kalbermatter Quote Link to comment
UserXXX Posted February 15, 2007 Author Report Share Posted February 15, 2007 Thank you Rolf. I made clusters inside clusters and it seems to work ok in this case. I still have some troubles; how do I create cluster from a large data array for example: unsigned char data[32768]; I tried to make it from unsigned char array constant, but "array to cluster" is limited to 256 elements? This array size is dynamic in C, but it would be better to allocate memory for maximum in LV? Array's size is huge anyway Quote Link to comment
Rolf Kalbermatter Posted February 15, 2007 Report Share Posted February 15, 2007 QUOTE(UserXXX @ Feb 14 2007, 02:36 AM) Thank you Rolf.I made clusters inside clusters and it seems to work ok in this case. I still have some troubles; how do I create cluster from a large data array for example: unsigned char data[32768]; I tried to make it from unsigned char array constant, but "array to cluster" is limited to 256 elements? This array size is dynamic in C, but it would be better to allocate memory for maximum in LV? Array's size is huge anyway You don't! A cluster with so many elements would be awkward to work with. One thing you can do if the entire cluster is still flat is treating it as a single array of U8. The difficulty with this is that you need to do your own Replace Array Subset into that array at the right offsets (you will have to calculate those offsets yourself) before passing the array to te CLN and also doing Array Subset or Index Array with the right offsets to get possible data out of the array afterwards. Still works but it is a major pita and the moment for me to start a C compiler and create an intermediate DLL for sure. Rolf Kalbermatter Quote Link to comment
UserXXX Posted February 15, 2007 Author Report Share Posted February 15, 2007 Hmm... I have to think a little bit more... How about 2D-arrays; how do I pass 2D-arrays by creating clusters? For example: 64 lines x 4 columns ? [long] Just add 4 "64 size long cluster" inside another cluster? (it doesn't matter which are columns/lines when dimensions & data type is correct?) Quote Link to comment
Tomi Maila Posted February 15, 2007 Report Share Posted February 15, 2007 QUOTE(UserXXX @ Feb 14 2007, 02:22 PM) How about 2D-arrays; how do I pass 2D-arrays by creating clusters? For example: 64 lines x 4 columns ? [long] Just add 4 "64 size long cluster" inside another cluster? (it doesn't matter which are columns/lines when dimensions & data type is correct?) As long as the array on the C-side is of fixed size at compile time then yes, the cluster trick works. If your 2D array is a top-level parameter i.e. is not inside of a C struct, then you can also pass it directly as an array assuming you have initialized the array to correct size first on LabVIEW side. Select array for parameter type and array data pointer for parameter format. Tomi Quote Link to comment
UserXXX Posted February 15, 2007 Author Report Share Posted February 15, 2007 $#!% happens... this 2D-array is inside a struct, and this whole struct is part of another struct, actually inside its "union" and inside this struct and its "union" there is also 1D-array [1400] (char type)... Actually I have to use LV:s "flatten string" also, because I must flatten these clusters to string before writing/receiving them with UDP/TCP-sockets. And it seems that it doesn't work if I just put normal arrays inside clusters... Have to read Rolf's advices once more... :headbang: Quote Link to comment
Tomi Maila Posted February 15, 2007 Report Share Posted February 15, 2007 QUOTE(UserXXX @ Feb 14 2007, 04:04 PM) Have to read Rolf's advices once more... :headbang: You are in a position where you should write a C wrapper for your call. Here you pass your data to your C wrapper what ever way you consider easiest and then construct the C structs from this data in your C wrapper. When it's time to pass your data back to LV do the reverse, construct your LV data from the structs. For detailed information and reference on how to interface C code from LabVIEW see http://digital.ni.com/manuals.nsf/websearch/8D930295FFBF9F7686256D2C00624728' target="_blank">Using External Code in LabVIEW. Quote Link to comment
UserXXX Posted February 16, 2007 Author Report Share Posted February 16, 2007 Thanks Tomi, so I'm trying to receive UDP-packet which I must unflatten from string to receive as a cluster. First I have to tell "unflatten to string" -function used cluster type. The problem is with arrays (see attachment). I'm not calling a DLL now, but I have to create some kind of wrapper with "CIN" which gives me a cluster(?) I can route to unflatten to string -function ("type")? Quote Link to comment
Tomi Maila Posted February 16, 2007 Report Share Posted February 16, 2007 I must assume that you cannot use LabVIEW UDP functions for some reason... ??? If the above is valid, would you please post your C interface definitions and the definitions of all non-native type the function interface uses. Tomi Quote Link to comment
Rolf Kalbermatter Posted February 17, 2007 Report Share Posted February 17, 2007 QUOTE(UserXXX @ Feb 15 2007, 03:00 AM) Thanks Tomi,so I'm trying to receive UDP-packet which I must unflatten from string to receive as a cluster. First I have to tell "unflatten to string" -function used cluster type. The problem is with arrays (see attachment). I'm not calling a DLL now, but I have to create some kind of wrapper with "CIN" which gives me a cluster(?) I can route to unflatten to string -function ("type")? You have a serious problem with that structure. The variable sized array can not be flattened to a stream without adding extra information as to the length of it. And considering the complexity of your structure it seems a very bad idea to try to resemble that completely in a LabVIEW cluster. There will be little else to do for you than dissecting that cluster into its more manageble parts in a VI and stream it yourself int a byte array and to the format required by your remote side. Personally I think an application level protocol that uses such complicated structures is is more or less useless! Rolf Kalbermatter Quote Link to comment
UserXXX Posted February 17, 2007 Author Report Share Posted February 17, 2007 Because it's not necessary to send this kind of packet I decided only to receive them. And yes, receiving these packets should be possible by dissecting this big cluster into parts by calculating received string lengths and unflatten these known-offset parts separately. Arrays I need are usually the last component in a packet after header so I can calculate the offset for the array and unflatten it separately (hoping the type for unflatten function is ok just by defining array constant without initialising it's size). This UDP-problem can be solved this way, right now I have some more troubles with TCP-packets, but that's another story & topic... Thank you all! I'll be back soon... Quote Link to comment
hviewlabs Posted November 22, 2007 Report Share Posted November 22, 2007 8.5 now has (exposes) means to work with pointers directly specifically to address the problems in interfacing with C dlls: http://forums.lavag.org/index.php?showtopi...ost&p=38888 These are inserted into wrapper VIs by DLL Wizard, so we can (are allowed) to use them too, I guess. Quote Link to comment
hviewlabs Posted November 22, 2007 Report Share Posted November 22, 2007 8.5 now has (exposes) means to work with pointers directly specifically to address the problems in interfacing with C dlls: http://forums.lavag.org/index.php?showtopi...ost&p=38888 These are inserted into wrapper VIs by DLL Wizard, so we can (are allowed) to use them too, I guess. 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.