Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :Trouver les macros embarquées
Grâce au
volet de navigation, il est simple d'accéder aux différents éléments qui composent une
base de données qu'il s'agisse des
tables, des
requêtes, des
formulaires, des
états, des
macros ou encore des
modules. Mais concernant les
macros embarquées, c'est-à -dire attachées à des contrôles de formulaires ou d'états, la sentence est toute autre. Plus la base est dense, plus il devient complexe de retrouver ces éléments encapsulés. C'est pourquoi, nous proposons ici de développer une solution par le
code VBA Access.
Sur l'exemple illustré par la capture, nous travaillons à partir d'une
base de données très dense, consistant notamment à facturer les clients. Lorsque l'utilisateur clique sur le
bouton intitulé
Lister, il déclenche un
processus VBA parcourant
tous les formulaires de l'application. A l'issue le verdict tombe dans la zone de texte sur la gauche du formulaire.
Toutes les macros embarquées y sont listées en rappelant le
nom du formulaire parent, le
contrôle attaché et l'
action qui l'engage (OnChange, OnClick...).
Base de données Access à télécharger
Pour développer cette nouvelle solution, nous devons appuyer l'étude sur une
base de données Access embarquant un certain nombre de
macros.
- Télécharger le fichier compressé trouver-macros-embarquees.rar en cliquant sur ce lien,
- Le décompresser dans le dossier de votre choix,
- Double cliquer sur le fichier résultant pour l'ouvrir dans Access,
- Cliquer alors sur le bouton Activer le contenu du bandeau de sécurité,
- Depuis le volet de navigation sur la gauche, double cliquer sur le formulaire F_trouver,
Nous retrouvons le formulaire de la présentation. Bien sûr, un clic sur le bouton Lister est inopérant à ce stade. Il s'agit de l'enjeu de ce développement.
En consultant le volet de navigation sur la gauche de l'écran, vous constatez que cette base de données Access est faite de nombreux objets. Elle héberge notamment un certain nombre de formulaires. Eux-mêmes embarquent un certain nombre de macros qui de fait, n'apparaissent pas dans le volet de navigation. Nous devons donc les débusquer pour mieux appréhender l'architecture et le fonctionnement de cette application.
La procédure du bouton
Pour commencer, nous devons attacher une
procédure se chargeant de déclencher un
code VBA au clic sur le
bouton Lister.
- A gauche du ruban Accueil, cliquer sur la flèche du bouton Affichage,
- Dans les propositions, choisir le mode Création,
- Sur le formulaire en conception, cliquer sur le bouton Lister pour le sélectionner,
- Activer alors l'onglet Evénement de sa feuille de propriétés,
- Puis, cliquer sur le petit bouton associé à son événement Au clic,
- Dans la boîte de dialogue qui suit, choisir le générateur de code et valider par Ok,
De cette manière, nous basculons dans l'
éditeur VBA Access, entre les bornes de la
procédure événementielle lister_Click. Son
code VBA se déclenchera au clic sur ce bouton. Vous découvrez de même la présence d'une autre procédure. Elle se nomme
fermerTout. Nous l'avions développée à l'occasion d'une formation démontrant comment
fermer automatiquement tous les formulaires ouverts. Nous l'appellerons à l'issue de notre code et nous comprendrons pourquoi.
La déclaration des variables
Nous avons besoin de
variables pour manipuler les
formulaires de l'application et les
contrôles qu'ils hébergent.
- Dans les bornes de la procédure lister_Click, ajouter les déclarations suivantes :
...
Dim chaqueForm As Object: Dim leForm As Form
Dim ctrl As Control: Dim prop As Property
...
Nous déclarons la
variable chaqueForm comme un objet classique. Elle prendra son type véritable au moment de la
boucle For Each que nous engagerons pour
parcourir tous les formulaires de la
base de données Access. La
variable leForm typée comme un
formulaire (As Form) doit représenter
chaque formulaire analysé tour à tour dans cette boucle. Dans chacun de ces formulaires, nous parcourrons également
tous les contrôles qu'ils hébergent. C'est la raison de la déclaration de la
variable ctrl comme un
contrôle classique (As Control). Enfin, nous déclarons une dernière variable (prop) pour accéder aux
propriétés (As Property) de ces
contrôles, afin de déceler la présence de
macros embarquées.
Concernant cette dernière déclaration, il faut savoir qu'une
référence doit avoir été ajoutée au projet pour permettre d'accéder aux ressources de ces contrôles. C'est ce que nous proposons de constater.
- En haut de l'éditeur VBA Access, cliquer sur le menu Outils,
- Dans les propositions, choisir la rubrique Références,
Comme vous pouvez le voir, la case d'une
librairie très spécifique est cochée. Elle se nomme
Microsoft Ado Ext. 6.0 for Dll and Security. Par Dll, comprenez librairie. C'est elle donc qui permet cette dernière déclaration et l'exploitation que nous allons en faire par le biais de cet
objet Prop.
- Cliquer sur le bouton Ok de la boîte de dialogue pour revenir dans l'éditeur,
Parcourir tous les formulaires
Maintenant que les variables utiles sont déclarées, nous allons pouvoir les exploiter notamment pour
parcourir tous les formulaires de l'application.
- A la suite du code VBA, ajouter les instructions suivantes :
...
listeMacros.Value = ""
For Each chaqueForm In Application.CurrentProject.AllForms
If (chaqueForm.Name <> "F_trouver") Then
End If
Next chaqueForm
...
Tout d'abord, nous réinitialisons la zone de texte nommée
listeMacros, pour la purger des potentielles précédentes analyses. Ensuite, nous engageons notre
objet chaqueForm dans une
boucle For Each pour
parcourir tous les formulaires de l'application. Pour cela, nous exploitons la
propriété CurrentProject de l'
objet Application, qui désigne la
base de données active. Grâce à lui, nous descendons jusqu'à la
collection AllForms qui représente tous les
formulaires de l'application active. C'est à ce moment-là que notre
objet chaqueForm prend véritablement son type pour représenter tour à tour
chaque formulaire passé en revue. Naturellement et cela ne vous a pas échappé, nous ignorons le formulaire depuis lequel nous travaillons (If(chaqueForm.Name <> "F_trouver")) puisqu'il est en cours d'exécution.
Pointer sur chaque formulaire
A chaque passage dans cette boucle, nous devons prendre possession de
chaque formulaire passé en revue, grâce à la
variable leForm. C'est ainsi que nous pourrons ensuite exploiter la
variable ctrl pour analyser
tous les contrôles qu'il abrite.
- Dans le If de la boucle For Each, ajouter les deux instructions VBA suivantes :
...
DoCmd.OpenForm chaqueForm.Name, acDesign
Set leForm = Forms(chaqueForm.Name).Form
...
Grâce à la
méthode OpenForm de l'
objet VBA Access DoCmd, nous ouvrons le formulaire en cours d'analyse (chaqueForm.Name) en mode conception (acDesign) pour accéder à ses ressources. C'est alors que nous initialisons (Set) l'
objet leForm sur le formulaire en cours en passant son nom (chaqueForm.Name) Ã la
collection Forms pour atteindre le
formulaire en question (Form). C'est ainsi que nous allons pouvoir le manipuler, lui et les objets qu'il héberge.
Parcourir les contrôles du formulaire actif
Désormais, en impliquant notre
objet ctrl judicieusement typé, dans une
boucle For Each, nous allons pouvoir parcourir la
collection des contrôles hébergés par le formulaire en cours d'analyse par la première boucle.
- Dans la première boucle, ajouter la seconde boucle For Each suivante :
...
Set leForm = Forms(chaqueForm.Name).Form
For Each ctrl In leForm.Controls
Next ctrl
End If
Next chaqueForm
...
Grâce à l'initialisation précédente, l'
objet leForm a hérité des propriétés et méthodes permettant de manipuler le formulaire en cours. Avec sa
propriété Controls qui représente la
collection de ses contrôles, nous engageons une
boucle For Each sur la
variable ctrl pour les analyser tous, tour à tour.
Analyser les propriétés des contrôles scrutés
Par voie hiérarchique, c'est maintenant que nous allons devoir analyser les
propriétés de chaque contrôle à la recherche des
macros embarquées. Pour cela tenez-vous bien, c'est une
troisième boucle For Each à engager avec la
variable prop sur la
collection des propriétés de chaque contrôle (ctrl), qui est nécessaire.
- Dans la deuxième boucle For Each, ajouter la troisième boucle suivante :
...
For Each ctrl In leForm.Controls
For Each prop In ctrl.Properties
Next prop
Next ctrl
...
Tester la présence des macros
Grâce à la boucle précédente, l'
objet prop a hérité des propriétés pour accéder aux attributs du
contrôle en cours d'analyse par la boucle parent. Si son nom contient le terme
EMMacro, c'est qu'il est susceptible d'embarquer une macro, en tous cas qu'il en est en capacité.
- Dans la troisième boucle, créer l'instruction conditionnelle suivante :
...
For Each prop In ctrl.Properties
If InStr(prop.Name, "EMMacro") > 0 Then
End If
Next prop
...
Pour cela, nous engageons la
fonction de recherche InStr sur le
nom de la propriété en cours d'analyse pour trouver la potentielle position du terme. Si la position renvoyée est positive, nous l'avons dit, cela signifie que ce contrôle est en capacité d'accueillir une
macro embarquée, sur événement donc.
Trouver l'événement affecté
Mais cela ne veut pas dire qu'une macro est effectivement associée à l'un de ses événements disponibles. Pour cela, nous allons devoir vérifier si la valeur de la propriété en cours d'analyse est bien renseignée, signifiant qu'une macro a été affectée à l'événement associé.
- Dans l'instruction conditionnelle, ajouter le nouveau test suivant :
...
If InStr(prop.Name, "EMMacro") > 0 Then
If Len(prop.Value) > 0 Then
End If
End If
...
La
fonction Len renseigne sur la valeur de la chaîne qui lui est passée en paramètre, ici la
valeur de la propriété en cours d'analyse. Si elle est positive, c'est qu'il y a bien une
macro incorporée.
Evénements des macros embarquées
Maintenant que nous sommes en mesure de connaître l'
événement déclenché par une
macro embarquée sur le
contrôle en cours d'analyse du
formulaire en cours d'analyse, nous n'avons plus qu'à assembler ces informations et à les restituer dans la
zone de texte du formulaire.
- Dans la seconde instruction conditionnelle, ajouter la ligne VBA suivante :
...
If Len(prop.Value) > 0 Then
listeMacros.Value = listeMacros.Value & "Formulaire<br /><strong>" & leForm.Name &"</strong><br />" & ctrl.Name & "<br/>" & Replace(prop.Name, "EmMacro", "") & "<br /><br />"
End If
...
L'
attribut Format du texte de cette zone (listeMacros) est réglé sur la
valeur texte enrichi. C'est la raison pour laquelle nous pouvons exploiter des
balises Html pour réaliser des
sauts de lignes (<br />) et des
mises en forme en gras (<strong>...</strong>). C'est ainsi que nous restituons le
nom du formulaire parent (leForm.Name) en gras, avec juste en dessous le
nom du contrôle (ctrl.Name) embarquant une macro et l'
événement sur lequel cette dernière est déclenchée (Replace(prop.Name, "EmMacro", "")). La
fonction Replace, ainsi utilisée, permet effectivement d'éliminer le terme de recherche pour ne conserver que le
nom de l'événement. C'est ainsi.
Fermer tous les formulaires ouverts
Pour parachever la solution avant de la tester, nous devons fermer tous les formulaires que nous avons ouverts tour à tour en mode conception. Et pour cela, il suffit d'appeler la
procédure fermerTout.
- A la toute fin du code VBA, ajouter l'appel suivant :
...
Next chaqueForm
fermerTout
End Sub
...
- Enregistrer les modifications (CTRL + S) et basculer sur le formulaire Access (ALT + Tab),
- L'exécuter, par exemple avec la touche F5 du clavier,
- Puis, cliquer sur le bouton Lister,
Après un petit temps de traitement et la fermeture de tous les formulaires analysés, vous constatez que tous les événements des
macros embarquées sont restitués avec leurs contrôles dans leurs formulaires.
Voilà donc un très bon moyen de comprendre le fonctionnement des multiples formulaires impliqués dans une application Access volumineuse.