c++ - 从 GetProcAddress 转换的函数的签名是否必须完全匹配?

标签 c++ windows dll casting undefined-behavior

这个问题几乎可以归结为“我可以安全地将函数指针转换为参数可转换为这些类型的函数指针吗?”,但如果没有实际示例,这听起来非常可疑。

我制作了一个小的实用函数来从 DLL 中调用某些东西,给定 DLL 名称、函数名称、适当的返回类型以及参数类型和参数。但是,使用此实用程序时可能会出现超出所需的额外膨胀。我想知道不显式指定参数类型是否安全。以Windows API MessageBoxW为例:

callStdcallDllFunction<int, HWND, PCWSTR, PCWSTR, UINT>(
    L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0
);

这里我明确指定了MessageBoxW的返回类型和四种参数类型。当然,如果从右边开始的参数的类型与函数中的类型相同,我就不必指定它们。但是,只要参数首先有效传递给函数(这些都是),就可以推断出类型吗?

callStdcallDllFunction<int>(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);

在这里,我相信 GetProcAddress 的结果将被转换为 int(__stdcall *)(std::nullptr_t, std::nullptr_t, std::nullptr_t, int);。不过,传入的参数仍然符合实际功能。这仍然是明确定义的行为吗?它会一直做我想做的事吗?到目前为止,每次我测试它时它都有效。

当我这样做时,如果未使用,是否可以将返回类型保留为 void

//return type is void instead of the actual int
callStdcallDllFunction(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);

据我所知,每次我都尝试过,这也奏效了。如果这些真的能保证工作,我很乐意能够像这样使用它们,但我真的不知道它们是否总是会,而且我不会冒险让我写的东西成为未定义的行为.

确切的代码与问题无关,但您可以找到可用于测试的 stdcall 版本(如 MessageBox 是什么)here .这些版本与 cdecl 版本之间的唯一区别是在函数签名中添加了 __stdcall

最佳答案

你必须知道调用约定的确切细节和 ABI 才能给出准确的答案。

在一些调用约定中,参数是在堆栈上传递的。只要参数的大小相同,并且不涉及额外的转换,您就不会面临崩溃的风险。 返回值:如果是在栈上返回,要小心。如果它返回到寄存器中,则没有那么重要。

通常具有相同长度的类型不是问题。但是要小心更奇特的类型,例如成员(函数)指针,它们的大小不一定与 void* 相同。

可兑换还不够严格。 char 可以转换为 long,但它们在堆栈上占用的字节数不同,因此这样的函数指针转换会导致对堆栈内容的解释不同。

关于c++ - 从 GetProcAddress 转换的函数的签名是否必须完全匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16426062/

相关文章:

c++ - GetTokenInformation() 第一次调用。做什么的?

c++ - 如何在C++中修复 “No viable overloaded ' =' ”

c++ - glsl 顶点着色器 glGetUniformLocation 失败

c++ - 如何在不按 ENTER 且不使用 getch() 或 getche() 的情况下读取 C++ 中的字符?

php - 有没有办法在 Windows 上全局安装 Composer?

windows - 如何在 Windows 控制台上输出 Unicode 字符串

c++ - 绘制 2D map 坐标到 OpenGL 3D 投影

java - 依赖于 dll 的可执行 Jar

c++: 使用 Visual Basic dll

c# - 从 .NET 网络应用程序中删除 ReportViewer,仍在寻找 ReportViewer dll