我与一位程序员进行了一次小小的辩论。他在代码中使用了以下习语:
HWND hWnd = SomeFunctionWhichReturnsAWindow();
if(hWnd != NULL && hWnd != INVALID_HANDLE_VALUE)
{
// All good
}
else
{
// Error
}
我告诉他,在我看来这是一种错误的方法,因为HWND
类型与INVALID_HANDLE_VALUE
定义无关,但他确信这是好的代码,作为一个有效的句柄绝不能等于INVALID_HANDLE_VALUE
,而是“安全而不是抱歉”。
那么,这是一个可接受且正确的习语吗?
答案 0 :(得分:15)
将HWND
与INVALID_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
返回值:
如果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]
键入:HWNDZ顺序中定位窗口之前的窗口句柄。此参数必须是窗口句柄或以下值之一。
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)
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()?