将 ShellExecute return (HINSTANCE) 转换为 int 时避免 MSVC 警告

问题描述

docs for ShellExecute 状态(斜体强调我的):

返回值

类型:HINSTANCE

如果函数成功,则返回一个大于 32 的值。如果函数失败,则返回一个错误值,指出失败的原因。返回值被强制转换为 HINSTANCE,以便与 16 位 Windows 应用程序向后兼容。然而,这不是真正的 HINSTANCE。 它只能转换为 int 并与 32 或以下错误代码进行比较。

但是,像这样服从他们:

if ((int)ShellExecuteW(...) <= 32) ...

使用 MSVC 2019(32 位和 64 位)编译时产生警告:

warning C4311: 'type cast': pointer truncation from 'HINSTANCE' to 'int'
warning C4302: 'type cast': truncation from 'HINSTANCE' to 'int'

使用 reinterpret_cast<int> 会产生类似的结果。

我可以取消该行的警告:

#pragma warning(suppress: 4311 4302)
if ((int)ShellExecuteW(...) <= 32) ...

但我通常不喜欢这样做,除非没有其他选择。因此,我的问题是:还有其他选择吗?是否有一些 C++ 语法可以让我尊重 API 文档而不产生警告?

解决方法

HINSTANCE 是指针类型。编译器警告您指针的大小大于 int 的大小,因此在将 HINSTANCE 转换为 int 期间,位将被截断。当您为 64 位编译时会发生这种情况,其中指针为 8 个字节,int 为 4 个字节。

在这种特殊情况下,这种截断很好,因为这些值永远不会超过 int 可以容纳的值。但是,如果您真的想避免这些警告,那么只需使用 intptr_tINT_PTR 或任何其他类似的指针大小的整数类型,例如:

if (reinterpret_cast<intptr_t>(ShellExecuteW(...)) <= 32) {
    ...
}

否则,根本不要使用ShellExecute(),而是使用ShellExecuteEx()。它返回一个 BOOL 表示成功/失败,并使用 GetLastError() 报告失败时的标准 Win32 错误代码(ShellExecute() 返回的大多数错误代码不是标准的 Win32 错误代码),例如:

SHELLEXECUTEINFOW info = {...};

if (!ShellExecuteExW(&info)) {
    DWORD error = GetLastError();
    ...
}