GetProcAddress()函数动态调用DLL中的函数,是否必须通过extern C声明导出函数?

GetProcAddress()函数动态调用DLL中的函数,是否必须通过extern C声明导出函数?
通过GetProcAddress函数动态调用dll中的函数,是否必须通过extern "C"声明导出函数?

如题,网上搜了N多资料,一直找不到确定的答案,目前答案是“是”。

很多资料上都只是说明“如果没有 extern "C"修饰,输出函数仅仅能从 C++ 代码中调用”,却并没有明确这个调用是通过显式调用还是隐式调用,我也一直没有看到过有代码是通过显示调用没有 extern "C" 修饰的导出函数。

MSDN上也只是说:

The spelling and case of the function name pointed to by lpProcName must be  identical to that in the EXPORTS statement of the source DLL's module-definition (.DEF) file. The exported names of Win32 API functions may differ from the names you use when calling these functions in your code.

下面再从理论方面进行一些分析:

GetProcAddress函数声明是:

FARPROC GetProcAddress(

  HMODULE hModule,   // handle to DLL module 

  LPCSTR lpProcName   // name of function 

); 

C++是支持函数重载的,也就是说允许多个不同的函数可以有同样的函数名,如果不通过extern "C"修饰,就可以输出相同的函数名。这样,就和GetProcAddress函数声明不一致了,所以推断不能动态调用没有extern "C"修饰的导出函数,因为GetProcAddress函数是通过函数名来唯一确定被调用函数的地址的。

第1个回答

显示调用必须使用extern "C"修饰符。隐式调用可以使用任何类型,但只有C++能调用没有extern "C"修饰的导出函数。GetProcAddress是一种通用的获取函数入口点的API,能被任何语言调用,所以限制一定比较多,比如它的参数一定是一个ANSI串(操作系统并未提供UNICODE版本)。

第2个回答

GetProcAddress实际上跟直接调用myfunc()一样,都是查询Export表来得到函数地址再去调用,因此修饰符不对就会造成找不到entry,是不行的。

第3个回答

C函数和C++函数的名称是不一样的,可以使用工具来查看,比如Dependency Walker。如果想试验,可以根据工具看到的名称来调用GetProcAddress试试。

第4个回答

有两种例外情况可以不加extern "C":

1. 如果不是用C++编译器而是用C编译DLL,名字不会变,可以不加extern "C";

2. 如果DLL的使用者知道是用C++编译器编译DLL,不加extern "C"也可以,因为他知道名字改变的规则。调用GetProcAddress,把函数名字改了就是了。

第5个回答

C++编译器和C编译器编译后生成的函数名不一样。GetProcAddress认为是cdecl的函数,而编译DLL的是VC++,所以要加一个extern "C"的修饰符指明以cdecl的方式生成函数。

第6个回答

发现不用加extern "C"也是可以的,只要在调用端用修饰过的函数名即可,不能用原函数名。

例子关键代码如下:

DLL部分:

// This is an example of an exported function.

DLL1_API int __cdecl fnDll1(void) 

return 42; 

输出的修饰函数名为?fnDll1@@YAHXZ 

DLL1_API int __cdecl fnDll1(int a) 

return 42+a; 

输出的修饰函数名为?fnDll1@@YAHH@Z 

-----------------------------

EXE部分: 

HINSTANCE hModule = LoadLibrary("dll1.dll"); 

ASSERT(hModule); 

typedef int (*fnDll1)(); 

fnDll1 pfnDll1 = NULL; 

//VERIFY(pfnDll1 = (fnDll1)::GetProcAddress(hModule, "fnDll1")); 

VERIFY(pfnDll1 = (fnDll1)::GetProcAddress(hModule, "?fnDll1@@YAHXZ")); 

ASSERT(pfnDll1() == 42); 

typedef int (*fnDll2)(int); 

fnDll2 pfnDll2 = NULL; 

VERIFY(pfnDll2 = (fnDll2)::GetProcAddress(hModule, "?fnDll1@@YAHH@Z")); 

ASSERT(pfnDll2(3) == 45); 

---------------------------

这事暂时可以告一段落了,实验还是最有力的证明。
--------------------- 
作者:机器视觉001 
来源:CSDN 
原文:https://blog.csdn.net/liubing8609/article/details/82052769 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值