检查`HWND`对`INVALID_HANDLE_VALUE`是错误的吗?

时间:2014-10-10 15:36:28

标签: c windows winapi

我与一位程序员进行了一次小小的辩论。他在代码中使用了以下习语:

HWND hWnd = SomeFunctionWhichReturnsAWindow();
if(hWnd != NULL && hWnd != INVALID_HANDLE_VALUE)
{
    // All good
}
else
{
    // Error
}

我告诉他,在我看来这是一种错误的方法,因为HWND类型与INVALID_HANDLE_VALUE定义无关,但他确信这是好的代码,作为一个有效的句柄绝不能等于INVALID_HANDLE_VALUE,而是“安全而不是抱歉”。

那么,这是一个可接受且正确的习语吗?

5 个答案:

答案 0 :(得分:15)

HWNDINVALID_HANDLE_VALUE进行比较是错误的。虽然,在实践中,这不是一个会伤害你的错误。

HWND保留的唯一CreateWindowEx值无效为NULL。现在,它恰好是INVALID_HANDLE_VALUE无法成为有效HWND的实现细节,但这只是实现细节。产生窗口句柄CreateWindowEx的函数使用NULL来指示失败。这就是你需要知道的全部内容。

如果您希望与同事一起赢得您的论点,我建议您查看SomeFunctionWhichReturnsAWindow内部并找出调用哪个Win32 API来生成HWND。然后查阅文档。这将显示NULL是保留的无效值。

为了清楚起见,您绝对应该将代码更改为仅针对NULL进行测试。

答案 1 :(得分:10)

INVALID_HANDLE_VALUE定义为-1。无效的HWND定义为0.没有API会在失败时返回HWND(-1),因此检查INVALID_HANDLE_VALUE毫无意义,它永远不会发生。

但是,有些API接受保留的非零HWND值作为输入,因此不能用作有效的HWND返回值:

PeekMessage()GetMessage()

  

如果hWnd为NULL,则(Peek / Get)消息检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd值为NULL的任何消息(请参阅MSG结构)。因此,如果hWnd为NULL,则处理窗口消息和线程消息。

     

如果hWnd为-1 ,(Peek / Get)消息仅检索当前线程的hwnd值为NULL的消息队列中的消息,即PostMessage发布的线程消息(当hWnd时)参数为NULL)或PostThreadMessage。

因此HWND(0)HWND(-1)之间存在逻辑差异。事实上,由于存在这种差异,有效的HWND将永远不会为-1,因为消息循环永远无法为其检索消息。

同样SetWindowPos()也有一些保留值:

  

hWndInsertAfter [in,optional]
  键入:HWND

     

Z顺序中定位窗口之前的窗口句柄。此参数必须是窗口句柄或以下值之一。

     

HWND_BOTTOM
  (HWND)1
  将窗口放在Z顺序的底部。如果hWnd参数标识最顶层窗口,则窗口将失去其最顶层状态,并放置在所有其他窗口的底部。

     

HWND_NOTOPMOST
  (HWND)-2
  将窗口放在所有非最顶层窗口(即所有最顶层窗口后面)上方。如果窗口已经是非最顶层窗口,则此标志无效。

     

HWND_TOP
  (HWND)0
  将窗口置于Z顺序的顶部。

     

HWND_TOPMOST
  (HWND)-1
  将窗口放在所有非最顶层的窗口上方。即使停用窗口,窗口也会保持最高位置。

答案 2 :(得分:2)

CreateWindowEx和返回HWND的类似函数清楚地表明无效HWND为0.其他任何东西都可能有效。

因此,无论您采取什么假设,检查INVALID_HANDLE_VALUE都是100%错误。

做出“这可能永远不会受到伤害”这样的假设是非常危险的,虽然此时有效,但在将来你可能会习惯于承担不同于无辜的类似特征。

答案 3 :(得分:1)

与INVALID_HANDLE_VALUE相比,不能使用

HWND,因为这是两个不同的东西。大多数资源(例如文件等)返回HANDLE,并且必须与INVALID_HANDLE_VALUE进行比较,以确保该资源可以被任何依赖于此的函数使用。但是,HWND指的是Windows GUI对象的句柄。因此保存以将HWND值与0进行比较以获取无效的返回句柄,而不是使用也为-1的INVALID_HANDLE_VALUE。

此外,要了解有关“ HANDLE”类型的更多信息,可以查看此StackOverflow先前的答案以了解更多信息。

HANDLE是上下文特定的唯一标识符。根据具体情况, 我的意思是从一个上下文获得的句柄不一定是 在任何其他适用于HANDLE的框架环境中使用。

例如,GetModuleHandle将唯一标识符返回给 当前加载的模块。返回的句柄可用于其他 接受模块句柄的函数。不能赋予功能 需要其他类型的手柄。例如,您不能给 从GetModuleHandle返回到HeapDestroy的句柄,并期望它 做些明智的事情。

HANDLE本身只是一个整数类型。通常,但不是 必然是指向某些基础类型或内存的指针 位置。例如,GetModuleHandle返回的HANDLE是 实际上是指向模块基本虚拟内存地址的指针。 但是没有规则说明句柄必须是指针。一个手柄 也可以是一个简单的整数(可能被 一些Win32 API作为数组的索引。

答案 4 :(得分:0)

问题是Windows句柄是否有效,为什么不只使用IsWindow()