0. Introduction

Dans ce tutoriel, nous allons aborder l'utilisation d'une application Microsoft ACCESS sur un Cloud Storage.

0-A. Avertissement

Le Cloud Storage, du fait de son fonctionnement par synchronisation de fichiers, ne permet pas les accès concurrents.

Pour aborder ce tutoriel, vous devez avoir de sérieuses connaissances en VBA et maîtriser l'utilisation des classes. Vous devez également maîtriser les tables liées, ainsi que la gestion des conflits.

Retrouvez un excellent tutoriel pour vous former aux classes VBA http://fauconnier.developpez.com/articles/vba/general/classes/.

I. Prérequis

Outre la possession d'une connexion haut débit permanente, vous devrez installer une des solutions de Cloud Storage et vous documenter sur sa gestion de conflits pour adapter la classe.

La solution choisie pour illustrer ce tutoriel est Dropbox dont un lien est disponible ci-dessous. La classe est adaptée à ce produit, libre à vous de l'adapter pour un autre.

Les solutions de Cloud Storage possèdent toutes une offre gratuite mais peuvent être plus ou moins avantageuses en termes techniques (possibilités, capacité de stockage, fonctionnement, rapidité, gestion des conflits).

I-A. Skydrive de Microsoft

Vous ne pouvez l'installer qu'à partir de Windows Vista en version 32 ou 64 bits. Plus d'informations sur cette page :

http://windows.microsoft.com/fr-FR/skydrive/system-requirements

I-B. GDrive de Google

Installable à partir de XP, il dispose d'une capacité de stockage de 5 Go gratuit.

Pour l'installer, rendez-vous sur votre iGoogle. GDrive est présent dans la barre de menu.

image

I-C. Dropbox de Dropbox Inc.

Dropbox propose 2 Go d'espace de stockage extensible. J'ai choisi cette solution pour illustrer ce cours.

Vous pouvez faire l'installation dès à présent en utilisant l'adresse suivante :

http://db.tt/luWcVhHB (gagnez 500 Mo supplémentaires en utilisant ce lien de parrainage)

II. Fonctionnement

Ces solutions de stockage fonctionnent toutes sur le mode de la synchronisation de fichiers.

Un plug-in, petit logiciel résident, est installé sur le poste en même temps qu'un répertoire est créé. Lorsque l'utilisateur copie, crée, modifie ou supprime un fichier, le changement est automatiquement répercuté sur le Cloud. Enfin les serveurs renvoient le changement vers les autres postes abonnés.

Les postes ne sont donc pas connectés à un espace de travail sur un serveur. Il n'y a pas à proprement parler un espace de travail sur un serveur, juste un stockage sur une multitude de serveurs qui ne sont pas identifiables par l'utilisateur.

II-A. Schéma de fonctionnement du Cloud Storage

Image non disponible
Schéma de fonctionnement du Cloud Storage

II-B. Installation

À partir du lien indiqué plus haut, vous avez installé Dropbox sur votre poste. Le plug-in est chargé au démarrage de la session et on peut le contrôler via la barre des tâches.

image

Lors de l'installation, le dossier est créé par défaut dans le dossier de l'utilisateur.

image

Un raccourci vers ce dossier est également créé sur le bureau.

image

Le plug-in reste en mémoire jusqu'à sa fermeture et est accessible dans la barre des tâches. C'est lui qui observe les fichiers et les synchronise.

image

Notez qu'une liaison internet haut débit est obligatoire pour avoir un fonctionnement optimal.

III. Le Cloud appliqué à MS ACCESS

Outre la gratuité, le partage de données d'une application est un avantage indéniable. Il convient cependant d'être objectif, ce n'est pas la solution miracle et ça ne remplacera pas une base de données en ligne du type Microsoft Azure, notamment pour les accès concurrents.

III-A. Inconvénient

Le seul inconvénient majeur et sûrement rédhibitoire pour certaines applications est de ne pas pouvoir l'appliquer à un fonctionnement multiutilisateur. En effet, comme il s'agit de synchronisation de fichiers, si plusieurs machines modifient le même fichier de données en même temps, il y aura conflit.

En cas de conflit, les fichiers ne sont pas perdus ; leur nom est complété par le nom de la machine et la date du conflit.

Voici un exemple de conflit sur deux fichiers.

image

III-B. Avantages

Outre la gestion des conflits indiquée précédemment, un avantage non négligeable est la taille des fichiers. Dropbox bénéficie d'une marge confortable avec ses 10 Go maxi par fichier, soit bien au-delà d'un fichier Microsoft Access.

Vous disposez également d'un archivage des versions sur une durée de trente jours (extensible moyennant un abonnement payant) et également la possibilité de partager des répertoires individuellement.

III-C. Précautions

Il convient de choisir une architecture frontale/dorsale pour éviter de synchroniser des informations inutiles, comme l'IHM.

N'hésitez pas à crypter la dorsale, Dropbox Inc. vous l'autorise.

IV. Fonctionnement de l'application

Avec une architecture Frontale/Dorsale, Microsoft ACCESS n'accède au fichier dorsal que lorsqu'il y a accès à l'une des tables. Si le fichier dorsal est ouvert, il sera forcément synchronisé à sa fermeture. C'est en gardant à l'esprit ce mécanisme que nous allons travailler.

Vous l'aurez compris, cette technique proscrit l'utilisation des accès concurrents. Il faut donc se prémunir contre tout risque d'accès multiples en s'assurant qu'au démarrage de l'application personne n'est connecté et ainsi éviter la génération de conflits.

IV-A. Comment ça marche

Dès le démarrage et avant même tout accès à une des tables de la dorsale, l'application vérifie qu'un fichier, que nous appellerons « lock », existe dans le dossier synchronisé.

  • Si ce n'est pas le cas, l'application le crée. Dès lors, le plug-in Dropbox l'envoie dans le Cloud, qui le renvoie vers les postes abonnés. L'application fonctionne normalement. À la fermeture, le fichier « lock » est effacé et le plug-in répercute l'action dans le Cloud.
  • Si le fichier « lock » existe, l'application affiche un message et se ferme.

IV-A-1. Schéma de fonctionnement

Image non disponible
Schéma de fonctionnement

IV-B. Fichier lock vs laccdb

Pourquoi utiliser un fichier dit « lock » au lieu d'utiliser directement le fichier  « laccdb » de la dorsale ?

La question mérite d'être posée. Le choix s'est porté sur un fichier texte pour pouvoir contrôler les homonymies de nom d'utilisateur.

V. Mise en pratique

Il est quand même plus facile de gérer ce genre de fonctionnalité dans une entité. Les classes feront donc pleinement l'affaire.

V-A. Table de paramètres

Comme nous l'avons vu dans l'installation, le chemin Dropbox local comme l'utilisateur peuvent être différents d'un poste à l'autre. Une table locale à l'application est donc nécessaire pour stocker ces deux paramètres importants.

Créez une table dans l'application suivant cette structure :

Nom Type Longueur
Idiparametre NuméroAuto  
Parametre Texte 25
Valeur Texte 255


Parametre contiendra le nom du paramètre et Valeur sa valeur. Cette table contiendra le paramètre CheminPartage qui donne le chemin vers la Dropbox locale et Utilisateurlocal, l'utilisateur local de l'application.

Inutile de la remplir, c'est le code qui s'en chargera.

Enregistrez-la sous le nom tiParametres. Le i indique que cette table est interne à l'application (fichier Frontal), par opposition à une table de paramètres qui serait stockée dans la dorsale.

V-B. Création de la Classe CCloud

Créez un module de classe nommé CCloud, n'oubliez pas de le paramétrer grâce aux propriétés comme l'indique la copie d'écran suivante.

image

Nous sommes fin prêts pour créer les attributs et les méthodes.

V-C. Attributs et méthodes

Voici le diagramme de classe CCloud qui permet d'en avoir une vue d'ensemble.

Image non disponible
Schéma de classe

V-C-1. Attributs

Nom Description
StationLocale Le nom de la station locale
Conflit Indique s'il y a conflit de fichier dorsal
UtilisateurLocal L'identifiant CCloud de l'utilisateur local
Occupe La détection de l'utilisation de l'application par un tiers
UtilisateurConnecte L'identifiant CCloud de l'utilisateur connecté
CheminPartage Le chemin local de la dorsale (Dossier Dropbox)

V-C-2. Méthodes

Nom Description
Class_Initialize Initialisation de la classe
Class_Terminate Terminaison de la classe
CreerFichier Création du fichier « lock »
EffacerFichier Effacement du fichier « lock »

V-D. En-tête de classe

L'en-tête est important dans une classe, car c'est là qu'on y retrouve les variables locales.

 
Sélectionnez
Option Compare Database
Option Explicit

Dim vStationLocale As String        ' nom de la station locale
Dim vCheminPartage As String        ' le chemin SkyDrive/DropBox/GDrive local
Dim vUtilisateurLocal As String     ' l'utilisateur local
Const cNomFichier As String = "occupe.txt"  'nom du fichier lock

La constante cNomFichier contient le nom du fichier « Lock ». Si ce nom ne vous convient pas vous pouvez très bien le modifier ; le fonctionnement n'en souffrira pas.

V-E. Initialize/Terminate

La méthode d'initialisation Class_Initialize contient l'initialisation de certaines variables comme le nom de l'utilisateur local ainsi que celui de la station.

La méthode Class_Terminate, qui s'exécute à la libération de la classe, permet de déclencher la méthode d'effacement du fichier « lock » et de contrôler un éventuel conflit.

 
Sélectionnez
Private Sub Class_Initialize()
' démarre la classe
  vStationLocale = Environ("ComputerName")
  'on fixe le nom de l'utilisateur si celui-ci n'existe pas.
  If vUtilisateurLocal = "" Then
     UtilisateurLocal = vStationLocale & ";" & Environ("UserName")
  End If
End Sub

Private Sub Class_Terminate()
'Fermeture de la classe
'à appeler sur le close du dernier formulaire ouvert ou avant un quit
' supprime le fichier lock
    EffacerFichier
End Sub

V-F. Les attributs

Certains attributs n'ont pas de Setter car ils renvoient des valeurs initialisées par la classe.

V-F-1. Le nom de la station locale - StationLocale

Le nom de la station sera utile pour déterminer un conflit d'écriture sur la dorsale au moment de la fermeture.

 
Sélectionnez
Public Property Get StationLocale() As String
    StationLocale = vStationLocale
End Property

Cet attribut est renseigné au moment de l'initialisation de la classe par la méthode Class_Initialize. Il renvoie le nom de la station locale.

V-F-2. L'utilisateur local - UtilisateurLocal

Pour cet attribut vous devez créer le Getter et le Setter.

Le Set n'est utilisé que pour un type Objet, dans le cas d'un type natif (string, long, boolean...) , il faut utiliser Let.

 
Sélectionnez
Public Property Let UtilisateurLocal(vLocalUser As String)
' définit l'utilisateur local à partir de
' nom d'utilisateur Windows +
On Error GoTo errSub

Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tIParametres", dbOpenDynaset)
rst.FindFirst "Parametre='UtilisateurLocal'"
' le paramètre existe on le renseigne
If Not rst.NoMatch Then
   rst.Edit
   rst.Fields(2) = vLocalUser & "-" & Replace(CDbl(Now()), ".", "")
   rst.Update
Else
' il n'existe pas on le crée
   rst.AddNew
   rst.Fields(1) = "UtilisateurLocal"
   rst.Fields(2) = vLocalUser & "-" & Replace(CDbl(Now()), ".", "")
   rst.Update
End If

rst.Close

ExitSub:
  Set rst = Nothing
  Set db = Nothing
  On Error GoTo 0
  Exit Property

errSub:
  Resume Next 
End Property

Le Setter de cet attribut stocke le nom de la station et de l'utilisateur. Pour rendre sa valeur unique, nous utilisons l'astuce d'ajouter la date/heure/minute/seconde au format Double, son format natif de stockage, auquel nous enlevons le séparateur décimal.

En voici un exemple :

 
Sélectionnez
PC-WINDOWS7;fabrice;412348217708333

Ce nouveau nom d'utilisateur unique sera inscrit dans le fichier « lock » où l'application ira le contrôler.

Le Getter est construit sur le même modèle.

 
Sélectionnez
Public Property Get UtilisateurLocal() As String
' renvoie l'utilisateur local si défini
On Error GoTo errSub
' renvoie la valeur de l'attribut demandé
Dim db As DAO.Database
Dim rst As DAO.Recordset

Set db = CurrentDb
Set rst = db.OpenRecordset("tIParametres", dbOpenSnapshot)
rst.FindFirst "Parametre='UtilisateurLocal'"
If Not rst.NoMatch Then
   UtilisateurLocal = Nz(rst.Fields("Valeur"), "")
Else
   UtilisateurLocal = ""
End If
rst.Close
ExitSub:
  Set rst = Nothing
  Set db = Nothing
  On Error GoTo 0
  Exit Property

errSub:
    GoTo ExitSub
End Property
End Property

Attention ! Dans le cas où il n'y pas d'utilisateur enregistré, ce qui ne devrait pas se produire, on utilise NZ() pour éviter une erreur de typage au retour de la valeur.

V-F-3. Le chemin local de la Dropbox - CheminPartage

Pour le chemin de la Dropbox, le répertoire contenant la dorsale, nous allons utiliser la même méthode que précédemment.

 
Sélectionnez
Public Property Let CheminPartage(vChemin As String)
' enregistre le chemin de partage
On Error GoTo errSub

Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tIParametres", dbOpenDynaset)
rst.FindFirst "Parametre='CheminPartage'"
If Not rst.NoMatch Then
   rst.Edit ' enregistre le chemin de partage
   rst.Fields(2) = vChemin
   rst.Update
Else
   rst.AddNew  ' crée le paramètre
   rst.Fields(1) = "CheminPartage"
   rst.Fields(2) = vChemin
   rst.Update
End If
' stockage du chemin pour la classe
vCheminPartage = vChemin
rst.Close
ExitSub:
  Set rst = Nothing
  Set db = Nothing
  On Error GoTo 0
  Exit Property

errSub:
  Resume Next
End Property

Le Getter est similaire à la différence près que s'il est connu, on ne va pas le chercher.

 
Sélectionnez
Public Property Get CheminPartage() As String
' renvoie le chemin de partage si déjà défini
On Error GoTo errSub

If Len(vCheminPartage) <> 0 Then
   CheminPartage = vCheminPartage
   Exit Property
End If

Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("tIParametres", dbOpenSnapshot)
rst.FindFirst "Parametre='CheminPartage'"
If Not rst.NoMatch Then
   CheminPartage = Nz(rst.Fields("Valeur"), "")
Else
   CheminPartage = ""
End If

rst.Close

ExitSub:
  Set rst = Nothing
  Set db = Nothing
  On Error GoTo 0
  Exit Property

errSub:
    GoTo ExitSub
End Property

V-F-4. L'utilisateur connecté - UtilisateurConnecte

Il est inutile de stocker l'utilisateur connecté. Un Getter suffira largement pour cet attribut.

Pour le connaître, on ouvre le fichier « lock » et on lit la seule ligne présente.

 
Sélectionnez
Public Property Get UtilisateurConnecte() As String
' retourne l'utilisateur qui est connecté actuellement
' celui-ci n'est pas forcément l'utilisateur local
On Error Resume Next ' une erreur peut se produire si le fichier lock
                     ' est fermé dans l'intervalle
    Dim vFile As Long
    Dim strLigne As String
    Dim strUtilisateur() As String
    
    If Dir(vCheminPartage & cNomFichier, vbNormal) <> "" Then
        vFile = FreeFile
        Open vCheminPartage & cNomFichier For Input As vFile
        Line Input #vFile, strLigne
        Close #vFile        ' Ferme le fichier.
    End If
    
    strUtilisateur = Split(strLigne, ";")
    UtilisateurConnecte = strUtilisateur(0) & ";" & strUtilisateur(1)
    
End Property 

Comme l'utilisateur local, le connecté est composé du nom de la station, du nom de l'utilisateurWindows et du numéro date/heure/minute/seconde sans caractère décimal.

Nous ne prenons que les deux premiers paramètres soit le nom de la station et de l'utilisateur. Notez que vous pouvez aller plus loin en testant la durée de la connexion. Cela peut vous renseigner sur un éventuel problème de libération de l'application.

V-F-5. La détection de l'utilisation de l'application par un tiers - Occupe

Cet attribut ne possède qu'un Getter. En effet, il n'y pas de stockage possible puisque c'est la photographie à un instant T de l'état de l'application.

 
Sélectionnez
Public Property Get Occupe() As Boolean
' Renvoie vrai si le fichier de lock existe
' et que l'utilisateur n'est pas le local
Dim vOccupe As Boolean
    vOccupe = Dir(vCheminPartage & cNomFichier, vbNormal) <> ""
    If vOccupe Then
       If UtilisateurConnecte = UtilisateurLocal Then
          vOccupe = False ' c'est la même connexion
       End If
    End If
    Occupe = vOccupe
End Property

Pour déterminer si l'application est occupée, on teste l'existence du fichier « lock » et si l'utilisateur connecté est différent de l'utilisateur local.

V-F-6. La détection des conflits - Conflit

Pour détecter un conflit, il faut tester l'existence d'une copie de la base effectuée par le serveur Dropbox.

La copie se nommera ainsi :

image

Nom de la dorsale (copie de Nom de la station en conflit Date au format anglo-saxon).accdb

Un Dir donnera ceci :

 
Sélectionnez
Dir *Pc-windows7 en conflit 2012-11-21.accdb

En voici l'équivalent avec l'attribut de la classe.

 
Sélectionnez
Public Property Get Conflit() As Boolean
On Error GoTo errSub
Conflit = Dir(CDropb.CheminPartage & "*" & CDropb.StationLocale & " en conflit " & Format(Date, "yyyy-mm-dd") & ").accdb") <> ""
ExitSub:
  On Error GoTo 0
  Exit Property
errSub:
    GoTo ExitSub
End Property

Cet attribut est appelé depuis un formulaire muni d'un timer.

V-G. Les méthodes

Il n'y a que deux méthodes à mettre en place pour parfaire la classe.

  • Création du fichier  « lock ».
  • Effacement du fichier « lock ».

Rien ne vous empêche de l'étoffer suivant vos besoins personnels.

V-G-1. Création du fichier - CreerFichier

On crée le fichier « lock » simplement à partir d'un Open. On y stocke l'utilisateur local et la date/heure de connexion.

 
Sélectionnez
Public Sub CreerFichier()
' création du fichier de lock
' composé de l'utilisateur local + date heure de connexion
    Dim vFile As Long
    Dim strLigne As String
    vFile = FreeFile
    strLigne = UtilisateurLocal & ";" & Format(Now(), "dddd dd mmmm yyyy hh:mm:ss")

    Open vCheminPartage & cNomFichier For Append As vFile
    Print #vFile, strLigne
    Close #vFile        ' Ferme le fichier.

End Sub

V-G-2. Effacement du fichier Lock - EffacerFichier

L'effacement comporte une condition. Les utilisateurs, le local et le connecté doivent être les mêmes pour pouvoir supprimer le fichier.

 
Sélectionnez
Private Sub EffacerFichier()
' efface le fichier (lors de la libération)
' uniquement si l'utilisateur actuel est l'utilisateur local
    If UtilisateurConnecte = UtilisateurLocal Then
       Kill vCheminPartage & cNomFichier
    End If
End Sub

Cette méthode est appelée lorsque la classe est déchargée.

VI. Mise en œuvre de la classe CCloud

Tout d'abord il faut la déclarer dans l'en-tête de module pour qu'elle vive tout le temps de l'activité de l'application.

 
Sélectionnez
Option Compare Database
Option Explicit
Public CDropb As New CCloud

Ensuite, dans une procédure appelée au démarrage, on lance la procédure d'attachement automatique qui retourne le chemin.

 
Sélectionnez
    CDropb.CheminPartage = pGestionTables.fgAttache  ' attache les tables et renvoie le chemin de la Dorsale

Dans la procédure d'attachement, les variables globales sont :

  • strLstTable contient la liste des tables à attacher ;
  • strFichierData contient le nom de la dorsale ;
  • strPassWordBD contient le mot de passe pour l'attache.
 
Sélectionnez
Global Const strlstTable As String = "tTable1;tTable2;tTable3"
' nom du fichier de base de données à attacher
Global Const strFichierData As String = "AgaData01.accdb"
Global Const strPassWordBD As String = "monmotdepasse"

Function fgAttache() As String
'--------------------------------------------------------------------------------
' Procedure : pgAttache
' Author    : Fabrice CONSTANS (MVP)
' Date      : 18 / 07 / 2012
' Purpose   : Procédure standard d'attachement des tables
'               Vérifie l'attachement ou le refait
' Parametres: Utilise strlstTable qui contient les tables
'                     strFichierData qui contient le fichier des tables
' Return    : chemin de la dorsale
'----------------------------------------------------------------------------------
'
    On Error GoTo err_demarrage

    Dim db As DAO.Database
    Dim rst As Recordset        ' pour le test d'attache
    Dim lstTable() As String    ' contient les tables
    Dim i As Integer            ' the Compteur
    Dim tbl As TableDef
    Dim strChemin As String

    ' utilise le chemin de la table des paramètres
    strChemin = CDropb.CheminPartage & strFichierData
    ' si le fichier Dorsal n'existe pas on le demande
    If Not FichierExiste(strChemin) Then
        strChemin = fIndiqueFichier(strChemin)
    Else
        strChemin = strChemin
    End If

    ' sauve le chemin dans la table des paramètres internes
    CDropb.CheminPartage = fFichierExt(strChemin, eChemin)
    ' si user local n'est pas user courant
    If CDropb.Occupe Then
        MsgBox "La base est actuellement utilisée par : " & CDropb.UtilisateurConnecte & vbCrLf & "Faites une tentative ultérieurement.", vbExclamation + vbOKOnly, fVersionProduit()
        ' libération de la classe
        Set CDropb = Nothing
        DoCmd.Quit  'quitte l'application
    End If
    ' Création du fichier, réservation de l'application
    CDropb.CreerFichier

    ' à partir de  on commence les procédures d'attachement sur la dorsale
    lstTable = Split(strlstTable, ";")      ' la liste des tables à traiter

    Set db = DBEngine(0)(0)
    For i = 0 To UBound(lstTable)           ' liste les tables et tente l'ouverture
        Set rst = db.OpenRecordset(lstTable(i), dbOpenSnapshot)
        rst.Close
        Set rst = Nothing
    Next

    db.TableDefs.Refresh
    If strChemin = "" Then
        strChemin = db.TableDefs(lstTable(0)).Connect
        strChemin = Right(strChemin, Len(strChemin) - InStr(1, strChemin, ";DATABASE=") - 9)
    End If
    fgAttache = fFichierExt(strChemin, eChemin)
    Exit Function

err_demarrage:

    If Err.Number = 3078 Then  ' ne trouve pas la table
        Set tbl = db.CreateTableDef(lstTable(i))
        tbl.Connect = "MS Access;PWD=" & strPassWordBD & ";DATABASE=" & strChemin    'Me.CheminBD '";DATABASE=" &
        tbl.SourceTableName = lstTable(i)
        db.TableDefs.Append tbl
        db.TableDefs(tbl.Name).RefreshLink
        Resume
    End If

    For Each tbl In db.TableDefs
        If tbl.Attributes = dbAttachedTable Then
            tbl.Connect = "MS Access;PWD=" & strPassWordBD & ";DATABASE=" & strChemin
            db.TableDefs(tbl.Name).RefreshLink
        End If
    Next
    Resume
End Function

Il y a plusieurs lignes faisant référence à notre classe.

  • Récupération du chemin de la Dropbox et du nom de la dorsale.
 
Sélectionnez
    strChemin = CDropb.CheminPartage & strFichierData
  • Si l'application est utilisée par un tiers. On affiche le message d'avertissement, on libère la classe et on quitte l'application.
 
Sélectionnez
    If CDropb.Occupe Then
        MsgBox "La base est actuellement utilisée par : " & CDropb.UtilisateurConnecte & vbCrLf & "Faites une tentative ultérieurement.", vbExclamation + vbOKOnly, fVersionProduit()
        ' libération de la classe
        Set CDropb = Nothing
        DoCmd.Quit  'quitte l'application
    End If
  • On crée le fichier « lock ».
 
Sélectionnez
    CDropb.CreerFichier

L'application peut poursuivre son activité.

VI-A. Procédure à la fermeture de l'application

À la fermeture de l'application, il faut libérer l'application en supprimant le fichier « lock ».

VI-A-1. Événement Sur Fermeture

Sur cet événement, on ouvre un formulaire d'attente et de contrôle des conflits. Le mode acDialog stoppe l'exécution jusqu'à la fermeture du formulaire.

 
Sélectionnez
Private Sub Form_Close()
    DoCmd.OpenForm "fAttente", , , , , acDialog
    Set CDropb = Nothing
    Doevents
    DoCmd.Quit
End Sub

VII. Formulaire fAttente

Le formulaire fAttente permet de faire patienter l'utilisateur pendant que l'application vérifie, à intervalles réguliers, les conflits matérialisés par la présence d'une copie du fichier dorsal.

J'ai choisi cette représentation, libre à vous de faire la vôtre !

image

VII-A. Les contrôles

Ce formulaire est composé des contrôles suivants :

  • une cadre qui fait office de barre de progression ;
  • une zone de titre ;
  • une zone de message ;
  • un bouton de commande.
Nom Visible Contenu Type
Barre oui Couleur Cadre
TxtMsg non Vide Étiquette
btnFermer non Quitter Bouton de commande
EtiqTitre oui Vérification des conflits éventuels Étiquette

VII-B. Le code

Nous avons besoin d'une variable locale pour ce module. Elle est donc déclarée dans l'en-tête du module. Cette variable permettra de faire évoluer la barre de progression.

 
Sélectionnez
Option Compare Database
Option Explicit
Dim i As Long 'stocke le pas de progression pour la barre

VII-B-1. Sur Ouverture

Sur l'événement d'ouverture, nous initialisons la variable à 500 qui est la valeur du pas de progression de la barre.

 
Sélectionnez
Private Sub Form_Open(Cancel As Integer)
i = 500 'pas de progression
End Sub

VII-B-2. Le bouton Fermer

Il s'agit du bouton qui permettra de fermer le formulaire en cas de détection de conflit et d'affichage du message.

 
Sélectionnez
Private Sub btnFermer_Click()
    DoCmd.Close
End Sub

VII-B-3. Le Timer

C'est le cœur du formulaire. C'est cet événement qui, déclenché à intervalles réguliers, testera s'il y a conflit et affichera le message.

 
Sélectionnez
Private Sub Form_Timer()

If Me.Barre.Width > i Then ' si la barre n'a pas atteint son dernier pas
    If Not CDropb.Conflit Then  ' si pas de conflit
       Me.Barre.Width = Me.Barre.Width - i  'progression de la barre
    Else
       ' si conflit
       Me.TxtMsg.Caption = "Vous avez créé un conflit d'écriture avec un autre utilisateur."
       Me.btnFermer.Visible = True 'on affiche le bouton
       Me.TxtMsg.Visible = True    ' on affiche le message
       Me.Barre.Visible = False    ' on cache la barre pour
       Me.TimerInterval = 0        ' on arrête le timer
    End If
Else
    DoCmd.Close ' on ferme automatiquement le formulaire si la progression est finie
End If

End Sub

VIII. Annexe

Dans ce chapitre, sont recensées les fonctions et procédures qui sont utilisées accessoirement dans la solution.

VIII-A. Fonction fHasBackSlash

Cette fonction renvoie la valeur passée avec un \ de terminaison.

 
Sélectionnez
Function fHasBackSlash(vlChemin As Variant) As String
'---------------------------------------------------------------------------------
' Procedure : fHasBackSlash
' Author    : Fabrice CONSTANS
' Date      : 01 / 06 / 2012
' Purpose   : s'il n'y a pas de backslash à la fin d'un chemin passé en référence, l'ajoute
' Parametres:
' - vlchemin    = le chemin à modifier
'--------------------------------------------------------------------------------
    On Error GoTo ExcfHasBackSlash
    ' teste si le caractère de la fin est un \
    If Right(Trim(vlChemin), 1) <> "\" Then
        ' l'ajoute
        fHasBackSlash = Trim(vlChemin) & "\"
    Else
        ' renvoie sans espace
        fHasBackSlash = Trim(vlChemin)
    End If
    On Error GoTo 0
    Exit Function

ExcfHasBackSlash:
    If Err.Number = 94 Then
        fHasBackSlash = "c:\"
        Exit Function
    End If

errSub:
    fHasBackSlash = False    ' une erreur quelconque se produit
End Function

VIII-B. Stockage documentaire

Vous pouvez indiquer le chemin de la Dropbox pour y stocker des documents liés à l'application.

 
Sélectionnez
vgStrRepertoireDocument = fHasBackSlash(CDropb.CheminPartage) & "Documents Amap\"

La fonction fHasBackSlash() teste et ajoute l'antislash en fin de chaîne. Elle est présente dans l'annexe en fin du tutoriel.

IX. Conclusion

Comme vous l'avez constaté dans ce tutoriel, le Cloud Storage, malgré sa puissance, n'est pas adapté au fonctionnement des fichiers de données de Microsoft ACCESS lors d'accès concurrents. Ce que l'on économise financièrement, en faisant l'impasse sur une véritable solution de base de données hébergée, se paye en rigidité de fonctionnement et en développement de techniques de prévention.

Si vous souhaitez une vraie solution de base de données partagée, tournez-vous plutôt vers SQL Azure. Ce service est payant mais vous n'aurez pas les inconvénients du Cloud Storage.

XI. Remerciement

Je remercie Pierre Fauconnier et f-leb pour leurs conseils durant la rédaction de ce tutoriel, Claude Leloup et Zoom61 pour leurs corrections orthographiques.