关键技术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的官方例子
为基础,修正若干错误。下载分别在这
、和这
。
实现这一技术主要分为两阶段:
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的官方例子
为基础,修正若干错误。下载分别在这
、和这
。
相关文章推荐
- 模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论
- Dll 模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论
- 【原】模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论
- Dll 模块间(dll, exe)使用导出变量、静态变量和外部变量的试验与结论
- C#使用 WebBrowser制作网页游戏辅助工具关键技术分析
- Python:使用ctypes库调用外部DLL 数据类型对应
- 使用 __declspec(dllimport) 能够优化对DLL导出函数的调用.
- 一起谈.NET技术,ASP.NET缓存初探 使用得当是关键
- 使用dumpbin命令查看DLL导出函数列表
- C#直接使用DllImport外部Dll的方法
- C# 中使用C++导出的DLL文件
- 动态链接库DLL导出函数并导入使用
- 使用 __declspec(dllexport) 从 DLL 导出
- C# winform 导出导入Excel/Doc 完整实例教程 使用Aspose.Cells.dll——第二篇
- 利用openssl管理证书及SSL编程第3部分:将MinGW编译的openssl dll导出def和lib供MSVC使用
- 【MSDN】使用 __declspec(dllexport) 从 DLL 导出
- 使用def文件简化dll导出
- DLL导出对话框技术要点
- SOA的使用的关键技术XML/SOAP/UDDI/ESB
- 使用java技术将数据导出到excel中