如果我声明这样的函数:
#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位
最佳答案
这里有一些鲜为人知的魔术在起作用。让我们来看一些WIN32
API
函数,例如RegQueryValueExW
。像这样在winreg.h
文件中定义它:
WINADVAPI LSTATUS APIENTRY RegQueryValueExW(...);
其中
WIADVAPI
是__declspec(dllimport)
,而APIENTRY
是__stdcall
命名约定的绰号。还要注意, header 中的所有函数都声明为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 - 使用__stdcall的DLL,不带名称修饰: why does it even work?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38710243/