2

There is a few intents of using IUIAutomation with VBA in this forum. But all of them relies on the fact that you know the name of the class to use it in FindWindowEx. In the most popular one is:

Controlling IE11 "Do you want to Open/Save" dialogue window buttons in VBA

hWnd = FindWindowEx(hWnd, 0, "Frame Notification Bar", vbNullString)

The code in this website can help you to understand how PARENTS and CHILDRENS handlers are related http://www.vbaexpress.com/kb/getarticle.php?kb_id=52

And Autoit -> AutoIt Window Info) https://www.autoitscript.com/site/autoit/ allows you to click on a window and get the handler/class/name details.

It is very frustrating and hard to narrow down to the element we want to click. This code allows you to do that

enter image description here

Sub test2()

Dim h1, h2 As Long
Dim sWindowName As String

    Dim AutomationObj As IUIAutomation
    Dim WindowElement As IUIAutomationElement
    Dim Button As IUIAutomationElement
    Dim hWnd As LongPtr

sWindowName = vbNullString

Set AutomationObj = New CUIAutomation

h1 = FindWindow("#32770", "Internet Explorer")

Debug.Print h1

While h1 <> 0

    h2 = FindWindowEx(h1, 0, vbNullString, sWindowName)

    If h2 <> 0 Then


       Set WindowElement = AutomationObj.ElementFromHandle(ByVal h2)
       Dim iCnd As IUIAutomationCondition
       Set iCnd = AutomationObj.CreatePropertyCondition(UIA_NamePropertyId, "Save")

       Set Button = WindowElement.FindFirst(TreeScope_Subtree, iCnd)
       Dim InvokePattern As IUIAutomationInvokePattern

       If Button.CurrentName = "Save" Then
            Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
            InvokePattern.Invoke
            h1 = 0

     Else

        h1 = h2
       End If


    Else
        h1 = 0
    End If

    Debug.Print h2

Wend

End Sub

h1 and the FindWindow allows you to narrow down to get the handle of the IE window (and the SAVE button)

Does anyone have a batter approach than this?.. Because here I'm just looping through the handlers under #32770 waiting to get the SAVE button. It does work, but I'm hopping it should be a systematic/efficient way to understand how to get the correct handler to use in IUIAutomation

Community
  • 1
  • 1
Weichafe
  • 97
  • 1
  • 10

1 Answers1

0

There are multiple ways as you can see thru inspect.exe to determine your elements. Within autoit in examples section you can find many examples on how to deal with ms uia. You can start filtering from getrootelement with a createtruecondition which will also work with vba. You then get all main windows of the desktop rootelement.

edit 2021 With Powershell 5.1 and ISE you can have a very rudimentary spy based on your mouse location with a hotkey defined and then you can play a bit within ISE with the different UIA patterns. No need to install additional tooling.

  1. Open powershell ISE (5.1 is fine)
  2. Run the script it will extend the ISE environment with a new menu (but more importantly a hotkey)
  3. Hover your mouse to your object of interest
  4. Press ctrl+shift+w
  5. You should see some output in your ISE window
  6. Play with your $ae automation element from the cmdline Extend the get-elementInfo function to your own ideas (run only function as it will reload directly)

clear-host 
#region load the most important GUI assemblies
Add-Type –AssemblyName UIAutomationClient
Add-Type –AssemblyName UIAutomationTypes
Add-Type –AssemblyName UIAutomationProvider
Add-Type –AssemblyName UIAutomationClientsideProviders

Add-Type -AssemblyName System.Windows.Forms
[void] [System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
#endregion

#region addons
$spyName='Spy'

$MyEntry = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus | ?{$_.DisplayName -eq $spyName}

if ($myEntry -ne $null) {$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Remove($MyEntry)}

$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add($spyName,{ get-elementInfo },"CTRL+SHIFT+W") | out-null

#endregion

function get-elementInfo() {
    $Mouse = [System.Windows.Forms.Cursor]::Position
    $global:ae = [System.Windows.Automation.AutomationElement]::FromPoint([system.windows.point]::new($mouse.x,$mouse.y))
    $ae.current
}

get-elementInfo

# Stuff you could type in your blue part of ISE
# $ae.getcurrentpattern([Windows.Automation.ValuePattern]::Pattern).setvalue("Hello world")
# $ae.GetCurrentPattern([Windows.Automation.InvokePattern]::Pattern).Invoke()
junkew
  • 116
  • 5