Visual Studio是否会覆盖stdcall?

4
在Windows XP 32位上,这行代码可以编译通过,但在Windows Vista 64位上,这行代码会出现问题:
m_FuncAddr = ::GetProcAddress (somthing);

出现以下错误:

error C2440: '=' : 无法将类型为 'FARPROC' 的值转换为类型为 'int (__cdecl *)(void)' 的值

GetProcAddress 的定义如下:

WINBASEAPI FARPROC WINAPI GetProcAddress (somthing)

并且m_FuncAddr作为

int (WINAPI *m_FuncAddr)();

据我所知,两者都是stdcall调用。

为了避免错误,我不得不加上

m_FuncAddr = (int (__cdecl *)(void))::GetProcAddress(somthing);

我的问题:

如果 m_FuncAddr 和 GetProcAddress 都使用 stdcall 调用约定,为什么我还需要使用 cdecl 进行“重新调用”?

是否可能 VS 项目设置中的“默认调用约定”(设置为 cdecl)会覆盖上面的赋值语句?

提前感谢!

[编辑]

为了澄清问题:

在等式的一侧(称为第1侧),我有

int __stdcall * m_FuncAddr

在另一侧(第二侧)
INT_PTR far __stdcall GetProcAddress

那么如果两者都是stdcall,我为什么要使用cdecl来转换第二个参数?或者我理解错了什么?

在你编辑之后,我的答案仍然有效。在64位构建中,int和INT_PTR是非常不同的! - Adam Mitz
如果你只是查看“响应”选项卡,请看下面我的编辑。 - Adam Mitz
2个回答

3

返回类型应该是INT_PTR(64位构建中的64位值)。不要在此错误周围进行转换 - 编译器试图告诉您有问题。

来自WinDef.h:

#ifdef _WIN64
typedef INT_PTR (FAR WINAPI *FARPROC)();

因此,m_FuncAddr的声明应该是:
INT_PTR (WINAPI *m_FuncAddr)();

Adam,你的答案是正确的,但请稍微编辑一下。我发现一个有用的东西,这个错误实际上与调用约定没有关系,就像我最初想的那样。我所做的只是将m_FuncAddr的返回类型更改为INT_PTR,问题就自己解决了。所以请让你的答案更完整。 - RomanM

2

在32位编译正确只是巧合;正确的语法是:

typedef int (WINAPI *FFuncType)();
FFuncType m_FuncAddr;
m_FuncAddr = (FFuncType)::GetProcAddress (somthing);

您需要将 ::GetProcAddress 的结果显式转换为正确的函数签名。在32位系统中,FARPROC 可以与您拥有的签名一起使用,但在64位系统中可能无法使用。
编辑:事实上,在查看 windef.h 后,返回类型在64位系统中为 INT_PTR,因此您会收到编译器错误。对于任何不恰好匹配 FARPROC 占位符的函数,您仍需要按照上述方式转换为函数签名,因此您应该通常按照上述方式进行操作。

请记住,在64位编译中,int仍然是32位。 - Adam Mitz
调用约定可能是特定于DLL的,因此唯一“安全”的方法是将其转换为头文件定义的typedef。也许所有的DLL都使用相同的约定,但我不确定这一点。 - Nick
调用约定匹配,两边都是WINAPI。问题在于返回类型不匹配(请参见我的答案)。 - Adam Mitz
int和INT_PTR有什么区别? 通常这只会给出一个警告... - RomanM
只需将INT_PTR替换为__int64,您就会立即看到问题。您真的想将这些函数指针截断为32位吗? - Adam Mitz
显示剩余4条评论

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