【问题标题】:How to get hWnd for a child window and activate it using FindWindowEx API如何获取子窗口的 hWnd 并使用 FindWindowEx API 激活它
【发布时间】:2019-02-11 00:46:56
【问题描述】:

我正在使用 MS Access 2016 VBA 自动访问外部应用程序。外部应用程序窗口有一个显示在子窗口中的视频。

如果我使用 spyxx.exe,我可以使用“查找工具”来获取视频控件的句柄(当然会改变)、标题(“面板”)、类(“wxWindowNR”)和样式(52000000 )。当我使用 spyxx.exe 返回的句柄时,我可以成功地使用该句柄将正确的应用程序带到顶部并激活它。但由于该句柄发生了变化,我需要使用 MS Access VBA 动态获取它。

我遇到的问题是,当我使用 FindWindowEx API 尝试获取子视频窗口的句柄时,我无法弄清楚如何获取 spyxx.exe 提供的相同句柄。这是我正在尝试的(以及主题的一些变体): 声明是:

Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As String, ByVal lpszWindow As String) As Long

并且(尝试)获取子视频窗口句柄的代码是(其中 WinHand 是父窗口的句柄):

FindWindowEx(WinHand, 0, "wxWindowNR", "panel")

我知道 WinHand 对于父窗口是正确的,因为使用 WinHand 我可以使应用程序成为活动的最顶层窗口。但是,我永远无法让 FindWindowEx 返回 spyxx.exe 显示的句柄是子“面板”窗口的句柄。

当我将子窗口的名称留空时,它确实返回句柄,如下所示:

FindWindowEx(WinHand, 0, "wxWindowNR", "")

但绝不是 spyxx.exe 显示的正确句柄。

从一天中大部分时间在网上搜索,看来我可能需要使用 EnumChildWindows API 做一些事情,但我不知道如何在 MS Access VBA 中引用它,也不知道如何循环通过返回的窗口找到“面板”窗口句柄。

【问题讨论】:

  • 你弄错了句柄?你拿什么把手?可能有另一个带有类名的窗口。你也应该在 Spy++ 中找到错误的句柄
  • 感谢@xMRi。 Spy++ 确实没有 找到错误的句柄——这就是重点。我知道 Spy++ 返回的句柄是正确的,因为当我在 VBA 代码中使用 Spy++ 句柄时,该代码可以操作目标子窗口。我需要的是一种通过使用 VBA FindWindowEx 或 EnumChildWindows 获得 Spy++ 找到的相同句柄的方法。显然,FindWindowEx 现在返回的句柄不正确,但我无法确定如何更正它以找到 Spy++ 找到的句柄。这就是问题所在:如何让 VBA 找到 Spy++ 找到的相同(正确)句柄?
  • “你得到什么句柄?”当目标窗口关闭并重新打开时,该句柄编号(当然)会发生变化。但是 Spy++ 每次都能找到正确的句柄,但 VBA 从来没有使用 FindWindowEx 找到正确的句柄。我知道这一点是因为如果我使用 Spy++ 返回的句柄,我可以在 VBA 中操作目标窗口,但是,如果我使用 VBA 返回的句柄,我无法操作目标窗口。因此,VBA 必须返回错误的句柄,而 Spy++ 必须返回正确的句柄。问题是:如何让 VBA 返回 Spy++ 返回的正确句柄?
  • 为什么投反对票?如果有人认为这是一个不好的问题,请发布为什么这是一个不好的问题,或者请发布明显的答案。
  • 投反对票可能是因为您没有给我们提供足够的信息。你拿什么把手? FindWindow 永远不会返回不存在的东西......所以如果你得到一个结果,这个窗口就符合条件。而且由于您无法向我们展示可重现的代码,因此可能会导致否决票。滴滴你用GetWindow API函数自己遍历Window树?

标签: vba ms-access winapi


【解决方案1】:

为了那些将来可能遇到类似问题的人的利益,我发布了我使用的解决方案(尽管我希望看到使用 EnumChildWindows 提供的解决方案,因为这似乎是更优雅的方法,但我对 API 不够了解,不知道如何设置它)。

FindWindowEx 找不到我正在寻找的子视频控件窗口,因为该控件被掩埋为父子的子的子的子的子的子的子的子。 FindWindowEx 只会搜索前一个父级的子级。因此,您必须嵌套搜索隐藏的子控件。

我遵循的步骤:

  1. 打开需要从 VBA 访问其窗口和子窗口的目标应用程序。
  2. 运行 Spyxx.exe(又名 Spy++)
  3. 使用查找窗口工具,获取您需要其句柄的子窗口控件的句柄、标题和类
  4. 记下这些项目,然后关闭“查找窗口”工具
  5. 仍在使用 Spyxx.exe,使用菜单项“树/将树保存到文件...”(或按 CTRL+S)将窗口树保存到文本文件(请注意,Save 默认将其另存为 .sxt Spy++ 对象,您在此处不希望这样做)
  6. 打开您在最喜欢的文本编辑器中保存的 Windows 文本文件的树形列表(我使用 Notepad++ 对其进行了很好的格式化)并搜索您在上面的步骤 #3 和 #4 中记下的窗口句柄
  7. 这应该可以在树中找到所需的子窗口
  8. 现在按照以下步骤逆向操作树,直到到达父窗口句柄
    1. 记下下一级窗口的窗口标题——标题用双引号括起来;稍后编写 VBA 代码时将需要该标题
    2. 现在移动到上一个窗口级别,并为该窗口写下标题
    3. 继续向上移动窗口级别,直到到达应用程序本身的父窗口

最后一步:现在在 VBA 代码中,要找到目标子窗口控件的窗口句柄,您必须嵌套 FindWindowEx 命令,从父窗口开始,然后像这样向下工作(将“wxWindowNR”替换为与您要查找的子控件相关的任何窗口类):

FindWindowEx (ParentWindowHandle, 0, "wxWindowNR", "[caption from steps 9 to 11]")

例如,这是我必须使用的代码(其中 ChildWindow5 是我正在寻找的视频控制窗口的句柄;需要 While...Wend 命令,因为在我所针对的应用程序中,并非所有子窗口在应用程序运行时立即存在):

ParentWindow = 0
While ParentWindow = 0
    ParentWindow = FindWindow("Target Window Caption")
Wend

ChildWindow1 = 0
While ChildWindow1 = 0
    ChildWindow1 = FindWindowEx(CLng(ParentWindow), 0, "wxWindowNR", "ID_BOOKMARK_SPLITTERWINDOW")
Wend

ChildWindow2 = 0
While ChildWindow2 = 0
    ChildWindow2 = FindWindowEx(CLng(ChildWindow1), 0, "wxWindowNR", "ID_TOPPANEL_SPLITTERWINDOW")
Wend

ChildWindow3 = 0
While ChildWindow3 = 0
    ChildWindow3 = FindWindowEx(CLng(ChildWindow2), 0, "wxWindowNR", "ID_MAINDISPLAY_PANEL")
Wend

ChildWindow4 = 0
While ChildWindow4 = 0
    ChildWindow4 = FindWindowEx(CLng(ChildWindow3), 0, "wxWindowNR", "ID_VIDEODISPLAY_PANEL")
Wend

ChildWindow5 = 0
While ChildWindow5 = 0
    ChildWindow5 = FindWindowEx(CLng(ChildWindow4), 0, "wxWindowNR", "panel")
Wend

请注意,随后对子窗口句柄的每次搜索都会引用先前的父窗口。

这对我有用。我仍然认为,如果有人可以指出如何使用 EnumChildWindows 做到这一点,那么解决方案可能会更加优雅。

【讨论】:

    猜你喜欢
    • 2020-02-03
    • 2010-11-24
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多