我和一位程序员进行了一次小小的辩论。 他在他的代码中使用了以下成语:
HWND hWnd = SomeFunctionWhichReturnsAWindow(); if(hWnd != NULL && hWnd != INVALID_HANDLE_VALUE) { // All good } else { // Error }
我告诉他,我认为这是一个错误的方法,因为HWND
types与INVALID_HANDLE_VALUE
定义没有任何关系,但是他确定这是好的代码,因为有效的句柄永远不可能等于INVALID_HANDLE_VALUE
,并且它在“比对不起更安全”的心情。
那么,这是一个可以接受的正确的习惯用法吗?
将HWND
与INVALID_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%错误,不管你可能会假设。
假设“这可能永远不会受到伤害”是非常危险的,虽然在这个时候是有效的,但是在将来你可能被用来假定类似的特征不是那么无辜的。