Developer Center Resources

cancel
Showing results for 
Search instead for 
Did you mean: 

Passing and Receiving Pointers with C/C++ DLLs from LabVIEW

 

» Calling External Code » Calling C/C++ DLLs » Passing and Receiving Pointers

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

Passing Pointers to Integers (and other primitives)

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);

010PassingPointerToInteger.png

Passing Arrays

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);

020PassingPointerToArray.png

 

 

Passing Pointers to Strings

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);

030PassingPointerToString.png

 

 

Passing Structs and Pointers to Structs

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);

040PassingPointerToStructs.png

 

 

Receiving Pointers

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

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.

 

045ReceivingPointer.png

 

Receiving Pointer as Memory Address and Manually Dereferencing

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.

 

050ReceivingPointer.png

 

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

Conclusion / Next Steps

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

 

Jervin Justin
NI TestStand Product Manager
Comments
Pie56694
Active Participant
Active Participant
on

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

rolfk
Knight of NI Knight of NI
Knight of NI
on

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.

Rolf Kalbermatter
My Blog
JCC_(SK)
Active Participant
Active Participant
on

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.

rolfk
Knight of NI Knight of NI
Knight of NI
on

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.

Rolf Kalbermatter
My Blog
JCC_(SK)
Active Participant
Active Participant
on

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

Southern_Cross
Member
Member
on

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?