d) 在LabVIEW项目中使用DLL中的函数。
一、配置Call Library Function Node(CFN)
无论在LabVIEW中使用自己开发的DLL,硬件驱动供应商或者操作系统提供的API,都可以通过配置Call Library Function Node
在CFN图标的右键菜单上选择“Configure…”打开Call Library Function配置对话框,通过该对话框,可以指定动态库存放路径、调用的函数名以及传递给函数的参数类型和函数返回值的类型。在配置完后,CLF节点会根据用户的配置自动更新其显示。通过Browse按钮或者直接在“Library Name or Path”输入框中指定调用函数多在.dll文件的路径。通过Browse按钮下的控件用户可以指定多个线程同时调用DLL。默认情况下,LabVIEW以“Run in UI Thread”方式调用DLL,调用的函数将直接在用户线程中运行。另外一种方式为递归方式“Reentrant”,在这种情况下可以允许多个线程同时调用DLL中的函数。但要确保正常调用,必须使DLL中的代码线程安全。以下是一些最基本的线程安全特性:
a. 代码不含有未受保护的全局数据(如全局变量,文件);
b. 代码不访问硬件(即不含有寄存器一级的代码);
c. 代码不调用非线程安全的函数、DLL或者驱动;
d. 代码使用信号量或者互斥量来保护全局量;
e. 代码被一个非递归的VI调用时为线程安全。
在“Function Name”输入框中指定要调用函数的函数名。通过“Call Conventions”下拉列表框指定调用DLL中函数的方式。可以指定调用方式为“C”(默认方式)或Windows标准调用方式“stdcall”。一般来说用“C”方式调用开发人员自己写的DLL函数,而 “stdcall”一般做为标准调用方式来调用windows的API 通过Parameter域可以指定所调用函数的返回值类型。默认情况下CFN节点没有输入参数而且只有一个void类型的返回参数。该参数由CFN节点第一对连接点的右端返回,代表CFN执行结果。如果返回参数的类型是void类型,则CFN连接点为未启用状态(保持为灰色)。CFN的每一对连接点代表一个输入或输出参数,若要传递参数给CFN则将参数连接至相应连接点的左端,若要读取返回值,则将相应连接点的右端连接到Indicator。
CFN返回参数的类型可以是Void,Numeric或String。只能为返回参数指定Void类型,输入参数不能指定为Void类型。调用的函数没有返回值时,指定CFN的返回参数类型为void类型。即使参数有确定类型的返回值,也可以指定CFN的返回类型为Void,但是此时,函数的返回值将被忽略。有些时候,调用的函数返回值不是以上三种类型,可以使用与以上三种类中有相同大小的一个来代替。例如如果调用的函数返回一个Char类型数据,则可以用一个8-bit unsigned integer的Numeric类型来代替。此外,由于LabVIEW中没有指针,因此调用DLL中的返回指针的函数似乎不可能。但是可以设定返回值类型为一个与指针有相同大小的Integer类型,LabVIEW将把地址以整型值来看待,并且用户可以在以后的调用中直接使用它。 通过Parameter域和其右边的“Add a Parameter Before”,“Add a Parameter After” 和“Delete this Parameter”三个按钮可以增加、删除以及修改CFN的输入参数和类型。当用户选择某参数的类型后,其详细的数据类型列表和参数传递方式列表将显示出来,以方便进行详细设定。
有时可能在CFN配置对话框中并不能找到要传递给它的参数类型,在这种情况下可以通过下面方法来解决。如果参数不含指针,则可以通过Flatten to String函数( )将参数转换为字符串,并将此字符串指针传递给函数。还有其它一些技巧请参见NI手册。设定后的最终结果显示在“Function Prototype”文本框中,在确认前,可以在此检查设定是否正确。如果不正确可以在此修改设定。
二、调用自己开发DLL中的函数
开发人员可以在LabVIEW中指定DLL函数的原型,然后在外部IDE中完成代码并编译生成.dll文件以供项目使用。
下面就以一个简单的求数组求和的项目为例来说明这种开发过程。
1. 在LabVIEW中创建DLL函数原型。
a) 在LabVIEW的diagram面板上添加一个CFN并通过其右键菜单打开CFN的配置对话框;
b) 使“Library Name or Path”输入框为空;
c) 指定函数名“Function Name”和调用方式“Calling Conventions”分别为add_num和C;
d) 重命名返回参数的名称为“error”,并指定其类型为Numeric的Signed 32-bit Integer;
e) 用“Add a Parameter After”按钮添加第一个参数p,指定其类型为Array的4-byte Single并设定Array Format为Array Data Pointer;
f) 用“Add a Parameter After”按钮添加第二个参数size,指定其类型为为Numeric的Signed 32-bit Integer并设置参数传递方式为Value;
g) 用“Add a Parameter After”按钮添加第三个参数sum,指定其类型为为Numeric的4-byte Single并设置参数传递方式为Pointer to Value;
h) 至此,函数的原型应如下所示(图6-14):long add_num(float *p, long size, float *sum
i) 确定后会发现CFN根据配置自动进行了更新。
2. 生成.C或.C++文件,完成实现函数功能的代码并为函数添加DLL导出声明;
在CFN节点上通过右键菜单选择“Create .C File…”生成mydll.c文件
在完成实现函数功能的代码后,还必须为函数添加导出声明以便能在LabVIEW中使用这些函数。C/C++声名导出函数的关键字是_declspec (dllexport),使用该关键字可以代替模块定义文件。对于此处的例子来说,只要在函数声明和定义部分添加关键字即可。
3. 在外部IDE(以VC++为例)中创建DLL项目并编译生成.dll文件。
用VC++ 6.0进行编译生成.dll文件的步骤如下:
a) 在VC++中创建一个DLL项目,如果在DLL中没有使用MFC就选择创建“Win32 Dynamic-Link Library”,否则选择“MFC AppWizard(dll)”,对此例子来说选择前者。选定后进入下一步选择创建一个空的DLL项目。
b) 通过Project»Add to Project»Files添加mydll.c到创建的mydll项目之中
c) 通过Project»Settings打开项目配置对话框,选择C/C++选项卡。
d) 配置项目的All Configurations。选择Settings For下拉列表框中的All Configurations,选择Category下拉列表框中的Code Generation,最后设置Struct member alignment为1 Byte。
e) 配置项目的Release版本。选择Settings For下拉列表框中的Win32 Release,选择Category下拉列表框中的Code Generation,最后从Use run-time library下拉列表框中选择Multithreaded DLL。
f) 配置项目的Debug版本。选择Settings For下拉列表框中的Win32 Debug,选择Category下拉列表框中的Code Generation,最后从Use run-time library下拉列表框中选择Debug Multithreaded DLL。
4. 在LabVIEW项目中调用.dll中的函数。