none
UI Automation click sur un menu item d'une application externe RRS feed

  • Question

  • Bonjour,

    Je souhaite piloter une application externe depuis VBA. Tout fonctionne parfaitement à l'aide de l'API Windows, mais échoue pour le menu. Je souhiate donc utiliser UI Automation pour arriver à mes fins. Pouvez-vous s'il vous plaît m'aider à débugger le code suivant (je ne détaille pas l'API Windows, dont toutes les déclarations se trouve dans le module API) et je prends l'example de Bloc-Notes. En fait, j'arrive à contrôler le menu de Bloc-Notes via l'API Windows, mais pas celui de l'application cible.

    Option Private Module
    Option Explicit

    Private pUIA As UIAutomationClient.CUIAutomation 'Implements the IUIAutomation interface

    '
    Public Sub main()
        
        #If Win64 Then
            Dim hWnd As LongPtr: hWnd = API.FindWindow(lpClassName:="Notepad", lpWindowName:="*Untitled - Notepad")
        #Else
            Dim hWnd As Long: hWnd = API.FindWindow(lpClassName:="Notepad", lpWindowName:="Sans titre - Bloc-notes")
        #End If
        
        If hWnd = 0 Then Exit Sub
        
        'I think it also work, it the app is minimized..
        API.ShowWindow hWnd:=hWnd, nCmdShow:=API.SW_SHOW
        
        Dim iuae As IUIAutomationElement3
        
        'attemps to display the context menu
        'I don't know if it actually makes sense. I read that IUIAutomationElement2 extends IUIAutomationElement, and so on
        Set iuae = pUIA.ElementFromHandle(hWnd:=ByVal hWnd) _
             .FindFirst(scope:=TreeScope.TreeScope_Descendants, _
                        condition:=pUIA.CreatePropertyCondition(propertyId:=UIA_PropertyIds.UIA_NamePropertyId, _
                                                                Value:="Text Editor"))
         
         iuae.ShowContextMenu 'has bo effect
        
        'Directly refers to one of the menus
        With pUIA.ElementFromHandle(hWnd:=ByVal hWnd) _
             .FindFirst(scope:=TreeScope.TreeScope_Descendants, _
                        condition:=pUIA.CreatePropertyCondition(propertyId:=UIA_PropertyIds.UIA_NamePropertyId, _
                                                                Value:="Format"))
            
            'Debug.Print .CurrentName, .CurrentAccessKey
            
            Dim expandCollapsePattern As UIAutomationClient.IUIAutomationExpandCollapsePattern
            Set expandCollapsePattern = .GetCurrentPattern(patternId:=UIAutomationClient.UIA_PatternIds.UIA_ExpandCollapsePatternId)
            
            expandCollapsePattern.Expand
            
            Dim invokePattern As UIAutomationClient.IUIAutomationInvokePattern: Set invokePattern = .GetCurrentPattern(patternId:=UIAutomationClient.UIA_PatternIds.UIA_InvokePatternId)
            invokePattern.Invoke
            
            'How can I move to let's say "&Print\tCtrl+P"? and trigger the click on the menu?
            '...
            
        End With

    End Sub

    Merci par avance !

    dimanche 22 septembre 2019 17:00

Toutes les réponses

  • Je ne fais pas de VBA, mais en VB.NET, un test cliquant sur [Fichier] [Ouvrir] du Notepad (sur Windows 10 FR)

    Il faut utiliser le sous-menu en cache qui existe après un clic sur [Fichier]

    ça doit être facilement adaptable =>

    Dim uiA As IUIAutomation = New CUIAutomation()
    Dim hWndNotepad As IntPtr = FindWindow("Notepad", Nothing)
    If (hWndNotepad) Then
    
        If (IsIconic(hWndNotepad)) Then
            ShowWindow(hWndNotepad, SW_SHOWNORMAL)
        End If
    
        Dim windowElement As IUIAutomationElement = uiA.ElementFromHandle(hWndNotepad)
        Dim condition = uiA.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_MenuBarControlTypeId)
        Dim menubarElement As IUIAutomationElement = windowElement.FindFirst(TreeScope.TreeScope_Children, condition)
        Dim elementArray As IUIAutomationElementArray = menubarElement.FindAll(TreeScope.TreeScope_Children, uiA.CreateTrueCondition())
        Dim nNbItems As Integer = elementArray.Length
        For nItem As Integer = 0 To nNbItems - 1
            Dim mainmenuItemElement As IUIAutomationElement = Nothing
            mainmenuItemElement = elementArray.GetElement(nItem)
            Dim sMainMenuItem As String = Nothing
            sMainMenuItem = mainmenuItemElement.CurrentName()
            Console.WriteLine("Main Menu Item: {0}", sMainMenuItem)
            If (sMainMenuItem = "Fichier") Then
                mainmenuItemElement.SetFocus()
                System.Threading.Thread.Sleep(500)
    
                Dim cacheRequest As IUIAutomationCacheRequest = uiA.CreateCacheRequest()
                cacheRequest.AddProperty(UIA_PropertyIds.UIA_NamePropertyId)
                cacheRequest.AddPattern(UIA_PatternIds.UIA_InvokePatternId)
                cacheRequest.TreeScope = TreeScope.TreeScope_Element Or TreeScope.TreeScope_Children
                cacheRequest.AutomationElementMode = AutomationElementMode.AutomationElementMode_None
                Dim conditionMenu = uiA.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_MenuControlTypeId)
                Dim elementMenuCache As IUIAutomationElement = windowElement.FindFirstBuildCache(TreeScope.TreeScope_Children, conditionMenu, cacheRequest)
                If (elementMenuCache IsNot Nothing) Then
                    Dim sMenuCachedName As String = elementMenuCache.CachedName
                    Dim elementArrayChildren As IUIAutomationElementArray = elementMenuCache.GetCachedChildren()
                    Dim nNbMenuItems As Integer = elementArrayChildren.Length
                    For nMenuItem As Integer = 0 To nNbMenuItems - 1
                        Dim menuItemElement As IUIAutomationElement = Nothing
                        menuItemElement = elementArrayChildren.GetElement(nMenuItem)
                        Dim sMenuItem As String = Nothing
                        sMenuItem = menuItemElement.CurrentName()
                        Console.WriteLine("Menu Item: {0}", sMenuItem)
                        ' "Ouvrir...\tCtrl+O"
                        If (sMenuItem = "Ouvrir..." + vbTab + "Ctrl+O") Then
                            Dim invokePattern As IUIAutomationInvokePattern = menuItemElement.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId)
                            invokePattern.Invoke()
                        End If
                    Next
                End If
            End If
        Next
    End If

    lundi 23 septembre 2019 13:59