通过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函数是通过函数名来唯一确定被调用函数的地址的。
欢迎大家讨论!
------解决方案--------------------
显示调用必须使用extern "C"修饰符。隐式调用可以使用任何类型,但只有C++能调用没有extern "C"修饰的导出函数。
GetProcAddress是一种通用的获取函数入口点的API,能被任何语言调用,所以限制一定比较多,比如它的参数一定是一个ANSI串(操作系统并未提供UNICODE版本)。
------解决方案--------------------
我的理解是这样的:GetProcAddress实际上跟你直接调用myfunc()一样,都是查询Export表来得到函数地址再去调用,因此你修饰符不对就会造成找不到entry,是不行的。当然我没试过,没有完全的把握。
------解决方案--------------------
主要是就是名字的问题
有两种例外情况可以不加extern “C”:
1。如果不是用C++编译器而是用C编译DLL,名字不会变,可以不加extern "C"
2。如果DLL的使用者知道是用C++编译器编译DLL,不加extern “C”也可以,因为他知道名字改变的规则。调用GetProcAddress,把函数名字改了就是了
------解决方案--------------------
C++编译器和C编译器编译后生成的函数名不一样。
GetProcAddress认为是cdecl的函数,而
编译DLL的是VC++,所以要加一个extern “C"的修饰符
指明以cdecl的方式生成函数。
------解决方案--------------------
学习学习,
不错。
讨论讨论共同提高
如题,网上搜了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函数是通过函数名来唯一确定被调用函数的地址的。
欢迎大家讨论!
------解决方案--------------------
显示调用必须使用extern "C"修饰符。隐式调用可以使用任何类型,但只有C++能调用没有extern "C"修饰的导出函数。
GetProcAddress是一种通用的获取函数入口点的API,能被任何语言调用,所以限制一定比较多,比如它的参数一定是一个ANSI串(操作系统并未提供UNICODE版本)。
------解决方案--------------------
我的理解是这样的:GetProcAddress实际上跟你直接调用myfunc()一样,都是查询Export表来得到函数地址再去调用,因此你修饰符不对就会造成找不到entry,是不行的。当然我没试过,没有完全的把握。
------解决方案--------------------
主要是就是名字的问题
有两种例外情况可以不加extern “C”:
1。如果不是用C++编译器而是用C编译DLL,名字不会变,可以不加extern "C"
2。如果DLL的使用者知道是用C++编译器编译DLL,不加extern “C”也可以,因为他知道名字改变的规则。调用GetProcAddress,把函数名字改了就是了
------解决方案--------------------
C++编译器和C编译器编译后生成的函数名不一样。
GetProcAddress认为是cdecl的函数,而
编译DLL的是VC++,所以要加一个extern “C"的修饰符
指明以cdecl的方式生成函数。
------解决方案--------------------
学习学习,
不错。
讨论讨论共同提高