VS2013 编写调用 动态链接库
2015-08-15 22:30
344 查看
VS2013 编写调用 动态链接库
说明: 学习资料:孙鑫C++教程19 动态链接库 。
生成dll问题:导出函数名会发生改变问题,可采用
extern " c"或模块定义 方法
dll加载方式:1.隐式链接 2.显示加载
存在问题:1.编码方式 ANSI/Unicode
2.调用约定 (calling convention) _stdcall/_cdecl
3.模块定义属性设置(未解决)
1.编写dll 文件。(编译--生成)
新建--项目--win32项目(文件名Dll1)--DLL(空项目)--完成
1)源文件--新建项Dll1.cpp
头文件--新建项Dll1.h
当其它程序调用Dll1.h头文件时,_declspec(dllimport)可将add()/sub()函数导入这些程序中.
但是在函数导出过程中,函数名字会产生变化,如“add”函数名变为“?add@@YGHHH@Z”。在大多数情况下,并不会影响程序逻辑,但遇到跨语言编程时,就会出现错误。使用
extern "C" 可使得函数名不发生改变,但有一定的缺陷,如上述代码中的注释。
通常解决这种问题可采用 模块定义的方法 。
以上两个程序
2)模块定义(确保导出后,函数名不发生变换)
在项目当前文件夹下新建文本文件,后缀名改为.def(Dll2.def).
资源文件--添加现有项--Dll2.def--编辑如下:
此时源文件--添加新建项Dll2.cpp。采用模块定义方式,Dll2.cpp 本身无需export出
add()和sub()函数
动态链接库两种加载方式
1)隐式链接
需要.lib 文件 .h文件 .dll文件
测试程序添加头文件
同时将1.1)Debug后生成的.lib 文件复制到项目文件DllTest/Dll1Test文件夹下。将1.1)Debug后生成的.dll文件复制到DLLTest/Debug文件夹下。
这样测试程序就可以正常调用动态链接库中的add() 或sub()函数了。
测试程序部分内容:
2)动态加载
动态加载是在使用该函数的时候才加载到内存中,较隐式链接节省空间。
动态加载不需要手工添加.h .lib .dll 文件的路径,加载方法直接写在程序语句中。
若调用动态链接库时,只提供了.dll 文件,则采用动态加载。
存在问题解答:1.vs2013默认采用Unicode(16位)方式编码,不同于以往的ANSI(8位)编码,孙鑫老师视频中的有些代码不适用。解决方法:项目--属性--配置属性--常规--字符集--使用多字节字符集。
2.使用不同的调用约定(函数参数压栈顺序),动态链接库中导出函数的名字会产生不同的变化,默认的调用约定为_cdecl(加 extern “C” 有效),但是使用_stdcall,即使使用extern “C”,函数名仍会发生变化,此时可采用模块定义的方法解决。
菜鸟一枚 ,多多指教
说明: 学习资料:孙鑫C++教程19 动态链接库 。
生成dll问题:导出函数名会发生改变问题,可采用
extern " c"或模块定义 方法
dll加载方式:1.隐式链接 2.显示加载
存在问题:1.编码方式 ANSI/Unicode
2.调用约定 (calling convention) _stdcall/_cdecl
3.模块定义属性设置(未解决)
1.编写dll 文件。(编译--生成)
新建--项目--win32项目(文件名Dll1)--DLL(空项目)--完成
1)源文件--新建项Dll1.cpp
<span style="font-size:12px;">#define Dll1_API _declspec(dllexport) //动态链接库本身导出 //#define Dll1_API extern "C" _declspec(dllexport) #include "Dll1.h" #include <WINDOWS.h> #include <stdio.h> int _stdcall add(int a, int b) { return a + b; } int _stdcall sub(int a, int b) { return a - b; }</span>
头文件--新建项Dll1.h
<span style="font-size:12px;">#ifdef Dll1_API//其他函数调用dll ,未定义Dll1_API ,则为 导入 add(),sub()函数。 #else #define Dll1_API _declspec(dllimport)//_declspec为标识符 //#define Dll1_API extern "C" _declspec(dllimport) //加extern "C",为了使得 导出后函数名字不发生改变, //但是extern "C"只针对全局函数,类或类的成员函数不可以使用。 //调用约定(_stdcall/c约定)发生变化,即使使用 extern “C”,函数名字仍然改变 #endif // Dll1_API Dll1_API int _stdcall add(int a, int b); Dll1_API int _stdcall sub(int a, int b); </span>Dll1.cpp 标识_declspec(dllexport)可导出全局函数add()和sub()函数.
当其它程序调用Dll1.h头文件时,_declspec(dllimport)可将add()/sub()函数导入这些程序中.
但是在函数导出过程中,函数名字会产生变化,如“add”函数名变为“?add@@YGHHH@Z”。在大多数情况下,并不会影响程序逻辑,但遇到跨语言编程时,就会出现错误。使用
extern "C" 可使得函数名不发生改变,但有一定的缺陷,如上述代码中的注释。
通常解决这种问题可采用 模块定义的方法 。
以上两个程序
2)模块定义(确保导出后,函数名不发生变换)
在项目当前文件夹下新建文本文件,后缀名改为.def(Dll2.def).
资源文件--添加现有项--Dll2.def--编辑如下:
<span style="font-size:12px;">LIBRARY Dll2 EXPORTS add subtract</span>在VS2013还需要设置 项目--属性--链接器--输入--模块定义文件--./Dll2.def (网上资料介绍这样配置,但是本人的程序有错,对比老师的程序也没有找到症结所在。)
此时源文件--添加新建项Dll2.cpp。采用模块定义方式,Dll2.cpp 本身无需export出
add()和sub()函数
<span style="font-size:12px;">int /*_stdcall*/ add(int a,int b) { return a+b; } int /*_stdcall*/ sub(int a,int b) { return a-b; }</span>2.调用dll文件(测试程序执行)
动态链接库两种加载方式
1)隐式链接
需要.lib 文件 .h文件 .dll文件
测试程序添加头文件
#include "..\..\Dll1\Dll1\Dll1.h"即上述1.1)所生成的头文件(在vs2013中,要写对路劲)
同时将1.1)Debug后生成的.lib 文件复制到项目文件DllTest/Dll1Test文件夹下。将1.1)Debug后生成的.dll文件复制到DLLTest/Debug文件夹下。
这样测试程序就可以正常调用动态链接库中的add() 或sub()函数了。
测试程序部分内容:
<span style="font-size:12px;">void CDllTestDlg::OnBtnAdd() { // TODO: Add your control notification handler code here CString str; str.Format("5+3=%d",add(5,3)); //配置好.h .lib .dll后,可直接调用add()函数. MessageBox(str); <span style="font-size:18px;">}</span></span>
2)动态加载
动态加载是在使用该函数的时候才加载到内存中,较隐式链接节省空间。
动态加载不需要手工添加.h .lib .dll 文件的路径,加载方法直接写在程序语句中。
若调用动态链接库时,只提供了.dll 文件,则采用动态加载。
<span style="font-size:12px;">// TODO: 在此添加控件通知处理程序代码 HINSTANCE hInst; hInst = LoadLibrary("Dll2.dll"); //加载动态链接库 typedef int(/*_stdcall*/ *ADDPROC)(int a, int b); // ADDPROC为函数指针类型 ADDPROC Add = (ADDPROC)GetProcAddress(hInst, "add"); //Add指向dll中add()函数的地址 //ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"?add@@YAHHH@Z");//使用改变的函数名字 //ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));//通过序号调用 if (!Add) { MessageBox("获取函数地址失败!"); } CString str; str.Format(_T("%d") ,Add(5, 3)); //Add(5,3)=add(5,3); MessageBox(str); FreeLibrary(hInst); //释放动态链接库</span>
存在问题解答:1.vs2013默认采用Unicode(16位)方式编码,不同于以往的ANSI(8位)编码,孙鑫老师视频中的有些代码不适用。解决方法:项目--属性--配置属性--常规--字符集--使用多字节字符集。
2.使用不同的调用约定(函数参数压栈顺序),动态链接库中导出函数的名字会产生不同的变化,默认的调用约定为_cdecl(加 extern “C” 有效),但是使用_stdcall,即使使用extern “C”,函数名仍会发生变化,此时可采用模块定义的方法解决。
菜鸟一枚 ,多多指教
相关文章推荐
- FREEBASIC 编译可被python调用的dll函数示例
- DLL(Dynamic Linkable Library) 详解说明
- delphi中一个值得大家来考虑的DLL问题
- 将ocx文件转换成C#程序引用的DLL文件的办法
- 链接库动态链接库详细介绍
- C++与C#互调dll的实现步骤
- C++调用C#的DLL实现方法
- VC6.0如何创建以及调用动态链接库实例详解
- 自己写的文件操作的function和Sub vb.net dll
- C# 调用C++写的dll的实现方法
- javascript动态加载二
- JavaScript 动态加载脚本和样式的方法
- 动态加载jQuery的两种方法实例分析
- 一个简单的动态加载js和css的jquery代码
- jquery select动态加载选择(兼容各种浏览器)
- 使用jquery动态加载javascript以减少服务器压力
- 使用 JScript 创建 .exe 或 .dll 文件的方法
- js 动态加载事件的几种方法总结
- javascript动态加载三