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

通过GetProcAddress函数动态调用dll中的函数,是否必须通过extern "C"声明导出函数? [已结贴,结贴人:darongtou]

 

如题,网上搜了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); 
--------------------------- 
这事暂时可以告一段落了,实验还是最有力的证明。

 

posted @ 2011-07-22 09:49  忧郁的加菲猫  阅读(6968)  评论(0编辑  收藏  举报