» Calling External Code » Calling C/C++ DLLs » Passing and Receiving Pointers
C and C++ functions often accept pointers in their function prototypes. A pointer is basically an integer value representing a memory address.
To pass a pointer to a DLL, that is, the memory address of a value to a DLL from LabVIEW, you have to configure the Call Library Function Node to pass the data by reference, rather than by value. You cannot directly pass in the memory address as LabVIEW does not expose the memory allocation of data to programmers.
The following is the Call Library Function Node configuration for a function that takes a pointer to an integer. The Pass dropdown should be changed to Pointer to Value.
void ReturningValuesByReference_Integer(int x, int y, int *sum);
Arrays are by definition pointers in C/C++. This means that an array variable really just holds the memory address of the first element of the array.
The following is the Call Library Function Node configuration for a function that takes an array of integers. The Type should be set to Array. Pick the appropriate data type for the array (integer in this case), and leave the default Array Format dropdown value, Array Data Pointer.
int PassingParamters_ArrayOfIntegers (int x[], int length);
Strings are a special case because a string is really just an array of type char. Because of this, by default, they are already passed by reference.
The following is the Call Library Function Node configuration for a function that takes a string input. Leave the String Format as its default – C String Pointer.
int PassingParamters_String (char *str);
The following is the Call Library Function Node configuration for a function that takes a struct and a pointer to a struct. To pass a struct, you can simply pass in the constituent elements in order, and to pass a pointer to a struct, you can pass the cluster representing the struct as Adapt to Type input with its data format set to Handle by Value.
void ReturningValuesByReference_SimpleStruct (struct simpleStructCircle circle, struct simpleStructCircle *largerCircle);
C/C++ DLLs will often return data using a pointer to the memory location of the value requested. This is done in one of two ways:
1. Returning a pointer: The pointer is returned as the ‘return value’ of the function, as in the following example.
int * ReturnAValue_PointerToInteger(void)
{
int *x = (int *) malloc(sizeof(int));
*x = 5;
return x;
}
Because the Call Library Function Node only allows return types of Integer, String and Void types, you must accept the pointer as an integer representing the memory address and manually dereference the pointer to get its value.
See section Receiving Pointer as Memory Address and Manually Dereferencing
2. Pass by Reference: The pointer is returned through a parameter of the function
void ReturningValuesByReference_Integer (int x, int y, int *sum)
{
//sum is a pointer
*sum = x + y;
}
Based on the data typed returned, you can either automatically dereference the pointer (such as numerics and simple structs), or accept the pointer as an integer value representing the pointer and manually dereference the pointer to get its value.
See section Receiving Pointer as Memory Address and Manually Dereferencing and Receiving Pointer and Automatically Dereferencing
The Call Library Function Node will allow you to automatically dereference pointers to some of the common data types in LabVIEW such as numerics and simple structs. The process to do this is exactly the same as passing a pointer to a DLL, and treating the parameter as an output rather than as in input.
To receive a pointer you must configure the Call Library Function Node to accept an Integer Value. This integer value is the memory address. Once you have the memory address, you must dereference the address to get the actual value.
To configure the Call Library Function Node to receive a pointer, set the Type to Numeric and the data type to Signed Pointer-sized Integer. The Pointer-sized Integer will automatically use the appropriate pointer size (32-bit vs. 64-bit) on the Call Library Function Node based on your OS and LabVIEW.
Note: You will see a coercion dot if you pass a 32-bit Integer to this input, even if you are on a 32-bit OS.
For details on how to dereference the pointer (that is, get the value that the pointer ‘points’ to), refer to:
Dereferencing Pointers from C/C++ DLLs in LabVIEW
For details on how to dereference a pointer in LabVIEW as well as special cases, refer to:
Dereferencing Pointers from C/C++ DLLs in LabVIEW
For examples on handling pointers using both methods described above, refer to:
Calling C/C++ DLLs Containing Simple and Complex Datatypes from LabVIEW
This is a great article and it helped me a great deal. For the Passing Structs and Pointers to Structs section: Handles by Value is correct for typedef struct {bla} TD1;. You should use Pointers to Handles for typedef struct {bla} TD1 **TD1Hdl;.
Actually Steve, it should not matter in this case. This option only applies to LabVIEW datatypes that are handles, when they are passed to the parameter configured as AdaptToType. A struct is never a handle, but LabVIEW internally simply a pointer to a memory block. As such this option only really applies to strings and arrays passed to the Call Library Node and is in fact redundant, since you can configure this in the according String and Array datatype too, more explicitedly. It's just that the Adapt to Type is really a superset of all other datypes, with the limitation that only native LabVIEW datatypes get passed into the function.
Thank you for great article.
I have got question: Is it possible to pass LabVIEW Data Value Reference to DLL? I need only read-only access in DLL to data stored behind Data Value Reference.
No, Data Value References are in fact refnums. Nothing you could dereference in there. And LabVIEW doesn't have a documented C API to retrieve the underlaying object from a Data Value Reference. Supposedly there is an API to do that, the functions starting with EDVR that are exported from LabVIEW.exe, but without a C header file and function documentation that is a dead end. And this API might be not documented for many reasons, among them might be that it is not considered stable and might be foreseen to change in future versions of LabVIEW.
Of course there is not much you couldn't just do by accssing the data inside the LabVIEW diagram through an in place structure, passing it throught the CLN and wiring the output of the CLN back into the in place structure.
The only thing you can't do that way is asynchronous data access in your DLL, but that would have a lot of extra implications for your C code, including actual management of threads, as you could otherwise easily deadlock your LabVIEW code.
Hi Rolfk
Thank you for replay.
I have got few GB of data in few DVRs and I wanted to pass it to DLL and use it and treat is as constant (no modification and multi-threads safe).
I only asked.
I will have to Delete DVR and send data to DLL normal way.
Thank you
Peter
I have a bit of a noob C/C++ shared library question.
I have C++ code that gets wrapped with a C interface so I can call/use it from labview. Let's say my interface is:
void* init(void); void step(void* ref); void close(void* ref);
where init creates the C++ object,
void* init(void) { ... myClass* obj = new myClass();
...
return obj; }
the reference to the obj is now passed to STEP and CLOSE from the LabVIEW diagram and cast as follows for use,
void step(void* ref) { myClass* obj = static_cast<myClass*>(ref); ... obj->someMemberfunc(); ... } void close(void* ref) { myClass* obj = static_cast<myClass*>(ref); delete obj; }
I've configured my Call Library Nodes a number of ways but none of these are working... (e.g. Signed Pointer-sized Integer, and Unsigned 64-bit Integer numerics).
I do NOT need to access the object on the LabVIEW diagram. I just need the object accessable by the other functions.
What am I missing here?