Access-Frontend automatisch aktualisieren

Wenn man allein mit einer Access-Anwendung arbeitet, die man währenddessen weiterentwickelt, ist man immer auf dem aktuellsten Stand. Wer eine Anwendung auf die Arbeitsplätze seiner eigenen Mitarbeiter oder sogar die der Mitarbeiter eines Kunden installiert hat, muss schon ein wenig Aufwand betreiben, wenn jeder immer die aktuellste Version der Anwendung vorfinden soll. Die alte Version muss entfernt und die neue installiert werden. Hier kann man die Benutzer informieren, sodass diese die notwendigen Schritte manuell durchführen oder man erledigt dies selbst. Praktischer wäre es jedoch, wenn die Anwendung selbst erkennen würde, wenn es eine neue Version gibt, und dann selbstständig ein Update durchführt. Das geht natürlich nicht, weil sie sich nicht selbst löschen und durch eine neue Version ersetzen kann, während sie läuft. Also benötigen wir einen kleinen Workaround: Wir stellen dem Öffnen der eigentlichen Anwendung eine weitere Access-Anwendung voran, die auf Updates prüft und diese durchführt und erst dann die eigentliche Anwendung aufruft. Alle notwendigen Schritte erläutern wir in diesem Beitrag.

Varianten von Frontend-Updatern

Eine solche vorgeschaltete Anwendung nennt man auch Frontend-Updater. Dabei muss es sich nicht zwingend um eine Access-Anwendung handeln – wenn man die notwendigen Programmierkenntnisse und Tools handelt, kann man dies auch in Form einer Exe-Datei auf Basis VB6, VB.NET oder twinBASIC erledigen.

Die Aufgabe bleibt jedoch gleich: Der Frontend-Updater soll vor der eigentlichen Access-Anwendung geöffnet werden und prüfen, ob die derzeit auf dem Rechner befindliche Frontend-Datenbank die aktuellste verfügbare Version ist. Ist diese Bedingung erfüllt, kann die Frontend-Datenbank geöffnet werden. Falls nicht, soll die vorhandene Frontend-Datenbank gelöscht (oder zumindest umbenannt) werden und die neue Version der Frontend-Datenbank soll stattdessen in das entsprechende Verzeichnis kopiert werden. Danach wird entweder die vorhandene oder die neu hinzugefügte Frontend-Datenbank gestartet.

Hier ergeben sich einige technische Herausforderungen:

  • Wie finden wir heraus, ob sich die aktuellste Version auf dem aktuellen Rechner befindet?
  • Wenn nicht – wie kopieren wir die aktuellere Version auf den Rechner und löschen die vorhandene Version oder benennen diese um?
  • Wie können wir von einer Access-Datenbank aus eine andere Access-Datenbank starten?
  • Welche Voraussetzungen sind für ein solches Vorgehen überhaupt erforderlich?

Voraussetzungen für ein automatisches Update des Frontends

Ein Update kann man nicht in jedem Fall ohne Weiteres über die vorhandene Version kopieren und dann einfach weiterarbeiten. Die erste Voraussetzung ist, dass die Daten, die von den Frontends aus bearbeitet werden, sich in einer Backend-Datenbank befinden. Das sollte aber im Mehrbenutzerbetrieb ohnehin der Fall sein. Gegebenenfalls befinden sich die Tabellen mit den Geschäftsdaten sogar in einer SQL Server-Datenbank.

Die zweite Voraussetzung ist, dass sich auch keine benutzerdefinierten Daten in der Frontend-Datenbank befinden. Es kommt beispielsweise oft vor, dass der Benutzer Optionen für die Anwendung selbst einstellen kann. So findet er beim Öffnen der Anwendung auf seinem Desktop-Rechner immer die Konfiguration vor, die er selbst eingestellt hat. Solche Daten speichert man üblicherweise in einer oder mehreren Optionen-Tabellen in der Frontend-Datenbank.

Um dies zu umgehen, gibt es beispielsweise die folgenden Alternativen:

  • Die Einstellungen für den jeweiligen Benutzer werden in einer Optionentabelle im Backend auf dem Server gespeichert, wobei dort noch ein Feld hinzuzufügen ist, dass kenntlich macht, zu welchem Benutzer die Einstellungen gehören.
  • Die Einstellungen werden in einem weiteren Backend gespeichert, das sich im gleichen Verzeichnis wie das Frontend des Benutzers befindet. Auf diese Weise können wir das Frontend austauschen, ohne dass die Einstellungen des Benutzers verlorengehen. Wir müssen nur sicherstellen, dass sich eine neue Version des Frontends automatisch wieder mit dem Backend mit den Optionentabellen verknüpft.
  • Oder wir speichern Optionen gar nicht in einer Tabelle, sondern in der Registry in dem für den aktuellen Benutzer für VBA-Anwendungen vorgesehenen Bereich. Wie das gelingt, zeigen wir beispielsweise im Beitrag Optionen einfach in der Registry speichern (www.access-im-unternehmen.de/1512).

Information über die aktuelle Version speichern

Wenn wir vergleichen wollen, ob die auf dem Server liegende Version des Datenbank-Frontends aktueller ist, als die vorliegende Version, müssen wir irgendwo in den Datenbankdateien die Versionsnummer speichern.

Zunächst einmal schlagen wir vor, hier einfach eine durchlaufende Nummer zu verwenden. Auf diese Weise können wir am einfachsten vergleichen, welche Version die aktuellere ist.

Dann benötigen wir einen geeigneten Ort für diese Information. Dazu gibt es mindestens die folgenden beiden Vorschläge:

  • Speichern der Versionsnummer in einer Optionentabelle der Frontends
  • Speichern der Versionsnummer in einer Eigenschaft der Access-Datenbank

Beide Informationen können wir einfach per VBA abfragen und manuell oder per Code setzen. Später beschreiben wir die technische Umsetzung.

Prüfen, ob die vorliegende Version die aktuellste Version ist

Wenn sich sowohl im vorliegenden Frontend als auch in der Version auf dem Server die Information über die Version entweder in einer Tabelle oder in einer Eigenschaft befindet, können wir diese einfach einlesen und vergleichen. In beiden Fällen müssen wir von der Frontend-Updater-Anwendung aus per VBA auf die jeweilige Version zugreifen. Wenn wir, wie oben vorgeschlagen, eine einfache Versionsnummer wählen, können wir diese auch ganz einfach vergleichen und entscheiden, ob die Version vom Server die aktuelle Version ersetzen soll.

Umbenennen/Löschen der alten Version und Kopieren der neuen Version

Wenn wir herausgefunden haben, dass sich auf dem Server eine aktuellere Version der Frontend-Datenbank befindet, sind die folgenden Schritte durchzuführen:

  • Löschen oder Umbenennen der vorliegenden Version, wobei wir das Umbenennen bevorzugen würden. Auf diese Weise könnten wir die vorliegende Version wiederherstellen, wenn das Update aus irgendeinem Grund nicht funktioniert. Beim Umbenennen könnten wir einfach die aktuelle Version hinten an den Dateinamen anhängen. Das Umbenennen oder auch das Löschen lässt sich per VBA realisieren.
  • Kopieren der neueren Version vom Server auf den aktuellen Rechner. Dies gelingt ebenfalls mit einem einfachen VBA-Befehl.

Starten der eigentlichen Datenbank von der Updater-Anwendung aus

Schließlich fehlt noch der Schritt, der bei jedem Start durchgeführt werden muss: Die Frontend-Updater-Datenbank muss die eigentliche Datenbank starten, unabhängig davon, ob diese zuvor aktualisiert wurde oder nicht.

Testszenario

Zum Testen verwenden wir zwei gleiche Datenbanken, die lediglich die Tabelle mit der Versionsnummer enthalten. Die zu prüfende und gegebenenfalls zu ersetzende Datenbank liegt in einem Verzeichnis mit der Frontend-Updater-Datenbank. Statt eines Servers verwenden wir ein Verzeichnis namens Server, das sich im gleichen Verzeichnis wie die beiden zuvor genannten Datenbankdateien befindet.

Die Struktur sieht also wie folgt aus:

Frontend.accdb
FrontendUpdater.accdb
Server
   Frontend.accdb (neuere Version)

Die Frontent.accdb-Datenbanken enthalten eine Tabelle namens tblVersion mit einem einzigen Feld mit dem Datentyp Zahl und dem Namen Version.

Nun bearbeiten wir die Datenbank FrontendUpdater.accdb, damit diese die notwendige Prüfung durchführt, gegebenenfalls das Frontend ersetzt und dieses dann startet.

Code beim Starten automatisch ausführen

Die Voraussetzung für eine automatische Prüfung beim Start der Datenbank FrontendUpdater.accdb ist, dass diese beim Starten den entsprechenden Code ausführt. Das können wir am einfachsten mit einem AutoExec-Makro realisieren, der wir den Namen der zu startenden VBA-Funktion für die Makroaktion AusführenCode übergeben (siehe Bild 1).

AutoExec-Makro, das beim Start automatisch ausgeführt wird

Bild 1: AutoExec-Makro, das beim Start automatisch ausgeführt wird

Die Funktion StartDb können wir testhalber zunächst wie folgt formulieren:

Public Function StartDb()
     MsgBox "Start"
End Function

Starten wir die Datenbank nun neu, sollte das Meldungsfenster erscheinen.

Version des vorliegenden Frontends einlesen

Mit der Funktion GetVersion aus Listing 1, der wir den Pfad zu der zu untersuchenden Datenbankdatei übergeben, erstellen wir ein Database-Objekt auf Basis der mit OpenDatabase geöffneten Datenbankdatei. Für diese öffnen wir ein Recordset auf Basis der Tabelle tblVersion. Enthält diese zumindest einen Datensatz, lesen wir daraus die Version aus und geben diese als Funktionswert zurück. Anderenfalls geben wir eine entsprechende Meldung aus.

Public Function GetVersion(strFrontend As String) As Long
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Set db = OpenDatabase(strFrontend)
     Set rst = db.OpenRecordset("SELECT Version FROM tblVersion")
     If Not rst.EOF Then
         GetVersion = rst!Version
     Else
         MsgBox "Keine Versionsnummer in ''" & strFrontend & "'' gefunden."
     End If
End Function

Listing 1: Einlesen der Version, längere Variante

Die zweite Version von GetVersion ist noch ein wenig kürzer (siehe Listing 2). Hier integrieren wir den Namen der zu untersuchenden Datenbank in die OpenRecordset-Methode. Dadurch sparen wir das Initialisieren des Database-Objekts für die Frontend-Datenbank.

Public Function GetVersion1(strFrontend As String)
     Dim rst As DAO.Recordset
     Set rst = CurrentDb.OpenRecordset("SELECT Version FROM tblVersion IN ''" & strFrontend & "''")
     If Not rst.EOF Then
         GetVersion1 = rst!Version
     Else
         MsgBox "Keine Versionsnummer in ''" & strFrontend & "'' gefunden."
     End If
End Function

Listing 2: Einlesen der Version, kürzere Variante

Egal, welche Version wir wählen – wir können damit sowohl die Version des vorliegenden Frontends als auch die der Version vom Server ermitteln und dann in per If…Then-Bedingung ermitteln, welche Aktion durchzuführen ist. Dazu nutzen wir die neue Version der Prozedur StartDb aus Listing 3.

Public Function StartDb()
     Dim strCurrent As String
     Dim strServer As String
     Dim lngVersionCurrent As Long
     Dim lngVersionServer As Long
     strCurrent = CurrentProject.Path & "\Frontend.accdb"
     strServer = CurrentProject.Path & "\Server\Frontend.accdb"
     lngVersionCurrent = GetVersion(strCurrent)
     lngVersionServer = GetVersion1(strServer)
     If lngVersionCurrent < lngVersionServer Then
         MsgBox "Muss von Version ''" & lngVersionCurrent & "'' auf Version ''" & lngVersionServer & "'' aktualisiert werden."
     Else
         MsgBox "Keine Aktualisierung nötig."
     End If
End Function

Listing 3: Vergleichen der Version und Ausgabe der zu treffenden Maßnahme

Sie schreibt die Pfade zu den zu untersuchenden Frontends in die Variablen strCurrent und strServer. Dann nutzt sie die Funktion GetVersion, um die Versionen zu den beiden Dateien zu ermitteln und in die Variablen lngVersionCurrent und lngVersionServer zu schreiben. Schließlich prüft sie, ob das Frontend vom Server eine größere Versionsnummer hat als das vorliegende und gibt eine entsprechende Meldung aus.

Bevor wir uns ansehen, wie wir das Frontend ersetzen, erstellen wir noch schnell eine kleine Hilfsprozedur, mit der wir die Versionsstände der Frontends jeweils auf 1 und 2 einstellen. So brauchen wir diese nicht immer manuell einzustellen:

Public Function SetVersions()
     Dim strFrontend As String
     strFrontend = CurrentProject.Path & "\Frontend.accdb"
     CurrentDb.Execute "UPDATE tblVersion IN ''" _
         & strFrontend & "'' SET Version = 1", dbFailOnError
     strFrontend = CurrentProject.Path _
         & "\Server\Frontend.accdb"
     CurrentDb.Execute "UPDATE tblVersion IN ''" _
         & strFrontend & "'' SET Version = 2", dbFailOnError
End Function

Ersetzen der vorliegenden Version durch die neue Version

In der Funktion StartDb ersetzen wir die Anweisung im If-Teil der If…Then-Bedingung wie folgt:

Public Function StartDb()
     ...
     If lngVersionCurrent < lngVersionServer Then
         ReplaceFrontend strCurrent, strServer, _
             lngVersionCurrent, lngVersionServer
     Else
         ...
     End If
End Function

Wir rufen also eine Prozedur namens ReplaceFrontend auf, der wir den Pfad zu dem aktuellen Frontend, den Pfad zum neuen Frontend sowie die Versionen des aktuellen und des neuen Frontends als Parameter übergeben (siehe Listing 4).

Public Sub ReplaceFrontend(strCurrent As String, strServer As String, lngVersionCurrent As Long, lngVersionServer As Long)
     Dim strCopy As String
     MsgBox "Muss von Version ''" & lngVersionCurrent & "'' auf Version ''" & lngVersionServer & "'' aktualisiert werden."
     strCopy = Replace(strCurrent, ".accdb", "_" & lngVersionCurrent & ".accdb")
     Kill strCopy
     Name strCurrent As strCopy
     FileCopy strServer, strCurrent
End Sub

Listing 4: Sichern der aktuellen Version und ersetzen durch die neue Version

Wir haben die Meldung über das notwendige Ersetzen des Frontends aus StartDb in diese Prozedur übertragen. Dann ermitteln wir den Namen der Sicherheitskopie, der aus dem Namen der aktuellen Version und dem Zusatz der bisherige Version entspricht. Aus Frontend.accdb wird für die Version 1 beispielsweise Frontend_1.accdb.

Wir löschen eine eventuell bereits vorhandene Datei dieses Namens mit der Kill-Anweisung und benennen die aktuelle Version mit der Name-Anweisung in den soeben ermittelten Dateinamen um. Dann können wir die FileCopy-Anweisung nutzen, um das Frontend vom Server auf den Client zu übertragen.

Starten des aktuellen Frontends

Nachdem wir entweder herausgefunden haben, dass wir bereits mit der aktuellsten Version des Frontends arbeiten oder diese auf den aktuellen Stand gebracht haben, können wir dieses Starten.

Das erledigen wir mit der folgenden Prozedur:

Public Sub StartFrontend(strFrontend As String)
     Dim objAccess As Access.Application
     Set objAccess = _
         CreateObject("Access.Application")
     With objAccess
         .OpenCurrentDatabase strFrontend
         .Visible = True
         .UserControl = True
     End With
End Sub

Man könnte meinen, dass es auch ein einfacher Aufruf der Shell-Methode wie folgt tun würde:

Shell "MSAccess.exe " & strFrontend

Allerdings ruft dieser nur die angegebene Datenbankdatei auf, aber holt diese nicht in den Vordergrund. Das heißt, dass der Benutzer sie nicht direkt sieht, was verwirrend sein könnte. Also wählen wir den obigen Ansatz. Hier erstellen wir eine neue Access-Instanz mit dem Typ Access.Application. Mit dieser öffnen wir mit OpenCurrentDatabase die mit strFrontend übergebene Datenbankdatei. Dann machen wir diese Instanz sichtbar und aktivieren sie durch das Setzen der Eigenschaft UserControl auf den Wert True.

Frontend-Updater-Datenbank unsichtbar öffnen

Aktuell starten wir die Frontend-Updater-Datenbank FrontendUpdater.accdb noch durch einen Doppelklick. Der Nachteil ist, dass dadurch mehr oder weniger kurz das Access-Fenster angezeigt wird, bevor die eigentliche Anwendung gestartet wird. Das ist an sich kein Problem, sieht aber nicht schön aus.

Abhilfe können wir mit einem kleinen VB-Skript schaffen, das wir in einer Datei namens Start.vbs hinterlegen (siehe Bild 2).

VB-Skript zum Starten der Frontend-Updater-Datenbank

Bild 2: VB-Skript zum Starten der Frontend-Updater-Datenbank

In VB-Skript können wir beim Deklarieren keine Dateitypen angeben, daher sieht das Folgende etwas ungewohnt aus:

Dim fso
Dim strFolder
Dim objAccess
Dim strFrontendUpdater
Set fso = CreateObject("Scripting.FileSystemObject")
strFolder = fso.GetParentFolderName(WScript.ScriptFullName)
strFrontendUpdater = strFolder & "\FrontendUpdater.accdb"
Set objAccess = CreateObject("Access.Application")
objAccess.OpenCurrentDatabase strFrontendUpdater

Im ersten Teil ermitteln wir mit dem FileSystemObject und seiner Funktion GetParentFolderName das Verzeichnis des Skripts, das sich im gleichen Verzeichnis wie die Datei FrontendUpdater.accdb befinden sollte. Damit setzen wir in strFrontendUpdater den vollständigen Pfad zur zu öffnenden Datenbankdatei zusammen. Wir erstellen dann eine Access-Instanz und öffnen mit OpenCurrentDatabase die Datenbankdatei aus strFrontendUpdater. Da wir hier nicht die Eigenschaft Visible auf True einstellen, wird das Access-Fenster gar nicht erst eingeblendet und. So kann das AutoExec-Makro unsichtbar die Funktion StartDb aufrufen, die den Update-Prozess und den Start des Frontends erledigt.

Der Benutzer soll jetzt also nicht mehr die Datei Frontend.accdb starten, sondern Start.vbs.

Schreibe einen Kommentar