Bonjour,

Je développe actuellement des classes pour encapsuler certaines fonctions de l'API Windows. L'idée est de pouvoir accèder à l'ensemble des fenêtres (y compris les enfants, les enfants des enfants,...) sans avoir à devoir spéficier les handles.

Constructeur (factory pattern ?)

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Option Explicit
 
Private pWindows As clsWindows ' je ne souhaiterais pas passer par un object global
 
' constructeur d'une fenêtre
Public Function clsWindow(ByVal hWnd As LongPtr) As clsWindow
 
    Dim window As New clsWindow
 
    window.initialize hWnd:=hWnd
 
    Set clsWindow = window
 
End Function
 
' je souhaite utiliser clsWindows comme un objet pré-déclarer (l'option "Attribute VB_PredeclaredId = True" ne me semble pas adapté, car je construit je me sers également de la clase clsWindows pour accèder aux enfants, aux enfants des enfants,... des fenêtres)
Public Function clsWindows() As clsWindows
 
    Set pWindows = New clsWindows
 
    EnumChildWindows hWndParent:=0&, lpEnumFunc:=AddressOf childWindows, lParam:=ObjPtr(ptr:=pWindows)
 
    Set clsWindows = pWindows
 
End Function
 
'callback
Private Function childWindows(ByVal hWnd As LongPtr, ByVal lpParam As LongPtr) As Boolean
 
    pWindows.add window:=clsWindow(hWnd:=hWnd) ' y-a-t'il un équivalent en reconstituant pWindows à partir de lpParam?
 
    childWindows = True
 
End Function
Par ailleurs, je n'ai pas réussi à implémenter EnumChildWindows dans la classe clsWindows, je passe provisoirement par FindWindowEx, mais je préférerais aussi passer par un callback.

clsWindows

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "clsWindows"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
 
Private pWindows As Collection
 
' default member
Public Property Get item(ByVal index As Integer) As clsWindows
Attribute item.VB_UserMemId = 0
 
    Set item = pWindows(index:=index)
 
End Property
 
'
Public Property Get count() As Integer
 
    count = pWindows.count
 
End Property
 
'
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
 
    Set NewEnum = pWindows.[_NewEnum]
 
End Property
 
'--------------------------------------------------------------------------------------------------
 
'
Private Sub Class_Initialize()
 
    Set pWindows = New Collection
 
End Sub
 
'
Private Sub Class_Terminate()
 
    Set pWindows = Nothing
 
End Sub
 
'--------------------------------------------------------------------------------------------------
 
Public Sub add(window As clsWindow)
 
    pWindows.add item:=window
 
End Sub
clsWindow

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "clsWindow"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
 
Private pHwnd As LongPtr
 
Private pChildren As Collection
 
'--------------------------------------------------------------------------------------------------
 
' default member
Public Property Get Children() As clsWindows
Attribute Children.VB_UserMemId = 0
 
    Set Children = pChildren
 
End Property
 
'
Public Property Get hWnd() As LongPtr
 
    hWnd = pHwnd
 
End Property
 
'
Public Property Get hasChildren() As Boolean
 
    If pChildren.count Then hasChildren = True
 
End Property
 
' 
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
 
    Set NewEnum = pChildren.[_NewEnum]
 
End Property
 
 
'--------------------------------------------------------------------------------------------------
 
'
Private Sub Class_Initialize()
 
    Set pChildren = New Collection
 
End Sub
 
'
Private Sub Class_Terminate()
 
    Set pChildren = Nothing
 
End Sub
 
'--------------------------------------------------------------------------------------------------
 
'
Public Sub initialize(ByVal hWnd As LongPtr)
 
    pHwnd = hWnd
 
    'EnumChildWindows hWndParent:=pHwnd, lpEnumFunc:=AddressOf childWindows, lParam:=ObjPtr(pChildren) ' je n'ai pas l'impression qu'il ait possible de faire appel ࠵n callback au sein mꭥ d'une clase...
 
    Dim hWndchild As LongPtr: hWndchild = FindWindowEx(hWnd1:=pHwnd, hWnd2:=0&, lpsz1:=vbNullString, lpsz2:=vbNullString)
 
    Do While hWndchild <> 0&
 
        pChildren.add item:=clsWindow(hWnd:=hWndchild)
 
        hWndchild = FindWindowEx(hWnd1:=pHwnd, hWnd2:=hWndchild, lpsz1:=vbNullString, lpsz2:=vbNullString)
 
    Loop
 
End Sub
 
'' callback
'Private Function childWindows(ByVal hWnd As Integer, ByVal lpParam As LongPtr) As Boolean
'
'    pChildren.add window:=clsWindow(hWnd:=hWnd)
'
'    childWindows = True
'
'End Function
P'tit test

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
Option Explicit
 
Sub test()
 
    Dim obj As Object: Set obj = clsWindows
 
    Dim window As clsWindow: For Each window In clsWindows
 
        If window.hasChildren Then Debug.Print window.hWnd
 
    Next window
 
End Sub
Code : Sélectionner tout - Visualiser dans une fenêtre à part
API (ultra minimaliste - défini global pour l'instant, à voir par la suite pour l'inclure en privée dans les classes)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
Option Explicit
 
Public Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
 
Public Declare PtrSafe Function EnumChildWindows Lib "user32" (ByVal hWndParent As LongPtr, ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Pouvez-vous donc m'aider à :
- Utiliser un callback avec un pointeur sur l'objet (c'est-à-dire, sans passer par un object global).
- Utiliser un callback dans une classe ?

Merci par avance !