在第三章的基础上,接着添加一个显示调用项目

显示调用项目创建:

1.给解决方案添加一个新的控制台项目DisplayCall用于测试动态库,创建完成后设置为启动项目

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

2.DisplayCall.cpp添加相关代码 1 // DisplayCall.cpp : 定义控制台应用程序的入口点。

 //

 #include "stdafx.h"
#include <windows.h> //需要包含windows.h typedef int(*PFUNC_MathSub)(int,int); //定义函数指针 int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hmdll = ::LoadLibrary(_T("../Debug/DynamicLibrary.dll"));//动态加载dll
if(!hmdll)
{
printf("LoadDll is fail");
}else
{
//获取动态库中的sub函数地址,强制类型转换为函数指针
PFUNC_MathSub pfMathSub = (PFUNC_MathSub)::GetProcAddress(hmdll,"MathSub");
int nResult = pfMathSub(,); //通过函数指针进行调用
printf("5 - 3 = %d",nResult);
21     ::FreeLibrary(hmdll);
}
getchar();
return ;
}

3.编译运行DisplayCall,结果发现出现异常?

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

4. 点击中断发现断在第19行,鼠标移到pfMathSub发现它的值为0. 说明没有获取到MathSub函数地址

打开动态库的头文件进行查看是不是输错函数名字了?函数名正确...

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

5. 真正导致bug产生的原因在于,C++函数编译时产生的函数名称与代码中实际函数名是不一样的

这里动态库项目采用的是c++, 那它生成时就是按C++编译方式生成函数名

这里可以使用depends来查看下dll信息,可是vs2012工具里尽然没有,那就只能借用第三方工具了

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

原始c++函数:int MathSub(int a ,int b) 编译后函数名称:?MathSub@@YAHHH@Z

c++函数名称都是以?开头,后面跟上函数名,然后@@YA代表的是c++默认调用方式__cdecl,

后面二个H代表是参数型是int型,返回值是int型,最后以@z代表结尾

6. 为了测试是否正确,修改代码, 把GetProcAddress第二个参数函数名改为?MathSub@@YAHHH@Z

F5运行,发现能成功调用MathSub函数了

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

7. 如果每次调用动态库中的函数都使用这种方式太过于复杂,于是忽另外一种简单的方式应运而生

修改动态库头文件,在函数最前面加上extern "C", 告诉编译器不要使用默认的C++方式编译,

该为使用C语言方式编译. 最后重新编译下动态库工程

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

8. 回到DisplayCall.cpp中,把代码改回来. 然后F5运行,发现异常信息消失了

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

9. 最后再用工具看一下用extern "C" 修饰的函数编译出来的函数名变成什么样了?

C语言方式编译出来函数名是MathSub, 这样我们就可以很方便的使用GetProcAddress获取函数地址了

VC 静态库与动态库(四)动态库创建与使用_显示调用-LMLPHP

总结:

如果需要显示调用动态库,尽量在导出函数前面加上extern "C"

而当使用第三方动态库,去GetProcAddress函数地址发现获取不到函数地址时,

可以尝试用工具去查看导出函数,以确定函数名称,以及查看相关的调用约定

05-20 11:24