4.1 静态库与动态库
·DLL支持任何其他Windows下的编程语言,避免了编译器的兼容问题
·只要DLL中导出函数的接口不变,修改动态链接库的功能模块时就不必修改与之相互依存的其他模块的代码
·在同一个Windows操作系统下,不同的应用程序可以共享使用相同的DLL,可以减少应用程序可执行文件的大小,节省空间
·以DLL发布的程序可以给用户提供一个方便的二次开发平台而又不必担心自身源代码的泄漏
一般情况下,编译生成DLL的时候导入库(.lib)文件会一同被创建。但若导入库文件丢失,在CVI中可以通过点击菜单Options-Generate DLL Import Library…来生成一个导入库文件。
图 4‑1 新建的工程目录
图 4‑2 工程运行结果
若此时我们右击StaticLib工程中的Main.c文件,选择Exclude File from Build,如图 4‑3所示,然后点击CVI菜单-Build-Target Type-Static Library,将工程的输出由exe文件改为静态库文件,则编译之后,CVI将会编译未被排除在编译列表的StaticLib.c文件,并在工程目录下会生成一个名为“StaticLib.lib”的静态库文件。
图 4‑3 将Main.c文件从编译列表中排除
生成静态库文件之后,将StaticLib.c文件排除在编译列表之外,将刚生成的StaticLib.lib文件添加进工程中,并恢复Main.c文件到编译列表中,恢复工程编译生成的目标类型为可执行文件(菜单Build-Target Type-Executable)。此时工程目录如图 4‑4所示。
图 4‑4 添加库文件的工程目录
图 4‑5 从静态库中运行的结果
4.2 CVI生成DLL
4.2.1 CVI下生成DLL文件
在上一节中,我们通过一个实例了解了在CVI下生成静态库文件的过程。生成DLL的步骤跟生成静态库的步骤基本相同,除了配置生成文件类型的时候选择“Dynamic Link Library”而不是“Static Library”之外。
图 4‑6 CVI提示没有任何函数被导出
图 4‑7 使用Depends程序查看DLL中发现不包含任何函数信息
出现以上问题的原因在于,我们没有定义导出的函数库列表。点击CVI菜单-Build-Target Settings…之后,弹出如图 4‑8所示的窗口,在窗口中可以对生成的DLL进行设置。
图 4‑8 设置目标DLL的属性
图 4‑9 设置工程的导出内容
设置导出列表之后,Build工程,则CVI发出如图 4‑10所示的提示,告诉用户DLL已经成功生成。
图 4‑10 DLL生成成功的提示
图 4‑11 调用DLL文件的工程目录
图 4‑12 调用DLL运行结果
建立VC工程
图 4‑13 在VC中新建控制台工程
编写C语言文件
编译、调试
问题的原因
void foo( int x, int y );
解决C++编译器兼容问题
再次编译、运行
图 4‑14 VC调用CVI生成的DLL运行测试
4.3 CVI调用DLL
图 4‑15 LoadLibrary工程目录
图 4‑16 显示调用DLL文件运行结果
生成DLL文件
组建VC下的DLL工程
图 4‑17 VC下新建一DLL工程
图 4‑18 生成的DLL文件内部函数查看
问题的原因
图 4‑19 DLL文件中已经包含导出的SubTest函数
图 4‑20 CVI调用VC生成的DLL的运行测试
4.4 CVI调用.Net平台下的DLL
CVI提供了帮助用户调用.Net程序集的.Net库。用户可以通过菜单-Tools-Create .Net Controller…向导生成可在CVI下使用的.Net库。通过使用CVI以及.Net库,我们可以完成以下工作:
·注册.Net控件并且加载控件
·创建.Net对象并且调用.Net对象
·管理系统资源
·创建.Net数组,并从.Net数据中获取元素
·获取.Net的错误与异常信息
·提供.Net组件的基本信息
·同COM组件交互操作
一般如 Initialize_[命名空间] 和 Close_[命名空间] 两个函数分别调用 CDotNetLoadAssembly 和CDotNetDiscardAssemblyHandle 两个函数,[命名空间]_[类名称]__Create 调用CDotNetCreateGenericInstance 函数, [命名空间]_[类名称]_[函数名称] 调用CDotNetInvokeGenericStaticMember 函数等。
图 4‑21 生成的仪器驱动函数树
特别注意的是,由于被调用的DLL没有在全局程序集缓存(GAC,Global Assembly Cache)中,调用前需要使用CDotNetRegisterAssemblyPath函数先注册.NET的DLL。如果没有注册将出现如图4所提示的调用失败的错误。全局程序集缓存所在的文件夹为C:\WINDOWS\assembly。
图 4‑22 .NET的DLL加载失败错误提示
(2)调用CDotNetRegisterAssemblyPath("[DLL名称] , Version=x.x.x.x, Culture=xx , PublicKeyToken=xx" , ''Full Path of DLL")注册.NET的DLL,DLL的路径分隔符用"\",如D:\\CVI\\Projects\\C#net DLL call;
新建C#类库工程
图 4‑23 新建C#类库工程
为工程添加密钥文件
点击Visual Studio 2008菜单Build-Build Solution,编译C#工程。在工程目录的bin\Debug目录下会生成ClassLibrary1.dll文件。
把DLL文件注册到系统全局程序集缓存中
图 4‑24 Microsoft .NET Framework 2.0 配置
添加.Net控件
新建CVI工程,在CVI中点击菜单Tools-Create .Net Controller…,添加生成的ClassLibrary1.dll文件,并添加生成的.fp文件的路径。点击确定之后,在CVI左下角的函数库窗口的Instruments文件夹下多出了ClassLibrary1库,在当前工程下多出了刚才指定的.fp文件。
编写代码,编译运行
图 4‑25 .Net程序运行结果
4.5 示例:CVI获取计算机CPU、硬盘、网卡ID
获取CPU序列号(Intel)
表 4‑1 CPUID指令返回值与输入值对应关系表
获取网卡号
VC最终代码
CVI调用DLL
图 4‑26 CVI获取CPU、网卡序列号的工程目录
调试、运行
图 4‑27 CVI获取CPU序列号、网卡物理地址运行结果
图 4‑28 用Everest软件检测得到的CPU序列号与网卡物理地址
4.6 探索与实验