DLL使用__stdcall没有名称装饰:为什么它甚至工作?

Ste*_*fan 11 c dll winapi linker

如果我声明一个这样的函数:

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

TESTAPI int __stdcall myadd(int a, int b);
Run Code Online (Sandbox Code Playgroud)

DLL中的符号_myadd@8对我来说非常有意义(在这里阅读其他问题几个小时后,就是这样).

但是Windows库似乎做了不同的事情.它们也使用__stdcall(伪装成WINAPI),但DLL中的符号没有名称装饰.如果上面的方法在windows libs中,那么符号就是myadd.

我的猜测是他们使用def文件来对符号进行别名.但是当我链接到其中一个DLL时,为什么我的链接器知道这个?

windows头文件声明了这些函数WINAPI,所以如果我调用它们,链接器应该查找装饰名称,因为它是一个__stdcall函数.但不知何故,链接器知道删除名称装饰.

我试图通过编写一个小DLL并使用def文件删除名称修饰来复制它.正如预期的那样,我发现链接器错误,因为链接器仍然在寻找装饰名称.我在纯C中完成了这个,以确保c ++名称修改不会影响它.

编辑:澄清,MSVC 14.0/VS2015,32位

Ari*_*nhh 9

这里有一些几乎无法记录的魔法.让我们看看一些WIN32 API功能,比如RegQueryValueExW.它在winreg.h文件中定义如下:

WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...);
Run Code Online (Sandbox Code Playgroud)

WIADVAPIa __declspec(dllimport)APIENTRYa 在哪里是__stdcall命名约定的绰号.另请注意,标头中的所有函数都声明为extern "C".所以无论如何,这个函数应该使用名称修饰,其DLL输出应该是_RegQueryValueExW@24.然而,当我们advapi32.dll使用dumpbin /exports命令查看导出时,我们会看到一个未修饰的名称:

advapi出口

现在让我们advapi32.lib使用dumpbin /headers advapi32.lib命令仔细检查文件:

在此输入图像描述

请注意说明undecorate符,它允许将装饰名称链接到未装饰的导出.您可以使用包含未修饰名称的部分的def文件为您的dll获得相同的结果EXPORTS.有关其他信息,请参阅 文章和此答案.

此外,上面写的所有内容仅对x86应用程序有效.x64位环境中的C函数没有名称修饰链接:

C函数的装饰形式取决于其声明中使用的调用约定,如下表所示.这也是当C++代码声明具有外部"C"链接时使用的装饰格式.默认调用约定是__cdecl.请注意,在64位环境中,函数未进行装饰.