如果我声明这样的函数:
#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif
TESTAPI int __stdcall myadd(int a, int b);
DLL中的符号是_myadd@8
,这对我来说非常有意义(在这里阅读其他问题几个小时后,就是这样)。
但是Windows库似乎做了不同的事情。他们还使用__stdcall
(伪装成WINAPI
),但DLL中的符号没有名称装饰。如果上面的方法在windows libs中,则符号为myadd
。
我的猜测是他们使用def文件来对符号进行别名。但是当我链接到其中一个DLL时,为什么我的链接器知道这个?
windows头文件用WINAPI
声明这些函数,所以如果我调用它们,链接器应该查找装饰名称,因为它是__stdcall
函数。但不知何故,链接器知道删除名称装饰。
我试图通过编写一个小DLL并使用def文件删除名称修饰来复制它。正如预期的那样,我发现链接器错误,因为链接器仍然在寻找装饰名称。我在纯C中完成了这个,以确保c ++名称修改不会影响它。
编辑:澄清,MSVC 14.0 / VS2015,32位
答案 0 :(得分:7)
这里有一些勉强记录的魔法。让我们看一些WIN32
API
函数,例如RegQueryValueExW
。它在winreg.h
文件中定义如下:
WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...);
其中WIADVAPI
是__declspec(dllimport)
,而APIENTRY
是__stdcall
命名约定的名字对象。另请注意,标头中的所有函数都声明为extern "C"
。所以,无论如何,这个函数应该使用名称修饰,其DLL导出应该是_RegQueryValueExW@24
。然而,当我们使用advapi32.dll
命令查看dumpbin /exports
导出时,我们会看到一个未修饰的名称:
现在让我们使用advapi32.lib
命令仔细检查dumpbin /headers advapi32.lib
文件:
请注意undecorate
说明符,它允许将修饰后的名称链接到未修饰的导出。您可以使用包含未修饰名称的def
部分的EXPORTS
文件为您的dll获得相同的结果。有关其他信息,请参阅this文章和this answer。
此外,上面写的所有内容仅对x86应用程序有效。 x64位环境中的C函数链接without name decoration:
C函数的装饰形式取决于调用 声明中使用的约定,如下表所示。 这也是C ++代码时使用的装饰格式 宣布有外部“C”联动。默认的调用约定是 __cdecl。请注意,在64位环境中,函数不会被修饰。