Jump to content

Calling DLL:s containing functions(parameters) with pointer to structure


Recommended Posts

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...

Link to comment
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

Link to comment

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?

Link to comment

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

Link to comment

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.

post-5791-1170870329.gif?width=400

-James

Link to comment
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

Link to comment
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

Link to comment
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.

Link to comment

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...? :unsure:

Link to comment
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...? :unsure:

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

Link to comment

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

Link to comment
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. :oops:

The people that know how to do it or at least know enough to be able to figure it out :book: 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

Link to comment

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 :blink:

Link to comment

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 :blink:

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

Link to comment

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

Link to comment

$#!% 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:

Link to comment

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")?

Link to comment

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

Link to comment

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... :P

Link to comment
  • 9 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.