多个应用程序窗口的特定实例的屏幕截图

时间:2018-08-31 15:38:02

标签: vb.net

我需要截屏捕获多窗口应用程序的特定窗口。 一个很好的例子:我使用两个窗口(邮件和日历)运行OUTLOOK。 当我使用Process.GetProcessesByName(ApplicationToWatch).FirstOrDefault()时,我当然会获得“第一个”窗口。如何访问“第二个”窗口或后续窗口? (有趣的是,这里有一个FirstOrDefault,但没有其他方法可以得到别的东西-我很明显缺少了一些东西。)

2 个答案:

答案 0 :(得分:1)

您已经掌握了如何使用EnumChildWindowsGetClassName关联的子窗口句柄的说明。

因此,我将为您提出另一种使用UI Automation的方法。
它可能不太知名,但是在这种情况下,它非常简单,可以简化此任务。

您只需要知道主窗口的句柄,就可以使用LINQ的AutomationElementCollection.Where()方法枚举并过滤其子窗口的集合(.FirstOrDefault())。 br />

请注意,UI自动化枚举不如EnumChildWindows完整。同样,在某些情况下,返回的类名称可能与特定UI元素的实际类名称不同。
但是这些可能是您不感兴趣的UI元素。

要获取Outlook主窗口的句柄,我们照常使用Process.GetProcessesByName()
然后使用AutomationElement.FromHandle()方法获取自动化元素。

要查找特定的子元素,我们可以使用此主要自动化元素(源引用).FindAll()方法,并根据需要使用.Where()过滤返回的集合,以定义子集合-或.FirstOrDefault(),以获得特定元素类或句柄(或其他已知细节)的引用。

这些方法展示了如何拍摄Outlook的侧面“日历”面板和“主日历”窗口的屏幕截图。

使用code already discussed in your previous question拍摄所选屏幕边界的实际屏幕截图。

  

此代码需要添加对以下内容的引用:
UIAutomationClient
   UIAutomationTypes
WindowsBase

Imports System.Diagnostics
Imports System.Drawing
Imports System.Windows.Automation

Dim OutLookProc As Process = Process.GetProcessesByName("OUTLOOK").FirstOrDefault()
Dim MainElement As AutomationElement = AutomationElement.FromHandle(OutLookProc.MainWindowHandle)

Dim SmallCalendar As AutomationElement =
        MainElement.FindAll(TreeScope.Subtree, Automation.RawViewCondition).
                    OfType(Of AutomationElement)().
                    FirstOrDefault(Function(elm) elm.Current.Name.Contains("NUIDocument") AndAlso
                                   (Not String.IsNullOrEmpty(elm.Current.AutomationId)))

Dim CalendarNavigator As AutomationElement =
        MainElement.FindAll(TreeScope.Subtree, Automation.RawViewCondition).
                    OfType(Of AutomationElement)().
                    FirstOrDefault(Function(elm) elm.Current.ClassName.Contains("TreeDisplayNode"))

If SmallCalendar IsNot Nothing Then
    Dim SmallCalendarHeight As Integer = CInt(CalendarNavigator.Current.BoundingRectangle.Y -
                                              SmallCalendar.Current.BoundingRectangle.Y)
    Dim CalLocation As Point = New Point(CInt(SmallCalendar.Current.BoundingRectangle.Location.X),
                                         CInt(SmallCalendar.Current.BoundingRectangle.Location.Y))
    Dim CalSize As Size = New Size(CInt(SmallCalendar.Current.BoundingRectangle.Width), SmallCalendarHeight)

    Dim SmallCalendarBounds As Rectangle = New Rectangle(CalLocation, CalSize)
    SmallCalendarBounds.Inflate(-20, 0)

    'CopyFormScreen() the SmallCalendarBounds rectangle. Inflate as needed
End If

这部分代码计算Outlook侧面Calendar对象的屏幕边界。
可能没有那么有用,但是它是一种显示如何使用这些类来解析/检查流程主窗口的UI元素的方法。

这是结果:

Outlook Small calendar

“主日历”窗口更易于识别和捕获。
所有Calendars类的名称都以ViewWnd结尾,因此,无论选择/使用哪种日历,您始终可以很容易地识别它。

Dim LargeCalendar As AutomationElement =
        MainElement.FindAll(TreeScope.Descendants, Automation.RawViewCondition).
                    OfType(Of AutomationElement)().
                    FirstOrDefault(Function(elm) elm.Current.ClassName.Contains("ViewWnd"))

If LargeCalendar IsNot Nothing Then
    Dim LCalLocation As Point = New Point(CInt(LargeCalendar.Current.BoundingRectangle.Location.X),
                                          CInt(LargeCalendar.Current.BoundingRectangle.Location.Y))
    Dim LCalSize As Size = New Size(CInt(LargeCalendar.Current.BoundingRectangle.Width),
                                    CInt(LargeCalendar.Current.BoundingRectangle.Height))
    Dim LargeCalendarBounds As Rectangle = New Rectangle(LCalLocation, LCalSize)
End If

这是结果:

Outlook Main Calendar

答案 1 :(得分:0)

这应该有帮助:

获取窗口位置:

How to get and set the window position of another application in C#

获取窗口句柄:

Get Application's Window Handles

将另一个应用程序带到前面:

https://social.msdn.microsoft.com/Forums/en-US/b5a91ac4-4894-45a1-aa66-b4d548ca8163/bring-another-application-to-front?forum=winforms

您可以尝试这些技巧,然后从屏幕上复制。