I. Contexte▲
Depuis la sortie de la version 2007 de Microsoft Access (eh oui, 14 ans déjà…), il se trame sur la toile de nombreux
utilisateurs qui ont essuyé la fameuse erreur 2001 au démarrage de leur application ou lors de l’exécution d’une
requête particulière.
Cette erreur caractéristique au départ d’une signification de sécurité est causée par plusieurs phénomènes qu’il
est difficile de maîtriser car dans le contexte où se situe l’affichage de cette erreur, c’est le plus souvent à
la suite de l’exécution du code au démarrage qu’elle est levée et il n’est pas possible de prendre la main pour
savoir d’où elle provient.
I-A. Pourquoi ce tutoriel ?▲
Ayant eu la charge de la tierce maintenance applicative d’une application complexe qui avait été développée
sous Access 2003 et utilisée maintenue sous Access 2010 et 2013, l’idée était de faire en sorte que le
comportement de l’application reste le même sous l’une comme sous les autres versions. De nombreuses
fonctionnalités et corrections ont été apportées à celle-ci au fur et à mesure des années et lors des derniers
tests, en vue de préparer le déploiement, l’application a été confrontée à cette erreur plutôt difficile à
débugger.
Pourquoi ?
Tout simplement parce qu’il n’y avait pas d’erreur…
Enfin pas à proprement parler et encore moins visible en tout cas.
Et donc, quand il n’y a pas d’erreur, il n’est pas aisé de comprendre et résoudre l’affichage de ce message,
vous en conviendrez et c’est pourquoi, j’ai eu l’idée d’écrire ce tutoriel car vous pourriez très bien à votre
tour être confronté à la même problématique.
II. Appliquer ce que l’on trouve sur le WEB▲
Avant de rentrer dans le vif du sujet, je voudrais préciser une chose importante car parmi les solutions de contournement qui sont exposées sur la toile, nombreuses sont celles qu’il ne faut surtout pas mettre en œuvre y compris celles proposées sur ce site « Developpez.com ».
II-A. Les solutions de contournement à éviter▲
On trouve de tout sur Internet et en matière de solution « corrective » proposée par autrui, on tombe souvent
sur des suggestions qu’il ne faut éviter d'appliquer à l'aveugle...
Je suis notamment tombé sur ce post « [AC-2010] Erreur 2001 uniquement à l'ouverture base[AC-2010] Erreur 2001 uniquement à l'ouverture base » du forum Microsoft Access et ce qui m’embête un
peu à l’égard de la solution qu’a mise en place l’utilisateur, c’est que d’autres développeurs néophytes en
la matière l’on sans doute appliquée considérant que c’était LA solution.
Cette solution exposée dans le post du 30 juillet 2012 à 00h19 ne doit pas être appliquée comme telle sans
prendre conscience des conséquences utltérieures.
Effectivement, posté à cette heure tardive, on peut considérer que l’utilisateur était motivé pour
trouver une solution qui, certes, sera sans doute fonctionnelle mais qui n’est pas une solution en
soi. Cela s’appelle plutôt une rustine de confort.
En réalité, le problème qui résultera de la mise en œuvre cette suggestion (qui consiste à activer toutes
les macros au sein des propriétés générales de Microsoft Access) s’appliquera à l’ensemble des projets et
impactera l’ensemble des applications qui y seront ouvertes et exécutées.
En d’autres termes, et en admettant que vous l’appliquiez, à partir du moment où vous ouvririez une
autre application Microsoft Access que vous auriez téléchargé de l’extérieur et qui contiendrait du code
malveillant, cela pourrait être fatal à votre environnement de travail voir votre ordinateur complet sans
aucun avertissement préalable ni aucun moyen de le contrer forcément à temps.
III. Les solutions de détection possibles▲
Les éléments à mettre en place pour le débogage et l’éventuelle interception de cette erreur consisterait à poser
des marqueurs de bonne exécution dans un fichier LOG.
Par exemple, une procédure dédiée aurait pour rôle d’écrire
toute anomalie ou à l’inverse, pourrait mentionner que telle procédure s’est bien exécutée avec succès.
Cette méthode reste préférable à la mise en place d’appels via un MsgBox() qui, comme il
interagirait avec l’utilisateur, permettrait à une partie du code (basic ou non basic) d’avoir le temps de
s’exécuter en arrière-plan et ralentir en quelque sorte le code tel qui s’exécuterait sans cela.
Mais cela resterait vain car le code s’exécuterait correctement et votre fichier LOG marquerait point par point
que les procédures auraient été lues et traitées sans erreur.
Le plus frustrant est que le plus souvent, cette erreur n’est que rarement levée sur le poste
du développeur et donc, il est donc délicat pour lui de trouver une solution de débogage en local.
III-A. Oui mais du coup, je n’arrive pas à capturer l’erreur !▲
Effectivement la réalité est toute autre.
Cette erreur est loin d’être aléatoire et surviendra à chaque fois tant qu’un correctif idoine n’est pas
appliqué.
Et comme il s’agit d’une erreur qualifiée de « Non basic », vous ne pourrez pas
l’intercepter dans un gestionnaire d’erreur, si complet soit-il.
En parallèle à cela, cette erreur ne sait pas identifier exactement l’origine de sa source : en effet,
si votre application est construite de la façon suivante :
- AutoExec
- ExecuterCode
- DemarrerApplication()
- DoCmd.OpenForm "Accueil", acNormal, , , , acDialog
- [...]
- Exit Function
et que ce formulaire « Accueil » ouvre l’écran principal via une procédure après connexion ou sur un événement Timer comme par exemple :
- cmdOK_Click
- DoCmd.Close acForm, "Accueil"
- DoCmd.OpenForm "Menu Général", acNormal
- [...]
- Exit Sub
et que l’erreur 2001 est levée juste après cet événement, le message de la boîte de dialogue de l’erreur 2001 affichera comme source d’erreur la fonction initiale appelante : à savoir :
- nom la macro : AutoExec
- nom de l’action : ExecuterCode
- nom de l’argument : DemarrerApplication()
Et après coup, l’erreur ne viendrait pas du tout ce cette procédure « DemarrerApplication() »
puisqu’elle aurait été levée après l’événement de Fermeture du formulaire « Accueil »
dans ce contexte précis.
Quoi qu’il en soit et quel que soit le contexte, vous ne serez pas en mesure de déterminer d’où vient
exactement l’erreur.
Même si vous cherchez la description via la commande AccessError(2001) vous n’obtiendrez que
peu d’information, si ce n’est :
« Opération annulée.@@@1@2@5738@1 »
Et effectivement, vous n’avez pas d’autre choix que d’annuler par le biais du bouton
« Arrêter toutes les macros » lorsque ce message apparaît :
IV. Quelles sont les causes de cette erreur ?▲
Il existe selon mes connaissances quatre causes possibles qui génèrent la levée de ce message qui bloque au final votre application et la rend partiellement ou totalement inutilisable.
IV-A. Erreur au démarrage de l’application▲
La première de ces causes est celle qui est levée au démarrage de votre application.
Celle-ci déclenche un arrêt de l’exécution causé par cette erreur 2001 et affiche une boîte de dialogue
qui précise qui, comment et quoi provoque cet arrêt :
- le nom la macro ou la procédure responsable ;
- le nom de l’action déclenchée par la macro ;
- et enfin l’argument représentant le nom de la fonction à l’origine de l’erreur.
Côté bouton, le mode « Pas à pas » (4) est désactivé donc impossible de savoir d’où cela vient.
Le bouton « Continuer » (5) ne sera accessible qu’après avoir cliqué sur le bouton
« Arrêter toutes les macros » (6).
Toutefois, si l’erreur a été causée par une procédure Visual Basic pour Application issue de votre code,
il ne le sera pas et l’exécution sera interrompue.
IV-A-1. Côté développeur▲
Le premier réflexe que vous avez eu a été de vérifier, ainsi que cela est mentionné de toute part sur la toile à ce sujet, que l’erreur est causée par une histoire de sécurité de votre application mais malheureusement vous n’êtes pas concerné car celle-ci se trouve bel et bien dans un environnement de confiance1 sur votre poste de développeur et vous n’obtenez jamais cette erreur (je précise ici, en mode développeur, vous comprendrez pourquoi plus loin).
IV-A-2. Côté utilisateur▲
Et lorsque vous exécutez votre application sur le poste de l’utilisateur, vous n’avez pas forcément
prévu de la déployer avec un outil capable de définir les environnements de confiance1
et c’est cela qui peut provoquer l’erreur.
1 - (traduit plus communément par « Emplacement approuvé »)
IV-A-3. Vous en concluez…▲
A ce constat, vous déclarez donc les fameux emplacements sur le poste cible et pour vos futurs déploiements, vous ferez en sorte de fournir dans votre outil de déploiement, une routine qui visera à automatiser cette opération.
IV-A-4. Après définition…▲
A partir du moment où vous avez défini les emplacements approuvés sur le poste de l’utilisateur
et en admettant que votre application ne comporte pas d’autres erreurs, elle devrait
s’ouvrir normalement.
Si c’est le cas, c’est que c’était bien cela la cause du problème.
Sinon, voyez ci-après les autres rubriques pointant des états de fait et leur solution.
V. Comment vérifier préalablement les erreurs ?▲
Pour vérifier à la base que votre application ne comporte pas d’erreur, cela signifie de base que la compilation
du code compile sans erreur ; pour autant, cela ne signifie pas qu’il n’y a pas d’autre erreur dans votre projet.
Ainsi, après compilation sur le poste de test, il est bon de vérifier que :
- les références aux applications externes sont cochées au profit des versions équivalentes en place sur le poste d’utilisateur notamment pour Microsoft Office ;
- qu'au besoin, il est préférable d’utiliser des appels tardifs plutôt que de déclarations explicites dans votre code (Late Binding vs Early Binding) à savoir :
Set
MyAppObj =
CreateObject
(
"Object.Application"
)
plutôt que :
Set
MyAppObj =
New
Object.Application
où Object représente l'objet concerné (Word, Excel...) et cela évite les problèmes de compatibilité descendante d’Office ;
- que les déclarations Option Explicit sont bien présentes partout dans le projet ;
- que l’Option Base n’est pas déclaré à 1 alors que vous indices LBound démarrent à 0 ;
- que si l’Option Compare est à Text ne pas comparer au niveau Binary ;
- que si vous avez utilisé des Modules de Classe, qu’ils soient correctement instanciés ;
- etc...
Il y a certainement d’autres erreurs potentiellement présentes dans votre projet mais il est difficile ici de
toutes les énumérer d’une part et le compilateur ne saura pas les intercepter d’autre part.
De manière presque rassurante, si votre code compile bien, on peut supposer que votre application va
tourner correctement au départ.
VI. Comment procéder à des tests avant déploiement▲
Quoi qu’il en soit, et comme je l’ai déjà précisé maintes fois, notamment dans mes tutoriels concernant le
déploiement d’applications Microsoft Access avec le Runtime, il est important de pouvoir tester votre application
dans un contexte identique aux environnements dans lequel elle est vouée à être installée.
L’idéal étant l’usage de machines virtuelles.
VI-A. Déploiement de votre application▲
Utilisez les outils de déploiement disponibles sur ce forum ou bien utilisez un outil de déploiement vous
permettant de :
- déclarer les emplacements approuvés ;
- inscrire les éventuelles bibliothèques DLL sur le poste cible (compte admin requis) ;
- mettre à disposition tout fichier externe nécessaire à votre application.
Le lien des outils de déploiement se trouve iciComment déployer vos applications professionnelles développées avec Microsoft Access en incluant le Runtime.
VI-B. Test de votre application sur le poste cible▲
Lorsque vous avez finalisé l’installation de votre application sur le poste cible de test, machine virtuelle ou poste dédié, si malgré la déclaration des emplacements approuvés effectuée l’erreur persiste, c’est qu’il existe une erreur ailleurs et levé lors du démarrage de l’application ou durant le chargement d’un formulaire voire, l’exécution d’une requête ou les trois en même temps.
VII. Les autres causes probables de l’erreur 2001▲
Nous allons exposer dans les paragraphes qui vont suivre les différentes causes qui peuvent justifier la persistance de cette erreur au démarrage ou après l’affichage d’un formulaire.
VII-A. Erreur 2001 uniquement à l'ouverture base▲
C’est la première cause d’erreur la plus répandue qui justifie l’affichage de ce message.
Si ce message s’affiche alors qu’aucune autre erreur n’a été décelée selon vous et que votre application
tourne sur la plupart des postes de travail excepté quelques-uns, c’est que vous n’avez pas
déclaré d’environnement de confiance pour les postes en question.
Si cette déclaration a été automatisée au niveau du Registre par un SETUP.EXE, c’est que
celui-ci n’a pas déclaré les emplacements pour la bonne version d’Office par rapport aux versions
présentes sur ledit poste (Office14, Office15, Office16 etc…) ; par exemple, l’utilisateur
possède Microsoft Office 2013 et votre SETUP déclare les emplacements sur 2016 car vous avez développé
votre application à partir de Microsoft Access 2016, cela sera considéré comme non déclaré.
Lorsque sur le message vous cliquez sur le bouton « Continuer », suit alors un message qui précise
qu’un problème de sécurité potentielle a été identifié et qu’il est impossible de vérifier que ce
contenu provienne d’une source fiable.
Le message expose le fait que si vous approuvez la source, l’ouverture se poursuivra et que si vous avez
un doute, de le laisser désactivé.
Imaginez la tête d’un utilisateur ayant pas ou peu de connaissances en informatique confronté à un message
où il est dit que le fichier qu’il essaye d’ouvrir risque de comporter un contenu qui pourrait endommager
son ordinateur et de lui proposer malgré tout de l’ouvrir...
Important
Il est à noter que si l'utilszteur clique sur Annuler et votre application possède à cet instant
une procédure automatisée de rattache automatique des tables pas très bien structurée ou et que
celle-ci est appelée à un moment particulier :
1. une ou plusieurs tables sont susceptibles d’être mal liées (rattachées) ou de garder leur
lien d’origine voire même supprimée si votre propcédure de rattache suprime le lien pour le rattacher
correctement par la suite et ainsi, empêcher un bon fonctionnement de votre application une fois ouverte ;
2. d’afficher ce message à répétition pour autant de tables qu’il existe à rattacher dans votre projet
si votre application est structurée en Front End / Back End (Frontale / Dorsale).
Ce point est important car il pourrait déclencher d’autres erreurs non prévisibles comme la
N° 3265 ou la N° 3078 pour des objets ou tables absentes ou la N° 3044 pour une
inaccessibilité à la liaison réseau (entre autres).
VII-B. Erreur 2001 opération annulée▲
C’est la seconde cause d’erreur la plus répandue qui justifie l’affichage de ce message.
Remarque
Ceci dit, l’erreur 2001 est décrit comme « opération annulée » ; c’est sa description au niveau système
car c’est avant tout une erreur générique peu précise.
Dans ce post intitulé « [VBA]probleme : erreur 2001 operation annuléeErreur 2001 operation annulée » d'il y a quelques années, l’erreur avait été
causée par une double mauvaise compréhension de l’écriture de conditions WHERE au sein de sa
requête.
Quand je précise double, la première avait été causée par l’écriture de la condition elle-même
bien que la concaténation avait été appliquée correctement :
"[idExpo] BETWEEN '*"
&
Me![c_idExpo]
&
"' AND '"
&
Me![c1_idExpo]
&
"*' "
Ce qui se traduit par :
idExpo BETWEEN
'*2'
AND
'15*'
Le rédacteur ayant rencontré le problème avait fait l’amalgame d’un LIKE avec caractères joker
couplé à un BETWEEN ce qui n’est pas possible.
De plus, la clause WHERE était vouée à établir un intervalle de valeurs numérique entre 2 et 15 au
moment de l’exécution et donc l’intéressé aurait dû inscrire :
"[idExpo] BETWEEN "
&
Me![c_idExpo]
&
" AND "
&
Me![c1_idExpo]
&
" "
Ce qui se traduit par :
idExpo BETWEEN
2
AND
15
Comme précisé plus haut dans cet article, le compilateur ne sait pas voir ce type d’erreur car ce n’est pas une erreur de syntaxe visible.
VII-B-1. Comment prévenir les erreurs de syntaxe dans les requêtes dynamiques▲
Pour ce faire, il est recommandé de mieux découper vos requêtes lors de leur rédaction quitte à
utiliser plusieurs variables à concaténer au final plutôt que d’écrire en bloc toute la lignée de la
clause SQL ainsi que cela était le cas dans l’exemple précité.
1/ Dans l’exemple ci-dessous, on exploite la condition WHERE pointant des valeurs
numériques dans un intervalle via une clause BETWEEN :
Private
Sub
AlimenteListeDeroulante
(
)
Dim
SQLBase As
String
Dim
SQLWhere As
String
Dim
vntValeurDebut As
Variant
Dim
vntValeurFin As
Variant
vntValeurDebut =
Nz
(
Me!ChampDebut, 0
)
vntValeurFin =
Nz
(
Me!ChampFin, 0
)
If
(
vntValeurDebut >
0
) And
(
vntValeurFin >
0
) Then
SQLBase =
"SELECT Champ1, Champ2, Champ3, IIf(Year([ChampDate])=Year(Now()), 0, 1) AS Actuel "
SQLBase =
SQLBase &
"FROM TableCible "
SQLWhere =
"WHERE ChampIntervalle BETWEEN "
&
vntValeurDebut &
" AND "
&
vntValeurFin &
";"
With
Me.cboListeCorrespondante
.RowSource
=
SQLBase &
SQLWhere
.Enabled
=
True
.SetFocus
End
With
Else
MsgBox
"L'intervalle de valeurs n'est pas correct."
, vbExclamation
, "Erreur"
Me.ChampDebut.SetFocus
With
Me.cboListeCorrespondante
.RowSource
=
""
.Enabled
=
False
End
With
End
If
End
Sub
Vous constatez ici que les valeurs de la clause WHERE n’ont aucun caractère qui délimite leur valeur
ainsi que cela est appliqué pour les valeurs de type texte.
2/ Dans l’exemple ci-dessous, on exploite la condition WHERE pointant des valeurs texte fixes dans une plage via une clause OR :
Sub
AlimenteListeDeroulante
(
)
'[…]
vntValeurDebut =
Nz
(
Me!ChampDebut, Null
)
vntValeurFin =
Nz
(
Me!ChampFin, Null
)
'[…]
If
Not
IsNull
(
vntValeurDebut) AND
Not
IsNull
(
vntValeurFin) Then
'[…]
SQLWhere =
"WHERE ChampIntervalle = '"
&
vntValeurDebut &
"' OR ChampIntervalle = "
' & vntValeurFin & "'"
'[…]
End
Sub
Vous constatez ici que les valeurs de la clause WHERE sont ici délimitées par des quotes ('), soit, le caractère N°39 dans la table ASCII.
3/ Dans l’exemple ci-dessous, on exploite la condition WHERE pointant des valeurs texte approximatives dans une plage via une clause OR
Sub
AlimenteListeDeroulante
(
)
'[…]
SQLWhere =
"WHERE ChampIntervalle LIKE '*"
&
vntValeurDebut &
"*' OR ChampIntervalle LIKE "
'* & vntValeurFin & "*'"
'[…]
End
Sub
De façon identique, vous constatez ici que les valeurs de la clause WHERE sont ici délimitées par des quotes ('), concaténé au caractère joker *.
4/ Dans l’exemple ci-dessous, on exploite la condition WHERE pointant des valeurs date exactes dans un intervalle souhaité via une clause BETWEEN :
Sub
AlimenteListeDeroulante
(
)
Dim
SQLBase As
vnting
Dim
SQLWhere As
vnting
Dim
vntValeurDebut As
Variant
Dim
vntValeurFin As
Variant
vntValeurDebut =
Nz
(
Me!ChampDebut, Null
)
vntValeurFin =
Nz
(
Me!ChampFin, Null
)
If
Not
IsNull
(
vntValeurDebut) Then
If
IsDate
(
vntValeurDebut) Then
vntValeurDebut =
Format
(
vntValeurDebut, "mm/dd/yyyy"
)
End
If
End
If
If
Not
IsNull
(
vntValeurFin) Then
If
IsDate
(
vntValeurFin) Then
vntValeurFin =
Format
(
vntValeurFin, "mm/dd/yyyy"
)
End
If
End
If
If
Not
IsNull
(
vntValeurDebut) And
Not
IsNull
(
vntValeurFin) Then
SQLBase =
"SELECT Champ1, Champ2, Champ3, IIf(Year([ChampDate])=Year(Now()), 0, 1) AS Actuel "
SQLBase =
SQLBase &
"FROM TableCible "
SQLWhere =
"WHERE ChampDate BETWEEN #"
&
vntValeurDebut &
"# AND #"
&
vntValeurFin &
"#;"
With
Me.cboListeCorrespondante
.RowSource
=
SQLBase &
SQLWhere
.Enabled
=
True
.SetFocus
End
With
Else
MsgBox
"L'intervalle de dates n'est pas correct."
, vbExclamation
, "Erreur"
Me.ChampDebut.SetFocus
With
Me.cboListeCorrespondante
.RowSource
=
""
.Enabled
=
False
End
With
End
If
End
Sub
Vous constatez ici que les valeurs de la clause WHERE sont ici délimitées par des dièses (#), soit, le caractère N°35 dans la table ASCII d'une part et que le format de date est forcé en format US (mois,jour et année) d'autre part.
VII-B-2. Garantir la bonne saisie selon le type de donnée▲
Vous pouvez garantir la bonne saisie de votre condition WHERE selon le type de donnée du champ à
conditionner en mettant en place une fonction générique dédiée à « enquoter » correctement
vos valeurs.
Ainsi, à titre d’exemple que vous pouvez peaufiner, vous pouvez utiliser une fonction comme :
Public
Function
EnquoteSQLCondition
(
ByVal
NomChampCible As
String
, ByVal
ValeurChamp As
String
, ByVal
TypeChamp As
DAO.DataTypeEnum
, Optional
ByVal
Operateur As
String
=
"="
) As
String
Dim
strTemp As
String
Select
Case
TypeChamp
Case
dbText, dbMemo
strTemp =
"["
&
NomChampCible &
"] "
&
Operateur &
" '"
&
Replace
(
ValeurChamp, "'"
, "''"
) &
"'"
Case
dbDate
strTemp =
"["
&
NomChampCible &
"] "
&
Operateur &
" #"
&
ValeurChamp &
"#"
Case
Else
'dbNumeric etc...
strTemp =
"["
&
NomChampCible &
"] "
&
Operateur &
" "
&
ValeurChamp
End
Select
EnquoteSQLCondition =
strTemp
End
Function
Attention,
l’usage de cette fonction ne prévient pas des erreurs de saisie au niveau des paramètres que vous lui
passerez.
Elle permet juste de ne pas se soucier de la syntaxe car c’est elle qui l’écrit.
Vous pouvez l’agrémenter avec des conditions de nullité ou de validité de valeurs voire greffer des
notions d’intervalle ; elle se transformerait alors en fonction de création de condition WHERE et
nécessiterait plus d’attention quant à son élaboration.
VII-B-2-a. Quelques exemples d’application...▲
Debug.Print EnquoteSQLCondition("Mon champ","23",dbNumeric)
[Mon champ] = 23
Debug.Print EnquoteSQLCondition("Mon champ","9346",dbNumeric,">=")
[Mon champ] >= 9346
Debug.Print EnquoteSQLCondition("Mon champ","01/12/2021",dbDate)
[Mon champ] = #01/12/2021#
Debug.Print EnquoteSQLCondition("Mon champ"," Ma valeur",dbText)
[Mon champ] = 'Ma valeur'
VII-B-2-b. Exemple d’application de la clasue WHERE concaténée▲
Vous pouvez alors concaténer dans votre condition WHERE ainsi :
SQLWhere =
"WHERE (ChampDate BETWEEN "
&
EnquoteSQLCondition
(
"ChampDate"
, vntValeurDebut, dbDate) &
" AND "
&
EnquoteSQLCondition
(
"ChampDate"
, vntValeurFin, dbDate) &
") AND "
&
EnquoteSQLCondition
(
"ChampNombre"
, strValeurNombre, dbNumeric, ">="
)
Ce qui donnerait alors :
WHERE (ChampDate BETWEEN #01/12/2021# AND #31/12/2021#) AND ChampNombre >= 9346
VII-C. Erreur 2001 après l'ouverture d’un formulaire▲
C’est la troisième cause d’erreur la plus probable qui justifie l’affichage de ce message.
- Vous avez déclaré les emplacements approuvés tels que cela doit être fait sur les postes utilisateur ;
- vous n’avez pas commis d’erreur dans vos rédactions de requêtes, dynamique ou non ;
- vous n’avez pas commis d’erreur dans vos rédactions d’appel de paramètre dans les objets de type QueryDef ou dans la condition WHERE d'un Recordset.
Tout fonctionne parfaitement sur votre poste en mode production mais pour autant, l’erreur 2001 persiste au démarrage de votre application lorsque qu’elle est ouverte directement via un raccourci Windows ou via l’Explorateur de fichiers.
Par ailleurs, sur votre poste de développeur, l’erreur n’est jamais levée.
Vous ne comprenez pas ce qui se passe.
VII-C-1. Test sur le poste utilisateur▲
Idem ici, l’erreur 2001 persiste et lorsque vous cliquez sur le bouton « Arrêter toutes les macros », l’application s’arrête et s’affiche sous cette forme sans aucune autre alternative que fermer Microsoft Access :
VII-C-1-a. Analyse approfondie et Pas à pas exécutif▲
Après une relecture rapide de la procédure mentionnée dans la boite de dialogue de l’erreur 2001,
vous avez identifié que l’erreur pouvait venir de la procédure DemarrerApplication() ou d’une
sous-procédure appelée par cette même procédure en cascade le tout commandé depuis un AutoExec
qui déclenche un ExecuterCode.
Cette procédure, en fin d’exécution ouvre un formulaire quelconque personnalisé
(invitant l’utilisateur à se connecter ou à choisir un élément parmi ceux proposés ;
cela n’a aucune importance) :
- Vous n’avez décelé aucune erreur au sein de cette procédure et lorsque vous l’exécuter au pas à pas, l’erreur n’est pas levée sur votre poste de développeur ;
- vous avez mis en place une gestion d’erreur musclée qui n’est pour autant pas sollicitée ;
- vous avez également noté qu’aucune erreur n’est levée dans les procédures événementielles du formulaire lui-même ;
- vous avez beau chercher la cause, il n’y a aucune piste apparente.
VII-C-1-a-1. Alors, pourquoi sur mon poste ça marche et pas sur celui de l’utilisateur ?▲
Lorsque vous cherchez à regarder plus attentivement le contenu de ladite fonction dans le code
que vous avez écrit, il semble en toute apparence qu’il n’y ait pas de quoi justifier une erreur
et même après une relecture approfondie pour vous, il n’y a pas d’erreur.
Et si vous exécutez
depuis VBE ladite fonction au pas à pas, aucun message n’apparaît..., et c’est là que
l’adrénaline négative commence à monter.
Du fait que ce n’est pas une histoire de sécurité sur votre poste (vous avez encore vérifié)
mais ce n’est pas cela.
VII-C-1-a-2. Il faut passer en mode triche...▲
Effectivement, vous n’avez guère le choix et il vous faut bidouiller la fameuse fonction
« DemarrerApplication() » (ou celle que vous avez mentionné dans la section Argument de la
macro « ExecuterCode ») pour la réduire à son stricte nécessaire en mettant en
Remarque les lignes code (avec une apostrophe devant la ligne) ne bloquant pas l’application.
A la limite même, vous renommez provisoirement la fonction « DemarrerApplication() »
en « DemarrerApplication_origine() »
et vous créez une nouvelle fonction bidon
« DemarrerApplication() » qui ne fera que se contenter d’ouvrir le formulaire dit d’Accueil.
Vous testez… le formulaire s’ouvre et l’erreur 2001 apparaît encore.
Grrrr !!!
Conclusion, ce n’est pas votre fonction « DemarrerApplication() » qui pose problème.
VII-C-1-a-3. Tests par élimination▲
Donc après l'exécution de cette fonction de démarrageb« DemarrerApplication() », vous
diagnostiquez les événements au sein du formulaire qui s’ouvre juste après l’exécution de cette fonction.
Vous décidez de les mettre en remarque tous autant qu’ils sont quitte à provoquer une erreur
d’exécution locale autre que vous maitrisez cette fois – ce n’est pas bloquant sur ce point.
Vous testez de nouveau… le formulaire s’ouvre et là, miracle l’erreur 2001 n’apparaît plus.
Vous avez donc identifié la source ; elle se situe dans l’un des événements du formulaire.
Vous décidez de retirer une à une les lignes en remarque précédemment modifiées et testez à
chaque fois jusqu’à ce que l’erreur apparaisse de nouveau.
Au final et par élimination, vous trouvez l’événement responsable de l’erreur que voici :
Private
Sub
Form_Current
(
)
Me.Visible
=
True
If
Val
(
Application.Version
) >=
12
Then
If
Not
MODE_DEBOGAGE Then
DoCmd.ShowToolbar
"Ribbon"
, acToolbarNo
End
If
End
If
DoCmd.Maximize
End
Sub
Ainsi que vous pouvez le lire dans ce bloc événementiel, rien de probant ne peut être asujetti à
une quelconque erreur.
Ici :
- on rend le formulaire visible ;
- on vérifie la version de Microsoft Access ;
- si la version est suprérieure ou égale à 12 (2007) alors ;
- si l'application ne se trouve pas en mode DEBOGAGE alors ;
- on masque le ruban ;
- puis on agrandit la fenêtre au maximum.
Tant que la constante MODE_DEBOGAGE restée à True durant vos tests sur votre poste
de developpeur, le masquage du ruban n’était pas effectué. Et vous n’aviez pas forcément prêté
attention à cela jusqu’alors.
Mais pourquoi le fait de masquer le ruban provoque l’erreur 2001 ?
Question intéressante...
D’autant plus que si vous mettez un point d’arrêt dans cette procédure « Form_Current() » et
que vous l’exécutez au pas à pas, l’erreur 2001 n’est pas levée.
C’est à y rien comprendre.
Mais voici la réponse
La réponse à ce comportement se trouve dans les propriétés de la base de données active, autrement dit, votre application.
Dans l’événement « Form_Current() » se trouve une routine visant à masquer le ruban uniquement
lorsque votre version de Microsoft Access est supérieure ou égale à 2007 et que la constante
MODE_DEBOGAGE était à False.
Mais au sein des propriétés de votre base de données, le ruban est déjà masqué.
Du coup, erreur interne non capturable.
Remarque :
Cette erreur serait également survenue si vous avez en annexe, une procédure qui vise à définir
ce type de propriété dynamiquement par code.
VII-D. Erreur 2001 après l’exécution d’un événement ou d’une procédure▲
C’est la quatrième et dernière cause de l’erreur 2001 non identifiable et qui provoque l’affichage
de ce message.
Vous devez dans ce cas procéder comme à la section précédente, à savoir procéder par élimination.
Souvent, c’est à la suite d’un ajout d’une nouvelle fonctionnalité que cela peut être causé et comme
les applications Microsoft Office ne proposent pas d’outil de gestion de version, vous pouvez, bien
que cela ne soit guère pratique si votre projet n’est pas structuré pour, envisager de publier les
modules de code dans Github ou équivalent.
Quoi qu’il en soit, vous devez prendre l’habitude de greffer à chaque évolution de votre application
un commentaire avec un mot clé :
- au sein du module avec date et heure et ce qui a été modifié ;
- au sein de la procédure (événementielle ou non) ou d’une fonction ;
- et rédiger dans un module dédié, sous forme de texte en remarque ou dans un fichier externe, les évolutions dans les objets non codés (requêtes, formulaires, états, macros).
Grâce à ce mot clé associé ou non à la date, vous pourrez alors revenir à un point de restauration sur votre projet fonctionnel juste avant l'apparition de cette erreur, en omettant pas de sauvegarder ce que vous aviez modifié dans un fichier annexe, et ainsi tenter de réappliquer les évolutions sans erreur cette fois.
VIII. Conclusion▲
Ce tutoriel va sans doute aider quelques-uns d’entre vous à comprendre et gérer cette fameuse erreur
2001 de manière plus souple et plus simple.
Sur le principe, ce type d’erreur n’étant pas aisée à intercepter, il est probable que certains aient
eu à employer des méthodes drastiques et non conventionnelles pour la contrer et faire en sorte que
leur application fonctionne.
J’espère que ces quelques paragraphes vous aideront à l'éliminer si vous la côtoyez...
Après tout, ce n’est pas un si grand « Odyssée ».