动态调用C++动态库

         StreamClient_PlayBackByTime定义可能为:

         extern "C" __declspec(dllexport)  int  StreamClient_PlayBackByTime(parm1,parm2....)

 

         _StreamClient_PlayBackByTime@36定义可能为:

         extern "C" __declspec(dllexport)  int  __stdcall StreamClient_PlayBackByTime(parm1,parm2....)

         ?StreamClient_PlayBackByTime @@YAHHV@...定义可能为:

         __declspec(dllexport)  int  __stdcall StreamClient_PlayBackByTime(parm1,parm2....)

         __declspec(dllexport)  int   StreamClient_PlayBackByTime(parm1, parm2....)

         当调用者(一般为C++)使用lib库进行链接调用的话,函数修饰符名不严格;而当调用者(可能为java或者C++)使用动态加载方式调用的话,        函数修饰符名需要很严格,必须要使用def

动态加载dll部分函数获取不到地址

 

一、           案例描述

         发现动态加载StreamClient.dll后,获取部分函数地址会失败,下面分析获取函数地址失败的原因以及解决方法。

二、           案例分析和解决

调试时,发现LoadLibrary成功后,GetProcAddress获取不到StreamClient_DownLoadStreamClient_PlayBackByTime等几个函数的地址。在确认当前工作目录,LoadLibrary传入文件地址,StreamClient.dll依赖文件后,找不到问题所在。怀疑GetProcAddress传入函数名错误,用depends工具打开dll文件,发现部分函数的导出函数名与代码中定义不同,如图:

         GetProcAddress传入DLL导出函数名,可以获取到函数地址。

         现在有这么一个问题,若StreamClient重新编译后,函数修饰名,也就是depends查看DLL时的导出函数名,被修改为其它名称,那回放控件就会无法正常工作,所以必须保证函数修饰名不变。(函数修饰名:编译器在编译期间,依据一定规则,创建的一个字符串,用来指明一个函数。)

         现在我们针对进行分析:

         StreamClient_PlayBackByTime定义可能为:

         extern "C" __declspec(dllexport)  int  StreamClient_PlayBackByTime(parm1,parm2....)

 

         _StreamClient_PlayBackByTime@36定义可能为:

         extern "C" __declspec(dllexport)  int  __stdcall StreamClient_PlayBackByTime(parm1,parm2....)

         ?StreamClient_PlayBackByTime @@YAHHV@...定义可能为:

         __declspec(dllexport)  int  __stdcall StreamClient_PlayBackByTime(parm1,parm2....)

         __declspec(dllexport)  int   StreamClient_PlayBackByTime(parm1, parm2....)

         当调用者(一般为C++)使用lib库进行链接调用的话,函数修饰符名不严格;而当调用者(可能为java或者C++)使用动态加载方式调用的话,        函数修饰符名需要很严格,必须要使用def

 

         查阅资料得知,动态库导出函数时,想要函数修饰名不变,需满足下面两个条件:

1.      要以extern "C"标识函数,保证函数以c方式编译。

2.      函数调用方式需使用__cdecl

修改代码编译验证,函数修饰名的确没变。__cdecl是调用者清理堆栈,就像函数内

部申请的内存,函数外部释放,是一种不推荐的方式,只有可变参数的函数才使用。Windows通常使用__stdcall方式调用函数,此方式是被调用函数清理堆栈。

         上面的方法不能使用,继续寻找其它方法。重于找到另一个办法:工程中加入def文件定义动态库函数名,可以保证编译后函数修饰名不变。该方法经过验证,可行。

         def文件定义StreamClient_PlayBackByTime,如图:

         depends工具打开dll文件,检查 dll 导出函数名StreamClient_PlayBackByTime,如图:

 

三、           经验总结

开发DLL时,要使用def文件定义要导出的函数名,保证DLL编译后导出的函数名不变,避免动态加载DLL时出现问题。

 

猜你喜欢

转载自blog.csdn.net/changeholdon/article/details/50635303
今日推荐