XL 2016 VBA - Comment savoir si un Handle de Window est celui d'une Window Excel

  • Initiateur de la discussion Initiateur de la discussion Dudu2
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Dudu2

XLDnaute Barbatruc
Bonjour,

J'ai un petit souci avec l'interception des évènements de fenêtres que je dois utiliser pour détecter leurs déplacements..
Parfois je récupère des évènements qui ne sont pas liés à une fenêtre Excel mais d'une fenêtre de recherche VBE ou d'un UserForm et ça crash méchamment.

D'où la question en titre. Est-ce que la Class Name d'une fenêtre Excel est toujours "XLMAIN" ?
 
Dernière édition:
Solution
hello dudu2,
avec flaUiInspect dont j'ai déjà parlé voilà ce que l'on peut constater :
InspectWindows.gif




Les fenêtres de VBE , Excel, un UserForm ont le même processID mais ont un handle et un nom de classe différents.

Si le problème que tu as est dans ton traitement par hook des evénements move de fenêtres :
VB:
#If VBA7 Then
    Private Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
                                  ByVal hWnd As LongPtr, ByVal idObject As Long, ByVal idChild As Long, _
                                  ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
#Else
    Private Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _...
hello dudu2,
avec flaUiInspect dont j'ai déjà parlé voilà ce que l'on peut constater :
InspectWindows.gif




Les fenêtres de VBE , Excel, un UserForm ont le même processID mais ont un handle et un nom de classe différents.

Si le problème que tu as est dans ton traitement par hook des evénements move de fenêtres :
VB:
#If VBA7 Then
    Private Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
                                  ByVal hWnd As LongPtr, ByVal idObject As Long, ByVal idChild As Long, _
                                  ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
#Else
    Private Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, _
                                  ByVal hWnd As Long, ByVal idObject As Long, ByVal idChild As Long, _
                                  ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
#End If
    Dim thePID As Long
    Static Running As Boolean  
    If Running Then Exit Function    
    'This function is a callback passed to the win32 api
    'We CANNOT throw an error or break. Bad things will happen.
    On Error Resume Next
    Running = True
    If LEvent = EVENT_SYSTEM_MOVESIZESTART Then
        'Debug.Print hWnd
        GetWindowThreadProcessId Application.hWnd, thePID
        If thePID = GetCurrentProcessId Then
          'Application.OnTime Now, "Event_MoveStart"
          Call Event_MoveStart
        End If
    ElseIf LEvent = EVENT_SYSTEM_MOVESIZEEND Then
        GetWindowThreadProcessId Application.hWnd, thePID
        If thePID = GetCurrentProcessId Then
            'Application.OnTime Now, "Event_MoveEnd"
             Call Event_MoveEnd
        End If
    End If    
    Running = False
    On Error GoTo 0
End Function
au lieu de tester le PID il faut tester le hWnd qui est transmis et qui permet de savoir quelle fenêtre est à l'origine de l'événement :
Code:
 If hWnd = Application.Hwnd Then

Ami calmant, J.P
 
Bonjour @jurassic pork,
Merci pour ton retour.
Tu as l'ancienne version qui traine quelque part dans une discussion que je viens de mettre à jour
J'ai dû la modifier car les Hook persistent au-delà de l'existence d'un classeur et il a fallu virer les Hook inconnus au risque de plantages.

En fait je peux avoir plusieurs classeurs et fenêtres Excel ouverts en même temps.
De plus je ne sais pas bien à quoi s'applique Application.hWnd. Au classeur actif ? A sa fenêtre principale ?
Donc je n'ai pas testé le Application.hWnd mais le ClassName à XLMAIN.
En test, j'ai effectivement récupéré des Move des fenêtres de recherche VBE avec un ClassName différent.
 

Pièces jointes

Dernière édition:
Avec UIAutomation plus besoin des API Windows pour récupérer les propriétés des fenêtres.
Exemple pour lister toutes les fenêtres du bureau et afficher certaines propriétés :
VB:
Sub GetAllWindows()
Dim c As New CUIAutomation, oDesktop As IUIAutomationElement, oCondition As IUIAutomationCondition, res
Dim allElem As IUIAutomationElementArray, oUIAelem As IUIAutomationElement
'On Error Resume Next
Set oCondition = c.CreatePropertyCondition(UIAutomationClient.UIA_ControlTypePropertyId, 50032) ' Window=50032 Pane=50033
Set oDesktop = c.GetRootElement
res = ""
Set allElem = oDesktop.FindAll(TreeScope_Descendants, oCondition)
    For i = 0 To allElem.length - 1
        Set oUIAelem = allElem.GetElement(i)
        res = res + AffPropElem(oUIAelem)
    Next i
UserForm1.TextBox1.Text = res
UserForm1.Show
DoEvents
End Sub
Function AffPropElem(elem As IUIAutomationElement)
Dim res, rect As UIAutomationClient.tagRECT
rect = elem.CurrentBoundingRectangle
res = "Titre : " + elem.CurrentName + vbCrLf
res = res + "Classe : " + elem.CurrentClassName + vbCrLf
res = res + "Hwnd : " + CStr(elem.GetCurrentPropertyValue(30020)) + vbCrLf
res = res + "ProcessId : " + CStr(elem.CurrentProcessId) + vbCrLf
res = res + "top : " + CStr(rect.Top) + " - left : " + CStr(rect.Left) + _
      " - width : " & CStr(rect.Right - rect.Left) & " - height : " & CStr(rect.bottom - rect.Top) + vbCrLf
res = res + "========================================" + vbCrLf
AffPropElem = res
End Function
AllWindows.png
 
Bonjour @jurassic pork fait lui la même pour @Dudu2 pour lister les parties de la fenêtre excel
Hello Patrick,
ben le problème c'est que les fenêtres sont au même niveau , le Userform et les fenêtres VBA ne descendent pas de la fenêtre Excel par contre ils ont le même ProcessID et on peut faire une condition avec :
VB:
Sub GetAllWindowsExcel()
Dim c As New CUIAutomation, oDesktop As IUIAutomationElement, res
Dim oCondition1 As IUIAutomationCondition, oCondition2 As IUIAutomationCondition, oConditions As IUIAutomationCondition
Dim allElem As IUIAutomationElementArray, oExcel As IUIAutomationElement, oUIAelem As IUIAutomationElement
'On Error Resume Next
Set oExcel = c.ElementFromHandle(ByVal Application.ActiveWindow.hwnd)
Set oCondition1 = c.CreatePropertyCondition(UIAutomationClient.UIA_ProcessIdPropertyId, oExcel.CurrentProcessId)
Set oCondition2 = c.CreatePropertyCondition(UIAutomationClient.UIA_ControlTypePropertyId, 50032)
Set oConditions = c.CreateAndCondition(oCondition1, oCondition2)
Set oDesktop = c.GetRootElement
Set allElem = oDesktop.FindAll(TreeScope_Descendants, oConditions)
    For i = 0 To allElem.length - 1
        Set oUIAelem = allElem.GetElement(i)
        res = res + AffPropElem(oUIAelem)
    Next i
UserForm1.TextBox1.Text = res
UserForm1.Show
DoEvents
End Sub
Cela met un certain temps car on balaie tout le bureau. Si on sait ce que l'on cherche, il est préférable de faire partir le find à partir d'un élément identifiable (par elementFromHandle ou elementFromIAccessible ou elementFromPoint) qui n'est pas le bureau.

A noter que c'est beaucoup plus rapide quand on ne cherche que les éléments fils . Par exemple pour le bureau :
VB:
Sub GetAllChildrenWindows()
Dim c As New CUIAutomation, oDesktop As IUIAutomationElement, oCondition As IUIAutomationCondition, res
Dim allElem As IUIAutomationElementArray, oUIAelem As IUIAutomationElement
'On Error Resume Next
Set oCondition = c.CreatePropertyCondition(UIAutomationClient.UIA_ControlTypePropertyId, 50032) ' Window=50032 Pane=50033
Set oDesktop = c.GetRootElement
res = ""
Set allElem = oDesktop.FindAll(TreeScope_Children, oCondition)
    For i = 0 To allElem.length - 1
        Set oUIAelem = allElem.GetElement(i)
        res = res + AffPropElem(oUIAelem)
    Next i
UserForm1.TextBox1.Text = res
UserForm1.Show
DoEvents
End Sub
 
Dernière édition:
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD
Retour