LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to use Call to Library Function with routine that expects (void *)?

I have a function in a DLL which can a accept large number of input arguments by reference, each of which can be of any one of many different data types. These argument refenences are all typed as (void *) in the DLL. It takes information in other arguments telling it what the type of the data referenced actually is. My problem is that the "Call to Library Function" node doesn't have an option for (void *) input parameters. This means that the Call node has to be separately configured for every separate use involving different numbers and types of input arguments. Since I don't have the developer version of Labview, I couldn't get around this problem by creating polymorphic VI which handles the
different permutations of inputs and corresponding configurations of the Call node. Even if I could create a polymorphic VI, the number of permutations of input types is nightmarishly large, which makes creating a polymorphic VI impractical (given my understanding of how they are created). So, my question is this: what might I do to make a single, general purpose subVI that does all the necessary work to use the Call node for a large variety of input parameter number and type permutations? I've looked into a couple of technologies that seem to have promise, but I haven't found anything satisfactory. I've looked into using the Type Cast node to cast everything to byte arrays which I pass to the appropriately configured Call node, but, while this works without crashes or error messages, somehow the data get scrambled in passage. I've considered using flattened data, but my understanding is that flattened data is in some machine independent format, while the input parameters to my DL
L function are supposed to be in the native machine format. Any ideas?

Thanks,
Neal.
0 Kudos
Message 1 of 6
(3,229 Views)
> I have a function in a DLL which can a accept large number of input
> arguments by reference, each of which can be of any one of many
> different data types. These argument refenences are all typed as
> (void *) in the DLL. It takes information in other arguments telling
> it what the type of the data referenced actually is. My problem is
> that the "Call to Library Function" node doesn't have an option for
> (void *) input parameters. This means that the Call node has to be
> separately configured for every separate use involving different
> numbers and types of input arguments. Since I don't have the


My approach to this would be to determine how it is to be used. If
there are common situations, then you can add them specifically to the
polyVI, and
as the fallback, you should look to use the Variant. You
could do something like accepting an array of variants. You will then
have a rather challenging subVI to write that pulls the types out of the
variant array and passes them into the DLL.

The equivalent of void* by the way is the adapt to type setting in the
dialog. This will allow any LV type to pass to the DLL. This doesn't
mean it will work, but it does mean that LV will call the DLL and pass a
data reference.

Greg McKaskle
0 Kudos
Message 2 of 6
(3,229 Views)
Neal,

Greg is on totally on the right track, there is just one thing I wanted to add. LabVIEW stores items in memory in a Big Endian format. When you typecast the data to a byte array, the bytes for the data are still in Big Endian format. When you call into a DLL, LabVIEW will change the data format when it calls the DLL for you. However, since you typcasted it to a byte array, this array has no Endianness since there is only a single byte. Try playing with a small array of doubles and using the byte swapping rountines on the byte array before and after passing it to your DLL to see if this resolves your issue.

Randy Hoskin
Applications Engineer
National Instruments
http://www.ni.com/ask
0 Kudos
Message 3 of 6
(3,229 Views)
Thanks for replying. Unfortunately, a polyVI is out because I don't have the right version of LV and if I did, my understanding of how they are made is that I that a subVI must made for every possible combination of inputs, which, in this case, would be a combinatoric nightmare. The DLL routine is a variable argument list routine, which means it may called with any number of inputs. Each arg can be a scalar or array of any dimensionality and can be string or any numeric type. The type of each arg is independent. If I, for instance, decided to limit my polyVI to 4 args, which could be scalar or 1D to 3D arrays of strings, int32 or singles, the number of combinations of argument patterns is 4x4x3. That's 48 subVIs in the polyVI.

I thought about using variant args in the subVI which wraps my DLL, but I couldn't figure out how certain intermediate steps in the wrapper could be achieved. Inside the DLL, for the arguments which are (void *), the DLL needs to receive pointers to contiguous memory segements containing data in whatever the machine dependent format is for atomic data types (e.g. float and int32). This means that, from a C perspective, the pointers are to 1D arrays of atomic data types. The intermediate steps I would need to achieve in a wrapper subVI would be, for each arg, to extract a variable of unknown array dimensionality and atomic data type from a variant, reshape it to 1D and somehow pass to the DLL a pointer to a contiguous memory segement containing the array's data in machine dependent format. All these steps are beyond my grasp given my understanding of LV 6.0. If you have any ideas, I'd interested in hearing them. For instance, is there any approach to solving these problems using VI Server capabilities such as Invoke nodes and Property nodes? Is there an easy way to manipulate flattened data and the type values returned from the Flatten Data node to reshape arrays which are, at run time, of unknown data type and dimensionality (e.g. extracted from a variant)?

You mention that (void *) is equivalent to "Adapt To Type". My impression, based on the sparse info about "Adapt To Type" in the NI Developer Zone, is that if I wired an arg to an "Adapt To Type" terminal of the "Call to Lib. Func." node, the DLL would receive a pointer to a memory segment containing data in Labview's internal format. For 1D arrays, I gather that this amounts to a pointer to a contiguous memory segement containting a header with type and length info followed by a sequence of data elements in Labview internal format for the atomic data type. If this understanding is correct, then in I really can't use "Adapt to Type" terminals because, as stated above, the DLL routine expects pointers which point directly to the first data element of an array with data in C-style machine dependent format. Is this understanding correct?

Thanks,
Neal.
0 Kudos
Message 4 of 6
(3,229 Views)
This is somewhat more work than I'd like and somewhat less elegant, since I'd have to create an appropriate byte-array manipulation for every atomic data type and the manipulations would definitely be machine dependent. However, if I narrow my ambitions somewhat for my wrapper subVI, it may be a way to go.

Thanks,
Neal.
0 Kudos
Message 5 of 6
(3,229 Views)
....
>
> You mention that (void *) is equivalent to "Adapt To Type". My
> impression, based on the sparse info about "Adapt To Type" in the NI
> Developer Zone, is that if I wired an arg to an "Adapt To Type"
> terminal of the "Call to Lib. Func." node, the DLL would receive a
> pointer to a memory segment containing data in Labview's internal
> format. For 1D arrays, I gather that this amounts to a pointer to a
> contiguous memory segement containting a header with type and length
> info followed by a sequence of data elements in Labview internal
> format for the atomic data type. If this understanding is correct,
> then in I really can't use "Adapt to Type" terminals because, as
> stated above, the DLL routine expects pointers which point directly to
> the first data element of an array with data in C-style machine
> dependent format. Is this understanding correct?
>

Several topics up in the air here. First, void*. When using void* in
C/C++, it basically means that the type can't be used for anything but
pointer math. Casting types in C to void* does nothing but allow the
compiler to compile the code, it changes nothing and leaves them in
whatever form they were. That is pretty much what the LV Adapt to Type
does. The difference is that it passes pointers to the LV datatypes as
they are in memory, it doesn't convert to C types, to do that you have
to tell LV what you want, void* gives no information about what the DLL
is supposed to do.

Next, lets talk about the difficulty in doing this project. You are
trying to wrap an arbitrarily complex variable argument function with
fixed function wrappers. Unless you are willing to pick a subset of
common uses, you will never finish this task, in any language. You can
make some headway by looking at variants, but you will still have lots
of work as you will need to parse the variants out by type and build up
a record of some sort that you can move to the stack in a C wrapper
function. You can also use the DLL node each and every time you want to
call into the DLL, but each time it is dropped, the configuration will
need to be updated and correct or the program will fail, just as each
call from C will have to be correct or cause a failure.

You also haven't mentioned anything about what this DLL does. This
functionality may already be available, with someone else having solved
these problems.

Greg McKaskle
0 Kudos
Message 6 of 6
(3,229 Views)