1. 引言
实验室虚拟仪器工作平台是美国国家仪器公司研制的一种通用程序开发系统,以其强大的数据采集、数据处理、数据分析和仪器控制功能在现代测控领域中得到了广泛的应用。NI公司在推出LabVIEW语言同时,也推出了一系列的数据采集卡,但实际应用中往往会用到第三方厂家生产DAQ卡,在这种情况下就需要使用LabVIEW提供的外部程序接口。
LabVIEW的“调用函数库节点(CLF节点)”提供了调用标准函数和用户自定义函数的通用方法,对于LabVIEW不支持的硬件设备大部分采用这种方法进行驱动。但是CLF节点也存在不足,使用中遇到最多的问题是参数类型不匹配。使用重写动态链接库的方法,一方面可以兼容旧函数库的参数类型,另一方发面可以获得LabVIEW提供的高级函数库应用。以下以SDK2000图像采集卡为例,介绍重写函数库的基本原理和程序编写过程。
2. 实现方案及方案论证
SDK2000图像采集卡提供的Visual C++ IDE 程序开发包包含了外部程序调用的共享函数库,但是有些函数不能直接用CLF节点进行调用。主要有两个原因:库函数的参数类型与LabVIEW不兼容;图形化语言对于一些底层操作不易实现。SDK2000图像采集卡提供的库函数含有 LabVIEW不支持的数据类型,并且很多函数涉及到一些底层操作,如文件读取和内存管理。为了正确调用函数并返回有效数据,解决这两个问题是关键。
LabVIEW仅提供最基本的数据类型,虽然可以在CLF节点参数设置中选择“Adapt toType”,但只能够传递LabVIEW内部使用的参数类型而已,而共享库函数使用上百种非标准数据类型。参数类型不匹配可分为两种情况:
● 非标准数据类型定义。很多程序和函数用到一些非标准的类型定义,例如它们常常用char、short和long的类型定义代替 Windows API使用的BYTE、WORD和DWORD。这种情况下要正确调用这些程序和函数,必须找到这些参数在LabVIEW中同等的数据类型。
● 以结构或者类作为参数。一些程序和函数使用结构或者类作为参数,但是LabVIEW并不能够识别这些参数的数据结构。为了正确调用这些库函数,LabVIEW提供了两种解决办法:使用CIN节点或者重写函数库对这些函数进行重新封装,使这些函数的输入输出参数能够符合 LabVIEW的标准。
SDK2000提供的共享函数库使用了很多LabVIEW不支持的参数类型,如RECT、 VIDEOSTREAMINFO等。为了正确调用这些函数,必须用CIN节点或者重写函数库的方法对这些函数进行重新封装。相对而言,重新编写动态链接库方法比使用CIN节点更为常用。因为CIN代码直接嵌入到VI程序代码里,对于编程器的限制比较高,所以一般不采用CIN节点。
重新编写动态链接库的另一个原因,是为了获得LabVIEW提供的高级函数库应用。LabVIEW提供了在代码开发环境下的高级函数库,这些函数是针对于 LabVIEW使用的数据类型,如下面所介绍的NumericArrayResize()函数。NumericArrayResize()函数用于动态改变数组的大小,不过只适合于LabVIEW使用的数组结构。LabVIEW高级函数库还包含了一些底层操作,如文件读写与内存分配等等,不存在参数类型不同和底层操作困难的问题。
3. 软件编程
由于需要重写的函数比较多,这里仅以重写保存DIB图像数据函数为例,说明重写函数库的编写过程。新函数GetDib()对原函数DSStream_GetCurrentDib()进行了封装,其作用是向原函数传递有效参数并返回 LabVIEW能识别的数据。使用的编程环境为Visual C++6.0。
第一步:分析目标函数的参数类型
SDK2000开发包中对获得当前图像的DIB数据函数的声明为:
HRESULT DSStream_GetCurrentDib(int iCardID,BYTE* pBuffer,long* pSize)
pBuffer指向预分配的内存,值为NULL时,pSize得到保存图像需要的内存大小,若pBuffer不为NULL,函数将DIB图像数据保存到从pBuffer开始,长度为(*pSize)的内存区域。CLF节点不能直接调用该函数,因为LabVIEW编程环境下没有提供内存管理机制,并且 CLF节点不能把指向预分配内存的指针传递给该函数,所以必须对这个函数进行重新封装。
图像的DIB数据是非数字型的数据,为了返回 LabVIEW能够识别的数据,可以选择字符串或者单字节数组作为数据的载体,但是由于数据中包含了十进制的0,所以只能用单字节数组作为载体,并且为了能够动态改变数组的大小,必须以数组的句柄作为传递参数。因为在LabVIEW提供的高级函数库中,所有改变数组、字符串大小的函数都是针对于句柄进行的