Préambule :
Il s'agit ici principalement de montrer une des capacités de la Méthode ExecuteExcel4Macro.
La manière de procéder décrite ici, utilisant un "intermédiaire", sera toujours moins efficiente qu'un appel direct (par référence ou par appel dans l'entête d'un module).
Excel offre indirectement cette "possibilité" aux autres langages de programmation (VBS ou JS) pour l'appel des fonctions de l'api windows par exemple.
J'ajoute que cette méthode est également utilisable (avec encore d'autres paramètres) à d'autres fins que celles de l'utilisation de fonctions de dll (lancement d'exécutables, etc ...)
Extrait de l'aide en ligne :
Méthode Application.ExecuteExcel4Macro
La syntaxe utilisée ici :Exécute une fonction macro Microsoft Excel 4.0, puis renvoie le résultat de la fonction.
Le type renvoyé dépend de la fonction.
Syntaxe :
expression.ExecuteExcel4Macro(String)
expression : Variable représentant un objet Application.
Paramètres :
String : Obligatoire de type Chaîne (String) : Fonction de langage macro Microsoft Excel 4.0 sans signe égal.
Si String contient des guillemets, vous devez les doubler.
Valeur renvoyée : Variant
Application.ExecuteExcel4Macro("CALL(""NomDeLaDll"",""NomDeLaFonction"",""Paramètre"",""Arg1"",""Arg2""...)")
Remarque : les guillemets sont doublés (cf paragraphe de l'aide en ligne)
Les paramètres à passer à cette Méthode sont :
- Le nom de la dll,
- Le nom de la fonction,
- Paramètre : indique le type de valeur de retour de la fonction,
- Les arguments à passer à la fonction.
Le plus délicat est la détermination de ce paramètre ("JJJJ", "JJCJ", "CCC", "JCA", "2JN", "2JRJRR#" etc ...).
Mes recherches ne m'ayant pas permis de lire une documentation quant à leur détermination, il nous faut les trouver par essais successifs.
Dans les exemples qui suivent, pour des raisons évidentes (VBA ne le permettant pas), nous n'allons pas créer de dll.
Nous allons donc simplement appeler des fonctions de l'api Windows.
Utilisation simple : Simuler un clic gauche
Pour cela, il nous faut faire appel à la DLL user32 et particulièrement à sa fonction mouse_event.
Cette fonction, normalement utilisée dans VBA, serait déclarée, en entête de module, comme ceci :
et appelée par exemple comme ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Public Declare Sub mouse_event Lib "user32" _ (ByVal dwFlags As Long, ByVal dx As Long, _ ByVal dy As Long, ByVal dwData As Long, ByVal dwExtraInfo As Long)
Le paramètre à passer obligatoirement à cette fonction est : dwFlags As Long.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Sub ClicGauche() mouse_event 2, 0, 0, 0, 0 'Mouse_Down (Left Button) mouse_event 4, 0, 0, 0, 0 'Mouse_Up (Left Button) End Sub
Il peut prendre les valeurs suivantes :
- 2 : Bouton gauche down
- 4 : Bouton gauche up
- 8 : bouton droit down
- 16 : bouton droit up
- 32 : bouton du milieu down
- 64 : bouton du milieu up
Avec la syntaxe exposée plus haut, nous allons nous créer 4 Sub : Pause, Clic_Gauche, Mouse_Down_Left et Mouse_Up_Left :
La Pause utilise la fonction Sleep de la librairie Kernel32 :
Les Mouse_Down et Up utilisent la fonction mouse_event de la librairie (dll) user32 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Public Sub Pause(MilliSec As Long) 'utilisée par ClicGauche ExecuteExcel4Macro ("CALL(""kernel32"",""Sleep"",""JJJJJJ""," & MilliSec & ")") End Sub
Et enfin, le code d'appel :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Private Sub Mouse_Down_Left() 'utilisée par ClicGauche ExecuteExcel4Macro ("CALL(""User32"",""mouse_event"",""JJJJJJ""," & "2" & ")") End Sub Private Sub Mouse_Up_Left() 'utilisée par ClicGauche ExecuteExcel4Macro ("CALL(""User32"",""mouse_event"",""JJJJJJ""," & "4" & ")") End Sub
Remarque : nous aurions pu créer des fonctions pour récupérer une erreur éventuelle.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Public Sub Clic_Gauche() Mouse_Down_Left Pause 25 Mouse_Up_Left End Sub
Mais là, vous vous dites que c'est bien plus compliqué pour un résultat moins rapide.
C'est très exactement ce que j'annonçais dans le préambule : on ne fait ici que décrire une capacité d'une méthode moins efficiente.
Appel d'une fonction paramétrée
L'exemple choisi ici sera utilisé dans la dernière partie de cette contribution relative au déplacement d'un UserForm.
Il s'agit de la fonction FindWindow de la dll user32.
Elle sert à obtenir le Handle d'une fenêtre Windows, par exemple de la fenêtre application ou d'un UserForm.
Le code de la fonction paramétrée :
Le code d'appel (à partir d'un bouton d'UserForm par exemple) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Public Function FindWindo(ClassName As String, Caption As String) As Long 'FindWindowA FindWindo = ExecuteExcel4Macro("CALL(""user32"",""FindWindowA"",""JCC""," & """" & ClassName & """" & ", " & """" & Caption & """)") End Function
Remarque : Le nom de la classe est ici obligatoire. La fonction retourne une erreur si vous l'omettez ou le remplacez par vbNullString.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Private Sub CommandButton2_Click() MsgBox FindWindo("ThunderDFrame", Me.Caption) End Sub
Attention la classe des UserForm est différente selon les versions.
Appel d'une fonction dans une autre fonction :
Même principe que pour une fonction paramétrée, sauf que l'on remplace ici la variable par une fonction.
Pour l'exemple, nous allons retourner la couleur du pixel sous le pointeur de la souris.
Nous utiliserons donc :
- Pour trouver la position de la souris : La fonction GetMessagePos de la librairie user32
- Pour trouver la couleur du pixel : La fonction GetPixel de la librairie gdi32
- Pour créer un contexte : La fonction GetWindowDC de la librairie user32
- Pour retourner la valeur : la fonction MessageBox de la librairie user32
Détermination des coordonnées X et Y de la position de la souris :
Création du "Device Context" et retour de la couleur du pixel (à noter ici l'appel de la fonction GetWindoDC à l'intérieur de GetPixel) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 Private Function GetPosition() 'utilisée par GetX et GetY GetPosition = ExecuteExcel4Macro("CALL(""user32"",""GetMessagePos"",""J"")") End Function Public Function GetX() GetX = CLng("&H" & Right(Hex(GetPosition), 4)) End Function Public Function GetY() GetY = CLng("&H" & Left(Hex(GetPosition), (Len(Hex(GetPosition)) - 4))) End Function
Génération d'une MsgBox :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 Public Function GetPixel(X, Y) GetPixel = ExecuteExcel4Macro("CALL(""gdi32"",""GetPixel"",""JJJJJJ""," & GetWindoDC & "," & X & "," & Y & ")") End Function Private Function GetWindoDC() 'utilisée par GetPixel GetWindoDC = ExecuteExcel4Macro("CALL(""user32"",""GetWindowDC"",""JJJJJJ"")") End Function
Finalement, le code d'appel :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Public Function MessageBox(StrMessage As String) ExecuteExcel4Macro ("CALL(""user32"", ""MessageBoxA"", ""JJCCJ"", 0," & StrMessage & ",0)") End Function
Exemple d'utilisation : Déplacer, avec la souris, un UserForm sans barre de fenêtre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Sub Quelle_Couleur() MessageBox GetPixel(GetX, GetY) End Sub
Pour l'exemple, nous avons besoin :
- D'un Userform nommé UserForm1,
- Sur cet UserForm, un bouton de commande : CommandButton1.
Cet UserForm sera présenté sans barre de fenêtre (cf Sub Masque_Barre) et pourra être déplacé manuellement en maintenant la touche Shift et le clic gauche de la souris enfoncés simultanément (cf Sub DeplaceForm et événement UserForm_MouseDown).
Le code, à placer dans le module de l'UserForm, est :
Conclusion :
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 Option Explicit Private LeHwnD As Long '=================== Evénements Private Sub CommandButton1_Click() Unload Me End Sub Private Sub UserForm_Initialize() Masque_Barre Me.Caption End Sub Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) 'permet le déplacement de l'Userform par la combinaison Shift + clic gauche If Button = 1 And Shift = 1 Then DeplaceForm End Sub '=================== Procédures Public Sub Masque_Barre(strCapt As String) Dim style As Long, index As Long index = -16 LeHwnD = FindWindo("ThunderDFrame", strCapt) style = GetWindoLong(LeHwnD, index) And Not &HC00000 SetWindoLong LeHwnD, index, style DrawMenuB LeHwnD End Sub '=================== Utilisations des fonctions de l'api Public Sub DeplaceForm() 'ReleaseCapture & SendMessageA 'https://www.developpez.net/forums/d1517529/autres-langages/general-visual-basic-6-vbscript/vbscript/vos-contributions-vbscript/hta-deplacer-hta-n-barre-titre-bordures/ ExecuteExcel4Macro "CALL(""user32"",""ReleaseCapture"",""JJ"")" ExecuteExcel4Macro "CALL(""user32"",""SendMessageA"",""JJJJJ"",""" & LeHwnD & """,""" & &HA1 & """,""" & &O2 & """,""0"")" End Sub Private Function FindWindo(ClassName As String, Caption As String) As Long 'FindWindowA FindWindo = ExecuteExcel4Macro("CALL(""user32"",""FindWindowA"",""JCC""," & """" & ClassName & """" & ", " & """" & Caption & """)") End Function Private Function GetWindoLong(ByVal hwnd As Long, ByVal nIndex As Long) As Long 'GetWindowLongA GetWindoLong = ExecuteExcel4Macro("CALL(""user32"",""GetWindowLongA"",""JCA""," & hwnd & ", " & nIndex & ")") End Function Private Sub SetWindoLong(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) 'SetWindowLongA ExecuteExcel4Macro ("CALL(""user32"",""SetWindowLongA"",""JJJJJ""," & hwnd & ", " & nIndex & ", " & dwNewLong & ")") End Sub Private Sub DrawMenuB(H As Long) 'DrawMenuBar ExecuteExcel4Macro ("CALL(""user32"",""DrawMenuBar"",""JJ"", " & H & ")") End Sub
Voyez cette contribution comme la présentation d'une curiosité, d'une possibilité offerte par la Méthode ExecuteExcel4Macro.
Je le répète, il sera toujours préférable d'appeler directement ces fonctions.
Je dois néanmoins vous avouer que je me suis bien amusé dans cet exercice...
Merci à unparia pour la relecture.
Partager