您的位置:首页 > 其它

关键技术4:从CVI中导出dll供外部使用

2010-02-20 16:23 375 查看
NI的LabWindows/CVI 开发环境已经升级到2009版,不仅可以使用Windows下 Borland C++、Visual C++编译的dll,而且可以直接用这些外部编译器替代CVI本身的编译器来编译原来的代码资源!相比原来LabWindows/CVI 5.5 ,2009版在多编译器环境下协同开发的阻力大大减少,提供了诸多便利,由此组合出多编译环境的协同开发方法至少由9种。这里,考虑的是:将现有的CVI工程代码转换为dll,嵌入到Visual C++工程中去。用意很显然——用于半实物仿真系统构造。

实现这一技术主要分为两阶段:
1、在CVI中重新配置现有CVI工程代码,生成Visual C++可用的动态链接库;
2、在新的Visual C++做必要修改,调用CVI的动态链接库。

详细步骤如下:
一、CV部分,主要是代码上的修改和配置上的修改。

代码上,找出原有CVI工程的程序入口文件,一般是main所在C文件,修改之或者新建C文件包含之,相当于制造一个dll外壳。这个外壳至少要包含以下代码:

#include <cvirte.h>

int __stdcall DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{

switch (fdwReason)

{

case DLL_PROCESS_ATTACH:

if (InitCVIRTE (hinstDLL, 0, 0) == 0)

return 0; /* out of memory */

break;

case DLL_PROCESS_DETACH:

CloseCVIRTE ();

break;

}



return 1;

}

int __stdcall DllEntryPoint (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

{

/* Included for compatibility with Borland */

return DllMain (hinstDLL, fdwReason, lpvReserved);

}

这段代码基本上是操作系统的要求,不涉及CVI运行时系统。要生成可供外部实用的dll,代码方面还有一个细微的修改:修改面板的加载方式。一般的main函数加载面板的方式如下:
if ((panelHandle = LoadPanel (0, "testCVI.uir", PANEL)
) < 0)

return;

DisplayPanel (panelHandle);

RunUserInterface ();

DiscardPanel (panelHandle);

...


为了能够使面板能够使用dll中callback函数,必须使用LoadPanelEx加载之:
if ((panelHandle = LoadPanelEx (0, "testCVI.uir", PANEL, __CVIUserHInst
)
) < 0)

return;

DisplayPanel (panelHandle);

RunUserInterface ();

DiscardPanel (panelHandle);

...


其中的__CVIUserHInst
是默认的dll加载句柄。

不仅是main函数,整个工程代码中的LoadPanel都必须如上修改。


CVI编译配置还需要做一些修改。
1、Build -> Target Type 设置为Dynamic Link Library
2、Option-> Build Option,检查其中的函数调用方式,确保与Visual C++ 保持一致。一般WINAPI使用的是__stdcall方式,这里选择__stdcall。



3、Build -> Target Settings 设置导出函数的方式为使用专门为dll编写的"Include file"的符号:



不使用与UIR面板同名的testCVI.h是为了避免修改testCVI.UIR后自动覆盖了它。采用单独的.h来指定dll的导出函数更加安全。testCVIDLL.h中是关于dll的导出信息,用于外部编译器在编译期使用。由于Visual C++默认是C++编译模式,而CVI向来是标准C编译模式,因此,这个头文件必须使用C宏保护:


/*if using C++ Compiler to compile the file, adopting C linkage mode

*/

#ifdef __cplusplus

extern "C" {

#endif



/* your function declaration for dll
*/



#ifdef __cplusplus

}

#endif



4、嵌入UIR面板。旧版的LabWindows/CVI不支持嵌入面板,因此在使用CVI生成的dll同时,也需要将uir面板拷贝到相同的运行时路径(./Debug/)下。2009版的LabWindows/CVI则可以直接配置为嵌入UIR文件:


通过在该配置页面设置Custom Copy directory,甚至连拷贝dll到Visual C++工程下的运行时目录这一步也省了。

5、Ctrl+M 生成 dll、lib的debug版或者release版。

二、Visual C++部分

主要是编译设置和链接设置。

1、设置函数调用方式与CVI保持一致:




2、将dll的编译头lib添加进来:




需要说明的是,添加lib文件有多种方式:(1)直接add file;(2)添加目录到库搜索路径,然后给出库的文件名;(3)直接添加库的路径名。头文件的添加也是类似的,这里是将dll的头文件直接复制到了工程根目录下,因此无须多劳。另外,在Visual C++的编译器选项中,/Gz指定__stdcall调用方式, /Gd 指定__cdecl调用方式。

这个例子最后是实现在MFC程序中调用CVI面板程序:










常见问题:

1、链接错误2001:找不到dll中符号。这是由于Visual C++默认对*.cpp文件中的函数调用(包括dl中的导出函数)采用C++命名方式造成的,需要使用 extern "C"宏进行保护。 思路来自这里
关于dll调用原理的解释和dll头文件格式的分析




相关资源:
1、本文实例
NI的官方例子
为基础,修正若干错误。下载分别在
、和
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: