使用 Win32 API 验证 HWND

问题描述 投票:0回答:6

使用 C++ 的本机 Win32 API 有没有办法确定与 HWND 关联的窗口是否仍然有效?

c++ winapi
6个回答
34
投票

您可以使用 Win32 API IsWindow

不建议使用它,原因有两个:

  1. 一旦窗口被销毁,窗口句柄就可以重新使用,因此您不知道是否拥有完全不同窗口的句柄。
  2. 这次调用后状态可能会直接改变,你会认为它是有效的,但它可能真的无效。

来自 MSDN(与上面相同的链接):

线程不应该使用 IsWindow 它没有创建的窗口,因为 窗户可能会被摧毁后 这个函数被调用了。更远, 因为窗把手是回收的 句柄甚至可以指向 不同的窗口。

可以做什么?

也许您的问题可以重新架构,这样您就不需要检查有效的句柄。例如,也许您可以建立从客户端到服务器的管道。

您还可以创建一个 Windows 挂钩来检测某些消息何时发生,但这对于大多数需求来说可能有点过头了。


15
投票

这个问题很老了,但我自己需要这个功能,并且在阅读了这些警告后有点失望。然而,在进行了更多挖掘之后,似乎一切都很好。除非您处理 16 位程序,否则 IsWindow 似乎是最佳选择。据此,句柄重复使用的问题似乎已得到充分解决:

https://devblogs.microsoft.com/oldnewthing/20070717-00/?p=25983

因此,由于上部 16 位重用计数器,您不太可能遇到窗口重用问题。


8
投票

您可以使用 IsWindow() 或尝试使用 SendMessage(hWnd, WM_NULL) 向窗口发送 WM_NULL 消息,看看是否成功。

此外,如果不在你的控制之下,窗户确实可以随时被摧毁。正如其他人所说,由于句柄被重用,该句柄可能属于另一个窗口。事实上我不知道这种可能性有多大。

我所知道的唯一解决方案是创建一个系统范围的hook,它查找指示窗口被销毁的消息(WM_CLOSE、WM_DESTROY)。然后,您可以将消息窗口句柄与您持有的消息窗口句柄进行比较,以查看您关心的任何窗口是否受到影响。 有关系统范围挂钩的更多信息,请参阅此处。


5
投票

也许

IsWindow
FindWindow
GetWindowThreadProcessId
的组合会更准确

HWND windowHandle = FindWindow(NULL, TEXT("window_title"));
LPDWORD oldpid = 0;
GetWindowThreadProcessId(windowHandle, &oldpid);
//after some time
if (IsWindow(windowHandle))
{
    LPDWORD newpid = 0;
    GetWindowThreadProcessId(windowHandle, &newpid);
    if (newpid == oldpid)
    {
        //the window is still running
    }else
    {
        //the window exists but has changed
    }
}

1
投票

如果相关窗口的窗口过程在您的控制之下(或者您可以对其进行子类化),那么我建议注册一个自定义消息,该窗口将响应一个非零结果。将该消息发送到任何其他窗口(或无效的 HWND)将导致 0。

当然,这仅告诉您 HWND 是否引用您控制的窗口之一 - 但也许给出上面的其他答案可能会更有利。

使用 RegisterWindowMessage 来注册消息,并使用足够唯一的名称。


-1
投票
if(IsWindow(FindWindow(NULL , TEXT("Example Window Name")))){
     // do stuff
 }

将检查窗口是否存在并且具有适当的名称

© www.soinside.com 2019 - 2024. All rights reserved.