1. Avant-propos ▲
Ce tutoriel a pour objectif de vous proposer une solution de distribution de vos applications selon les différentes étapes de leur développement dans les trois environnements connus : Test, Recette (UAT)1 ou Prod (Production).
Pour ce faire, vous devez être à l'aise avec Microsoft Access et avoir déjà distribué des applications (avec ou sans Runtime) dans un contexte professionnel.
Ce tutoriel est né de l'idée conjoncturelle d'une situation moult fois rencontrée dans le cadre de mes activités professionnelles.
En effet, chaque fois que l'occasion se présente, je partage des bouts de mes applications qui ouvrent selon moi une voie
intéressante pour vous, en tout cas, c'est l'objectif.
Contexte professionnel
Cet article concerne une situation professionnelle réelle dans laquelle je vous propose de mettre en pratique une solution idéale pour le déploiement de vos applications dans votre propre contexte professionnel.
Dans l'exemple qui va suivre, j'ai intentionnellement supprimé des champs en réduisant leur nombre dans la table, et ce, dans l'esprit de
pouvoir simplifier la réalisation…
Il vous appartiendra d'ajuster le nombre de champs nécessaires à ajouter pour satisfaire vos besoins…
1-2. Niveau ▲
Ce tutoriel s'adresse plus particulièrement aux personnes qui possèdent déjà des bonnes notions en matière de développement d'applications à vocation professionnelles et ayant déjà été confrontés à la problématique conjointe du déploiement et de l'évolution de leurs applications.
Pour la distribution d'application, vous pouvez vous référer au tutoriel sur le Déploiement et empaquetage d'applications Access 2010
1-3. Contact ▲
Pour tous renseignements complémentaires, veuillez me contacter directement (Argyronet) par MP.
Si votre question est, disons publique, merci de poster un message dans le forum afin d'en faire partager le contenu...
1-4. Images ▲
Les images représentées ont été créées à l'aide d'un logiciel spécifique.
Elles ne sont pas disponibles en téléchargement.
1-5. Langue ▲
Les commentaires du code de ce tutoriel sont rédigés en français.
Les noms des contrôles et les procédures de code sont, quant à eux, en anglais
1-6. Versions ▲
Ce tutoriel est applicable pour vos applications qui ont été développées à partir de la version 97 de Microsoft Access (avec quelques adaptations à prévoir pour la version 97).
2. Présentation du projet▲
Ce tutoriel a pour objectif de vous apprendre à mettre en place une solution de déploiement simplissime pour que vous puissiez concevoir une version de Test puis mettre à la disposition des utilisateurs une version UAT1 puis une version de Production encapsulée ou non dans la même application.
On considère alors que la notion de Test, UAT1 ou Production concerne aussi bien la base de données dorsale que, l'application frontale.
En effet, un ou plusieurs utilisateurs vont être chargés de tester la nouvelle version de l'application que vous leur avez mis à disposition mais selon l'état de celle-ci, devoir affonter les éventuelles corrections ou évolutions au fur et à mesure que son développement progresse.
2-1. A qui s'adresse ce tutoriel ?▲
Ce tutoriel est destiné aux développeurs dont l'activité est majoritairement axée sur des solutions dites "tactiques" au sein de l'entreprise dans laquelle ils travaillent.
Le niveau de connaissance requis est élevé, mais c'est surtout la rigueur de la qualité du côté rédactionnel du code qui fait foi ici.
En effet, vous ne pourrez en quelque sorte mettre en application ce tutoriel que si votre code est structuré avec des imbrications
de fonctions et de procédures factorisées en grand nombre.
J'insiste là-dessus dans le sens où si vous êtes amené à modifier la résultante ou le contenu d'une fonction
sous prétexte qu'elle doive subir des évolutions alors que celle-ci est déjà en fonctionnement dans la version actuellement en place
chez vos utilisateurs, il sera plus aisé d'implémenter un bloc conditionnel vérifiant le contexte
de l'environnement et d'exécuter le code en conséquence.
2-2. Que sont et comment sont utilisés ces environnements ?▲
Les environnements sont au nombre de trois
L'environnement de TEST
Il s'agit en fait de votre propre environnement durant lequel, vous procédez comme son nom l'indique à des tests au moment
de l'exécution du code pour contrôler le bon fonctionnement de l'application avant la mise en Recette.
J'aurais pu tout aussi bien dans cet esprit le nommer Environnement de développement.
L'environnement de RECETTE
Il s'agit de l'environnement qui se traduit par la phase d'acceptation des utilisateurs avant la mise en production effective.
En fait, une fois vos tests concluants, vous proposez une mise en recette. Vous attendez alors les éventuelles remontées des utilisateurs
qui peuvent inclure aussi bien des bugs que des dysfonctionnements qui émanent en toute logique des dernières modifications apportées
sauf biensûr s'il s'agit d'une première livraison.
L'environnement de PROD
Il s'agit de la version finalisée et opérationnelle de votre application exempt de bugs et de mauvais comportements.
Toutes les corrections apportées après la mise en recette ont bien entendu été soumises à une nouvelle mise en recette une fois
les tests concluants.
2-3. Principe de fonctionnement▲
Le principe de fonctionnement est simple et complexe à la fois...
Simple parce que la solution mise en place pour le contrôle de l'environnement reste rudimentaire.
Complexe parce qu'il vous appartiendra d'adapter votre code de façon bien ficelée pour que ce complément s'adapte à bon escient. Il est en effet délicat pour moi de vous proposer quelque chose d'absolument générique prêt à être encapsuler dans votre code du fait de la diversité des méthodes de développement employée par tout un chacun.
En effet, si vous souhaitez mettre en oeuvre ce tutoriel, l'idéal est de mettre en place les procédure de détection de
l'environnement dès la création du projet.
Dans le cas d'un projet existant en revanche, la mise en place des routines de détection des environnements sera d'autant
plus accessible que votre code est bien rédigé et bien entendu, l'inverse lorsque que vous avez face à vous un code écrit
à la mode plat de spaghettis.
A titre d'exemple (Historique) :
Le dernier projet que j'ai mis en œuvre importait selon de multiples conditions définies dans des tables de paramètres, un lot de fichiers Excel (avec de nombreux onglets d'une part et des structures différentes d'autre part) générés par l'ERP PeopleSoft® avec tous les inconvénients que cela relève...
Une fois importés, les onglets cibles étaient dispatchés ou fusionnés selon le cas dans différentes tables.
Un long traitement de nettoyage, de mise en forme, de contrôle de validité, de corrections automatiques, de notifications automatiques
dans un fichier LOG était généré durant le cycle d'exécution. Ce cycle allait, selon l'environnement choisi, chercher les
fichiers dans les dossiers spécifiés par la table définissant l'environnement.
Une fois toutes les données importées et mises en forme, donc présentées dans un formulaire de présentation final,
l'utilisateur pouvait effectuer des exports vers Excel pour l'ensemble des données, cette fois adaptées et corrigées
manuellement par lui-même. L'export construisait dynamiquement autant de classeurs que nécessaire et les
répartissaient dans des dossiers cibles ainsi que dans des dossiers Document Library5 d'un portail SharePoint®.
En résumé, l'utilisateur pouvait alors conserver son travail de Prod en cours et tester une nouvelle version de l'application en UAT1 dans le même temps, et ce, sans affecter les données de la base de données de production, ni les classeurs générés déjà dans les dossiers ou dans le portail SharePoint.
****************************************************************************************************
Le souci majeur était que le cahier des charges de ce projet était de base incomplet et confus mais le temps pressait et
j'avais un temps limité par mon estimation pour le réaliser. Constatant au fur et à mesure que des problèmes naissaient dès les
premières mises en recette, j'ai eu l'idée de mettre en place ce concept afin de me garantir plus de souplesse au fur et à mesure
que les corrections étaient appliquées et que les nouvelles demandes tombaient. Entre les premières lignes de code écrites et la
mise en production finale, pas moins de cent quarante modifications, évolutions ou nouvelles demandes ont été traitées.
****************************************************************************************************
L'objectif est donc que vous puissiez transposer cet exemple de contexte professionnel de ce tutoriel pour vos propres projets.
Déroulement synoptique
La représentation schématique du programme de ce projet exécutait telle ou telle procédure ou telle ou telle fonction en prenant les informations requises dans la table des environnements afin de définir le comportement de l'application et de travailler sur la base de données dorsale en rapport...
Je vous propose donc de mettre en application l'exemple de ce tutoriel sachant bien évidemment qu'une grande partie du contenu du formulaire
à créer autant que le sujet abordé ici ne s'accorderont pas forcément avec votre projet.
Seule l'idée est à retenir du fait que dans la plus grande partie des cas rencontrés en entreprise, les applications Access ont très souvent à
importer et / ou exporter des fichiers...
Dans ce synoptique, j'ai illustré un contexte similaire à mon projet dont l'objectif était d'importer des fichiers plats (quels qu'ils soient) et de générer des rapport statistiques, cas typique d'une application lambda...
On suppose ici détenir des fichiers plats mis à disposition dans un certain dossier défini en fonction de l'environnement dans lequel l'application est configurée.
Un processus d'importation, de traitement, de stockage (partiel ou total) et de formatage suivi éventuellement d'autres procédés [...] est alors exécuté, et ce dans la base de données cible dont les tables sont censées être liées.
Il se passe un certain nombre de choses dans l'application une fois tous ces processus exécutés et l'utilisateur
peut alors "jouer" avec les interfaces de consultation, de mise à jour et de gestion de l'application en général.
Lorsque ce dernier le souhaite, il peut générer des fichiers de sortie, classeurs Excel ou fichiers plats ou d'autres exportations
diverses et variées. La génération des fichiers s'exécutera et déposera les fichiers dans les dossiers cibles définis encore une fois
selon l'environnement.
En parallèle à cela, le projet veut que les fichiers générés soient déposés sur un site SharePoint (donc dans des dossiers de type Document Library5).
Je spécifie cela pour la forme car cela n'apporte rien au projet si ce n'est vous apprendre à coller une adresse dans une zone de texte et
contrôler en parallèle, sa validité.
Les tables associées
Dans ce projet, je pars du principe sans les aborder que des tables existent pour tous les traitements notamment celles
contenant les noms des fichiers à importer.
2-4. Mise en oeuvre du projet▲
Pour mettre en œuvre ce tutoriel, votre application devra être une scindée en une structure Frontal/Dorsal.
Vous devrez alors vous appuyer sur le synoptique et donc copier 3 exemplaires (si nécessaire) de la base de données dorsale initiale et donc finalisée. Considérez alors la notion de version de la base de données afin de garantir le bon fonctionnement.
Vous pouvez par exemple créer une table tblDBVersion dans laquelle un champ spécifie la version en vigueur, un autre la date correspondant à la dernière évolution et un autre qui résume, pourquoi pas, les derniers changements mis en application. Pour ce dernier point, il est fortement recommandé de noter dans un document annexe tous les changements relatifs aux tables :
- Ajouts de champs
- Changements de type de champ
- Changements de taille de champ
- Changements de nom de champ
- Etc...
Le but consiste à répercuter ces modifications sur la base de données UAT1 puis sur celle de production.
au final.
Parallèlement à cela, notez que pour tous types ou tailles des champs existants qui auraient été modifiés, une répercussion non
négligeable est à prendre en considération côté risque de perte de données. Il est alors recommandé de procéder à des
sauvegardes avant de procéder à de telles opérations...
2-5. Création de la table des environnements▲
Le projet exposé ici ne comporte qu'une seule table et contient donc les trois environnements de base et un réservé au développeur.
En réalité, les deux environnement de TEST sont réservés au développeur puisque c'est sous cet environnement que justement, les tests sont
réalisés avant la mise en Recette. Dans cette section, j'explique la raison de la présence
du champ ReservedToDeveloper.
La table est composée de treize champs :
Pour mettre en application ce tutoriel, vous devez créer la table des environnements. Il vous appartient de mettre autant de champs que
nécessaire selon l'objectif de votre projet.
Ici, dans notre exemple, j'ai ajouté les champs qui sont en rapport direct avec le projet
d'importation et d'exportation de fichiers même si ce n'est qu'une partie du projet en lui-même. Le travail expliqué ici n'a pas forcément
de rapport avec votre projet mais si vous lisez ces lignes, c'est que vous y portez tout de même un intérêt.
Dans ce contexte, nous avons besoin des champs définissant tous les éléments requis pour effectuer ces opérations.
Le tableau ci-dessous propose la liste des champs et leur description.
Nom | Type | Taille | Description |
---|---|---|---|
EnvironmentID | Entier long | 4 | Identifiant de l'environnement |
IsInUse | Oui/Non | 1 | True si l'environnement est actif |
ReservedToDeveloper | Oui/Non | 1 | True si réservé au développeur |
EnvironmentName | Texte | 64 | Nom donné à l'environnement |
LinkedDatabaseName | Texte | 64 | Nom de la base de données source |
LinkedDatabasePath | Texte | 255 | Chemin de la base de données source |
WorkingPath | Texte | 255 | Dossier de travail |
DataFileFolder | Texte | 64 | Dossier source où sont puisés les fichiers de données |
OutputFolder | Texte | 64 | Dossier où sont stockés les fichiers exportés |
OutputFilename | Texte | 64 | Nom du fichier final de sortie (par exemple Excel) |
DateFormat | Texte | 32 | Format de la date dans le nom du fichier par exemple yyyymmdd |
IsUSFormat | Oui/Non | 1 | True si le format de la date du nom de fichier est américain |
ArchiveFolder | Texte | 64 | Dossier où sont archivés les fichiers de données sources |
SharePointEnabled | Oui/Non | 1 | True si le site SharePoint est actif |
SharePointAddress | Texte | 255 | Adresse du site SharePoint |
Remarque:
Les trois premiers champs représentent la clé primaire.
En effet, lorsque l'on rend un environnement actif, il faut considérer le trio
EnvironmentID, IsInUse et ReservedToDeveloper.
Dans le tableau ci-dessus, ces champs sont en gras.
Il n'est en effet pas possible alors de créer un environnement portant le même ID et le même nom qu'il soit réservé
au développeur ou non.
Rappel
Par principe, ne mettez jamais d'accents ni d'espaces dans le nom des champs. C'est pourquoi je nomme toujours mes
champs en anglais.
Pour plus d'information sur les conventions de nommage des objets, vous pouvez lire
ce tutoriel.
Vous enregistrez la table par exemple sous le nom tblEnvironment.
2-5-1. Vue de la table en mode création▲
2-6. Remplissage de la table▲
Pour pouvoir utiliser la notion de gestion d'environnements dans votre projet, vous devez créer/ajouter manuellement les trois environnements.
Cela se résume à renseigner seulement les quatre premiers champs, car les autres seront ou pourront
être ajoutrés depuis le formulaire que vous allez créer et dans lequel des boutons de commande vous permettront
de sélectionner la base de dnnées dorsale, le chemin de travail et les dossiers cibles pour chacun des environnements. Cela évitera les erreurs de
saisie, chose courante lorsque des données sont entrées directement dans une table.
2-6-1. Vue de la table en mode feuille de données▲
La table en mode feuille de données une fois les environnements saisis.
Comme vous pouvez le constater, j'ai fait en sorte que la table ne soit pas intégralement remplie...
=> ce tutoriel et son application ne prévoient pas que la table soit dépourvue de spécifications d'environnement.
Ces derniers n'existent qu'à travers leurs ID respectifs. Aucun processus ne se charge de la saisie des ID dans cette table d'une part,
et que de toute façon, cette table et le formulaire qui l'accompagne sont réservés au développeur ou à l'équipe informatique d'autre part...
Vous saisirez donc les 3 environnements, ID + Nom directement depuis la table, ces données étant figées...
3. Création du formulaire▲
La réalisation présentée ici est purement suggestive... Ici, elle est en tout cas très fidèle à l'existant original.
Je pars donc du principe que vous allez vous en inspirer.
Vous créez donc un nouveau formulaire vide (Mode création) sans en-tête / pied de formulaire dans lequel vous
aurez à insérer autant de contrôles qu'il en existe dans la table source parmi zones de texte (textbox),
zones de liste modifiable (ComboBox), étiquettes (Label) et
boutons de commande (CommandButton)...
Il existe cependant deux contrôles cachés :
- qui pour l'un, représente l'identifiant de l'environnement (IDEnvironment)
- et pour l'autre qui représente le nom de l'environnement (EnvironmentName)
Ces deux zones de texte indépendantes restent masquées et seront exploitées par le programme au moment de l'utilisation.
Sans rentrer dans le détail sur l'aspect graphique du formulaire, point pour lequel je vous laisse libre cours à votre
imagination, je vais aborder sa conception au niveau des contrôles propres à son utilisation.
Comme vous pouvez le voir, j'ai utilisé un grand nombre d'objets dessinés et notamment des Lignes (Shape) dans le seul
but de faire joli d'une part et de séparer les valeurs qui ont un point commun d'autre part.
Pourquoi les contrôles sont indépendants
Tous les contrôles du formulaire présentés ici sont indépendants. En d'autres termes, ils ne n'ont pas de propriété ControlSource (Origine Source).
C'est ainsi que je procède dans la majorité des applications que je développe où j'ai pris l'habitude de concevoir des formulaires
indépendants de la source. Même si cela est un procédé plus complexe à mettre en oeuvre, il est évident, et c'est mon opinion, que cela
rend plus souple leur utilisation.
Si vous préférez lier les contrôles à la table source précédemment créée, il n'y a pas d'objection. Toutefois, le code présenté ici
n'aborde pas ce cas de figure et il vous appartiendra de l'adapter en conséquence et de gérer tous les événements inhérents à ce mode de réalisation
de formulaires Access.
De haut en bas :
0°) Tout d'abord, dans un coin du formulaire, dessinez deux zones de texte cachées (Visible=Non) que vous nommez respectivement
EnvironmentID et EnvironmentName.
Ces deux contrôles sont utilisés par le code pour identifier l'environnement par son ID et son nom en vue de les
appliquer à d'autres contrôles ou a des messages utltérieurement...
1°) Vous dessinerez ensuite en haut et à gauche, une zone de liste déroulante qui servira a proposer les différents environnements.
Cette liste voit sa propriété RowSource (Contenu) basée sur la chaîne SQL suivante :
SELECT
EnvironmentID, EnvironmentName
FROM
tblProcessEnvironment
WHERE
ReservedToDeveloper=
False
;
Il est recommandé de sauvegarder la requête sous un nom approprié plutôt que de laisser la chaîne SQL dans la zone
de propriétés, soit par exemple qry_cboEnvironmentList.
Vous nommerez par exemple cette liste déroulante cboCurEnvironment.
Dans l'idéal, et du fait que j'ai prévu une constante qui défini la valeur du champ ReservedToDeveloper, il est effectivement
préférable de faire en sorte que cette liste déroulante possède une source de contrôle dynamique et établie en fonction de la
valeur de cette constante.
L'événement Form_Load() vu plus bas sera aussi proposé avec cette condition...
Dim
SQLEnvList As
String
SQLEnvList=
"SELECT EnvironmentID, EnvironmentName FROM tblProcessEnvironment "
SQLEnvList=
SQLEnvList &
"WHERE ReservedToDeveloper="
&
RESERVED_TO_DEVELOPER &
";"
2°) A droite de cette zone de liste, vous dessinerez une case à cocher qui va permettre à l'utilisateur ou à vous-même de choisir si
vous voulez définir l'environnement affiché comme étant actif. L'événement Timer du formulaire changera la couleur de sa
légende et celle du cadre qui l'entoure selon que l'environnement choisi dans la liste est actif ou non.
Cette case à cocher sollicitera la valeur du champ IsInUse dans la table au moment de l'exécution du code.
Pour plus de commodité, vous nommerez cette case à cocher avec le même nom que le champ qu'elle alimentera (IsInUse).
L'ensemble des zones de texte
Maintenant, nous allons dessiner 11 zones de texte dont les longueurs varient en fonction de leur contenu.
Chacune de ces zones de texte reçoit une étiquette avec sa description du contenu concerné.
Pour la plupart d'entre elles, un petit bouton est dessiné à droite avec pour illustration, l'action Ouvrir, dont l'icône
caractéristique pour les opérations similaires sur les fichiers est affectée à leur propriété Image.
Cette illustration fait partie de la liste des bitmaps disponibles directement depuis l'assistant [...] Images de Microsoft Access.
Ces boutons auront pour action d'ouvrir la boîte de dialogue permettant de sélectionner un fichier ou un dossier selon le cas.
Pour chacun d'entre eux, une fonction appropriée sera appelée et retournera une chaîne de caractères qui représentera :
- soit le dossier,
- soit le nom du fichier,
- soit le chemin complet.
3°) La première zone de texte à dessiner permettra de recevoir le chemin dans lequel se trouve la base de données dorsale.
Vous nommerez cette zone txtDatabasePath et lui affecterez une longueur suffisante, à savoir pratiquement toute la longueur du formulaire.
L'étiquette de cette zone de texte voit sa propriété Caption (légende) affectée avec le texte Chemin de la base de données dorsale :
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe qui permet de l'identifier : lblDatabasePath.
À droite de cette zone de texte, vous dessinerez un petit bouton carré comme évoqué ci-avant. Il portera le nom cmdDatabasePath.
Le code affecté à ce bouton sera abordé un peu plus loin...
4°) Juste en dessous de ce contrôle, vous dessinerez une autre zone de texte qui contiendra cette fois le nom de la base de données dorsale.
Vous nommerez cette zone txtDatabaseName et lui affecterez une longueur qui représente grossièrement un tiers de la zone de texte représentant le chemin.
L'étiquette de cette zone de texte est porte la légende Nom de la base de données dorsale :
Le nom de ce contrôle Label rappelle le même que le nom de la zone de texte excepté son préfixe : lblDatabaseName.
Juste au-dessous de ces deux zones de texte vous avez la possibilité de dessiner un trait de séparation ainsi que vous le voyez dans l'illustration.
5°) La zone de texte suivante contiendra cette fois le chemin du dossier de travail. il s'agit en réalité du chemin qui fait
office de racine pour tous les sous-dossiers qui vont contenir les différents éléments contenus dans la fenêtre et que nous
allons aussi affecter à des différentes zones de texte.
Vous nommerez cette zone txtWorkingPath et lui affecterez la même longueur que celle que vous avez donnée à la zone de texte représentant le
chemin de la base de données et ce, dans le but de respecter l'aspect graphique du formulaire.
L'étiquette de cette zone de texte est porte la légende Chemin principal de travail :
Le nom de ce contrôle Label rappelle le même que le nom de la zone de texte excepté son préfixe : lblWorkingPath.
Au même titre que vous l'avez fait pour la zone de texte représentant le chemin de la base de données dorsale, vous dessinerez à
droite de celle-ci le même petit bouton carré, le mieux étant bien entendu de faire un copier-coller de celui que vous avez déjà posé.
Il portera le nom cmdWorkingPath et le code qui lui sera affecté sera abordé un peu plus loin...
6°) Nous continuerons dans la même lancée, la zone de texte suivante contiendra le nom du dossier où sont stockés les fichiers
de données sources. C'est effectivement dans ce dossier que seront stockés les fichiers qui contiennent les données importées dans la base.
On peut ici considérer qu'un processus externe dépose les fichiers automatiquement dans ce dossier, mais on peut également envisager de
les déposer à la main. Quel que soit le procédé, votre programme est censé lire ce dossier pour vérifier qu'il y a ou non des nouveaux
fichiers arrivés. Le cas n'a pas été prévu ici, mais il peut être intéressant de faire en sorte que votre programme ne lise les fichiers
qui portent une certaine convention typographique et éventuellement un horodatage.
Dans mon cas personnel, les fichiers à importer portaient toujours le même nom et ils étaient au nombre de quatre, de ce fait, il n'y avait qu'à vérifier leur présence. Du fait de leur nom était identique à chaque fois, le seul moyen de pouvoir faire la différence entre un fichier déjà importé et sa présence effective dans ce dossier consistait de les ouvrir pour en lire le contenu dans une zone spécifique dudit fichier. Ces fichiers étaient des fichiers Excel et la lecture de quelques cellules prédéfinies pour vérifier la période suffisait.
Vous nommerez cette zone txtDataFileFolder et lui affecterez une longueur suffisante pour que le nom de ce fichier soit lisible dans
son entier.
L'étiquette de cette zone de texte est nantie de la légende Dossier où sont stockés les fichiers de données source :
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblDataFileFolder.
Juste à côté de cette zone de texte, vous dessinerez ou recopierez le bouton permettant de sélectionner ce dossier. Vous lui attribuerez le
même nom que ce pourquoi il est destiné, hormis son préfixe, à savoir cmdDataFileFolder.
7°) En dessous de cette zone de texte, vous dessinerez une autre zone de texte qui contiendra le nom du dossier où seront stockés les fichiers générés.
Vous nommerez cette zone txtOutputFolder et lui affecterez une longueur suffisante, à savoir pratiquement toute la longueur du formulaire.
L'étiquette de cette zone de texte est nantie de la légende Dossier où sont stockés les fichiers générés :
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblOutputFolder.
Juste à côté de cette zone de texte, vous dessinerez ou recopierez le bouton permettant de sélectionner ce dossier. Vous lui attribuerez le
même nom que ce pourquoi il est destiné, hormis son préfixe, à savoir cmdOutputFolder.
8°) En dessous de ce contrôle, vous dessinerez deux zones de texte qui contiendront respectivement le nom et l'extension du fichier de sortie.
Vous nommerez ces zones txtOutputFilename et txtFileExtension leur affecterez une longueur suffisante, celle de l'extension ne devant contenir que 5 caractères max.
Les étiquettes de ces zones de texte sont nanties de la légende Nom du fichier de sortie : et Extension :
Le nom de ces contrôles Label est le même que le nom de leur zone de texte excepté les préfixes : lblOutputFilename et
lblFileExtension.
9°) En dessous de ces deux contrôles, vous dessinerez une zone de texte qui contiendra le format de sortie pour l'horodatage du fichier et
juste à côté de cette zone de texte, une case à cocher qui permet de spécifier que l'on souhaite ou non un format US pour la date.
Vous nommerez cette zone txtDateFormat et lui affecterez une longueur identique à celle du dessus (côté esthétique) et ferez en sorte que la
position gauche de la case à cocher soit alignée avec le bord gauche de la zone de texte au-dessus et contenant l'extension. Vous nommerez
la case à cocher chkIsUSFormat.
L'étiquette de cette zone de texte est nantie de la légende Format de la date pour le fichier : et celle de la case à cocher Format US
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblDateFormat et lblIsUSFormat pour
l'étiquette de la case à cocher
10°) La zone de texte suivante contiendra le nom du dossier où seront archivés les fichiers sources une fois le traitement terminé...
C'est effectivement dans ce dossier que seront stockés les fichiers tels que reçus avant traitement dans leur intégrité.
Vous nommerez cette zone txtArchiveFolder et lui affecterez la même longueur que le contrôle txtDataFileFolder.
L'étiquette de cette zone de texte est nantie de la légende Dossier où sont stockés les fichiers de données source :
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblArchiveFolder.
Juste à côté de cette zone de texte, vous dessinerez ou recopierez le bouton permettant de sélectionner ce dossier. Vous lui attribuerez le
même nom que ce pourquoi il est destiné, hormis son préfixe, à savoir cmdArchiveFolder.
11°) Juste en dessous de ce contrôle, vous pouvez ajouter ainsi que je l'ai fait, un contrôle label qui permet de préciser que
les dossiers qui n'existent pas seront créés automatiquement par le programme.
L'étiquette de cette zone de texte est nantie de la légende * Si un de ces dossiers n'existe pas, il sera créé automatiquement par le programme.
Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblSubFolderInfo.
12°) Juste en dessous de ce contrôle, vous dessinerez deux lignes superposées en guise de séparateur.
Vous les nommerez line03 et line04
*** FACULTATIF ***
Ainsi que je vous l'avais précisé, le projet initial disposait de zones de saisie de sites SharePoint.
Vous n'êtes en aucun cas tenu d'ajouter ce contrôle et les boutons qui l'accompagnent. C'est juste à titre d'exemple pour fidéliser
le projet en question d'une part et vous apprendre à l'envisager si cela vous concernait un jour d'autre part.
13°) Donc, vous dessinerez une dernière zone de texte qui contiendra l'adresse du site SharePoint où sont déposés les fichiers
si cela vous concerne, bien évidemment.
Vous adapterez et l'interface et le code selon le cas.
Vous nommerez cette zone txtSharePointAddress et lui affecterez une longueur suffisante, à savoir pratiquement toute la longueur
du formulaire, mais prêterez attention au fait que deux boutons de commandes jouxtent celle-ci. Vous ferez alors en sorte que le bouton le plus
à droite ait la même position que celui définissant le choix du chemin principal de travail.
- L'étiquette de cette zone de texte est nantie de la légende Adresse du site SharePoint où sont déposés les fichiers :
- Le nom de ce contrôle Label est le même que le nom de la zone de texte excepté son préfixe : lblSharePointAddress.
- Le premier bouton servant à coller une adresse web porte le nom cmdPasteSPAddress et se voit attribuer l'image du symbole Coller.
- Le second bouton servant à vérifier l'adresse web porte le nom cmdCheckSPAddress et se voit attribuer l'image du symbole représentant
une feuille et un globe.
3-1. Affectation des propriétés aux contrôles▲
Seule la zone de liste reçoit des propriétés initiales...
3-1-2. Les propriétés des autres contrôles▲
Toutes les propriétés des autres contrôles restent celles par défaut à l'exception :
- des boutons cmdUpdate et cmdValid qui ont leur propriété Activé (Enabled) définie à Non (False) car
leur état sera modifié dynamiquement le programme en fonction de ce qui se passe dans le formulaire.
- des zones de texte txtDatabaseName, txtDatabasePath et txtWorkingPath qui voient leur propriété
Verrouilé (Locked) définie à Oui (True) puisque le formulaire veut que ces chemins soient inscrits par le biais des
fonctions qui permettent de les sélectionner.
3-1-3. Disposition des contrôles▲
Vous agencerez ce formulaire comme bon vous semble. Celui présenté ici reste comme déjà précisé, une suggestion.
Ordre de tabulation
Dans ce formulaire, vous devez affecter à la propriété Arrêt tabulation (TabStop) la valeur Oui
(True) pour les contrôles de zone de texte (Textbox), zone de liste (Listbox) ;
concernant les deux boutons du bas (CommandButton), cette affectation est facultative qui plus est si vous avez
défini leur légende avec une esperluette idoine.
L'ordre sera alors 0 pour la zone de liste, 1 pour la première, zones de texte et ainsi de suite...
Il n'est pas ou peu utile de donner les focus par la touche TAB aux contrôles qui possède un bouton de sélection
car il n'y a pas lieu d'intervenir dedans en mode d'utilisation disons standard.
Exécution du formulaire en l'état
Vous pouvez passer en mode formulaire (ou appuyer sur F5) pour voir si votre agencement vous paraît correct.
Cela doit ressembler à :
Vu qu'aucun code n'a été affecté au formulaire et ses contrôles, il est évident que rien n'est rempli dans les zones de texte...
3-1-4. Sauvegarde du formulaire▲
Il est maintenant temps, si ce n'est déjà fait, de sauvegarder le formulaire.
Pensez au fur et à mesure que vous construisez le formulaire à presser les touches Ctrl+S pour sauver ce que vous avez déjà fait.
Pour cet objet, vous lui attribuerez le nom de frmEnvironmentManagement ou tout autre nom qui vous convient.
3-1-5. Mise en place du code événement▲
Pour affecter des événements aux différents contrôles, différentes solutions sont possibles...
Tout d'abord...
Pour mettre en place le code événement, il se peut que vos options ne soient pas définies pour attaquer à chaque fois
l'éditeur Visual Basic (VBE)...
Aussi, pour rendre plus confortable la rédaction du code, je vous invite à forcer l'usage de procédures
événementielles pour chaque événement et éviter l'apparition systématique de cette boîte de dialogue :

Veuillez activer les options d'Access et cocher la case appropriée dans la rubrique concernée :
la rubrique est intitulée :
"Toujours utiliser les procédures événementielles"...
Passer dans l'éditeur Visual Basic
À l'extérieur du formulaire tout en restant dans la fenêtre de celui-ci, effectuez un clic droit et choisissez
la commande : "Créer code événement…"
Dans l'éditeur Visual Basic, une fenêtre blanche va vous proposer d'écrire
un bout de code correspondant à l'événement attaché au chargement du formulaire.
Option
Explicit
Option
Compare Database
Private
Sub
Form_Load
(
)
End
Sub
Cet événement s'appelle Form_Load qui de par sa traduction signifie ce qu'il fait...
Pour plus d'informations sur les événements des contrôles et autres objets, veuillez vous référer à l'aide en ligne en mettant en surbrillance l'événement souhaité et appuyez sur la touche F1.
Rappelez-vous qu'un événement est quelque chose qui se passe lorsque l'utilisateur effectue une certaine opération "avant", "pendant", "après", etc. sur tel ou tel contrôle.
Il faut que vous sachiez qu'un contrôle de type zone de liste ne possède pas les
mêmes événements d'un contrôle bouton de commande par exemple et pour autant,
ils ont des événements communs.
Il vous appartiendra alors de choisir l'événement le plus approprié lorsque tel ou
tel contrôle est utilisé dans votre formulaire si vous souhaitez en gérer d'autres ou bien changer ceux mis en place dans le code.
3-1-5-1. Description des événements du projet▲
Dans la classe du formulaire, un jeu d'un peu plus de mille (1000) lignes est à écrire pour que ce formulaire soit (presque)
totalement opérationnel.
Il est vrai que cela peut paraître beaucoup, mais en fait, il y a beaucoup de blocs qui sont soit similaires soit dupliqués, car ils effectuent
les mêmes actions. Et puis en parallèle, il y a aussi à considérer le nombre de lignes de commentaire.
Dans son ensemble, le code est assez simple en soi à comprendre, mais il faut tout de même avoir déjà manipulé ce langage, car
en plus d'être dommage, il est plutôt frustrant de copier-coller du code sans comprendre à quoi il sert ou ce qu'il fait.
Liste des procédures et fonctions de la classe de formulaire
- cboCurEnvironment_AfterUpdate : Procédure Private Déclenche l'événement AprèsMaj de la liste déroulante des environnements.
- chkIsUSFormat_Click : Procédure Private Appelle l'événement Clic pour adapter le format de la date.
- chkSharePointEnabled_Click : Procédure Private Appelle l'événement Clic permettant de définir si le site SharePoint est disponible.
- cmdArchiveFolder_Click : Procédure Private Appelle l'événement Clic permettant de sélectionner le dossier d'archive.
- cmdCheckSPAddress_Click : Procédure Private Appelle l'événement Clic permettant de sélectionner vérifier l'adresse SharePoint.
- cmdDatabasePath_Click : Procédure Private Appelle l'événement Clic permettant de sélectionner le chemin de la base de données dorsale.
- cmdExit_Click : Procédure Private Appelle l'événement Clic permettant de fermer le formulaire avec alerte.
- cmdOutputFolder_Click : Procédure Private Appelle l'événement Clic permettant de sélectionner le dossier des fichiers générés.
- cmdPasteSPAddress_Click : Procédure Private Appelle l'événement Clic permettant de coller l'adresse du site SharePoint.
- cmdSave_Click : Procédure Private Appelle l'événement Clic permettant de sauvegarder l'environnement.
- cmdWorkingPath_Click : Procédure Private Appelle l'événement Clic permettant de sélectionner le chemin de travail.
- IsInUse_Click : Procédure Private Appelle l'événement Clic de la case à cocher de l'environnement.
- Form_Load : Procédure Private Appelle l'événement SurChargement du formulaire.
- Form_Timer : Procédure Private Appelle l'événement SurMinuterie du formulaire (clignotement de la zone de liste).
- txtSharePointAddress_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte de l'adresse SharePoint.
- txtSharePointAddress_KeyPress : Procédure Private Appelle l'événement SurToucheActivée dans la zone de texte de l'adresse SharePoint.
- txtArchiveFolder_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du dossier d'archives.
- txtArchiveFolder_KeyPress : Procédure Private Appelle l'événement SurToucheActivée dans la zone de texte du dossier d'archives.
- txtDataFileFolder_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du dossier du fichier source.
- txtDateFormat_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du format de la date.
- txtLinkedDatabaseName_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte de du nom de la base de données.
- txtLinkedDatabasePath_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du chemin de la base de données.
- txtOutputFilename_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du dossier du fichier de sortie.
- txtOutputFolder_Change : Procédure Private Appelle l'événement SurChangement dans la zone du dossier où sont générés les fichiers.
- txtOutputFolder_KeyPress : Procédure Private Appelle l'événement SurToucheActivée dans la zone de texte du dossier où sont générés les fichiers.
- txtWorkingPath_Change : Procédure Private Appelle l'événement SurChangement dans la zone de texte du chemin de travail.
- SelectedEnvironment : Propriété Get Private Propriété permettant de connaître le nouvel environnement sélectionné.
- SelectedEnvironment : Propriété Let Private Propriété permettant de définir le nouvel environnement sélectionné.
- CurrentEnvironment : Propriété Get Private Propriété permettant de connaître l'environnement en cours.
- CurrentEnvironment : Propriété Let Private Propriété permettant de définir l'environnement en cours.
- GetFolderForThisField : Function Private Procédure permettant de sélectionner un dossier.
- GetRecordSource : Function Private Procédure permettant d'obtenir la source de données du formulaire.
- InitializeControls : Procédure Private Procédure permettant d'initialiser les contrôles.
- NewDataCompleted : Function Private Procédure permettant de vérifier si l'ensemble des informations saisies est correct.
- PasteWebSiteAddress : Procédure Private Procédure permettant de coller l'adresse WEB pour le site SharePoint.
- DisableAllEnvironments : Procédure Private Procédure permettant de désactiver tous les environnements.
- EnableThisEnvironment : Procédure Private Procédure permettant d'activer un environnement particulier.
La liste ci-dessus n'est pas exhaustive ; telle qu'exposée ici, elle représente l'ensemble des procédures (événementielles ou non)
qui sont appliquées à ce formulaire...
3-1-6. Rédaction du code du formulaire▲
J'ai tâché de découper les blocs de code par événement et procédures/fonctions privées de manière à ce que vous puissiez mieux aborder l'ensemble
qui constitue l'intégralité du module de classe.
Le code est largement commenté pour que quiconque (avec un peu d'expérience tout de même) puisse comprendre toutes
les lignes et les instructions en regard.
De nombreuses fonctions sont externalisées dans un autre module avec quelques déclarations publiques
également ; nous verrons cela dans les paragraphes suivants...
Voici l'ensemble des blocs de code de la classe du formulaire :
3-1-6-1. En-tête du module▲
Dans l'en-tête du module, vous retrouvez des constantes et des variables privées.
Les trois constantes définissent respectivement le nom d'une table liée (ici, la table des utilisateurs), et les deux
formats de date servant à être greffés au nom du fichier de sortie pour l'horodatage.
La variable m_blnDataChanged est exploitée dans tout le module pour servir de témoin aux changements apportés dans les
contrôles Textboxes et les Cases à cocher. Vous voyez également les variables de membre des deux propriétés privées
CurrentEnvironment et SelectedEnvironment servant à connaître et définir l'ID de l'environnement.
Les autres variables sont affectées lorsque des valeurs dans les contrôles sont affectés aussi. Elles concernent ici le format de la date
inscrit dans le nom du fichier généré par le projet.
Rappelez-vous...
Rappelez-vous que lorsque je mentionne des termes comme «le projet», je parle bien entendu du clone du projet
que j'ai évoqué au début de cet article. Bien entendu, ce que vous êtes en train de concevoir ne saura pas ni importer, ni exporter,
ni générer des fichiers tel que cela est décrit dans plusieurs paragraphes.
Ce formulaire est construit pour ce type de projet et donc, les zones de texte requises y sont créées.
'**********************************************************************
' Module : Form_frmEnvironmentManagement
' Type : Document VBA
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Review : Jean-Philippe AMBROSINO
' Review date : 25/11/2012
' Purpose : Classe du formulaire de définition de l'environnement
'
''**********************************************************************
Option
Compare Database
Option
Explicit
'Table liée par défaut
Private
Const
TBL_USERS As
String
=
"tblUsers"
'Format des dates
Private
Const
FORMAT_DATE_FR As
String
=
"ddmmyyyy"
Private
Const
FORMAT_DATE_US As
String
=
"yyyymmdd"
'Flag des changements apportés aux contrôles
Private
m_blnDataChanged As
Boolean
'Statut de l'état
Private
m_blnIsInUse As
Boolean
'Environnement en cours
Private
m_lngCurrentEnvironment As
Long
'Nouvel environnement sélectionné
Private
m_lngSelectedEnvironment As
Long
'Format de la date du nom du fichier de sortie
Private
m_strDateFormat As
String
Private
Property
Get
SelectedEnvironment
(
) As
Long
'Nouvel environnement sélectionné
SelectedEnvironment =
m_lngSelectedEnvironment
End
Property
Private
Property
Let
SelectedEnvironment
(
ByVal
SelEnvironment As
Long
)
'Nouvel environnement sélectionné
m_lngSelectedEnvironment =
SelEnvironment
End
Property
Private
Property
Get
CurrentEnvironment
(
) As
Long
'Environnement en cours
CurrentEnvironment =
m_lngCurrentEnvironment
End
Property
Private
Property
Let
CurrentEnvironment
(
ByVal
CurEnvironment As
Long
)
'Environnement en cours
m_lngCurrentEnvironment =
CurEnvironment
End
Property
3-1-6-2. Classe du formulaire - Événements du formulaire▲
Le chargement Load du formulaire appelle la fonction GetRecordSource() pour remplir les contrôles via la procédure InitializeControls
si elle est appelée avec succès. Sinon, une erreur est levée.
L'événement Timer fait clignoter un cadre et change la couleur et l'aspect gras de l'étiquette de la case à cocher.
Il surveille par la même l'état Boolean de la variable m_blnDataChanged pour affecter la propriété Enabled du bouton
cmdSave qui, lorsqu'il est actif, signifie qu'un changement a été opéré et que donc, que la sauvegarde est possible.
Private
Sub
Form_Load
(
)
'---------------------------------------------------------------------------
' Procedure : Form_Load
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Chargement du formulaire
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strErrDescription As
String
On
Error
GoTo
L_ErrForm_Load
'On initialise les données pour l'environnement enregistré (on suppose qu'il y en a un)
If
GetRecordSource
(
True
, 0
) =
False
Then
'Sinon lève une erreur
Err
.Raise
3032
, "Données source"
, "Impossible de récupérer les données de l'environnement"
End
If
'On initialise les contrôles
InitializeControls
On
Error
GoTo
0
L_ExForm_Load
:
Exit
Sub
L_ErrForm_Load
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExForm_Load
End
Sub
Comme dit plus haut, voici le bloc de code qui traite le chargement du formulaire qui alimente dynamiquement la liste
déroulante des environnements en considérant la valeur de la constante de l'environnement réservé au développeur.
Ce bloc est totalement facultatif et si vous n'êtes pas concerné par ce cas, vous prendrez le bloc ci-dessus.
Private
Sub
Form_Load
(
)
'---------------------------------------------------------------------------
' Procedure : Form_Load
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Chargement du formulaire
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strErrDescription As
String
Dim
SQLEnvList As
String
On
Error
GoTo
L_ErrForm_Load
'Chaîne SQL listant les environnement selon la constante RESERVED_TO_DEVELOPER
SQLEnvList =
"SELECT EnvironmentID, EnvironmentName FROM tblProcessEnvironment "
SQLEnvList =
SQLEnvList &
"WHERE ReservedToDeveloper="
&
CInt
(
RESERVED_TO_DEVELOPER) &
";"
'Affectation de la clause SQL à la liste déroulante
With
cboCurEnvironment
.ColumnWidths
=
"0cm;2cm"
.BoundColumn
=
1
.LimitToList
=
True
.ColumnCount
=
2
.RowSource
=
SQLEnvList
End
With
'On initialise les données pour l'environnement enregistré (on suppose qu'il y en a un)
If
GetRecordSource
(
True
, 0
) =
False
Then
'Sinon lève une erreur
Err
.Raise
3032
, "Données source"
, "Impossible de récupérer les données de l'environnement"
End
If
'On initialise les contrôles
InitializeControls
On
Error
GoTo
0
L_ExForm_Load
:
Exit
Sub
L_ErrForm_Load
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExForm_Load
End
Sub
Le formulaire délenche aussi l'événement SurMinuterie().
Private
Sub
Form_Timer
(
)
'---------------------------------------------------------------------------
' Procedure : Form_Timer
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Timer sur le formulaire (fait clignoter l'environnement actif)
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
On
Error
Resume
Next
'Si l'environnement est actif
If
Nz
(
Me.IsInUse
, False
) Then
'On change l'aspect de l'étiquette et de son cadre
With
Me.lblIsInUse
DoEvents
.ForeColor
=
IIf
(
.ForeColor
=
255
, 10053222
, 255
)
.FontBold
=
(
.ForeColor
=
255
)
Me.shpIsInUse.Visible
=
(
.ForeColor
=
255
)
End
With
End
If
'On change la couleur le l'étiquette de l'adresse SharePoint
If
Nz
(
Me.chkSharePointEnabled
, False
) Then
Me.lblSharePointEnabled.FontBold
=
(
Me.lblIsInUse.ForeColor
=
255
)
End
If
'On active le bouton de sauvegarde si un changement a été opéré (flag)
cmdSave.Enabled
=
m_blnDataChanged
End
Sub
3-1-6-3. Classe du formulaire - Evénement AprèsMaj de la zone de liste déroulante▲
Lors de la sélection d'un nouvel environnement, l'événement AfterUpdate de la liste des environnements charge le nouvel environnement en appelant la fonction GetRecordSource() et permet de réaffecter les contrôles en conséquence.
Private
Sub
cboCurEnvironment_AfterUpdate
(
)
'---------------------------------------------------------------------------
' Procedure : cboCurEnvironment_AfterUpdate
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de choisir un autre environnemnet
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strErrDescription As
String
On
Error
GoTo
L_ErrcboCurEnvironment_AfterUpdate
'La propriété prend la valeur de la liste
SelectedEnvironment =
Me.cboCurEnvironment
'Si l'on peut obtenir l'environnement dans la table...
If
GetRecordSource
(
False
, SelectedEnvironment) =
False
Then
'Sinon, on lève l'erreur
Err
.Raise
3032
, "Données source"
, "Impossible de récupérer les données de l'environnement"
End
If
'On alimente les étiquettes
'du titre de la fenêtre
Me.lblData.Caption
=
"Les paramètres pour l'environnement "
&
Me.cboCurEnvironment.Column
(
1
) &
" :"
'Met en gras l'étiquette de l'adresse SharePoint si la case est cochée
Me.lblSharePointEnabled.FontBold
=
Me.chkSharePointEnabled
'On désactive le bouton de sauvegarde
Me.cmdSave.Enabled
=
False
On
Error
GoTo
0
L_ExcboCurEnvironment_AfterUpdate
:
Exit
Sub
L_ErrcboCurEnvironment_AfterUpdate
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExcboCurEnvironment_AfterUpdate
End
Sub
3-1-6-4. Classe du formulaire - Événements Click des cases à cocher▲
Lorsque les cases à cocher son affectées avec leurs valeurs True ou False, l'évenement Click est déclenché.
- IsInUse_Click : Vérifie la modification de l'affectation du nouvel environnement avec affectation de l'intervalle du Timer en conséquence ;
- chkIsUSFormat_Click : Attribut le format US pour les dates du nom de fichier de sortie si elle est égale à True ,;
- chkSharePointEnabled_Click : Change la valeur de la variable flag m_blnDataChanged selon sa valeur et permet d'assurer la validité
de l'adresse du site SharePoint s'il en existe un.
Rappel
La définition du site SharePoint reste totalement facultative et hors contexte si votre entreprise ne possède pas de base documentaire du même nom.
Private
Sub
IsInUse_Click
(
)
'---------------------------------------------------------------------------
' Procedure : IsInUse_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie la modification de l'affectation du nouvel environnement
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strErrDescription As
String
On
Error
GoTo
L_ErrIsInUse_Click
'On compare les environnements
If
SelectedEnvironment <>
CurrentEnvironment Then
'On averti en conséquence
If
MsgBox
(
"Seulement un seul environnement peut être affecté au statut 'Actif'"
_
&
vbCrLf
&
"Si vous définissez l'environnement '"
&
Me.cboCurEnvironment.Column
(
1
) &
_
"' comme nouvel environnement, tous les autres seront désactivés..."
&
vbCrLf
&
vbCrLf
&
_
"Souhaitez-vous définir cet environnement comme environnement de travail actuel ?"
, _
vbExclamation
+
vbYesNo
+
vbDefaultButton2
, "Definir l'environnement"
) _
=
vbYes
Then
'IOn desactive alors tous les environnements (conflits éventuels avec intervention directe dans la table)
DisableAllEnvironments
'Et on active celui sélectionné
EnableThisEnvironment Me.cboCurEnvironment
'On obtient les info de la table pour cet environnement
If
GetRecordSource
(
False
, Me.cboCurEnvironment.Value
) =
False
Then
'Si il n'y a pas de données
Err
.Raise
3032
, "Données source"
, "Impossible de récupérer les données de l'environnement"
End
If
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
'On modifie l'interval du Timer
Me.TimerInterval
=
600
Else
'On décoche la case de l'environnement actif
Me.IsInUse.Value
=
False
'On désactive le Timer
Me.TimerInterval
=
0
End
If
'On libère l'état du bouton de sauvegarde
Me.cmdSave.Enabled
=
Nz
(
Me.IsInUse
, False
)
Else
'On averti les mauvaise manip pour la gestion des environnements
MsgBox
"Il n'est pas possible de désactiver un enviromnent qui est définit comme environnement de travail actuel."
_
&
vbCrLf
&
vbCrLf
&
"Si vous souhaitez désactiver l'environnement '"
&
Me.cboCurEnvironment.Column
(
1
) &
_
"', vous devez d'abord choisir l'environnement que vous souhaitez activer, et donc, celui-ci est désactivé automatiquement."
, _
vbCritical
, "Opération refusée"
'On force la case à cocher
Me.IsInUse.Value
=
True
End
If
On
Error
GoTo
0
L_ExIsInUse_Click
:
Exit
Sub
L_ErrIsInUse_Click
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExIsInUse_Click
End
Sub
Private
Sub
chkIsUSFormat_Click
(
)
'---------------------------------------------------------------------------
' Procedure : chkIsUSFormat_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Case à cocher du format US pour les dates
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Initialise la variable de module du format pour un usage ultérieur
m_strDateFormat =
Nz
(
Me.txtDateFormat
, vbNullString
)
'Vérifie la longueur de la chaîne
If
Len
(
m_strDateFormat) Then
'Si la case format US est cochée
If
Nz
(
Me.chkIsUSFormat
, False
) Then
Me.txtDateFormat
=
FORMAT_DATE_US
Else
Me.txtDateFormat
=
m_strDateFormat
End
If
Else
'Sinon le format est FR
Me.txtDateFormat
=
FORMAT_DATE_FR
End
If
End
Sub
Private
Sub
chkSharePointEnabled_Click
(
)
'---------------------------------------------------------------------------
' Procedure : chkSharePointEnabled_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
'Met en gras l'étiquette de l'adresse SharePoint si la case est cochée
Me.lblSharePointEnabled.FontBold
=
Me.chkSharePointEnabled.Value
'Active le bouton de vérification de l'adresse si la case à cocher est cochée
Me.cmdCheckSPAddress.Enabled
=
Me.chkSharePointEnabled.Value
End
Sub
3-1-6-5. Classe du formulaire - Sélection des dossiers▲
La sélection des dossiers est opérée par la même fonction GetFolderForThisField() qui exploite la propriété ControlTipText
du contrôle appelant pour définir le titre de la boîte de dialogue, la zone de texte cible recevant le nom du dossier et une variable témoin "blnHasChanged"
qui affecte la variable de module m_blnDataChanged pour savoir si effectivement un (autre) dossier a été sélectionné.
Si un dossier a effectivement été sélectionné, alors la variable témoin donne sa valeur True à la variable de module m_blnDataChanged
ce qui fait que le l'événement Timer du formulaire va réagir en conséquence vis à vis du bouton de commande cmdSave.
Private
Sub
cmdArchiveFolder_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdArchiveFolder_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier pour les archives
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
blnHasChanged As
Boolean
'Appelle GetFolderForThisField pour obtenir le dossier d'archive
Me.txtArchiveFolder
=
GetFolderForThisField
(
cmdArchiveFolder.ControlTipText
, Nz
(
Me.txtArchiveFolder.Value
, vbNullString
), blnHasChanged)
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
blnHasChanged
End
Sub
Private
Sub
cmdDataFileFolder_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdDataFileFolder_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier où sont les fichiers sources de données
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
blnHasChanged As
Boolean
'Appelle GetFolderForThisField pour obtenir le dossier des fichiers sources
Me.txtDataFileFolder
=
GetFolderForThisField
(
cmdDataFileFolder.ControlTipText
, Nz
(
Me.txtDataFileFolder.Value
, vbNullString
), blnHasChanged)
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
blnHasChanged
End
Sub
Private
Sub
cmdOutputFolder_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdOutputFolder_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier pour le fichier de sortie
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
blnHasChanged As
Boolean
'Appelle GetFolderForThisField pour obtenir le dossier des fichier de sortie
Me.txtOutputFolder
=
GetFolderForThisField
(
cmdOutputFolder.ControlTipText
, Nz
(
Me.txtOutputFolder.Value
, vbNullString
), blnHasChanged)
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
blnHasChanged
End
Sub
3-1-6-6. Classe du formulaire - Sélection des chemins▲
La sélection du chemin de la base de données dorsale est opérée par l'appel de la fonction SelectAnyFile()
qui alimente la variable strDBFullPath passée en paramètre.
Cette dernière est ensuite décomposée par les fonctions GetPathName et GetFileName pour respectivement
alimenter la zone de texte du chemin et la zone de texte du nom de ladite base de données.
Le sélection du chemin de travail est opérée par l'appel de la fonction SelectAnyFolder(). De ce chemin de travail
découlera la définition du dossier Racine duquel seront créés (par votre application s'ils n'existent pas)
les dossiers définis dans les autres zones de texte.
- En effet, si vous sélectionnez les dossiers, c'est que ces derniers existent...
- Si vous les saisissez à la main, c'est que vous souhaitez qu'ils soient créés dynamiquement par votre procédure de
traitement des fichiers.
Private
Sub
cmdDatabasePath_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdDatabasePath_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier pour la base de données dorsale
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
blnHasChanged As
Boolean
Dim
strDBFullPath As
String
Dim
strDBPathName As
String
Dim
strDBFileName As
String
'Permet de sélectionner un fichier
strDBFullPath =
SelectAnyFile
(
Me.HWnd
, cmdDatabasePath.ControlTipText
, Nz
(
Me.txtLinkedDatabasePath.Value
, vbNullString
))
'Affecte le flag de changement dans le formulaire en vérifiant que le fichier existe
m_blnDataChanged =
ThisFileExists
(
strDBFullPath)
'S'il existe alors...
If
m_blnDataChanged Then
'Les zones de texte reçoivent pour l'une le chemin et pour l'autre le nom de la base de données dorsale
Me.txtLinkedDatabasePath
=
GetPathName
(
strDBFullPath, False
)
Me.txtLinkedDatabaseName
=
GetFileName
(
strDBFullPath)
End
If
End
Sub
Private
Sub
cmdWorkingPath_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdWorkingPath_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier pour définir le chemin de travail
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strOldWorkingPath As
String
Dim
strNewWorkingPath As
String
Dim
strStartDirectory As
String
On
Error
GoTo
L_ErrcmdWorkingPath_Click
'Initialise l'ancien chemin de travail
strOldWorkingPath =
Nz
(
Me.WorkingPath.Value
, vbNullString
)
'Défini le dossier de démarrage pour la sélection
strStartDirectory =
CurrentProject.Path
'Initialise le nouveau chemin de travail
strNewWorkingPath =
SelectAnyFolder
(
"Sélectionner le dossier"
, strStartDirectory)
'Si un chemin a été selectionné...
If
Len
(
strNewWorkingPath) Then
chemin sont identiques
If
StrComp
(
strOldWorkingPath, strNewWorkingPath, 1
) =
0
Then
'On lève une erreur
Err
.Raise
58
, "Dossier identique"
, "Le chemin d'accès sélectionné est le même que celui en cours !"
End
If
'Sinon, on rempli la zone de texte avec le nouveau chemin
'Si l'ancien et le nouveau
Me.txtWorkingPath
=
strNewWorkingPath
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
If
On
Error
GoTo
0
L_ExcmdWorkingPath_Click
:
Exit
Sub
L_ErrcmdWorkingPath_Click
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExcmdWorkingPath_Click
End
Sub
3-1-6-7. Classe du formulaire - Sauvegarde de l'environnement▲
La sauvegarde de l'environnement passe par l'événement Click du bouton de commande cmdSave
Dans son exécution, l'appel de la fonction NewDataCompleted() permet de vérifier la cohérence des informations
saisies et retourne False en donnant le Focus au contrôle concerné accompagné d'un message circonstanciel
si toutefois une zone a été omise ou n'est pas conforme.
Voir exemple ici
Si tout est correct, alors une procédure d'écriture dans la table locale est exécutée par le biais d'un Recordset.
Private
Sub
cmdSave_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdSave_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Sauvegarde l'environnement
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strErrDescription As
String
Dim
oDB As
DAO.Database
Dim
oRS As
DAO.Recordset
Dim
strMissedValue As
String
Dim
SQLSelect As
String
Dim
SQLUpdate As
String
Dim
strCriteria As
String
Dim
blnIsInUse As
Boolean
Dim
lngEnvironmentId As
Long
Dim
strEnvironment As
String
Dim
strSharePointAddress As
String
Dim
strLinkedDatabasePath As
String
Dim
strLinkedDatabaseName As
String
Dim
strWorkingPath As
String
Dim
strDataFileFolder As
String
Dim
strArchiveFolder As
String
Dim
strOutputFilename As
String
Dim
strDateFormat As
String
Dim
strFileExtension As
String
Dim
strOutputFolder As
String
Dim
blnSharePointEnabled As
Boolean
Dim
blnIsUSFormat As
Boolean
Dim
blnSPPEnabled As
Boolean
Dim
strSPPAddress As
String
Dim
t As
Integer
On
Error
GoTo
L_ErrcmdSave_Click
'Sablier
DoCmd.Hourglass
True
'On affiche le traitement
Me.lblSaveInformation.Caption
=
"Vérification des données avant la mise à jour de cet environnement..."
DoEvents
Sleep 1000
'On affecte l'environnement en cours
strEnvironment =
Me.cboCurEnvironment.Column
(
1
)
'On vérifie que tous les champs sont correctement remplis
If
NewDataCompleted
(
strMissedValue) =
False
Then
'Sinon, on lève une erreur
Err
.Raise
3032
, "Enregistrement non sauvé"
, "Impossible de mettre à jour l'environnement actuel '"
&
strEnvironment _
&
"' parce que les données du champ '"
&
UCase
$(
strMissedValue) &
"' est manquante ou invalide !"
End
If
'On affecte les variables
'L'environnement (ID)
lngEnvironmentId =
Nz
(
Me.EnvironmentID.Value
, 0
)
'Le flag de l'activation
blnIsInUse =
Nz
(
Me.IsInUse.Value
, False
)
'Le chemin de travail
strWorkingPath =
Nz
(
Me.txtWorkingPath.Value
, vbNullString
)
'Le dossier de sortie
strOutputFolder =
Nz
(
Me.txtOutputFolder.Value
, vbNullString
)
'Le dossier d'archive
strArchiveFolder =
Nz
(
Me.txtArchiveFolder.Value
, vbNullString
)
'Le flag de l'activation du site SharePoint
blnSharePointEnabled =
Nz
(
Me.chkSharePointEnabled.Value
, False
)
'L'adresse du site SharePoint
strSharePointAddress =
Nz
(
Me.txtSharePointAddress.Value
, vbNullString
)
'Le chemin de la base de données dorsale
strLinkedDatabasePath =
Nz
(
Me.txtLinkedDatabasePath.Value
, vbNullString
)
'Le nom de la base de données dorsale
strLinkedDatabaseName =
Nz
(
Me.txtLinkedDatabaseName.Value
, vbNullString
)
'On change la liaison de la base de données dorsale
If
ChangeLinkedDatabase
(
strLinkedDatabasePath, strLinkedDatabaseName) =
False
Then
'Si la fonction échoue, une erreur est levée
Err
.Raise
3184
, "Echec de liaison"
, "Une erreur a été rencontrée pendant l'opération de réattachement des tables."
End
If
'On vérifie l'existence du chemin de travail
If
ThisFolderExists
(
strWorkingPath) =
False
Then
Err
.Raise
76
, "Chemin d'accès inexistant"
, "Le chemin d'accès :"
&
vbCrLf
&
Chr
(
171
) &
strWorkingPath &
Chr
(
187
) &
vbCrLf
&
_
"n'existe pas ou bien vos droits d'accès pour accéder à ce répertoire sont restrictifs."
&
vbCrLf
&
vbCrLf
&
_
"Contactez votre support informatique pour obtenir la raison pour laquelle vous n'avez pas été en mesure de choisir un "
_
&
"répertoire qui n'est pas disponible actuellement..."
End
If
'On informe l'utilisateur de ce qui se passe
Me.lblSaveInformation.Caption
=
"Vérification de la disponiblité du site SharePoint..."
DoEvents
'On affecte une variable temporaire
blnSPPEnabled =
blnSharePointEnabled
'Puis l'adresse du site
strSPPAddress =
strSharePointAddress
'Si le site est activé
If
blnSPPEnabled Then
'Si le site est disponible
If
IsSharePointURLIsAvailable
(
strSPPAddress) =
False
Then
'Sinon, on lève une erreur
Err
.Raise
404
, "Site SPP injoignable"
, "L'adresse du site SharePoint :"
&
vbCrLf
&
Chr
(
171
) &
_
strSPPAddress &
Chr
(
187
) &
vbCrLf
&
"est signalé comme disponible, mais il n'est pas possible d'accéder au site..."
_
&
vbCrLf
&
vbCrLf
&
"Modifier l'état ou vérifiez l'adresse pour voir pourquoi elle n'est pas disponible."
End
If
End
If
'On défini la BDD en cours dans la variable
Set
oDB =
CurrentDb
'On construit la chaîne SQl du RecordSet
SQLSelect =
"SELECT EnvironmentID, IsInUse, ReservedToDeveloper, EnvironmentName, LinkedDatabasePath, LinkedDatabaseName, WorkingPath, DataFileFolder, "
_
&
"OutputFolder, OutputFilename, FileExtension, DateFormat, IsUSFormat, ArchiveFolder, SharePointEnabled, SharePointAddress "
SQLSelect =
SQLSelect &
"FROM tblProcessEnvironment "
SQLSelect =
SQLSelect &
"WHERE (EnvironmentID="
&
SelectedEnvironment &
") AND (ReservedToDeveloper=False);"
'On ouvre le RecordSet pour modification
Set
oRS =
oDB.OpenRecordset
(
SQLSelect, 2
)
With
oRS
.Edit
.Fields
(
"EnvironmentID"
).Value
=
lngEnvironmentId
.Fields
(
"IsInUse"
).Value
=
CInt
(
blnIsInUse)
.Fields
(
"EnvironmentName"
).Value
=
strEnvironment
.Fields
(
"LinkedDatabasePath"
).Value
=
strLinkedDatabasePath
.Fields
(
"LinkedDatabaseName"
).Value
=
strLinkedDatabaseName
.Fields
(
"WorkingPath"
).Value
=
strWorkingPath
.Fields
(
"DataFileFolder"
).Value
=
strDataFileFolder
.Fields
(
"OutputFolder"
).Value
=
strOutputFolder
.Fields
(
"OutputFilename"
).Value
=
strOutputFilename
.Fields
(
"FileExtension"
).Value
=
strFileExtension
.Fields
(
"DateFormat"
).Value
=
strDateFormat
.Fields
(
"IsUSFormat"
).Value
=
blnIsUSFormat
.Fields
(
"ArchiveFolder"
).Value
=
strArchiveFolder
.Fields
(
"SharePointEnabled"
).Value
=
blnSharePointEnabled
.Fields
(
"SharePointAddress"
).Value
=
strSharePointAddress
.Update
.Close
End
With
'On affiche le message de succès
MsgBox
"L'environnement '"
&
strEnvironment &
"' est maintenant défini comme environnement de travail et a été mis à jour avec ses caractéristiques."
, _
vbInformation
, "Changements pris en compte"
'On ferme alors le formulaire
DoCmd.Close
acForm, Me.Name
'On ferme l'objet Database
If
Not
oDB Is
Nothing
Then
oDB.Close
On
Error
GoTo
0
L_ExcmdSave_Click
:
'On libère les objets
Set
oDB =
Nothing
Set
oRS =
Nothing
'On restitue le cuirseur
DoCmd.Hourglass
False
Exit
Sub
L_ErrcmdSave_Click
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExcmdSave_Click
End
Sub
3-1-6-8. Classe du formulaire - Annulation ou sortie du formulaire▲
Si la variable m_blnDataChanged est à True, alors un message vous demande de confirmer l'annulation.
Sinon, eh bien le bouton porte la légende Fermer et la condition ne s'y prête donc pas.
Private
Sub
cmdExit_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdExit_Click
' DateTime : 11/11/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Evénement déclenché quand l'utilisateur veut fermer ou annuler
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Select
Case
cmdExit.Caption
'Si le bouton de sortie porte la légende Annuler
Case
"&Annuler"
If
m_blnDataChanged Then
If
MsgBox
(
"Vous souhaitez annuler la nouvelle entrée et fermer ?"
, _
vbQuestion
+
vbYesNo
+
vbDefaultButton2
, "Annuler"
) =
vbNo
Then
Exit
Sub
End
If
End
If
'Sinon
Case
"&Fermer"
End
Select
'On ferme le formulaire
DoCmd.Close
acForm, Me.Name
End
Sub
3-1-6-9. Classe du formulaire - Vérification et collage de l'adresse SharePoint▲
La vérification de l'adresse est opérée par le biais de la fonction ShellOpenExec() qui tente d'ouvrir la page et retourne une valeur
supérieure à 32 si c'est positif.
Le collage exploite un objet Clipboard initialisé par un DataObject via la fonction PasteWebSiteAddress qui
vérifie par la même que le presse-papier n'est pas vide...
Private
Sub
cmdCheckSPAddress_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdCheckSPAddress_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie la validité de l'adresse web
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes : ShellOpenExec retourne une valeur supérieure à 32 en cas de succès
'---------------------------------------------------------------------------
Dim
strErrorReason As
String
'Vérifie la validité de l'adresse du site ne tentant de l'ouvrir
If
ShellOpenExec
(
Me.SharePointAddress.Value
, Application.hWndAccessApp
, , , strErrorReason) <
33
Then
'Si l'erreur n'est pas interprétée mais qu'il y a une erreur (donc < à 33)
If
Len
(
strErrorReason) =
0
Then
strErrorReason =
"The page '"
&
Me.SharePointAddress.Value
&
"'"
&
vbCrLf
&
"is not pointing to a valid address."
End
If
'On affiche le message
MsgBox
strErrorReason, vbExclamation
, "Impossible d'ouvrir la page"
End
If
End
Sub
Private
Sub
cmdPasteSPAddress_Click
(
)
'---------------------------------------------------------------------------
' Procedure : cmdPasteSPAddress_Click
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de coller une adresse pour le site SharePoint
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
PasteWebSiteAddress "SharePointAddress"
, "l'adresse du site SharePoint"
End
Sub
3-1-6-10. Classe du formulaire - Événements KeyPress sur les contrôles Textboxes▲
Les événements KeyPress sont exploités dans les contrôles Textbox pour empêcher la frappe de caractères interdits pour définir un nom de dossier ou une URL selon le cas.
Private
Sub
txtArchiveFolder_KeyPress
(
KeyAscii As
Integer
)
'---------------------------------------------------------------------------
' Procedure : txtArchiveFolder_KeyPress
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Interdit ou autorise la frappe de certains caractères
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
KeyAscii =
basApplication.CheckFolderName
(
KeyAscii)
End
Sub
Private
Sub
txtOutputFolder_KeyPress
(
KeyAscii As
Integer
)
'---------------------------------------------------------------------------
' Procedure : txtOutputFolder_KeyPress
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Interdit ou autorise la frappe de certains caractères
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
KeyAscii =
basApplication.CheckFolderName
(
KeyAscii)
End
Sub
Private
Sub
txtSharePointAddress_KeyPress
(
KeyAscii As
Integer
)
'---------------------------------------------------------------------------
' Procedure : txtSharePointAddress_KeyPress
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Interdit ou autorise la frappe de certains caractères
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
KeyAscii =
basApplication.CheckFolderName
(
KeyAscii, True
)
End
Sub
3-1-6-11. Classe du formulaire - Événements Change sur les contrôles Textboxes▲
Les événements Change sur les contrôles Textboxes permettent d'affecter l'état de la variable m_blnDataChanged pour déterminer le fait qu'un changement a été opéré.
Ce choix et cette façon de faire est plus fiable que la propriété Dirty pour ma part.
Private
Sub
txtArchiveFolder_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtArchiveFolder_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtDataFileFolder_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtDataFileFolder_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtDateFormat_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtDateFormat_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtLinkedDatabaseName_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtLinkedDatabaseName_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtLinkedDatabasePath_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtLinkedDatabasePath_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtOutputFilename_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtOutputFilename_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtOutputFolder_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtOutputFolder_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtSharePointAddress_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtSharePointAddress_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
Private
Sub
txtWorkingPath_Change
(
)
'---------------------------------------------------------------------------
' Procedure : txtWorkingPath_Change
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Change le statut du flag m_blnDataChanged puisque changement effectué dans la zone texte
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Affecte le flag de changement dans le formulaire
m_blnDataChanged =
True
End
Sub
3-1-6-12. Classe du formulaire - Procédures et Fonction privées de la classe▲
La classe du formulaire possède ses fonctions et procédures privées qui lui sont propres dans le sens où elles n'ont pas lieues d'être
partagées ; elles ne sollicitent que les contrôles de ce formulaires et affectent que les données de ce formulaire.
Vous pouvez dénombrer sept de ces fonctions et procédures :
- InitializeControls
- DisableAllEnvironments
- EnableThisEnvironment
- GetFolderForThisField
- GetRecordSource
- NewDataCompleted
- PasteWebSiteAddress
Vous retrouvez le rôle de ces dernières en cliquant ici.
Private
Sub
InitializeControls
(
)
'---------------------------------------------------------------------------
' Procedure : InitializeControls
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Intialise les contrôles
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
'Donne le focus au bouton de fermeture
Me.cmdExit.SetFocus
'Met en gras l'étiquette de l'adresse SharePoint si la case est cochée
Me.lblSharePointEnabled.FontBold
=
Me.chkSharePointEnabled
'L'étiquette des information de sauvegarde est vidée
Me.lblSaveInformation.Caption
=
vbNullString
'Active le bouton de vérification de l'adresse si la case à cocher est cochée
Me.cmdCheckSPAddress.Enabled
=
Nz
(
Me.chkSharePointEnabled.Value
, False
)
End
Sub
Private
Sub
DisableAllEnvironments
(
)
'---------------------------------------------------------------------------
' Procedure : DisableAllEnvironments
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Désactive tous les environnements
'...........................................................................
' Parameters : None
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
SQLUpdate As
String
On
Error
GoTo
L_ErrDisableAllEnvironments
SQLUpdate =
"UPDATE tblProcessEnvironment SET IsInUse = False;"
'Exécution du script SQL avec gestion d'erreur
CurrentDb.Execute
SQLUpdate, dbFailOnError
On
Error
GoTo
0
L_ExDisableAllEnvironments
:
Exit
Sub
L_ErrDisableAllEnvironments
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExDisableAllEnvironments
End
Sub
Private
Sub
EnableThisEnvironment
(
ByVal
CurEnvironment As
Long
)
'---------------------------------------------------------------------------
' Procedure : EnableThisEnvironment
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Active cet environnment comme environnement par défaut
'...........................................................................
' Parameters : CurEnvironment = ID de l'environnment en cours
' Return Codes : = True if so success
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
SQLUpdate As
String
On
Error
GoTo
L_ErrDisableAllEnvironments
SQLUpdate =
"UPDATE tblProcessEnvironment SET IsInUse = True "
SQLUpdate =
SQLUpdate &
"WHERE (EnvironmentID="
&
CurEnvironment &
") AND (ReservedToDeveloper=False);"
'Exécution du script SQL avec gestion d'erreur
CurrentDb.Execute
SQLUpdate, dbFailOnError
On
Error
GoTo
0
L_ExDisableAllEnvironments
:
Exit
Sub
L_ErrDisableAllEnvironments
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExDisableAllEnvironments
End
Sub
Private
Function
GetFolderForThisField
(
ByVal
Title As
String
, ByVal
CurrentFolder As
String
, ByRef
HasChanged As
Boolean
) As
String
'---------------------------------------------------------------------------
' Procedure : GetFolderForThisField
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Retourne le dossier sélectionné après vérification de la conformité
'...........................................................................
' Parameters : Title = Titre du dialogue
' CurrentFolder = Dossier source
' HasChanged = True si nouveau dossier
' SelectFolderOnly = True si l'on ouvre le dialogue des dossiers
' ReturnFullPath = True si l'on retourne le chemin complet
'
' Return Codes : String = True if so success
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strNewFieldFolder As
String
Dim
strNewFieldPath As
String
Dim
strStartDirectory As
String
On
Error
GoTo
L_ErrGetFolderForThisField
'Le paramètre est false car aucun dossier n'est encore sélectionné
HasChanged =
False
'On effecte le dossier de départ
strStartDirectory =
GetPathName
(
GetLinkedDatabasePath
(
CurrentDb, TBL_USERS, False
), False
)
'L'utilisateur sélectionne un dossier
strNewFieldPath =
SelectAnyFolder
(
"Sélectionner le dossier"
, strStartDirectory)
'Si un dossier a été effectivement sélectionné
If
Len
(
strNewFieldPath) Then
'On compare les dossier
If
StrComp
(
CurrentFolder, strNewFieldPath, 1
) =
0
Then
'Et on lève une erreur s'ils sont identiques
Err
.Raise
58
, "Dossier identique"
, "Le dossier que vous avez sélectionné est le même que celui en cours !"
End
If
'On éclate le chemin pour obtenir le dossier (qui sera un enfant du chemin de travail)
strNewFieldFolder =
Mid
$(
strNewFieldPath, InStrRev
(
strNewFieldPath, "\"
) +
1
)
'Le flage est a True car il y a eut changement
HasChanged =
True
Else
'Sinon, le doissier est conservé tel que
strNewFieldFolder =
CurrentFolder
End
If
On
Error
GoTo
0
L_ExGetFolderForThisField
:
'La fonction retourne le nom du dossier
GetFolderForThisField =
strNewFieldFolder
Exit
Function
L_ErrGetFolderForThisField
:
strNewFieldFolder =
CurrentFolder
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExGetFolderForThisField
End
Function
Private
Function
GetRecordSource
(
ByVal
FormLoaded As
Boolean
, ByVal
EnvironmentSelected As
Long
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : GetRecordSource
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet d'obtenir l'environnment en cours définit dans la table
'...........................................................................
' Parameters : FormLoaded = True sur le formulaire est chargé auquel cas, la condition where s'adapte
' EnvironmentSelected = ID de l'environnement en cours
'
' Return Codes : Boolean = True if so success
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
SQLSelect As
String
Dim
oDB As
DAO.Database
Dim
oRS As
DAO.Recordset
Dim
strErrorMissingParameter As
String
On
Error
GoTo
L_ErrGetRecordSource
'On construit la chaîne SQL pour remplir le formulaire
SQLSelect =
"SELECT EnvironmentID, IsInUse, ReservedToDeveloper, EnvironmentName, LinkedDatabasePath, LinkedDatabaseName, WorkingPath, DataFileFolder, "
_
&
"OutputFolder, OutputFilename, FileExtension, DateFormat, IsUSFormat, ArchiveFolder, SharePointEnabled, SharePointAddress "
SQLSelect =
SQLSelect &
"FROM tblProcessEnvironment "
'Si le paramètre FormLoaded est True
If
FormLoaded Then
'On prend l'environnment actif
SQLSelect =
SQLSelect &
"WHERE (IsInUse=True) AND (ReservedToDeveloper=False);"
Else
'Sinon, on prend l'environnement choisi
SQLSelect =
SQLSelect &
"WHERE (EnvironmentID="
&
EnvironmentSelected &
") AND (ReservedToDeveloper=False);"
End
If
'On initialise l'objet Database
Set
oDB =
CurrentDb
'On ouvre le RecordSet
Set
oRS =
oDB.OpenRecordset
(
SQLSelect, 2
)
'Et on rempli les contrôles
With
oRS
Me.EnvironmentID.Value
=
.Fields
(
"EnvironmentID"
).Value
Me.IsInUse.Value
=
Nz
(
.Fields
(
"IsInUse"
).Value
, False
)
Me.EnvironmentName.Value
=
.Fields
(
"EnvironmentName"
).Value
Me.cboCurEnvironment
=
.Fields
(
"EnvironmentID"
).Value
Me.txtLinkedDatabaseName
=
Nz
(
.Fields
(
"LinkedDatabasePath"
).Value
, vbNullString
)
Me.txtLinkedDatabaseName
=
Nz
(
.Fields
(
"LinkedDatabaseName"
).Value
, vbNullString
)
Me.txtWorkingPath
=
.Fields
(
"WorkingPath"
).Value
Me.txtDataFileFolder
=
Nz
(
.Fields
(
"DataFileFolder"
).Value
, vbNullString
)
Me.txtOutputFolder
=
Nz
(
.Fields
(
"OutputFolder"
).Value
, vbNullString
)
Me.txtOutputFilename
=
Nz
(
.Fields
(
"OutputFilename"
).Value
, vbNullString
)
Me.txtFileExtension
=
Nz
(
.Fields
(
"FileExtension"
).Value
, "xls"
)
Me.txtDateFormat
=
Nz
(
.Fields
(
"DateFormat"
).Value
, "yyyymmdd"
)
Me.chkIsUSFormat
=
Nz
(
.Fields
(
"IsUSFormat"
).Value
, False
)
Me.txtArchiveFolder
=
Nz
(
.Fields
(
"ArchiveFolder"
).Value
, vbNullString
)
Me.txtSharePointAddress
=
.Fields
(
"SharePointAddress"
).Value
Me.chkSharePointEnabled
=
Nz
(
.Fields
(
"SharePointEnabled"
).Value
, False
)
.Close
End
With
'On affecte les propriétés pour parer aux erreur autour d'un changement d'environnement mal opéré
If
FormLoaded Then
CurrentEnvironment =
Me.EnvironmentID
SelectedEnvironment =
CurrentEnvironment
End
If
'On affecte la liste déroulante
Me!cboCurEnvironment =
SelectedEnvironment
'On change le titre
Me.lblData.Caption
=
"Les paramètres de l'environnement "
&
Me.cboCurEnvironment.Column
(
1
) &
" :"
'La fonction est un succès
GetRecordSource =
True
On
Error
GoTo
0
If
Not
oDB Is
Nothing
Then
oDB.Close
L_ExGetRecordSource
:
Set
oRS =
Nothing
Set
oDB =
Nothing
Exit
Function
L_ErrGetRecordSource
:
'La fonction est un échec
GetRecordSource =
False
Resume
L_ExGetRecordSource
End
Function
Private
Function
NewDataCompleted
(
ByRef
MissedField As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : NewDataCompleted
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie que toutes les données sont correctement saisies
'...........................................................................
' Parameters : MissedField = Nom ou rubrique de la donnée incorrecte
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
blnAllIsOK As
Boolean
Dim
blnIsInUse As
Boolean
Dim
lngEnvironmentId As
Long
Dim
strEnvironment As
String
Dim
strSharePointAddress As
String
Dim
strLinkedDatabasePath As
String
Dim
strLinkedDatabaseName As
String
Dim
strWorkingPath As
String
Dim
strDataFileFolder As
String
Dim
strArchiveFolder As
String
Dim
strOutputFilename As
String
Dim
strDateFormat As
String
Dim
strFileExtension As
String
Dim
strOutputFolder As
String
Dim
blnSharePointEnabled As
Boolean
Dim
blnIsUSFormat As
Boolean
'On initialise toutes les variables en fonction du contenu des contrôles (via Nz pour éviter l'erreur 94)
lngEnvironmentId =
Nz
(
Me.EnvironmentID
, vbNullString
)
strEnvironment =
Nz
(
Me.Environment
, vbNullString
)
strLinkedDatabasePath =
Nz
(
Me.txtLinkedDatabasePath
, vbNullString
)
strLinkedDatabaseName =
Nz
(
Me.txtLinkedDatabaseName
, vbNullString
)
strWorkingPath =
Nz
(
Me.txtWorkingPath
, vbNullString
)
strDataFileFolder =
Nz
(
Me.txtDataFileFolder
, vbNullString
)
strOutputFilename =
Nz
(
Me.txtOutputFilename
, vbNullString
)
strFileExtension =
Nz
(
Me.txtFileExtension
, vbNullString
)
strDateFormat =
Nz
(
Me.txtDateFormat
, vbNullString
)
strSharePointAddress =
Nz
(
Me.txtSharePointAddress
, vbNullString
)
strArchiveFolder =
Nz
(
Me.txtArchiveFolder
, vbNullString
)
strOutputFolder =
Nz
(
Me.txtOutputFolder
, vbNullString
)
blnSharePointEnabled =
Nz
(
Me.chkSharePointEnabled.Value
, False
)
blnIsUSFormat =
Nz
(
Me.chkIsUSFormat.Value
, False
)
On
Error
GoTo
L_ErrNewDataCompleted
'On vérifuie une à une chaque variable
'Si une donnée manque, on lève l'erreur et la fonction retourne False
blnAllIsOK =
False
If
Len
(
strLinkedDatabasePath) >
7
Then
If
Len
(
strLinkedDatabaseName) >=
7
Then
If
Len
(
strWorkingPath) >=
7
Then
If
Len
(
strDataFileFolder) >=
2
Then
If
Len
(
strOutputFilename) >=
2
Then
If
Len
(
strFileExtension) >=
3
Then
If
Len
(
strDateFormat) >=
8
Then
If
Len
(
strArchiveFolder) >=
2
Then
If
blnSharePointEnabled Then
If
Len
(
strSharePointAddress) >=
16
Then
Else
MissedField =
"Adresse SharePoint"
Me.txtSharePointAddress.SetFocus
: txtSharePointAddress.SelLength
=
Len
(
strSharePointAddress)
Err
.Raise
94
End
If
End
If
Else
MissedField =
"Dossier d'archives"
Me.txtArchiveFolder.SetFocus
: txtArchiveFolder.SelLength
=
Len
(
strArchiveFolder)
Err
.Raise
94
End
If
Else
MissedField =
"Format de la date"
Me.txtDateFormat.SetFocus
: txtDateFormat.SelLength
=
Len
(
strDateFormat)
Err
.Raise
94
End
If
Else
MissedField =
"Extension du fichier de sortie"
Me.txtFileExtension.SetFocus
: txtFileExtension.SelLength
=
Len
(
strFileExtension)
Err
.Raise
94
End
If
Else
MissedField =
"Nom du fichier de sortie"
Me.txtOutputFilename.SetFocus
: txtOutputFilename.SelLength
=
Len
(
strOutputFilename)
Err
.Raise
94
End
If
Else
MissedField =
"Dossier des fichiers sources"
Me.txtDataFileFolder.SetFocus
: txtDataFileFolder.SelLength
=
Len
(
strDataFileFolder)
Err
.Raise
94
End
If
Else
MissedField =
"Dossier de travail"
Me.txtWorkingPath.SetFocus
: txtWorkingPath.SelLength
=
Len
(
strWorkingPath)
Err
.Raise
94
End
If
Else
MissedField =
"Nom de la base de données"
Me.txtLinkedDatabaseName.SetFocus
: txtLinkedDatabaseName.SelLength
=
Len
(
strLinkedDatabaseName)
Err
.Raise
94
End
If
Else
MissedField =
"Chemin de la base de données"
Me.txtLinkedDatabasePath.SetFocus
: txtLinkedDatabasePath.SelLength
=
Len
(
strLinkedDatabasePath)
Err
.Raise
94
End
If
'Si le site est activé
If
blnSharePointEnabled Then
'On vérifie la validité de l'URL
If
URLIsValid
(
strSharePointAddress) =
False
Then
'Si elle est invalide... on lève une erreur
MissedField =
"Adresse SharePoint"
Me.txtSharePointAddress.SetFocus
: txtSharePointAddress.SelLength
=
Len
(
strSharePointAddress)
Err
.Raise
94
End
If
End
If
blnAllIsOK =
True
On
Error
GoTo
0
L_ExNewDataCompleted
:
NewDataCompleted =
blnAllIsOK
Exit
Function
L_ErrNewDataCompleted
:
blnAllIsOK =
False
Resume
L_ExNewDataCompleted
End
Function
Private
Sub
PasteWebSiteAddress
(
ByVal
TargetTextbox As
String
, ByVal
ItemSubject As
String
)
'---------------------------------------------------------------------------
' Procedure : PasteWebSiteAddress
' DateTime : 11/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Colle l'adresse copié dans le presse-papier
'...........................................................................
' Parameters : TargetTextbox = Zone de texte cible
' ItemSubject = Message d'information sur l'opération
'
' Return Codes : None
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strWebAddress As
String
Dim
oCTL As
Control
On
Error
GoTo
L_ErrPastWebSiteAddress
'Si le presse-papier contient des données
If
GetClipboardData
(
strWebAddress) =
False
Then
'Sinon on lève une erreur
Err
.Raise
13
, "Données invalides"
, "Aucune donnée n'est disponible actuellement dans le Presse-Papier..."
&
vbCrLf
&
_
"Assurez-vous que vous avez sélectionné un lien qui représente l'adresse du site Web SharePoint cible, puis, recommencez..."
End
If
'Si l'adresse est valide
If
URLIsValid
(
strWebAddress) =
False
Then
'Sinon on lève une erreur
Err
.Raise
13
, "Adresse HTTP"
, ItemSubject &
" que vous essayez de coller dans la zone de texte cible n'est pas valide !"
End
If
'On affecte le contrôle (cas de plusieurs zones d'adresse SharePoint)
Set
oCTL =
Me.Controls
(
TargetTextbox)
'Le contrôle reçoit l'adresse collée
oCTL.Value
=
strWebAddress
On
Error
GoTo
0
L_ExPastWebSiteAddress
:
'On libère l'objet
Set
oCTL =
Nothing
Exit
Sub
L_ErrPastWebSiteAddress
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExPastWebSiteAddress
End
Sub
Explications du déroulement
Le code est commenté ligne par ligne pour une meilleure compréhension ; il est recommandé de bien lire chacune des instructions pour
assimiler la philosophie adpotée ici...
Le déroulement reste simple puisqu'il s'axe sur le contenu des champs Textbox pour remplir ou mettre à jour la Table source.
Selon la (seule) valeur possible de la colonne IsInUse, si la table est intégralement remplie, le contenu des champs
alimente les contrôles Textbox en fonction de l'environnement choisi et donc l'enregistrement où la valeur du champ IsInUse
est True.
Il faut donc choisir l'environnement souhaité pour en changer. Tout remplissage (cas d'une zone de texte vide) ou modification
affecte la valeur de la variable de module m_blnDataChanged qui prend la valeur True.
L'événement Timer du formulaire faire clignoter le contrôle Rectangle (Shape) selon
la temporisation et indique que l'environnement est actif. L'état de la variable m_blnDataChanged active ou désactive
alors le bouton de sauvegarde selon le cas.
Vous-même ou l'utilisateur en charge de l'administration de la base de données peut alors remplir ou mettre à jour alors les éléments constitutifs
pour chacun des environnements.
Selon l'environnement choisi, l'ensemble des tables liées de la base de données dorsale spécifiée est réattaché
dynamiquement à l'application.
L'ensemble du code du projet, si peu que vous ayez adapté les fonctions et procédures du projet selon l'environnement, s'exécutera
en conséquence...
Normalement et en dehors des deux chemins de la base de données dorsale et de travail et l'eventuelle adresse SharePoint,
tous les dossiers doivent porter le même nom ; d'une part c'est plus souple et d'autre par c'est plus simple à définir.
Il n'est pas recommandé de définir des noms de dossier avec un suffixe Test ou UAT ou Prod car cela vous
sortirait du contexte de la réalité. Mais si vous pensez que c'est mieux de procéder ainsi, pourquoi pas.
3-1-7. Les modules externes complémentaires▲
Certaines fonctions et procédures du formulaire font appel à des fonctions qui ne font pas partie intégrante de son module de classe
en cours de réalisation. Et pour cause, ces fonctions sont considérées comme publiques et donc partagées.
Elles peuvent très bien, pour certaines d'entre-elles, avoir déjà été developpées au sein de votre projet...
Si tel était le cas, il est fort probable que vous ayez des adapations à mettre en oeuvre.
N'importe comment, dans un premier temps, créez le module et l'ensemble des fonctions qui l'accompagnent et vous verrez par
la suite comment vous organiser pour fusionner les éventuelles fonctions qui remplissent le même rôle si vous avez des fonctions
en double.
Vous ajouterez donc un module dédié au sein de votre projet ou bien dans un nouveau projet selon la situation...
Vous y écrirez l'ensemble des fonctions stipulées ci-après.
L'en-tête comporte des déclarations d'API utiles aux fonctions principalement orientées à l'accès aux fichiers et aux dossiers
du système. La structure OPENFILENAME est attachée à le fonction dédiée à la sélection d'un fichier. Les deux constantes sont pour l'une
la valeur flag définissant si l'environnement est réservé au développeur et pour l'autre la requête SQL permettant de sélectionner
l'environnement actif...
'**********************************************************************
' Module : basApplication
' Type : Module
' DateTime : 28/11/2012
' Author : Jean-Philippe AMBROSINO
' Review : Jean-Philippe AMBROSINO
' Purpose : Module used to share functions between modules
'
''**********************************************************************
Option
Compare Database
Option
Explicit
'Constante de mode d'ouverture pour ShellExecute
Private
Const
SW_SHOWNORMAL As
Integer
=
1
'API permettant d'exécuter différentes opérations selon lpOperation
Private
Declare
Function
ShellExecute Lib
"shell32.dll"
Alias "ShellExecuteA"
(
ByVal
HWnd As
Long
, ByVal
lpOperation As
String
, ByVal
lpFile As
String
, ByVal
lpParameters As
String
, ByVal
lpDirectory As
String
, ByVal
nShowCmd As
Long
) As
Long
'API permettant d'interrompre le temps en millisecondes
Public
Declare
Sub
Sleep Lib
"kernel32"
(
ByVal
dwMilliseconds As
Long
)
'API permettant de greffer un \ sur un chemin
Private
Declare
Function
PathAddBackslash Lib
"shlwapi.dll"
Alias "PathAddBackslashA"
(
ByVal
pszPath As
String
) As
Long
'API peremttant de vérifier qu'un chemin est une URL
Private
Declare
Function
PathIsURL Lib
"shlwapi.dll"
Alias "PathIsURLA"
(
ByVal
pszPath As
String
) As
Long
'API permettant d'ouvrir la boîte de dialogue des fichiers
Private
Declare
Function
GetOpenFileName Lib
"comdlg32.dll"
Alias "GetOpenFileNameA"
(
pOpenfilename As
OPENFILENAME) As
Long
'Structure OpenFileName
Private
Type
OPENFILENAME
lStructSize As
Long
hwndOwner As
Long
hInstance As
Long
lpstrFilter As
String
lpstrCustomFilter As
String
nMaxCustFilter As
Long
nFilterIndex As
Long
lpstrFile As
String
nMaxFile As
Long
lpstrFileTitle As
String
nMaxFileTitle As
Long
lpstrInitialDir As
String
lpstrTitle As
String
flags As
Long
nFileOffset As
Integer
nFileExtension As
Integer
lpstrDefExt As
String
lCustData As
Long
lpfnHook As
Long
lpTemplateName As
String
End
Type
'Enumération des 3 environnements possibles
Public
Enum g_eEnvironment
EnvironmentTest =
1
EnvironmentUAT =
2
EnvironmentProd =
3
End
Enum
'Constante définissant si l'environnement est réservé au développeur pour ses tests
Public
Const
RESERVED_TO_DEVELOPER As
Boolean
=
True
'Requête par défaut de la sélection de l'environnement actif
Private
Const
SQL_ENV As
String
=
"SELECT EnvironmentID FROM tblProcessEnvironment WHERE IsInUse = True AND ReservedToDeveloper = "
&
RESERVED_TO_DEVELOPER &
";"
La fonction GetCurrentEnvironment() permet de retourner l'ID de l'environnement actif.
Elle s'exécute en fonction de la requête définie en constante.
Public
Function
GetCurrentEnvironment
(
) As
g_eEnvironment
'---------------------------------------------------------------------------
' Procedure : GetCurrentEnvironment
' DateTime : 01/11/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Retourne l'environnement actif
'...........................................................................
' Parameters : None
' Return Codes : g_eEnvironment
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
oRS As
DAO.Recordset
On
Error
GoTo
L_ErrGetCurrentEnvironment
Set
oRS =
CurrentDb.OpenRecordset
(
SQL_ENV, dbOpenSnapshot)
With
oRS
If
Not
oRS.EOF
Then
GetCurrentEnvironment =
Nz
(
.Fields
(
0
).Value
, 0
)
End
If
.Close
End
With
On
Error
GoTo
0
L_ExGetCurrentEnvironment
:
Set
oRS =
Nothing
Exit
Function
L_ErrGetCurrentEnvironment
:
GetCurrentEnvironment =
0
Resume
L_ExGetCurrentEnvironment
End
Function
La fonction GetPathName() extrait le chemin d'accès d'un chemin complet.
Function
GetPathName
(
ByVal
FullPath As
String
, ByVal
KeepBackSlash As
Boolean
) As
String
'---------------------------------------------------------------------------
' Procedure : GetPathName
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Chemin extrait d'un chemin complet
'...........................................................................
' Parameters : FullPath = Chemin complet
' KeepBackSlash = True si on conserve le \
' Return Codes : String = Pathname
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
GetPathName =
Left
$(
FullPath, InStrRev
(
FullPath, "\"
) -
IIf
(
KeepBackSlash, 0
, 1
))
End
Function
La fonction GetFileName() extrait le nom du fichier d'un chemin complet.
Function
GetFileName
(
ByVal
FullFile As
String
) As
String
'---------------------------------------------------------------------------
' Procedure : GetFileName
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Fichier extrait d'un chemin complet
'...........................................................................
' Parameters : FullFile = Chemin complet
' Return Codes : String = Filename
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
GetFileName =
Mid
$(
FullFile, InStrRev
(
FullFile, "\"
) +
1
)
End
Function
La fonction AddDirSeparator() permet d'ajouter un séparateur de chemin s'il n'y en a pas.
Function
AddDirSeparator
(
ByVal
TargetPath As
String
) As
String
'---------------------------------------------------------------------------
' Procedure : AddDirSeparator
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Ajoute un \ au chemin
'...........................................................................
' Parameters : TargetPath = chein visé
' Return Codes : String = TargetPath\
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strPath As
String
strPath =
TargetPath &
vbNullChar
PathAddBackslash strPath
AddDirSeparator =
StripTerminator
(
strPath)
End
Function
La fonction StripTerminator() permet de supprimer la partie droite d'une chaîne où se trouvent des caractères 0
soit via la valeur Chr(0) ou via la constante vbNullChar souvent présents en fin de chaîne retournée par les API
comme justement la fonction GetOpenFileName().
Function
StripTerminator
(
ByVal
InputString As
String
) As
String
'---------------------------------------------------------------------------
' Procedure : StripTerminator
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Supprime le Chr(0) de la chaîne InputString
'...........................................................................
' Parameters : InputString = valeur concerné
' Return Codes : String = InputString
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
ZeroPos As
Long
ZeroPos =
InStr
(
1
, InputString, vbNullChar
, 0
)
If
ZeroPos >
0
Then
StripTerminator =
Left
$(
InputString, ZeroPos -
1
)
Else
StripTerminator =
InputString
End
If
End
Function
Le fonction GetLinkedDatabasePath() permet de renvoyer le chemin de la base de données dorsale en s'appuyant sur
le chaîne retournée par la propriété Connect d'une table liée.
Public
Function
GetLinkedDatabasePath
(
ByRef
DB As
DAO.Database
, ByVal
LinkedTableName As
String
, ByVal
WithBackSlash As
Boolean
) As
String
'---------------------------------------------------------------------------
' Procedure : GetLinkedDatabasePath
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Renvoie le chemin de la BDD dorsale
'...........................................................................
' Parameters : DB = Objet Database
' LinkedTableName = Nom de la table liée
' WithBackSlash = True si on conserve le \
' Return Codes : String = Chemin de la BDD avec ou sans \
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
strDBPath As
String
strDBPath =
Mid
$(
DB.TableDefs
(
LinkedTableName).Connect
, 11
)
strDBPath =
Mid
$(
strDBPath, InStrRev
(
strDBPath, " = "
) +
1
)
GetLinkedDatabasePath =
Left
$(
strDBPath, InStrRev
(
strDBPath, "\"
) -
IIf
(
WithBackSlash, 0
, 1
))
End
Function
La fonction ShellOpenExec() exploite l'API ShellExecute() pour effectuer une opération sur des fichiers
qu'il soient exécutables ou document.
On utilise cette fonction pour :
- soit ouvrir un document via l'exécutable correspondant identifié :
. par l'association du fichier ;
. par l'usage de l'API FindExecutable() ;
- soit imprimer un fichier ;
- soit ouvrir une page WEB.
Public
Function
ShellOpenExec
(
ByVal
ApplicationPath As
String
, Optional
ByVal
_
HWnd As
Long
=
0
, Optional
ByVal
Parameters As
String
=
vbNullString
, Optional
_
ByVal
Operation As
String
=
"open"
, Optional
ByRef
ShellError As
String
) As
Long
'---------------------------------------------------------------------------
' Procedure : ShellOpenExec
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Effectue une execution sur fichier selon l'opération souhaité
'...........................................................................
' Parameters : ApplicationPath = Fichier ou Dossier
' HWnd = Handle de l'application cible
' Parameters = Paramètres passés
' Operation = Quelle opération à effectuer
' ShellError = Message retourné si erreur
' Return Codes : Long > 32 si succès
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
Dim
lngReturn As
Long
On
Error
GoTo
L_ErrShellOpenExec
lngReturn =
ShellExecute
(
HWnd, Operation, ApplicationPath, Parameters, "C:\"
, SW_SHOWNORMAL)
On
Error
GoTo
0
L_ExShellOpenExec
:
Exit
Function
L_ErrShellOpenExec
:
ShellError =
"("
&
Err
.Number
&
")"
&
Err
.Description
Resume
L_ExShellOpenExec
End
Function
La fonction CheckFolderName() permet de retourner la valeur ASCII passée en paramètre à la procédure événementielle
KeyPress() appelante et retourne zéro (0) si elle ne correspond pas à la plage que j'ai définie dans le Select Case.
Elle exclut en résumé tous les caractères interdits et notamment les caractères spéciaux.
Public
Function
CheckFolderName
(
ByVal
KeyAscii As
Integer
, Optional
ByVal
IsURL As
Boolean
=
False
) As
Integer
'---------------------------------------------------------------------------
' Procedure : CheckFolderName
' DateTime : 10/10/2010
' Author : Jean-Philippe AMBROSINO
' Purpose : Retourne le carctère autorisé lors de la saisie d'un chemin ou d'une adresse
'...........................................................................
' Parameters : KeyAscii = ASCII Char
' IsURL = Vrai pour contrôler les URL
' Return Codes : Integer > 0 si succès
'...........................................................................
' Notes :
'---------------------------------------------------------------------------
If
IsURL Then
Select
Case
KeyAscii
Case
8
, 32
, 45
To
58
, 65
To
90
, 95
, 97
To
122
: CheckFolderName =
KeyAscii
Case
Else
: Beep: CheckFolderName =
0
End
Select
Else
Select
Case
KeyAscii
Case
8
, 32
, 45
, 48
To
57
, 65
To
90
, 95
, 97
To
122
: CheckFolderName =
KeyAscii
Case
Else
: Beep: CheckFolderName =
0
End
Select
End
If
End
Function
La fonction SelectAnyFile() exploite l'API GetOpenFileName() pour pouvoir sélectionner un fichier à partir de la boîte
de dialogue commune Ouvrir.
La fonction aboutie si un fichier est sélectionné et la chaîne en retour représente le chemin complet du fichier ; cette dernière
se voit traversée par la fonction StripTerminator() vue plus haut.
Public
Function
SelectAnyFile
(
ByVal
HWnd As
Long
, Optional
Title As
String
, Optional
StartFolderOrDrive As
String
) As
String
'---------------------------------------------------------------------------
' Procedure : SelectAnyFile
' DateTime : 28/11/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Returns
'...........................................................................
' Parameters : HWnd = handle de l'appelant
' Title = Titre de la fenêtre
' StartFolderOrDrive = Dossier de démarrage
' Return Codes : String = Nom complet du fichier
'...........................................................................
' Notes : Appelle GetOpenFilename()
'---------------------------------------------------------------------------
Const
FILE_FILTER As
String
=
"Base de données Microsoft Access (2007)"
&
vbNullChar
&
"*.accdb"
&
vbNullChar
_
&
"Base de données Microsoft Access (2003)"
&
vbNullChar
&
"*.mdb"
&
vbNullChar
Dim
tyOFN As
OPENFILENAME
With
tyOFN
.lStructSize
=
Len
(
tyOFN)
.hwndOwner
=
HWnd
.hInstance
=
Application.hWndAccessApp
.lpstrFilter
=
FILE_FILTER
.lpstrFile
=
Space
$(
254
)
.nMaxFile
=
255
.lpstrFileTitle
=
Space
$(
254
)
.nMaxFileTitle
=
255
.lpstrInitialDir
=
StartFolderOrDrive
.lpstrTitle
=
Title
.flags
=
0
If
GetOpenFileName
(
tyOFN) Then
SelectAnyFile =
StripTerminator
(
.lpstrFile
)
End
If
End
With
End
Function
La fonction SelectAnyFolder() exploite l'API Shell32() pour pouvoir sélectionner un dossier à partir d'une boîte
de dialogue.
Public
Function
SelectAnyFolder
(
Optional
Title As
String
, Optional
StartFolderOrDrive As
String
) As
String
'---------------------------------------------------------------------------
' Procedure : SelectAnyFolder
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de sélectionner un dossier
'...........................................................................
' Parameters : Title = Titre de la fenêtre
' StartFolderOrDrive = Dossier de départ : par défaut 'Ordinateur' ou 'My computer'
'
' Return Codes : String = Dossier sélectionné
'...........................................................................
' Notes : Faire référence à Microsoft Shell Controls And Automation
' Plusieurs autre solutions existent : BrowseForFolder, MSO Dialog,...etc.
' Shell32 options : 1 dossiers seuls ; 16384 dossiers et fichiers
'---------------------------------------------------------------------------
Dim
oShell As
Shell32.Shell
Dim
oFolder As
Shell32.Folder
On
Error
GoTo
L_ErrSelectAnyFolder
Set
oShell =
New
Shell32.Shell
Set
oFolder =
oShell.BrowseForFolder
(
0
, Title, 1
, StartFolderOrDrive)
If
Not
oFolder Is
Nothing
Then
SelectAnyFolder =
oFolder.Items.Item.Path
End
If
Set
oFolder =
Nothing
Set
oShell =
Nothing
On
Error
GoTo
0
L_ExSelectAnyFolder
:
Exit
Function
L_ErrSelectAnyFolder
:
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
Resume
L_ExSelectAnyFolder
End
Function
La fonction ThisFolderExists() permet de vérifier via un FileSystemObject l'existence d'un dossier.
Public
Function
ThisFolderExists
(
ByVal
FolderName As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : ThisFolderExists
' DateTime : 24/06/2007
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie l'existence d'un dossier
'...........................................................................
' Parameters : FolderName = Nom du dossier à vérifier
' Return Codes : Boolean = True si succès
'...........................................................................
' Notes : Faire référence à scrrun.dll
'---------------------------------------------------------------------------
Dim
oFSO As
Scripting.FileSystemObject
On
Error
GoTo
ThisFolderExists_Error
Set
oFSO =
New
Scripting.FileSystemObject
ThisFolderExists =
(
oFSO.FolderExists
(
FolderName))
On
Error
GoTo
0
ThisFolderExists_Exit
:
Set
oFSO =
Nothing
Exit
Function
ThisFolderExists_Error
:
ThisFolderExists =
False
Resume
ThisFolderExists_Exit
End
Function
La fonction ThisFileExists() permet de vérifier via un FileSystemObject l'existence d'un fichier.
Public
Function
ThisFileExists
(
ByVal
FileName As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : ThisFileExists
' DateTime : 24/06/2007
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie l'existence d'un fichier
'...........................................................................
' Parameters : FileName = Nom du fichier à vérifier
' Return Codes : Boolean = True si succès
'...........................................................................
' Notes : Faire référence à scrrun.dll
'---------------------------------------------------------------------------
Dim
oFSO As
Scripting.FileSystemObject
On
Error
GoTo
ThisFileExists_Error
Set
oFSO =
New
Scripting.FileSystemObject
ThisFileExists =
(
oFSO.FileExists
(
FileName))
On
Error
GoTo
0
ThisFileExists_Exit
:
Set
oFSO =
Nothing
Exit
Function
ThisFileExists_Error
:
ThisFileExists =
False
Resume
ThisFileExists_Exit
End
Function
La fonction IsSharePointURLIsAvailable() n'est ici pas écrite.
Initialement*, la fonction doit tenter de déposer un fichier dans un DocumentLibrary5 sur le site passé dans le
paramètre URL, et le détruire une fois le dépôt réussi et ce, dans le seul but de détecter que l'opération est possible.
J'ai intentionnellement forcé la valeur True pour l'application théorique du tutoriel.
Public
Function
IsSharePointURLIsAvailable
(
ByVal
URL As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : IsSharePointURLIsAvailable
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de contrôler qu'une adresse web est accessible
'...........................................................................
' Parameters : URL = adresse à contrôler
' Return Codes : Boolean = True if so success
'...........................................................................
' Notes : Fonction à écrire
'---------------------------------------------------------------------------
On
Error
GoTo
L_ErrIsSharePointURLIsAvailable
'[....]
IsSharePointURLIsAvailable =
True
On
Error
GoTo
0
L_ExIsSharePointURLIsAvailable
:
Exit
Function
L_ErrIsSharePointURLIsAvailable
:
IsSharePointURLIsAvailable =
False
Resume
L_ExIsSharePointURLIsAvailable
End
Function
La fonction URLIsValid() permet de vérifier la syntaxe d'une adresse Web. Elle exploite pour se faire l'API PathIsURL().
Public
Function
URLIsValid
(
ByVal
URL As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : URLIsValid
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Permet de contrôler qu'une adresse web est valide
'...........................................................................
' Parameters : URL = adresse à contrôler
' Return Codes : Boolean = True if so success
'...........................................................................
' Notes : Exploite PathIsURL pour contrôler l'adresse
'---------------------------------------------------------------------------
On
Error
GoTo
L_ErrURLIsValid
URLIsValid =
CBool
(
PathIsURL
(
URL))
On
Error
GoTo
0
L_ExURLIsValid
:
Exit
Function
L_ErrURLIsValid
:
URLIsValid =
False
Resume
L_ExURLIsValid
End
Function
La fonction GetClipboardData() permet de vérifier que le presse-papier contient une chaîne de caractères.
Public
Function
GetClipboardData
(
Optional
ByRef
Data As
String
) As
Boolean
'---------------------------------------------------------------------------
' Procedure : GetClipboardData
' DateTime : 10/10/2012
' Author : Jean-Philippe AMBROSINO
' Purpose : Vérifie si le Press-Papier n'est pas vide
'...........................................................................
' Parameters : [Data] = Contenu du Press Papier si nécessaire
' Return Codes : Boolean = True si succès
'...........................................................................
' Notes : Faire référence à FM20.dll
'---------------------------------------------------------------------------
Dim
oData As
DataObject
Set
oData =
New
DataObject
oData.GetFromClipboard
Data =
oData.GetText
GetClipboardData =
(
Len
(
Data) >=
1
)
Set
oData =
Nothing
End
Function
La fonction ChangeLinkedDatabase() pemret de réattacher toutes les tables de la base de données dorsale liée à l'application.
Public
Function
ChangeLinkedDatabase
(
ByVal
TargetDatabasePath As
String
, ByVal
TargetDatabaseName As
String
, Optional
ByVal
Pwd As
String
) As
Boolean
Dim
oDBApp As
DAO.Database
Dim
oDBBackEnd As
DAO.Database
Dim
oTDF As
DAO.TableDef
Dim
strTargetTableName As
String
Dim
strSourceTableName As
String
Dim
strLinkTemp As
String
Dim
strBackEndDBName As
String
'Défini le gestionnaire d'erreurs
On
Error
GoTo
L_ErrfBlnAttacherBase
'Désactive les messages système.
DoCmd.SetWarnings
False
'Change le curseur en sablier
DoCmd.Hourglass
True
'Affecte la BDD courante à l'objet Database
Set
oDBApp =
CurrentDb
'Construction de chemin complet
strBackEndDBName =
AddDirSeparator
(
TargetDatabasePath) &
TargetDatabaseName
'Si toutefois il y a un mot de passe...
If
Len
(
Pwd) Is
Nothing
Then
'On ouvre avec le mot de passe
Set
oDBBackEnd =
DBEngine.OpenDatabase
(
strBackEndDBName, False
, False
, "MS Access;PWD="
&
Pwd)
Else
'Sinon on ouvre simplement
Set
oDBBackEnd =
DBEngine.OpenDatabase
(
strBackEndDBName, False
, False
)
End
If
'On referme la base de données Dorsale qui n'est plus utilisé dans l'état
If
Not
oDBBackEnd Is
Nothing
Then
oDBBackEnd.Close
'Ensuite pour chacune des tables de la BDD
For
Each
oTDF In
oDBApp.TableDefs
'Avec la table...
With
oTDF
'Si elle n'est pas système et qu'elle est attachée
If
.Attributes
=
dbAttachedTable And
Not
.Attributes
=
dbSystemObject Then
'On affecte la chaîne de connexion à la variable
strLinkTemp =
oTDF.Connect
'Si dans la variable strLinkTemp se trouve le nom et le chemin de la base de données visée
If
InStr
(
1
, strLinkTemp, TargetDatabaseName, vbTextCompare) >
1
_
And
InStr
(
1
, strLinkTemp, TargetDatabasePath, vbTextCompare) >
1
Then
'On affecte alors le nom de la table à la variable
strSourceTableName =
oTDF.Name
'On supprimer alors la table liée de l'application (l'objet doit exister)
DoCmd.DeleteObject
acTable, strSourceTableName
'On égalise le nom de la table source et celle de destination
strTargetTableName =
strSourceTableName
'On procède à l'attachement de la table dans l'application
DoCmd.TransferDatabase
acLink, "Microsoft Access"
, strBackEndDBName, acTable, strSourceTableName, strTargetTableName
End
If
End
If
End
With
'On passe à la table suivante
Next
oTDF
'Si l'objet Database de l'application est valide, on ferme la BDD
If
Not
oDBApp Is
Nothing
Then
oDBApp.Close
'Si l'objet Database de la BDD Dorsale est valide, on ferme la BDD
ChangeLinkedDatabase =
True
On
Error
GoTo
0
L_ExfBlnAttacherBase
:
'On libère tous les objets de la mémoire
Set
oTDF =
Nothing
Set
oDBApp =
Nothing
Set
oDBBackEnd =
Nothing
'On restitue le cursor dans son aspect par défaut...
DoCmd.Hourglass
False
Exit
Function
L_ErrfBlnAttacherBase
:
'La fonction a échoué
ChangeLinkedDatabase =
False
'Un message décrit l'erreur
MsgBox
Err
.Description
, vbExclamation
, Err
.Source
'On reprend pour sortir de la fonction
Resume
L_ExfBlnAttacherBase
End
Function
Le module se termine ici.
Ainsi que dit plus haut, il probable que votre projet comporte une ou plusieurs des fonctions exposées ici.
3-1-8. Affectation du comportement des procédures et fonctions du projet selon l'environnement▲
Il ne suffit donc pas de changer d'environnement pour que tout se passe comme vous l'entendez...
En effet, le but de cette définition dynamique de l'environnement consiste de prime abord à tester des nouvelles fonctionnalités ou des
modifications apportées à tel ou tel objet, qu'il soit formulaire, état, requête dynamique ou module de classe...
Au sein de votre code doit alors être élaboré des blocs conditionnels typiques afin de faire en sorte que le code s'exécute de la façon dont
l'entend l'environnement sélectionné.
Imaginez par exemple que vous ajoutiez une nouvelle table qui est en relation avec une table existante en production et que du code
spécifique doive être greffé autour de cette définition de table et de son contenu pour proposer à l'utilisateur de nouvelles données. Il semble
alors évident que cette nouvelle table se trouve alors dans la base de données Dorsale de Test, puis celle de Recette (UAT1).
Votre code doit alors considérer l'existence de cette table, mais dans l'environnement de Production, elle n'existe pas encore.
Il vous faut donc rédiger le code en conséquence...
Dans un contexte supposé réel, voici un exemple. Initialement, un ancien développeur avait développé une fonction permettant de calculer
l'âge d'une personne avec une fonction qui retournait un entier et donc, il avait été contraint de bricoler des chaînes de caractères
afin de greffer à l'âge retourné, le mot an ou ans avec un s selon que la personne avait un an ou plus et donc,
accorder le pluriel dans les différentes zones de texte des formulaires faisant appel à cette fonction...
Vous, en charge de faire évoluer l'application, avez donc décidé de créer une nouvelle fonction Age() qui se charge en une fois de
retourner l'âge textuel au singulier ou au pluriel selon le cas.
Vous avez donc réécrit la fonction sans altérer le code existant...
Débordant d'initiative, vous avez fait en sorte que cette fonction puisse calculer un âge selon
une date autre que celle du jour comme date de référence ce qui augmente la puissance de cette nouvelle fonction...
Option
Compare Database
Option
Explicit
'On inscrit en dur l'énumération des 3 environnements uniquement pour la démo
Private
Enum m_eEnvironment
envTest =
1
envUAT =
2
envProd =
4
End
Enum
'Variable définissant l'environnement pour l'ensemble du projet
'Préférez une propriété au sein d'une classe plutôt qu'une variable publique.
Public
g_intExcecMode As
m_eEnvironment
Sub
Main
(
)
'On force l'environnement en Test
'(bien entendu, cet environnement doit être puisé dans la table en fonction de son état actif ou non)
g_intExcecMode =
envTest
'On cherche à calculer l'âge d'une personne selon une date
MsgBox
QuelAge
(
#6
/
9
/
1966
#)
End
Sub
Private
Function
QuelAge
(
ByVal
DateValue
As
Date
, Optional
ByVal
DateRef As
Date
) As
String
Dim
strAge As
String
Dim
intAge As
Integer
'On vérifie qu'une adte est bien passée en paramètre
If
Not
IsDate
(
DateRef) Or
CLng
(
DateRef) =
0
Then
DateRef =
Now
(
)
End
If
'On retourne l'âge en fonction de l'environnement
Select
Case
g_intExcecMode
Case
envTest
'La nouvelle fonction est complète
strAge =
AgeNewVersion
(
DateRef, DateValue
, True
)
Case
envUAT, envProd
'On appelle la fonction originale
intAge =
Age
(
DateValue
)
'On bricole avec un IIf pour construire la chaîne
strAge =
Trim
$(
Str
(
intAge)) &
IIf
(
intAge =
1
, " an"
, " ans"
)
End
Select
QuelAge =
strAge
End
Function
Private
Function
Age
(
ByVal
DateValue
As
Date
) As
Variant
'L'ancienne fonction qui retourne l'âge en entier
Age =
(
Now
-
DateValue
) \
365
.25
End
Function
Private
Function
AgeNewVersion
(
ByVal
DateValue
As
Date
, ByVal
DateRef As
Date
, Optional
ByVal
FullSentence As
Boolean
) As
String
'La nouvelle fonction qui retourne l'âge en texte
Dim
lngResult As
Long
lngResult =
(
DateValue
-
DateRef) \
365
.25
AgeNewVersion =
lngResult &
IIf
(
FullSentence, " an"
&
IIf
(
lngResult <=
1
, vbNullString
, "s"
), vbNullString
)
End
Function
Bon, soyez indulgent, ce n'est pas le super exemple par définition...
J'ai écrit ce bloc de code pour vous montrer un peu l'utilité et la mise en application de la gestion de l'environnement.
En réalité, la mise en oeuvre est beaucoup plus fine et donc un peu plus complexe que cela.
La surcharge n'existant pas en Visual basic, il n'est pas possible de créer une nouvelle fonction Age()
avec les deux paramètres que j'ai ajoutés pour la circonstance.
Toutefois, il est possible de créer une fonction avec le même nom et des paramètres différents, mais dans deux modules séparés... Dans ce cas, si vous souhaitez l'appeler, il vous faudra qualifier son nom avec celui du module...
Option
Compare Database
Option
Explicit
'On inscrit en dur l'énumération des 3 environnements
Private
Enum m_eEnvironment
envTest =
1
envUAT =
2
envProd =
3
End
Enum
'Variable définissant l'environnement pour l'ensemble du projet
'Préférez une propriété au sein d'une classe plutôt qu'une variable publique.
Public
g_intExcecMode As
m_eEnvironment
Sub
Main
(
)
'On force l'environnement en Test
'(bien entendu, cet environnement doit être puisé dans la table en fonction de son état actif ou non)
g_intExcecMode =
3
'On cherche à calculer l'âge d'une personne selon une date
MsgBox
QuelAge
(
#6
/
9
/
1966
#)
End
Sub
Private
Function
QuelAge
(
ByVal
DateValue
As
Date
, Optional
ByVal
DateRef As
Date
) As
String
Dim
strAge As
String
Dim
intAge As
Integer
'On vérifie qu'une adte est bien passée en paramètre
If
Not
IsDate
(
DateRef) Or
CLng
(
DateRef) =
0
Then
DateRef =
Now
(
)
End
If
'On retourne l'âge en fonction de l'environnement
Select
Case
g_intExcecMode
Case
envTest
'On appelle la nouvelle fonction Age()
strAge =
basNewFunctions.Age
(
DateRef, DateValue
, True
)
Case
envUAT
'Pas déployé
strAge =
"Non disponible"
Case
envProd
'On appelle la fonction originale
intAge =
basFunctions.Age
(
DateValue
)
'On bricole avec un IIf pour construire la chaîne
strAge =
Trim
$(
Str
(
intAge)) &
IIf
(
intAge =
1
, " an"
, " ans"
)
End
Select
QuelAge =
strAge
End
Function
Remarquez la qualification de l'appel de la fonction Age() par les modules "basNewFunctions" pour
le nouvel environnement de Test ou plus exactement celui initialisé dans la variable g_intExcecMode et le module
basFunctions pour l'environnement de Production.
Les modules contiennent donc respectivement chacun une fonction Age().
La différence réside dans le fait que la nouvelle fonction est plus générique et possède plus d'arguments.
Bien que cela ne puisse pas s'assimiler comme une fonction surchargée2, il s'avère bien pratique d'avoir recours à ce type de méthode
pour employer un même nom de fonction qui ne retourne pas le même type de résultat ou bien qui se comporte différemment du fait notamment
des paramètres qui lui auraient été greffés.
Option
Compare Database
Option
Explicit
Public
Function
Age
(
ByVal
DateValue
As
Date
) As
Integer
'L'ancienne fonction qui retourne l'âge en entier
Age =
(
Now
-
DateValue
) \
365
.25
End
Function
Option
Compare Database
Option
Explicit
Public
Function
Age
(
ByVal
DateValue
As
Date
, ByVal
DateRef As
Date
, Optional
ByVal
FullSentence As
Boolean
) As
String
'La nouvelle fonction qui retourne l'âge en texte
Dim
lngResult As
Long
lngResult =
(
DateValue
-
DateRef) \
365
.25
Age =
lngResult &
IIf
(
FullSentence, " an"
&
IIf
(
lngResult <=
1
, vbNullString
, "s"
), vbNullString
)
End
Function
En complément...
Un peu plus bas, j'aborde avec ce phénomène un autre cas plus typique et qui attaque
cette fois le comportement des contrôles...
4. Mise en exécution▲
Une fois le code mis en place, vous basculez de nouveau sur votre formulaire (Alt+Tab) ou bien vous quittez l'éditeur Visual Basic depuis le menu Fichier.
4-1. Définition de l'environnement▲
Je sous-entends par "définition de l'environnement" le procédé qui va vous permettre de faire en sorte que votre application se comporte
et agisse en fonction de celui que vous avez sélectionné. Il s'agit alors de mettre en exécution les différents processus tout en impactant la
base de données visée dorsale d'une part et les opérations de traitement des fichiers en rapport d'autre part si l'on reste dans le contexte de
ce tutoriel.
En effet, une mise en test dans un premier temps vous permet de faire vos propres évaluations et c'est donc vous et vous seul qui décidez lorsque
vous pouvez ou non délivrer l'application pour une mise en recette...
Une fois la mise recette (UAT1) validée, seul le ou les utilisaeurs pourront décidez lorsque
vous pourrez lancer la version de production...
Mise en situation exemple
Imaginons par exemple que votre projet est en production et tourne parfaitement bien (oui, oui, ça arrive)...
Des besoins spécifiques d'un autre service contraint de traiter des données annexes à celles déjà traitées par votre application vous parviennent avec
les spécifications fonctionnelles en rapports - du moins, il vaut mieux que ce soit écrit que verbal, je sais de quoi je parle ;o) -
Dans la sitatution actuelle, ces données se trouvent dans un des fichiers sources importés dans votre projet où justement certaines colonnes
ne sont pas importées ou traitées par votre processus de traitement et ce sont justement quelques-unes d'entre elles dont ce service a besoin.
Il va donc être nécessaire de modifier :
- les scripts d'importation,
- le traitement sur les données qui en découle,
- la modification de la structure des tables de destintion et les éventuelles requêtes,
- la création des processus d'export pour honorer le besoin du dit service
- etc...
Pour mettre cela en application sans perturber le fonctionnement de la production, vous pourrez alors une fois
tout mis en œuvre, basculer un ou des utilisateurs dans un environnement de "recette" pour apprécier vos modifications
ou nouveautés et ainsi, vérifier le comportement de non-régression de votre projet sans altérer les données de production déjà en base.
En effet, toute modification même contrôlée par vous peut générer des erreurs inattendues lorsque l'application est entre les mains d'autres utilisateurs...
4-2. Le formulaire de définition de l'environnement▲
Ce formulaire est ici le reflet de la structure de la table. Il vous appartient alors de faire en sorte que le nombre de contrôles utiles
à votre projet soit effectivement ajusté en conséquence. Dans le cas présenté ici, le minimum a été prévu notamment en matière de
sous-dossiers cibles. Dans mon projet initial qui a servi d'idée pour ce tutoriel, le nombre était largement doublé.
L'exemple étudié ici considère que le chemin principal est la racine de l'ensemble des sous-dossiers. Ainsi, si tel n'était pas le cas pour
vous, une adaptation serait nécessaire.
En parallèle à cela, il a été stipulé qu'une seule adresse SharePoint. Là aussi, il n'est pas utile de la considérer si toutefois
aucun site SharePoint n'existe pour votre projet.
4-3. Validation de la définition de l'environnement▲
Le processus de définition de l'environnement va tourner autour d'un jeu de fonctions faisant partie intégrante de la classe de formulaire correspondant, mais aussi des fonctions externes à la classe, celles-ci pouvant déjà exister dans votre projet ou bien pouvant avoir à être utilisées dans un autre contexte depuis un autre formulaire par exemple. Le principe de remplissage est simple :
- La sélection du fichier représentant la base de données dorsale
- la sélection du chemin racine est effectuée par sélection du dossier
- la sélection ou la saisie manuelle des sous-dossiers avec contrôle de cohérence de caractères acceptables
- la saisie manuelle du nom du fichier de sortie et de son extension
- la saisie manuelle ou le collage de l'adresse du site SharePoint avec contrôle de cohérence de caractères acceptables
- les annulations ou mauvaises manipulations
- et enfin la validation
4-3-1. Principe de validation▲
Pour que l'environnement soit accepté, toutes les données de base doivent être correctes.
- La base de données dorsale doit exister
- Le chemin de travail doit être disponible
- Dans le contexte de ce tutoriel, seuls les dossiers ne sont pas vérifiés dans leur existence en tant que dossier, car
(dans mon projet*) ils seront (étaient*) créés sur le chemin de travail dès que les processus
d'importation ou d'exportation seront (étaient*) exécutés (code non exposé ici*).
En revanche, leur stipulation dans les zones de texte est obligatoire.
Si la case à cocher du site SharePoint est cochée, c'est que vous avez décrété qu'un site est disponible et donc,
que l'adresse de ce site doit être valide...
Sauvegarde effective de l'environnement
Une fois toutes les zones de texte alimentées, vous cliquez sur le bouton de sauvegarde... Une analyse de quelques millisecondes
suffit à vérifier le bon contenu du formulaire.
4-3-1-1. Validation de la base de données dorsale▲
Lors du processus de validation de l'environnement sélectionné, une procédure va identifier l'existence de la base de données dorsale qui a été définie dans la zone de texte. Le processus ne vérifie pas l'intégrité de la base en nombre de tables, mais seulement l'existence du fichier.
Rien ne vous empêche si le coeur vous en dit de mettre oeuvre un algorithme idoine pour ce faire en comparant l'existence et la structure de toutes les tables de la base de production en regard de celles des bases de test et de recette...
Lorsque cette opération de vérification a abouti, une procédure de mise en place de suppression des tables attachées et de rattache
de ces mêmes tables issues de la base de données sélectionnée est exécutée. Toutes les liaisons sont rétablie à l'image de l'opération similaire
opérée par le Gestionnaire de tables liées.
Votre application sera alors configurée dans un environnement de Test, d'UAT1 ou de Production selon le cas.

Lorsque la sauvegarde est terminée avec succès, un message vous le confirme clairement.
Ensuite, le formulaire se referme (cela est prévu ainsi ici, vous pouvez très bien modifier cette opération).
Impossibilité de sauvegarder l'environnement
S'il a été omis de renseigner un élément ou bien si un élément est invalide, un message d'erreur s'affiche
et vous précise l'élement en question dans l'intitulé du message d'une part et lui donne le Focus d'autre part.

Vérifiez alors quel élément est susceptible d'être responsable de ce rejet.
* quand j'évoque mon projet, je fais allusion au projet qui m'a donné l'idée de rédiger ce tutoriel.
4-3-2. Exécution des processus de traitement▲
Quel que soit le contexte, évolution ou correction de l'application, il est évident que de procéder à des tests de non-régression
est indispensable.
Aussi, vous avez différents choix possibles quant à la mise à disposition des modifications que vous auriez apportées.
Remarque
Différence entre évolution et correction
Il existe une différence fondamentale entre la notion de "correction" et la notion "d'évolution".
Il vous appartient de bien définir le contexte avant d'entreprendre la mise en application de ce tutoriel et ce, afin de ne pas vous emmêler
les crayons si je puis dire…
Faire "recetter" votre application du fait qu'il ait eu lors de la dernière livraison des bugs ou des
dysfonctionnements n'est pas tout à fait la même approche que faire "recetter" votre application dans un contexte d'évolution suite à
de nouvelles demandes.
Même si l'un et l'autre se rejoignent, la philosophie de déploiement de votre application fraîchement "corrigée" ou fraîchement
"évoluée" n'est pas vu du même œil par l'utilisateur.
C'est pourquoi une grosse organisation de travail est nécessaire lorsque vos projets prennent une envergure de ce type et que ces derniers
nécessitent une validation avant d'être distribués à grande échelle.
Là encore, un remplissage de commentaires idoines au sein de votre code doit être parcimonieusement entrepris.
4-3-3. Scénarii d'importation et d'exportation▲
Sans rentrer dans le détail technique de la chose, les scénarii d'importation et d'exportation n'ont lieu d'être évoqués ici pour parfaire une situation complète en rapport avec ce tutoriel où l'objectif consiste à importer des données issues de fichiers plats et de générer des rapports (statistiques...) vers Excel par exemple.
4-3-3-1. Scénario d'importation▲
J'entends par "Scénario d'importation" le phénomène qui va vous permettre de remplir la table cible en faisant en sorte que
les fichiers soient bien importés depuis le dossier que vous avez spécifié ; le programme chargé d'avaler le fichier pourra extraire
le contenu après avoir vérifié qu'il n'a pas déjà été importé (par vérification du nom (horodatage) du fichier identique enregistré dans
la table des fichiers déjà traités qui est censée exister dans l'application).
Une fois l'importation effectuée et le traitement de remplissage de la table terminés avec succès, le fichier source est alors déplacé vers le
dossier d'archive.
4-3-3-2. Scénario d'exportation▲
J'entends par "Scénario d'exportation" le phénomène qui va vous permettre de générer les fichiers de sortie en faisant en sorte
que les fichiers soient bien déposés dans le dossier que vous avez spécifié ; ils pourront aussi si cela est prévu, être copiés dans la base
documentaire du site SharePoint quelle que soit l'adresse (celle-ci pouvant varier selon l'environnement)...
Le programme chargé de générer les fichiers pourra être exécuté autant de fois que l'utilisateur le souhaite (avec ou sans écrasement3
- c'est mieux avec).
Une fois l'exportation des données (filtrées ou non par l'utilisateur) effectuée et terminée avec succès, le fichier source peut
alors être déplacé vers le dossier des fichiers de sortie....
Attention ! Le code affairant aux processus d'importation et d'exportation ne fait pas partie de ce tutoriel qui reste un exemple de suggestion pour un contexte professionnel donné.
4-3-4. Comportement du code▲
Lorsque que le projet est en production, il ne doit pas exister de différence de comportement
entre votre version de développement et la version effectivement mise en production ;
Ainsi, la version de Test, d'UAT1 ou de Prod doivent de comporter à l'identique.
En revanche, si par exemple une nouvelle fonctionnalité a été ajoutée dans un formulaire, elle doit fonctionner que si l'environnement
le permet. En d'autres termes, un bloc de code conditionnel pourra par exemple être ajouté pour pouvoir faire en sorte que la nouvelle
fonctionnalité soit exploitable dans un premier temps uniquement en mode Test pour vous et une fois fonctionnelle, en mode
Recette par la suite.
On considère ici que les 3 environnements Test, UAT et Prod sont affectés à des identifiants numériques statiques
(ID) et qu'en aucun cas, leur valeur ne peut changer.
On pourra alors supposer les valeurs suivantes :
- Test: IDEnvironment=1
- UAT : IDEnvironment=2
- Prod : IDEnvironment=3
4-3-4-1. Côté déclaration des différents environnements▲
Ainsi que cela a été exposé, nous pouvons alors mettre en place une énumération pour définir ces différents environnements.
Plusieurs solutions s'ouvrent à vous pour les gérer :
Je vous propose ici de déclarer une variable qui instanciera la classe spécifiquement dédiée à la gestion de l'environnement
soit par exemple :
Public
g_cEnvironment As
New
clsEnvironment
Public
Enum g_eEnvironment
EnvironmentTest =
1
EnvironmentUAT =
2
EnvironmentProd =
3
End
Enum
Si vous êtes dans un cas d'ajout d'une nouvelle fonctionnalité dans un formulaire existant (par exemple un bouton de commande qui permet d'exporter vers Excel le contenu de ce qui est consulté à l'instant T dans ce même formulaire), vous devrez alors modifier les lignes dans le code de l'événement Form_Load() par exemple ; le nouveau bloc en environnement de Test ressemblerait alors à ceci :
Private
Sub
Form_Load
(
)
'Bloc de code existant en amont
'[...]
With
g_cEnvironment
Select
Case
.GetCurrentEnvironment
(
)
Case
EnvironmentTest
cmdExportToExcel.Visible
=
True
'cmdExportToExcel.Enabled = True
Case
EnvironmentUAT
cmdExportToExcel.Visible
=
False
'cmdExportToExcel.Enabled = False
Case
EnvironmentProd
cmdExportToExcel.Visible
=
False
'cmdExportToExcel.Enabled = False
End
With
'Bloc de code existant en aval
'[...]
End
Sub
Un autre exemple pourrait ressembler à cela :
Private
Sub
Form_Load
(
)
'Bloc de code existant en amont
'[...]
With
g_cEnvironment
cmdExportToExcel.Visible
=
(
.GetCurrentEnvironment
(
) =
EnvironmentTest)
'cmdExportToExcel.Enabled = (.GetCurrentEnvironment() = EnvironmentTest)
End
With
'Bloc de code existant en aval
'[...]
End
Sub
avec le même choix à définir entre Enabled et Visible.
Remarquez que j'ai mis en remarque la propriété Enabled ; a vous de choisir entre Visible et donc de préférer un bouton
Invisible ou un bouton Désactivé. Une fois le code de ce bouton opérationnel, la condition Case EnvironmentUAT verra
les valeurs des propriétés affectées à True.
Là, c'est à vous de choisir entre appliquer un état visible ou désactivé selon vos préférences ou bien un Exit Sub ou
un Exit Function en début de procédure événementielle déclenchée par l'événement Click de ce fameux bouton cmdExportToExcel.
Remarque
Tout ce que je viens de vous évoquer ici est circonstanciel à des modifications multiples qu'elles soient mineures ou majeures.
Vous avez bien entendu différents procédés qui vous permettront de mettre à disposition une ou plusieurs nouvelles fonctionnalités.
Ceci reste avant tout une suggestion. Il existe en effet moult possibilités de faire évoluer votre projet...
Duplication des objets
Pour faire évoluer de façon majeure les fonctionnalités d'un formulaire, vous pouvez avoir recours par exemple
à la duplication de ce formulaire pour y apporter la ou les nouvelles fonctionnalités.
Ainsi, vous conservez le formulaire original sans modifications, ce qui vous ouvre alors la liberté de procéder
à modifications majeure dans la version dupliquée sans altérer l'original...
Attention : Ce choix est plutôt à envisager en cas d'évolution et non de correction de bugs.
Ce mode opératoire facilite quelque peu la mise en oeuvre car seule la modification du script d'ouverture dudit formulaire
est alors à élaborer...
Voici un exemple :
Private
Sub
OpenMainDataForm
(
)
Dim
strWhereCondition As
String
Dim
strDataFormName As
String
Dim
strTargetValue As
String
'Bloc de code existant en amont
'[...]
strWhereCondition =
"[TargetField]='"
&
strTargetValue &
"'"
'[...]
With
g_cEnvironment
Select
Case
.GetCurrentEnvironment
(
)
Case
EnvironmentTest
'On ouvre le formulaire frmMainData de test
strDataFormName =
"frmMainData_Test"
Case
EnvironmentUAT
'On ouvre le formulaire frmMainData UAT
strDataFormName =
"frmMainData_UAT"
Case
EnvironmentProd
'On ouvre le formulaire original
strDataFormName =
"frmMainData"
End
Select
DoCmd.OpenForm
strDataFormName, acNormal, , strWhereCondition, acFormEdit, acDialog
End
With
'Bloc de code existant en aval
'[...]
End
Sub
4-3-4-2. C'est un peu confus tous ces environnements !▲
En fait, ce qui est délicat à assimiler ici et je vous comprends, c'est la différence qui peut exister entre les deux environnements Test
et Recette car il vous paraît sans doute étrange d'avoir des choses qui fonctionnent dans l'un et pas dans l'autre.
Ce qu'il faut comprendre, c'est que dans un cas d'évolutions/corrections comme celui auquel j'ai eu affaire (plus de 140), il peut exister des priorités de
réalisation. Ainsi, vous pouvez très bien rendre opérationnelle certaines fonctionnalités au détriment d'autres simplement parce qu'elle sont
inachevées et pour autant, d'autres ont besoin d'être opérationnelles.
Considérez ici qu'un utilisateur n'a pas la même vision des choses que vous
en matière de test de sa version de Recette et que donc il est susceptible de vous remonter des incompréhensions, des bugs ou des états de non
correspondance entre ce qui était demandé et ce qui a été délivré.
Par ailleurs, la disponibilité dudit utilisateur n'étant pas la même que la votre,
vous de votre côté vous avancez sur le développement des autres évolutions ou des corrections pendant que l'utilisateur, lui, teste
ce que vous avez apporté sur la version déployée.
Autre point encore, certaines corrections ou évolutions qui doivent être recettées peuvent empietter sur d'autres qui en dépendent et donc,
bloquer en quelque sorte votre propre avancée sur les suivantes. Cela demande donc un pointage parcimonieux des avancées.
Pour ma part, mes utilisateurs et moi-même partagions un classeur Excel dans lequel figuraient les différents états d'avancée
du projet avec la notion de gravité ou de priorité. Au fur et à mesure que les mises en recette étaient délivrées, de mon coté, je
pointais la colonne de l'état de realisation côté développement tandis que les utilisateurs pointaient la colonne qui validait ou non
la bonne marche de la fonctionnalité ou la correction effective du bug pour une ligne donnée.
Cette façon de procéder a permis un véritable suivi pour mener à bien la finalisation de l'application.
4-3-4-3. Et ensuite ?▲
Eh bien une fois que la validation de la version de Recette est effective, il vous suffit de copier/déplacer (selon
l'architecture que vous ave mis en place, tous les blocs de code s'exécutant dans cet environnement vers celui
de Prodution.
Vous condidérerez alors que cette action engendre la notion de version en vigueur.
Cette opération est identique entre la version de Test et la version Recette...
Bien entendu, il est recommandé de commenter ces opérations avec une date pour un meilleur suivi.
4-3-5. Le mode réservé au développeur▲
Vous avez effectivement remarqué la présence du champ ReservedToDeveloper dans la table des environnements.
Dans mon projet* évoqué au début de ce tutoriel, j'avais ajouté ce champ pour me créer un environnement personnel non accessible
aux utilisateurs.
Le but et le rôle de ce champ étaient de pouvoir effectuer certaines manipulations sur mon poste de développement et faire en sorte que
l'application s'adapte en conséquence pour l'environnement de Test. Parmi ces fonctionnalités particulières, une m'était propre et inévitable :
Les chemins définis pour cet environnement étaient en fait ceux pointant sur des lecteurs logiques de mon ordinateur portable en lieu et
place des chemins UNC4 déclarés pour l'environnment de Test de mon poste local dans l'entreprise.
J'avais donc créé pour la circonstance deux lecteurs H:\ et R:\ et ainsi faire ensorte que mon portable et ma station fixe locale
de l'entreprise possèdent les mêmes lecteurs mappés avec une structure des dossiers identique et évidemment, tout le contenu.
Lorsque je travaillais à domicile sur ce projet, je changeais manuellement l'environnement et basculait le mode Test où le champ
ReservedToDeveloper était à True. Cela me permettait donc de travailler dans une situation identique quelle que soit ma position géographique.
* quand j'évoque mon projet, je fais allusion au projet qui m'a donné l'idée de rédiger ce tutoriel.
5. Conclusion▲
J'ai souhaité partager avec vous ce nouveau tutoriel car j'estime, de par mes années d'expérience, qu'il est important de pouvoir développer
vos applications avec la plus grande souplesse possible.
L'emploi de fonctions factorisées, l'usage de procédures génériques et la bonne écriture du code sont déjà un piédestal.
Cette nouvelle brique que vous venez de lire et pour laquelle je vous laisse imaginer la souplesse de l'architecture avec laquelle vous pourrez
dès lors avec une grande aisance faire évoluer vos projets. Ce sera un plus pour vos clients ou vos utilisateurs et bien entendu, une valeur ajoutée
pour vous-même.
6. Sujets corrélatifs▲
Dans le fil complémentaire de cet article, il est conseillé de lire les tutoriels sur :
- La mise en place de bases de données Access en réseau
- Déploiement d'applications Access 2010 (et antérieures)
7. Remerciements ▲
Je tiens à remercier toutes celles et ceux qui ont participé à la relecture de ce document en y incluant leurs remarques et en particulier :
Dolphy35
Philippe JOCHMANS
Pierre Fauconnier
et
GAYOT
sans oublier Nono40 pour son outil permettant la rédaction des articles.
8. Glossaire▲
1 - UAT
User Acceptance Testing
Equivaut au terme français "Recette" et qui est la dernière phase d'acceptation avant la mise en production...
2 - Surcharge
La surcharge de méthode consiste à créer de nouvelles méthodes portant le même nom mais ayant des paramètres différents (sans évoquer le nom) de la méthode initiale.
Cela permet de conserver une seule et même nom de fonction et pour lesquelles des détails changent.
Voir l'article de Mohamed Elhadi Benzeghiba (https://mbenzeghiba.developpez.com/tutoriels/dotnet/heritagevbnet/)
3 - Ecrasement
Dans le contexte, on suppose que tout fichier généré n fois pour une même période efface et remplace les fichiers existants et
portant un nom identique qui ont déjà été généré auparavant.
- Sous Excel en OLE Automation, vous définirez la propriété DisplayAlerts à False pour l'objet "Application" instancié.
- En usant de FileSystemObject, le méthode CreateTextFile verra son paramètre Overwrite défini à True.
4 - UNC
En informatique, Universal Naming Convention abrégé UNC est une convention sur une manière de
définir l'adresse d'une ressource sur un réseau, mise en oeuvre par Microsoft Windows®.
Plutôt que de spécifier une lettre de lecteur et un chemin d'accès (par exemple, H:\partage), un nom UNC utilise la syntaxe suivante :
\\serveur\partage\chemin\nom_fichier
5 - Document Libraries