如果我这样声明一个函数:
#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 库中,符号将是 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
。然而,当我们使用 dumpbin/exports
命令查看 advapi32.dll
导出时,我们看到一个未修饰的名称:
现在让我们使用 dumpbin/headers advapi32.lib
命令仔细检查 advapi32.lib
文件:
注意 undecorate
说明符,它允许将修饰名称链接到未修饰的导出。您可以使用包含未修饰名称的 EXPORTS
部分的 def
文件为您的 dll 实现相同的结果。参见 this文章和this answer获取更多信息。
此外,上面写的所有内容仅对 x86 应用程序有效。 x64 位环境中的 C 函数链接 without name decoration :
The form of decoration for a C function depends on the calling convention used in its declaration, as shown in the following table. This is also the decoration format that is used when C++ code is declared to have extern "C" linkage. The default calling convention is __cdecl. Note that in a 64-bit environment, functions are not decorated.
关于c - 使用不带名称修饰的 __stdcall 的 DLL : why does it even work?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38710243/