I want to import a DLL to LabVIEW and create VIs from my functions, but for simple functions with common data types, the import works good. My problem is when the function have a struct data type.
I follow this tutorial to import.
My DLL files:
test.h
:
#ifndef TEST_H_
#define TEST_H_
typedef struct
{
int r_sum;
int r_minus;
int r_multiply;
float r_divide;
}CALC_t;
int sum(int a, int b);
int minus(int a, int b);
int multiply(int a, int b);
float divide(int a, int b);
CALC_t calc_all(int a, int b);
#endif /* TEST_H_ */
test.c
:
#include "test.h"
int sum(int a, int b)
{
return a+b;
}
int minus(int a, int b)
{
return a-b;
}
int multiply(int a, int b)
{
return a*b;
}
float divide(int a, int b)
{
return (float)a/b;
}
CALC_t calc_all(int a, int b)
{
CALC_t result;
result.r_sum = sum(a, b);
result.r_minus = minus(a, b);
result.r_multiply = multiply(a, b);
result.r_divide = divide(a, b);
return result;
}
When I import the DLL, the VIs of the functions sum
, minus
, multiply
and divide
is successfully created, and works good. But the function calc_all
isn't created and the LabVIEW show the warning message:
Cannot create VI
The following VI cannot be created. This might indicate that the associated function contains
parameters of a data type that cannot be converted directly. To work around this issue, you can
create a custom control or typedef control to represent a complex structure or multidimensional
array, then re-run the Import Shared Library wizard and select Update VIs from a shared library.
Using the same shared library, step through the wizard again. On the Configure VIs and Controls
page, assign the custom control or typedef to the associated parameter(s). Complex structures
include nested structures, structures containing arrays, arrays of strings, and multidimensional
arrays.
dll_calc_all.vi
I tried to change on the Configure VIs and Controls page, assign the custom control, cluster and another data type but without success.
I used cygwin32
to compile the library with Eclipse IDE and my LabVIEW is LabVIEW 2021 32 bits
.
The import functionality of LabVIEW struggles with non-trivial types and given that it cannot deduce things like memory allocation it is best avoided for any but the most simple calls.
This typically means that users looking to integrate C/C++ libraries into LabVIEW have to create their own VIs to perform the library calls and sometimes create a wrapper in C/C++ to convert the library's types to LabVIEW friendly ones.
In this case, I would advise modifying the calc_all
function to take a CALC_t
type pointer that can act as the result. On the LabVIEW-side we can create a cluster with exactly the same data structure as a CALC_t
type and pass a pointer to it to the library call.
In addition, for 32-bit systems, it is advisable to enforce the packing alignment using the #pragma pack
compiler directive.
Putting this all together:
test.h
#ifndef TEST_H_
#define TEST_H_
// enforce packing alignment for LabVIEW <-> C/C++ types when compiling for Windows 32-bit
// see https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019YsYSAU
#pragma pack(push)
#pragma pack(1)
typedef struct
{
int r_sum;
int r_minus;
int r_multiply;
float r_divide;
}CALC_t;
#pragma pack(pop)
int sum(int a, int b);
int minus(int a, int b);
int multiply(int a, int b);
float divide(int a, int b);
void calc_all(int a, int b, CALC_t* );
#endif /* TEST_H_ */
test.c
#include "test.h"
.
.
.
void calc_all(int a, int b, CALC_t* result_ptr)
{
result_ptr->r_sum = sum(a, b);
result_ptr->r_minus = minus(a, b);
result_ptr->r_multiply = multiply(a, b);
result_ptr->r_divide = divide(a, b);
}
LabVIEW Snippet
(Drag and Drop onto blank VI block diagram and point the call library node to your .dll
)