From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
» Calling External Code » Calling C/C++ DLLs » Simple and Complex Datatypes
LabVIEW developers often have to call C/C++ DLLs from LabVIEW and because of the differences between LabVIEW and C/C++ datatypes, passing and receiving data from these DLLs can be intimidating at first.
This example seeks to show developers how to pass and receive different types of data ranging from simple datatypes like numerics (int, float, double, etc), arrays and strings to more complex data types like pointers, struct (cluster), arrays of structs, and even arrays of structs that have arrays of structs in them.
In addition, this example seeks to show developers the different ways to pass and receive data in LabVIEW with a DLL – when functions pass data by value, return data using a return statement, or return data using pass by reference.
This example covers the following use cases:
DataType | Call Type |
---|---|
1. Numeric (Integer) | a) Returning a value (return statement) |
2. Array of Numerics | b) Returning a pointer (return statement) |
3. Strings | c) Passing a parameter (Pass by value) |
4. 2 Dimensional Array | d) Returning values by reference (pass by ref) |
5. Simple Struct (with basic datatypes) | |
6. Complex Struct (with structs & arrays) |
The majority of VIs in the example were automatically generated using the Import Shared Library Wizard. The wizard does not cover all cases, and could not generate VI wrappers for some functions, and some VI wrappers were incomplete. However, it gives us a really good starting point for calling our DLL.
For an example on using the Import Shared Library Wizard, refer to:
Tutorial: Creating Wrapper VIs for C/C++ DLL functions using the Import Shared Library Wizard
For an explanation on what the Import Shared Library Wizard missed, refer to the section titled Caveats with the Import Shared Library Wizard.
The VIs in the example are arranged in the following virtual folders in the library:
The following cases were not completely handled by the Import Shared Library Wizard:
In the following case, VIs were not generated at all:
In the example lvlib, these VIs were manually created and given the suffix “Added” to the name.
In the following cases, the VIs that were generated were incomplete in some fashion:
In the example lvlib, these VIs completed in a new VI that has the suffix “Complete” in the name.
In the following cases, the VIs that were generated had some incorrect behavior:
In the example lvlib, these VIs were corrected in a new VI and given the suffix “Corrected” to the name.
The following is a list of functions exposed by the C DLL as well as the VI that shows how to properly call the particular function.
For a spreadsheet view, refer to:
ListOfFunctionsAndVIs.xlsx
Passing data between LabVIEW and C/C++ DLLs can be challenging especially when dealing with complex data types and pointers. Use the VIs in this example as a reference when you need to call DLLs from LabVIEW.
Almost a decade later and this is still the best example of how to deal with dll's that I have ever found. NI common.
It's not the best example at all. The best example comes with the LabVIEW installation and explains the common problems. The more obscure ones explained here are in fact not complete or outright wrong. All the returning structs as function return values have at least one of these problems:
- returning data located on the stack, bad, bad, bad! The stack is not valid after the function returns to the caller!
- returning data that does not fit in a register (>32-bit, or 64-bit value). The generated code is compiler specific and not standardized at all!
- returning data pointers that were dynamically allocated. In principle a good idea but they do not show about proper memory deallocation, causing memory leaks and using malloc() from the C runtime makes it pretty impossible to do proper memory deallocation because the free() you might try to call from the caller (LabVIEW VI) is almost certainly not from the same C runtime library than the malloc() used in the DLL. Bad, bad, bad!
There are other problems such as not accounting for differences between 32-bit and 64-bit compiled DLLs. A fixed version would basically have to remove half of the VIs (and according DLL functions) in the AdditionalVIs subfolder as they are either wrong or the according C code is simply bad.
The whole problem basically started by using the Import Library Wizard. This can be a help in interfacing DLLs with many functions as it takes care about the nitty gritty basic creation of VIs. But:
- C syntax in a header file is absolutely insuffient to describe the management of memory buffers. This information has to be ideally described in a comprehensive library description document, and lacking that (which often happens) by trying to understand fully working and tested C code examples and some serious trial and error.
- The Import Library Wizard has no way of knowing when an integer parameter is meant to indicate a length for a buffer parameter that should be passed the actually allocated buffer size nor if the same or another value passed by reference will indicate the actual length filled into the buffer. This means it creates VIs with these values all wired to the connector pane and leaving the user of the VIs to worry about C memory management problems which for almost 100% of the cases will go wrong as that is not how other LabVIEW functions work. So a proper VI library should translate between the fully managed LabVIEW environment and the totally unmanaged DLL interface in a way that does not bother the user of that library with C memory management complications. The Import Library Wizard can't do that as there is no way for it to get such details from the information it has available.
- The icons and connector pane created by the Import Library Wizard are ugly and pretty useless.
All this makes reliance on the Import Library Wizard to create proper VIs for anything but the most simple example DLLs a very bad idea. If you can't create the VIs properly from scratch without the Wizard, you are definitely ill advised to even try to use it.