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

时间:2013-05-07 18:29:12

标签: 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);

据我所知,每次我都尝试过这个功能。如果这些确实可以保证有效,我很乐意能够像这样使用它们,但我真的不知道它们是否会永远存在,而且我不打算把我写的东西放在未定义的行为中

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

1 个答案:

答案 0 :(得分:1)

你必须知道调用约定的准确细节,ABI曾经能够给出精确的答案。

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

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

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