如何获取子窗口的hWnd并使用FindWindowEx API激活它

时间:2019-02-11 00:46:57

标签: winapi access-vba

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

如果我使用spyxx.exe,则可以使用“查找器工具”获取视频控件的Handle(当然会发生变化),标题(“ panel”),Class(“ wxWindowNR”)和Style(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中引用它,也不知道如何遍历返回的窗口以查找“面板”窗口句柄。

1 个答案:

答案 0 :(得分:0)

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

FindWindowEx找不到我正在寻找的子视频控件窗口,因为该控件被作为父对象的子对象的子对象埋了。 FindWindowEx将仅搜索前一父级的子级。因此,您必须嵌套搜索以隐藏儿童控件。

我遵循的步骤:

  1. 打开需要从VBA访问其窗口和子窗口的目标应用程序。
  2. 运行Spyxx.exe(又名Spy ++)
  3. 使用“查找窗口”工具,获取需要其句柄的子窗口控件的句柄,标题和类
  4. 记下这些项目,然后关闭“查找窗口”工具
  5. 仍然使用Spyxx.exe,使用菜单项“树/将树保存到文件...”(或按CTRL + S)将窗口树保存为 文本文件 (请注意,默认情况下,“保存”会将其另存为.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执行此操作,则解决方案可能会更加优雅。