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



通过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函数是通过函数名来唯一确定被调用函数的地址的。

    欢迎大家讨论! 100  第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);
              ---------------------------
              这事暂时可以告一段落了,实验还是最有力的证明。

              相关文章: