VC 静态库与动态库(四)动态库创建与使用_显示调用
在第三章的基础上,接着添加一个显示调用项目
显示调用项目创建:
1.给解决方案添加一个新的控制台项目DisplayCall用于测试动态库,创建完成后设置为启动项目
2.DisplayCall.cpp添加相关代码 1 // DisplayCall.cpp : 定义控制台应用程序的入口点。
2 // 3 4 #include "stdafx.h" 5 #include <windows.h> //需要包含windows.h 6 7 typedef int(*PFUNC_MathSub)(int,int); //定义函数指针 8 9 int _tmain(int argc, _TCHAR* argv[]) 10 { 11 HMODULE hmdll = ::LoadLibrary(_T("../Debug/DynamicLibrary.dll"));//动态加载dll 12 if(!hmdll) 13 { 14 printf("LoadDll is fail"); 15 }else 16 { 17 //获取动态库中的sub函数地址,强制类型转换为函数指针 18 PFUNC_MathSub pfMathSub = (PFUNC_MathSub)::GetProcAddress(hmdll,"MathSub"); 19 int nResult = pfMathSub(5,3); //通过函数指针进行调用 20 printf("5 - 3 = %d",nResult);
21 ::FreeLibrary(hmdll); 22 } 23 getchar(); 24 return 0; 25 }
3.编译运行DisplayCall,结果发现出现异常?
4. 点击中断发现断在第19行,鼠标移到pfMathSub发现它的值为0. 说明没有获取到MathSub函数地址
打开动态库的头文件进行查看是不是输错函数名字了?函数名正确...
5. 真正导致bug产生的原因在于,C++函数编译时产生的函数名称与代码中实际函数名是不一样的
这里动态库项目采用的是c++, 那它生成时就是按C++编译方式生成函数名
这里可以使用depends来查看下dll信息,可是vs2012工具里尽然没有,那就只能借用第三方工具了
原始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函数了
7. 如果每次调用动态库中的函数都使用这种方式太过于复杂,于是忽另外一种简单的方式应运而生
修改动态库头文件,在函数最前面加上extern "C", 告诉编译器不要使用默认的C++方式编译,
该为使用C语言方式编译. 最后重新编译下动态库工程
8. 回到DisplayCall.cpp中,把代码改回来. 然后F5运行,发现异常信息消失了
9. 最后再用工具看一下用extern "C" 修饰的函数编译出来的函数名变成什么样了?
C语言方式编译出来函数名是MathSub, 这样我们就可以很方便的使用GetProcAddress获取函数地址了