IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Comprendre et résoudre l'erreur 2001

Commentez Donner une note à l´article (0)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 :

Erreur 2001
Erreur 2001 au démarrage

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 :

  1. le nom la macro ou la procédure responsable ;
  2. le nom de l’action déclenchée par la macro ;
  3. et enfin l’argument représentant le nom de la fonction à l’origine de l’erreur.
Erreur 2001
Erreur 2001 au démarrage



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 :
 
Sélectionnez
Set MyAppObj = CreateObject("Object.Application")

plutôt que :

 
Sélectionnez
Set MyAppObj = New Object.Application

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.

Erreur de sécurité
Erreur de sécurité

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 :

 
Sélectionnez
"[idExpo] BETWEEN '*" & Me![c_idExpo] & "' AND '" & Me![c1_idExpo] & "*' "

Ce qui se traduit par :

 
Sélectionnez
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 :

 
Sélectionnez
"[idExpo] BETWEEN " & Me![c_idExpo] & " AND " & Me![c1_idExpo] & " "

Ce qui se traduit par :

 
Sélectionnez
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 :

 
Sélectionnez
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 :

 
Sélectionnez
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

 
Sélectionnez
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 :

 
Sélectionnez
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 :

 
Sélectionnez
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...
 
Sélectionnez
Debug.Print EnquoteSQLCondition("Mon champ","23",dbNumeric)

[Mon champ] = 23

 
Sélectionnez
Debug.Print EnquoteSQLCondition("Mon champ","9346",dbNumeric,">=")

[Mon champ] >= 9346

 
Sélectionnez
Debug.Print EnquoteSQLCondition("Mon champ","01/12/2021",dbDate)

[Mon champ] = #01/12/2021#

 
Sélectionnez
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 :

 
Sélectionnez
SQLWhere = "WHERE (ChampDate BETWEEN " & EnquoteSQLCondition("ChampDate", vntValeurDebut, dbDate) & " AND " & EnquoteSQLCondition("ChampDate", vntValeurFin, dbDate) & ") AND " & EnquoteSQLCondition("ChampNombre", strValeurNombre, dbNumeric, ">=")

Ce qui donnerait alors :

 
Sélectionnez
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.

Erreur 2001
Erreur 2001 au démarrage

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 :

Erreur 2001 sur une application
Affichage de l'application après l'erreur 2001

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 :

 
Sélectionnez
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 :

  1. on rend le formulaire visible ;
  2. on vérifie la version de Microsoft Access ;
  3. si la version est suprérieure ou égale à 12 (2007) alors ;
  4. si l'application ne se trouve pas en mode DEBOGAGE alors ;
  5. on masque le ruban ;
  6. 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.

Propriétés de la base de données active
Propriétés de la base de données active

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 ».

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Ce document est issu de https://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.