stdcall名称修饰在使用extern "C"和__declspec(dllexport)与模块定义(MSVC ++)之间的区别

17

我正在尝试导出一个简单的测试函数用于与指定调用约定(fyi:mIRC)的应用程序配合使用的DLL。

int __stdcall test_func(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
现在,要从应用程序中调用这个函数,我会使用test_func,但由于名称修饰,我发现这并不像我想象的那样简单。
通过在类似的主题上研究,我了解到,在模块定义(.def)中使用extern "C"__declspec(dllexport)结合使用是一种去除名称修饰的(有点)等效方法。然而,在使用extern/dllexport方法时,我的函数(例如)总是_test_func@numbers,而.def移除了所有所需的名称修饰以供我导出到的应用程序使用。
请问为什么会这样?我对这两种方法很感兴趣,请解释一下,谢谢!
2个回答

16

extern "C" 和 stdcall 没有任何关系:它只是声明了禁用 C++ 名称修饰(又称类型安全链接;在符号名称中包含类型信息)。你需要使用它,无论是否使用 C 调用约定或 stdcall 调用约定。

在 stdcall 调用约定中,被调用者会从堆栈中移除参数。为了使此过程安全,导出的名称包含被调用者将从堆栈中移除的字节数。

如果您要导出到的应用程序要求不向名称添加 @number 后缀,则可能意味着它期望使用 C 调用约定。因此,您应该停止将函数声明为 __stdcall。当您将其声明为 declspec(dllexport) 时,您应该在 DLL 中获得未经修饰的名称。

在 DEF 文件中,您可以根据需要给函数命名;不执行额外的检查。


21
Windows API函数是stdcall调用约定,但不带@数字,这在Windows中是标准做法。 - David Heffernan

13

dllexport/import被设计为可以被自身加载,而不是使用GetProcAddress的旧C库。你看到的名称修饰是所有微软编译器长期以来为__stdcall函数所做的。最有可能的是,你的目标需要一个__cdecl函数,而不是__stdcall,但如果不是,你将需要使用.def文件来特别取消名称修饰。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接