【问题标题】:How can I work around the GetParent/EnumChildWindows asymmetry?如何解决 GetParent/EnumChildWindows 不对称问题?
【发布时间】:2011-01-16 06:13:25
【问题描述】:

我最近使用 Microsoft 的 Spy++ 检查了一个 GUI,发现了一个奇怪的结构;它看起来像这样(警告,前面的 ASCII 艺术):

| + 002004D6 "MyRootWindow1" FooClassName | | | + 001F052C“MyChildWindow”ClassOfChildWindow | \ 001D0A8C "MyRootWindow2" SomeOtherClassName

有两个根窗口002004D6001D0A8c,其中一个有一个子窗口001F052C

现在,如果不是为了一件事,这一切都会好起来的:在子窗口 (001F052C ) 产生001D0A8C

读取:“MyChildWindow”是“MyRootWindow1”的子级,但“MyRootWindow1”不是“MyChildWindow”的父级。相反,“MyChildWindow”的父级是“MyRootWindow2” - 但是,为了完成这一点,枚举“MyRootWindow2”的子级不会产生“MyChildWindow”。

这是一个完全静态的 GUI 应用程序,所以这里没有竞争条件或任何东西。

有人知道这是怎么发生的吗?有人知道我该如何解决这个问题吗?直到 现在,我使用GetParentEnumChildWindows 来获取给定HWND 的父(或子),并且我假设这种关系是对称的。还有什么我应该使用的吗?

编辑:这是一个演示问题的小型 C++ 程序的代码:

const HINSTANCE thisModule = ::GetModuleHandle( NULL );
HWND oldParent = ::CreateWindow( TEXT("STATIC"),
                                 TEXT("Old parent"),
                                 WS_VISIBLE | WS_BORDER,
                                 0, 0, 850, 500,
                                 NULL,
                                 NULL,
                                 thisModule,
                                 NULL );
HWND child = ::CreateWindow( TEXT("STATIC"),
                             TEXT("This is a sample dialog"),
                             WS_OVERLAPPED | WS_POPUP | WS_VISIBLE | WS_BORDER,
                             100, 100, 300, 300,
                             oldParent,
                             NULL,
                             thisModule,
                             NULL );
HWND newParent = ::CreateWindow( TEXT("STATIC"),
                                 TEXT("Fake main window"),
                                 WS_VISIBLE | WS_BORDER,
                                 0, 0, 850, 500,
                                 NULL,
                                 NULL,
                                 thisModule,
                                 NULL );
::SetParent( child, newParent );

注意“子”对象如何设置WS_POPUP WS_OVERLAPPED,但不设置WS_CHILD

【问题讨论】:

  • 缺少子窗口WS_CHILD。此外,有可能(尽管不寻常)有一个与您的所有者窗口不同的父窗口。看起来您可能正在为子窗口设置两者。您能否详细说明您要完成的工作?
  • 是的,缺少 WS_CHILD。我在最后一句话中指出了这一点。 :-) 不幸的是,显示的代码不在我的控制之下。它是我想要自省的 GUI 应用程序代码的一部分。

标签: c++ c user-interface winapi


【解决方案1】:

GetParent 的文档说明: "请注意,尽管它的名字,这个函数可以返回一个所有者窗口而不是父窗口。"

由于您没有创建子窗口,我猜您遇到了这种情况。

您应该能够通过 GA_PARENT 调用 GetAncestor,如文档所述: "检索父窗口。这不包括所有者,因为它与 GetParent 函数一样。"

Win32 window Owner vs window Parent?

【讨论】:

  • 这在我的情况下不起作用; GetAncestor(GA_PARENT) 仍然返回错误的父级(示例代码中的oldParent)。问题是 SetParent() 调用没有更新引用。
  • 我对您想要实现的目标感到困惑 - SetParent 只有在调用之前在子窗口上设置 WS_CHILD 标志时才会起作用。
  • 是的,缺少 WS_CHILD。我在最后一句话中指出了这一点。 :-) 不幸的是,显示的代码不在我的控制之下。它是我想要自省的 GUI 应用程序代码的一部分。我想要实现的是能够获取任何给定 HWND 的父(或子),即使窗口层次结构被破坏,如上面的代码所示。这可能意味着我必须使用 Enum(Child)Windows 来模拟 GetParent,或者反过来。
【解决方案2】:

嗯,这当然没有多大意义。闻起来像是子窗口正在重新养育自己。这是 .NET Windows 窗体中的一种常用技术,它有一个“停放窗口”,当由于窗口样式发生更改而需要重新创建其容器窗口时,子控件可以在其中找到一个临时位置。这不是很明显的效果,也是暂时的。

另一种遥远的可能性是SetParent()。它具有 appcompat 行为以支持旧的 Windows 3.x 程序。在 SDK 文档中对此进行了很好的解释,简而言之,一个窗口可以作为父级,但不能设置其 WS_CHILD 样式标志。 Adobe Acrobat Reader 是执行此操作的程序的典型示例。我不清楚这将对 EnumChildWindows 产生什么影响。

最后但同样重要的是:不要忘记 Spy++ 提供了窗口的静态视图。按 F5 更新窗口列表对于跟踪更改非常重要。

没有很好的解释。尝试找出哪个顶层窗口处于活动状态是否重要,我怀疑它确实如此。

【讨论】:

  • 感谢您富有洞察力的回答!我还考虑了一个重新设置的问题,但我认为这会正确更新所有链接(因此重新设置操作会将旧父级的子级减少一个,并将新父级的子级增加一个)。没想到能进入这样的状态。兼容性行为的想法很有趣,我会看看我是否能找到任何关于它的东西!
  • 半相关问题——是否有一种相对简单的方法来重新创建控件,或者是为每种控件手动实现它的唯一方法?
  • 不相关。但我知道什么,为什么要问我? @morechilli 得到了认可,我只是发布了哇!基努·里维斯回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 2021-04-02
  • 2016-11-15
  • 2011-01-04
  • 2012-03-22
  • 2021-12-22
相关资源
最近更新 更多