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

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

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

我告诉他,我认为这是一个错误的方法,因为HWNDtypes与INVALID_HANDLE_VALUE定义没有任何关系,但是他确定这是好的代码,因为有效的句柄永远不可能等于INVALID_HANDLE_VALUE ,并且它在“比对不起更安全”的心情。

那么,这是一个可以接受的正确的习惯用法吗?

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

CreateWindowEx保留为唯一HWND值是无效的是NULL 。 现在,恰好是一个实现细节, INVALID_HANDLE_VALUE永远不可能是有效的HWND ,但这只是实现细节。 产生窗口句柄的函数CreateWindowEx使用NULL来表示失败。 这就是你所需要知道的。

如果你想和你的同事赢得你的观点,我建议你看看SomeFunctionWhichReturnsAWindow ,找出哪个Win32 API被调用来产生HWND 。 然后查阅文档。 这会告诉你NULL是保留的无效值。

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

INVALID_HANDLE_VALUE被定义为-1。 一个无效的HWND被定义为0.没有API会在失败时返回HWND(-1) ,所以检查INVALID_HANDLE_VALUE是没有意义的,它永远不会发生。

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

PeekMessage()GetMessage()

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

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

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

另外SetWindowPos()也有一些保留的值:

hWndInsertAfter [in,可选]
类型:HWND

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

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

HWND_NOTOPMOST
(HWND)-2-
将窗口放置在所有非最顶层的窗口之上(即所有最顶层的窗口之后)。 如果窗口已经是非最高窗口,则此标志不起作用。

HWND_TOP
(HWND)0
将窗口放在Z顺序的顶部。

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

CreateWindowEx和返回HWND的类似函数清楚地表明一个无效的HWND是0.任何其他可能是有效的。

因此,检查INVALID_HANDLE_VALUE是100%错误,不管你可能会假设。

假设“这可能永远不会受到伤害”是非常危险的,虽然在这个时候是有效的,但是在将来你可能被用来假定类似的特征不是那么无辜的。