1. Calling C-Style DLLs from Scripts
The first section will describe how to call a function in a simple C-Style DLL from Perl, Python and Tcl.
The C-Style DLL
We created a simple DLL using LabWindows/CVI that exports a single function called addNumbers. This function uses the cdecl calling convention and has the following four parameters and return value:
Prototype: int addNumbers (int x, int y, int* sum, char* string);
| Parameter | Type | Details |
| x (in) | int (by value) | First Addend |
| y (in) | int (by value) | Second Addend |
| sum (out) | int * (by reference) | Output: Sum of x and y |
| string (out) | char * (by reference) | Output: “Hello World” |
| Return value | int | 0 |
| CVI Code: addNumbers |
| int addNumbers (int x, int y, int* sum, char *string) { *sum = x+y; strcpy (string, "Hello World"); return 0; } |
You can download the precompiled DLL here: simpledll.dll
Caveats:
- Perl – Calling Convention: In order to call a function that uses the cdecl calling convention, you must specify the calling convention when you load the function.
For more on calling conventions, please refer to KnowledgeBase 2RCKK3TL: Calling Conventions in LabWindows/CVI. - Perl – Packing: Since numbers can be represented in multiple ways, in order to pass it to the DLL function, the number has to be stored in the same format as the DLL expects. In order to pass an integer pointer, you have to ‘pack’ it as an Int32 (‘i’) before calling the function. Packing in Perl basically tells the interpreter how to represent the data in memory.
For a tutorial on Packing in Perl, refer to PerlMonks: Pack/Unpack Tutorial. - Python – ctypes: Since numbers can be represented in multiple ways, in order to pass it to the DLL function, the number has to be stored in the same format as the DLL expects. In order to pass an integer pointer, Python has a library called ‘ctypes’ that includes types like c_int to facilitate passing integer pointers.
For more information on the ctypes library, refer to The Python Standard Library: ctypes – A foreign function library for Python. - Tcl – Yet Another DLL Caller: The example scripts below use a utility from the Tcl Wiki called ‘Yet Another DLL Caller’ that facilitates calling DLL functions from Tcl. This package contains a DLL as well as a Tcl file that must be included in your source code before you can use it.
For more information on this utility, refer to Tcl Wiki: Yet another dll caller.
Calling the DLL from Scripts
The following code snippets demonstrate how to call a DLL from Perl, Python and Tcl.
Note: You can download any of the script files by clicking on their filename above the code snippets.
| Perl: call_simple_dll.pl |
| #!/usr/bin/perl -w use strict; #include Win32::API to call DLLs use Win32::API; my $x = 5; my $y = 8; #First pack $sum as an Int32 since we have to pass this by reference my $sum = pack('i', 0); my $string = " " x 20; #Function Prototype: int addNumbers (int x, int y, int *sum, char *string) #Load the Function #The third argument here 'IIPP' refers to the types of the paramters, #i.e., two integers (I) followed by two pointers(P) #The fourth argument here 'I' refers to the return type, i.e., an integer. my $function = Win32::API->new('SimpleDLL','addNumbers','IIPP','I', '_cdecl'); #Call the Function my $return = $function->Call($x,$y,$sum,$string); #Unpack the sum back to a regular perl number my $sumUnpacked = unpack('i', $sum); #Print Results print "Sum: ", $sumUnpacked, "\n"; print "String: ", $string, "\n"; print "ReturnValue: ", $return, "\n"; |
| Python: call_simple_dll.py |
| #!/usr/bin/env python #The ctypes library includes datatypes for passing data to DLLs #For instance, c_int to pass integer pointers from ctypes import * #Load the DLL dll = cdll.LoadLibrary("SimpleDLL.dll") x = 5 y = 3 #Create sum as a c style integer sum = c_int(0) string = create_string_buffer("", 20) #Function Prototype: int addNumbers (int x, int y, int *sum, char *string) #Call the Function #Pass pointers using the byref keyword returnValue = dll.addNumbers(x, y, byref(sum), byref(string)) #Print Results print "Sum: ", sum, "\n" print "String: ", repr(string.raw), "\n" print "returnValue: ", returnValue, "\n" |
| Tcl: call_simple_dll.tcl |
| #!/bin/sh # -*- tcl -*- # The next line is executed by /bin/sh, but not tcl \ exec tclsh "$0" ${1+"$@"} #Import YetAnotherDLLCaller to facilitate calling DLL functions #Make sure your script directory contains dll_tcl.tcl and dll.dll from http://wiki.tcl.tk/12264 source dll_tcl.tcl #Load the DLL if {[catch {::dll::load SimpleDLL.dll -> simpleDLL}]} { error "SimpleDLL library not found!" } #Function Prototype: int addNumbers (int x, int y, int *sum, char *string) #Import the Function #Importing involves simply specifying the function prototype ::simpleDLL::cmd "int addNumbers(int, int, int *, char *)" set x 3 set y 5 set myString [::dll::buffer 20] #Call the Function #Pass arguments without the $ to pass by reference set returnValue [::simpleDLL::addNumbers $x $y sum $myString] #Print Results puts "Sum: $sum" puts "String: $myString" puts "ReturnValue: $returnValue" |
2. Data Acquisition in Scripts Using NI-DAQmx
NI-DAQmx is the high-performance, multithreaded, data acquisition (DAQ) driver software at the heart of NI measurement services software.
Installing the NI-DAQmx driver also installs and registers several DLLs. One such DLL is nicaiu.dll which is located at:
<Windows>\System32\nicaiu.dll
This particular DLL contains the function calls that are part of the NI-DAQmx C API. Script developers can use these functions to perform data acquisition using National Instruments DAQ devices.
You can find help on all of the NI-DAQmx C API functions in the NI-DAQmx C Reference Help which installs to:
Start»Programs»National Instruments»NI-DAQ»NI-DAQmx C Reference Help.
Getting Started
- Installing the NI-DAQmx Driver: In order to use the NI-DAQmx functions, you must have NI-DAQmx installed. This is a free download from http://ni.com/support.
- Using an NI-DAQmx Compatible Device: In order to perform data acquisition, you also need a device to read from. If you have a device, the following examples refer to the device as ‘dev1’. If you don’t already have a device, you can create and use a simulated device, and make sure that its alias is set to ‘dev1’. For instructions on creating a simulated device, refer to:
Developer Zone Tutorial: NI-DAQmx Simulated Devices
The Functions We Will Use
The following is a list of NI-DAQmx functions that are used will use in the following example scripts:
- DAQmxCreateTask
Prototype: int32 DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);
Purpose: Creates a task. - DAQmxCreateAIVoltageChan
Prototype: int32 DAQmxCreateAIVoltageChan (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], int32 terminalConfig, float64 minVal, float64 maxVal, int32 units, const char customScaleName[]);
Purpose: Creates channel(s) to measure voltage and adds the channel(s) to the task you specify with taskHandle. - DAQmxReadAnalogScalarF64
Prototype: int32 DAQmxReadAnalogScalarF64 (TaskHandle taskHandle, float64 timeout, float64 *value, bool32 *reserved);
Purpose: Reads a single floating-point sample from a task that contains a single analog input channel. - DAQmxClearTask
Prototype: int32 DAQmxClearTask (TaskHandle taskHandle);
Purpose: Clears the task. Before clearing, this function stops the task, if necessary, and releases any resources reserved by the task.
Note: All DAQmx functions return 0 on success. This example checks for zero at each step and reports an error for non-zero return values.
Detailed help on these functions can be found in the NI-DAQmx C Reference Help.
Calling the NI-DAQmx DLL
| Perl: calling_daq_dll.pl |
|
#!/usr/bin/perl -w #Steps: |
| Python: calling_daq_dll.py |
|
#!/usr/bin/env python |
| Tcl: Calling_daq_dll.tcl |
|
#!/bin/sh |
3. Instrument Control in Scripts Using VISA
National Instruments Virtual Instrument Software Architecture (VISA) is a standard for configuring, programming, and troubleshooting instrumentation systems comprising GPIB, VXI, PXI, Serial, Ethernet, and/or USB interfaces. VISA provides the programming interface between the hardware and development environments.
Installing the NI-DAQmx driver also installs and registers several DLLs. One such DLL is visa32.dll which is located at:
<Windows>\System32\visa32.dll
This particular DLL contains the function calls that are part of the VISA C API, and developers can use these functions to perform instrument control.
You can find help on all of the VISA C API functions in the NI-VISA Help which installs to:
Start»Programs»National Instruments»VISA»Documentation»NI-VISA Help.
Getting Started
- Installing the NI-VISA Driver: In order to use the VISA functions, you must have VISA installed. This is a free download from http://ni.com/support.
- Using the NI-VISA Device: In order to perform instrument control, you also need a device to communicate with. In the following example, we communicate via a GPIB Board to an Instrument Simulator on address 2. The example can easily be modified for serial communication as well.
The Functions We Will Use
The following is a list of NI-VISA functions we will use in our example:
- viOpenDefaultRM
Prototype: ViStatus viOpenDefaultRM(ViPSession sesn)
Purpose: This function returns a session to the Default Resource Manager resource. - viOpen
Prototype: ViStatus viOpen(ViSession sesn, ViRsrc rsrcName, ViAccessMode accessMode, ViUInt32 openTimeout, ViPSession vi)
Purpose: Opens a session to the specified resource. - viSetAttribute
Prototype: ViStatus viSetAttribute(ViObject vi, ViAttr attribute, ViAttrState attrState)
Purpose: Sets the state of an attribute. - viWrite
Prototype: ViStatus viWrite(ViSession vi, ViBuf buf, ViUInt32 count, ViPUInt32 retCount)
Purpose: Writes data to device or interface synchronously. - viRead
Prototype: ViStatus viRead(ViSession vi, ViPBuf buf, ViUInt32 count, ViPUInt32 retCount)
Purpose: Reads data from device or interface synchronously. - viClose
Prototype: ViStatus viClose(ViObject vi)
Purpose: Closes the specified session, event, or find list.
Note: All VISA functions return 0 on success. This example checks for zero at each step and reports an error for non-zero return values.
Detailed help on these functions can be found in the NI-VISA Help.
Calling the NI-VISA DLL
| Perl: calling_visa_dll.py |
|
#!/usr/bin/perl -w |
| Python: calling_visa_dll.py |
|
#!/usr/bin/env python |
| Tcl: calling_visa_dll.tcl |
|
#!/bin/sh |
4. Next Steps
Now that you have learned the basics of data acquisition and instrument control in these three scripting languages, you are ready to create your own test automation software. To see more resources on National Instruments products and scripting languages click on the links below.
Developer Zone Tutorial: Calling Scripting Languages from TestStand
Developer Zone Tutorial: Call Perl and Python Scripts from LabVIEW


