Verweise beim Start prüfen

Beim Einsatz von Access-Anwendungen gibt es manchmal Probleme, weil die Verweise auf Bibliotheken nicht korrekt gesetzt sind. Dann werden plötzlich VBA-Funktionen wie “Left” oder “Right” als fehlerhaft bewertet. Der Benutzer steht dann dumm da, weil er nicht weiß, was zu tun ist. Dieser Beitrag zeigt, wie Sie das Problem nachstellen können und welche Lösungsmöglichkeiten es gibt – von der manuellen Variante bis zur automatischen Korrektur des Verweises beim Start der Anwendung.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1904_VerweiseBeimStart.accdb.

Fehlerhafter Verweis

Probleme wie die oben genannten treten meist auf, wenn Sie eine Anwendung auf Ihrem Rechner entwickeln und diese dann an einen Benutzer weitergeben, auf dessen Rechner nicht alle per Verweis referenzierten Bibliotheken vorliegen – oder diese nicht in der richtigen Version vorliegen.

Verweise finden Sie grundsätzlich im Verweise-Dialog, den Sie vom VBA-Editors aus (zu öffnen mit Strg + G oder Alt + F11) mit dem Menübefehl Extras|Verweise anzeigen. Dieser Dialog zeigt die Liste der eingebundenen Bibliotheken, die bei einer neuen, leeren Access-Anwendung auf Basis von Access 2016 etwa wie in Bild 1 aussieht. Die Bibliotheken hinter diesen vier Einträge sollten überall, wo Access 2016 installiert ist, auch vorhanden sein.

Der Verweise-Dialog von Access

Bild 1: Der Verweise-Dialog von Access

Bei umfangreicheren Anwendungen kommen meist noch Verweise auf weitere Bibliotheken hinzu, zum Beispiel um Word, Excel oder Outlook zu automatisieren, die Datenzugriffs-Bibliothek ADODB zu nutzen oder auch um die Befehle für die Verarbeitung von XML hinzuzufügen.

Wenn Sie nun einen Verweis auf Outlook hinzufügen, die Datenbank auf den Zielrechner übertragen und dann aber Outlook gar nicht auf dem Zielrechner vorliegt, gibt es Probleme wegen des fehlenden Verweises.

Manchmal gibt es auch Probleme, wenn Sie mit einem Verweis auf die Objektbibliothek von Outlook 2016 programmieren und auf dem Zielrechner ist eine ältere Version von Outlook vorhanden.

Manuelle Lösung

Vorausgesetzt, die Bibliothek, auf die der Verweis zeigen soll, ist auf dem Zielrechner installiert und registriert, können Sie wie folgt vorgehen, um den Verweis zu erneuern:

  • öffnen Sie den Verweise-Dialog.
  • Entfernen Sie den mit NICHT VORHANDEN markierten Verweis.
  • Fügen Sie den Verweis auf die gewünschte Bibliothek zur Liste der Verweise hinzu, indem Sie den entsprechenden Eintrag per Haken selektieren.
  • Schließen Sie den Verweise-Dialog.

Danach sollte die Anwendung dann wie gewohnt funktionieren. Eine Ausnahme könnte sein, dass Sie in Ihrer Anwendung tatsächlich Funktionen einer neueren Bibliothek verwenden, die in der älteren, auf dem Zielrechner vorhandenen Version noch nicht verfügbar ist.

Wenn Sie eine Anwendung beim Kunden laufen haben, für die Sie regelmäßig neue Versionen liefern, dann ist es für den Kunden natürlich mühselig, immer die Verweise zu aktualisieren – daher stellen wir nun eine Alternative vor.

Verweise automatisch beim Start aktualisieren

Die Alternative lautet, beim Start einer Anwendung die Verweise zu prüfen und diese gegebenenfalls zu erneuern. Wenn ein Verweis nicht gesetzt werden kann, weil die entsprechende Bibliothek nicht verfügbar ist, soll eine Meldung erscheinen, die den Benutzer darüber informiert, damit dieser mit dem Entwickler der Software herausfinden kann, wo das Problem in diesem Fall liegt.

Zu Beispielzwecken nehmen wir an, dass wir Verweise auf die Bibliotheken für den Zugriff auf die Office-Anwendungen Excel, Outlook und Word hinzufügen sowie einen auf die Bibliothek Microsoft XML, v6.0 (siehe Bild 2).

Verweise-Dialog mit zusätzlichen Verweisen

Bild 2: Verweise-Dialog mit zusätzlichen Verweisen

Bei den mit diesen Verweisen referenzierten Bibliotheken handelt es sich sämtlich um registrierte Bibliotheken, für die es eine GUID gibt. Diese wollen wir nun zunächst ermitteln, indem wir diese per VBA-Routine im Direktbereich des VBA-Editors ausgeben:

Public Sub VerweisePruefenUndErneuern()
    Dim objReference As Reference
    Dim strGUID As String
    For Each objReference In References
        Debug.Print objReference.Name
        Debug.Print objReference.FullPath
        Debug.Print objReference.Guid
    Next objReference
End Sub

Das Ergebnis sieht dann so aus:

VBA
C:\Program Files (x86)\...\VBA7.1\VBE7.DLL
{000204EF-0000-0000-C000-000000000046}
Access
C:\Program Files (x86)\...\MSACC.OLB
{4AFFC9A0-5F99-101B-AF4E-00AA003F0F07}
stdole
C:\Windows\SysWOW64\stdole2.tlb
{00020430-0000-0000-C000-000000000046}
DAO
C:\Program Files (x86)\...\OFFICE16\ACEDAO.DLL
{4AC9E1DA-5BAD-4AC7-86E3-24F4CDCECA28}
Excel
C:\Program Files (x86)\...\EXCEL.EXE
{00020813-0000-0000-C000-000000000046}
Outlook
C:\Program Files (x86)\...\MSOUTL.OLB
{00062FFF-0000-0000-C000-000000000046}
Word
C:\Program Files (x86)\...\MSWORD.OLB
{00020905-0000-0000-C000-000000000046}
MSXML2
C:\Windows\SysWOW64\msxml6.dll
{F5078F18-C551-11D3-89B9-0000F81FE221}

Nun wollen wir ja gar nicht alle Einträge prüfen, sondern nur diejenigen, die nicht eingebaut sind. Das prüfen wir durch eine If…Then-Bedingung, mit der wir den Wert der Eigenschaft BuiltIn untersuchen. Ist diese True, handelt es sich um eine eingebaute Eigenschaft, die wir nicht ersetzen müssen, da diese meist vorhanden sind. Hat BuiltIn den Wert False, müssen wir handeln: Dann könnte es sein, dass ein falscher Verweis zu Fehlern führt. Mit der folgenden geänderten Version der Prozedur VerweisePruefenUndErneuern geben wir nur noch die Verweise aus, die wir erneuern können:

Public Sub VerweisePruefenUndErneuern()
    Dim objReference As Reference
    Dim strGUID As String
    For Each objReference In References
        If objReference.BuiltIn = True Then
            Debug.Print objReference.Name
            Debug.Print objReference.FullPath
            Debug.Print objReference.Guid
        End If
    Next objReference
End Sub

Damit erhalten wir dann ein ähnliches Ergebnis wie weiter oben, nur dass diesmal die eingebauten Verweise nicht berücksichtigt werden.

Was fangen wir nun damit an Wir könnten direkt in dieser Prozedur ein paar Zeilen unterbringen, die dafür sorgen, dass die Verweise auf Gültigkeit überprüft und gegebenenfalls erneuert werden. Das würde dann etwa wie in Listing 1 aussehen. Hier durchlaufen wir wieder alle Reference-Objekte, schließen aber durch die ersten beiden If…Then-Bedingungen zuerst die eingebauten und dann die vorhandenen Verweise aus.

Public Sub VerweisePruefenUndErneuern()
     Dim objReference As Reference
     Dim objReferenceNew As Reference
     Dim strReference As String
     Dim strGUID As String
     For Each objReference In References
         If objReference.BuiltIn = False Then
             If objReference.IsBroken = True Then
                 strGUID = objReference.Guid
                 strReference = objReference.Name
                 References.Remove objReference
                 Set objReferenceNew = References.AddFromGuid(strGUID, 0, 0)
                 If objReference Is Nothing Then
                     MsgBox "Der Verweis auf die Bibliothek '" & strReference & "' fehlt."
                 End If
             End If
         End If
     Next objReference
End Sub

Listing 1: Fehlende Verweise werden direkt erneuert

Sind beide If…Then-Bedingungen wahr, merken wir uns in den Variablen strGUID und strReference die GUID und den Namen der referenzierten Bibliothek. Dann fügen wir die Referenz auf eine Bibliothek über die Methode AddFromGUID wieder zur Liste References hinzu. Dabei übergeben wir als Parameter die GUID der Bibliothek sowie den Wert 0 für die beiden Parameter Major und Minor.

Eine fehlende Bibliothek sollte damit wieder referenziert werden können.

Diese Prozedur rufen wir am besten beim Start der Anwendung auf, damit keine Fehler durch fehlende Verweis auftreten. Wie das gelingt, zeigen wir am Ende des Beitrags.

Benötigte Verweise an anderer Stelle speichern

Das Problem ist nur: Wenn der Benutzer auf irgendeine Weise einen der Verweise entfernt, ohne diesen wieder hinzuzufügen, treten in der Folge Probleme auf an den Stellen, wo im Code Elemente dieser Bibliothek verwendet werden.

Wenn wir dann beim Starten der Anwendung die Prozedur aufrufen, durchläuft diese wieder alle Verweise und prüft die Verweise mit der Eigenschaft IsBroken. Wenn jedoch ein Verweis auf eine Bibliothek gar nicht mehr in der Liste der Verweise enthalten ist, kann er mit der hier vorliegenden Version der Prozedur auch nicht ersetzt werden – die Prozedur erfährt ja gar nicht, das ein Verweis fehlt. Das wird erst später offensichtlich, wenn die Anwendung das erste Mal auf Elemente der mit dem Verweis referenzierten Bibliothek zugreift und dadurch Laufzeitfehler ausgelöst werden.

Also wollen wir, bevor wir die Anwendung an den Benutzer weitergeben, die Verweise, die überprüft werden sollen, in irgendeiner Form speichern. Dabei gibt es zwei Möglichkeiten:

  • Wir speichern die GUIDs fest im Code.
  • Wir legen eine Tabelle an, der wir die Informationen über die Verweise hinzufügen. Diese Tabelle sollte dann im Frontend der Datenbankanwendung liegen, wenn diese in Frontend und Backend aufgeteilt ist.

Die Basis für beide Varianten sieht beispielsweise wie in Listing 2 aus. Diese Funktion nimmt den Parameter strGUID entgegen. Im Direktbereich könnten wir die Funktion wie folgt aufrufen:

Public Function VerweiseErneuern(strGUID As String) As Boolean
     Dim objReference As Reference
     Dim bolReferenceMissing As Boolean
     Dim bolReferenceBroken As Boolean
     bolReferenceBroken = False
     bolReferenceMissing = True
     VerweiseErneuern = True
     For Each objReference In References
         If objReference.Guid = strGUID Then
             bolReferenceMissing = False
             If objReference.IsBroken = True Then
                 bolReferenceBroken = True
             End If
             Exit For
         End If
     Next objReference
     If bolReferenceMissing = True Or bolReferenceBroken = True Then
         On Error Resume Next
         References.Remove objReference
         Set objReference = References.AddFromGuid(strGUID, 0, 0)
         If objReference Is Nothing Then
             VerweiseErneuern = False
         End If
     End If
End Function

Listing 2: Erneuern des Outlook-Verweises

 VerweiseErneuern("{00062FFF-0000-0000-C000-000000000046}")

Die Funktion stellt die Variablen bolReferenceBroken auf False und bolReferenceMissing auf True ein. Dann versucht sie, einen Verweis auf die Bibliothek mit der mit strGUID übergebenen GUID zu finden. Dies geschieht in einer For Each-Schleife über alle Elemente der Auflistung References. Wenn der aktuell mit objReference referenzierte Verweis die gesuchte GUID enthält, können wir die Variable bolReferenceMissing schon einmal auf False einstellen, denn der Verweis ist ja zumindest vorhanden.

Dann prüft die Prozedur mit der Eigenschaft IsBroken noch, ob der Verweis als NICHT VORHANDEN markiert ist. Das ist etwas missverständlich, denn NICHT VORHANDEN gibt ja nicht an, dass der Verweis fehlt, sondern die referenzierte Bibliothek. Jedenfalls stellt die Funktion die Variable bolReferenceBroken auf True ein, wenn IsBroken den Wert True aufweist. Sobald der Verweis passend zu strGUID gefunden wurde, verlassen wir dann auch mit Exit For die Schleife.

objReference enthält somit auch einen Verweis auf das Reference-Objekt. Damit gehen wir in eine If…Then-Bedingung, in der wir prüfen, ob entweder bolReferenceMissing oder bolReferenceBroken den Wert True hat. Das ist nun entweder der Fall, wenn der Verweis gar nicht vorhanden ist oder dieser “broken” ist.

Dann versucht die Funktion, den Verweis mit der Remove-Methode der References-Auflistung zu entfernen und diesen dann über die Methode AddFromGUID erneut hinzuzufügen, wobei ein Verweis auf das neue Reference-Objekt in der Variablen objReference landet – aber auch nur, wenn das Hinzufügen erfolgreich war.

Wenn etwa die Datei hinter der GUID nicht vorhanden ist, gelingt dies nicht und objReference bleibt leer.

Ist objReference danach leer, wird der Wert False mit dem Funktionswert zurückgegeben.

Von einer Prozedur aus könnten wir diese Funktion wie etwa in Listing 3 aufrufen. Dies würde, wenn die Outlook-Bibliothek nicht vorhanden oder fehlerhaft ist, eine Meldung liefern.

Public Sub VerweiseErneuernAufruf()
     Dim strGUID As String
     Dim strReference As String
     strGUID = "{00062FFF-0000-0000-C000-000000000046}"
     strReference = "Microsoft Outlook x.0 Object Library"
     If VerweiseErneuern(strGUID, strReference) = False Then
         MsgBox "Der Verweis auf die Bibliothek '" & strReference & "' ist fehlerhaft und wurde entfernt oder ist nicht " _
             & "vorhanden. Fügen Sie den Verweis auf die Bibliothek manuell hinzu."
     End If
End Sub

Listing 3: Aufruf der Funktion VerweiseErneuern

Reparieren eines Verweises testen

Das wollen wir nun ausprobieren. Solange der Verweis nicht auf eine nicht vorhandene Datei zeigt, was man nach dem öffnen des Verweise-Dialog schnell durch eine Prüfung auf den Hinweis NICHT VORHANDEN prüfen kann.

Ist der Verweis fehlerhaft, sieht der Eintrag im Verweise-Dialog wie in Bild 3 aus.

Der mit NICHT VORHANDEN markierte Eintrag

Bild 3: Der mit NICHT VORHANDEN markierte Eintrag

Gegebenenfalls erhalten Sie beim öffnen des Verweise-Dialogs auch gleich eine Meldung wie in Bild 4.

Hinweis auf ein Verweis-Problem

Bild 4: Hinweis auf ein Verweis-Problem

Wie aber wollen Sie das Reparieren eines Verweises testen, wenn sich auf Ihrem System überhaupt kein Probleme verursachender Verweis befindet Dann können Sie selbst ein solches Problem schaffen. Dazu suchen Sie beispielsweise die Datei MSOUTL.OLB auf, unter Windows 10 und Office 2016 etwa im Verzeichnis C:\Program Files (x86)\Microsoft Office\root\Office16 zu finden (den Pfad finden Sie aber auch über die FullPath-Eigenschaft des Reference-Objekts).

Diese benennen wir einfach in _MSOUTL.OLB um. Die dabei erscheinende Meldung, die nach Administratorberechtigungen verlangt, können Sie bestätigen. Vergessen Sie nicht, die Datei später wieder umzubenennen!

Wenn Sie nun die Beispieldatenbank starten und in den Verweise-Dialog schauen, finden Sie einen als NICHT VORHANDEN markierten Eintrag der Bibliothek Microsoft Outlook 16.0 Object Library.

Diesen können Sie dann versuchen, mit der obigen Funktion wiederherzustellen. Das wird in diesem Fall scheitern, da der Verweis tatsächlich ins Leere zeigt und die hinter der GUID angegebene Datei MSOUTL.OLB nicht vorhanden ist.

Den Fall, dass die Outlook-Bibliothek nicht in der gewünschten Version vorhanden ist und es dadurch einen Fehler gibt, konnten wir mangels anderer Outlook-OLB-Datei nicht nachstellen. Die Prozedur sollte jedoch in diesem Fall den alten Verweis löschen und den auf die korrekte Version hinzufügen können.

Funktion für mehrere Verweise aufrufen

Wenn Sie gleich für mehrere Verweise prüfen wollen, ob diese noch vorhanden und einsatzbereit sind, können Sie die Funktion auch für mehrere Verweise in einer Routine aufrufen (siehe Listing 4).

Public Sub VerweiseErneuernAufrufMehrere()
     Dim strGUID As String
     Dim strReference As String
     Dim strMeldung As String
     strGUID = "{00062FFF-0000-0000-C000-000000000046}" 'Outlook
     strReference = "Microsoft Outlook x.0 Object Library"
     If VerweiseErneuern(strGUID, strReference) = False Then
         strMeldung = strMeldung & strReference & vbCrLf
     End If
     strGUID = "{00020813-0000-0000-C000-000000000046}" 'Excel
     strReference = "Microsoft Excel x.0 Object Library"
     If VerweiseErneuern(strGUID, strReference) = False Then
         strMeldung = strMeldung & strReference & vbCrLf
     End If
     ... weitere Verweise
     If Len(strMeldung) > 0 Then
         strMeldung = "Ein oder mehrere Verweise konnten nicht wiederhergestellt werden:" _
             & vbCrLf & vbCrLf & strMeldung
         strMeldung = strMeldung & vbCrLf & "Fügen Sie diese manuell hinzu oder kontaktieren " _
             & "Sie den Entwickler."
         MsgBox strMeldung, , "Fehlerhafte Verweise"
    End If
End Sub

Listing 4: Erneuern mehrerer Verweise

Hier übergeben wir nacheinander die Parameter für die Prüfung und gegebenenfalls Erneuerung verschiedener Verweise. Immer wenn die Funktion den Wert False zurückliefert, wird der Variablen strMeldung eine Zeile mit der Bezeichnung der jeweils nicht reparierten Referenz hinzugefügt. Am Ende prüft die Prozedur, ob mindestens eine Referenz nicht repariert werden konnte und ergänzt die Meldung aus strMeldung aus eine führende und eine folgende Zeile, die dem Benutzer mitteilen, welche Schritte nun nötig sind.

Speichern der Referenzen in einer Tabelle

Wir können die Daten für die Verweise statt im Code auch in einer Tabelle speichern, was ein späteres Hinufügen oder Entfernen der Verweise erleichtert. Diese Tabelle heißt tblReferences und sieht nach dem Füllen etwa wie in Bild 5 aus.

Tabelle zum Speichern der Verweisinformationen

Bild 5: Tabelle zum Speichern der Verweisinformationen

Um uns die Arbeit zu erleichtern, schreiben wir eine Prozedur, mit der wir die Daten der Verweise in die Tabelle eintragen. Diese sieht wie in Listing 5 aus. Hier durchlaufen wir alle Verweise der aktuellen Datenbank und prüfen, welche davon nicht eingebaut sind. Für diese fügen wir dann per INSERT INTO-Anweisung jeweils einen Datensatz zur Tabelle tblReferences hinzu.

Public Sub VerweiseInDB()
     Dim objReference As Reference
     Dim db As DAO.Database
     Set db = CurrentDb
     db.Execute "DELETE FROM tblReferences", dbOpenDynaset
     For Each objReference In References
         If objReference.BuiltIn = False Then
             db.Execute "INSERT INTO tblReferences(ReferenceGUID, ReferenceName) " _
                 & "VALUES('" & objReference.Guid & "', '" _
                 & objReference.Name & "')", dbFailOnError
         End If
     Next objReference
End Sub

Listing 5: Eintragen der Verweisdaten in die Tabelle tblReferences

Vorher leeren wir die Tabelle noch per DELETE-Anweisung.

Sie können nach dem Durchlaufen dieser Prozedur noch manuell die Bezeichnungen der Verweise anpassen, also etwa Microsoft Outlook x.0 Object Library statt Outlook. Das Ergebnis sieht dann wie in Bild 6 aus.

Verweisinformationen mit ausgeschriebenen Bibliotheken

Bild 6: Verweisinformationen mit ausgeschriebenen Bibliotheken

Um die Funktion VerweiseErneuern für jeden Eintrag der Tabelle einmal aufzurufen, verwenden wir die Prozedur aus Listing 6. Diese erstellt ein Recordset auf Basis der Tabelle tblReferences. Danach durchläuft sie alle Datensätze dieses Recordsets und ruft für jeden Datensatz die Funktion VerweiseErneuern auf und übergibt den Wert des Feldes ReferenceGUID an die Funktion.

Public Sub VerweiseErneuernAusTabelleAufruf()
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT * FROM tblReferences", dbOpenDynaset)
     Dim strMeldung As String
     Do While Not rst.EOF
         If VerweiseErneuern(rst!ReferenceGUID) = False Then
             strMeldung = strMeldung & rst!ReferenceName & vbCrLf
         End If
         rst.MoveNext
     Loop
     If Len(strMeldung) > 0 Then
         strMeldung = "Ein oder mehrere Verweise konnten nicht wiederhergestellt werden:" & vbCrLf & vbCrLf & strMeldung
         strMeldung = strMeldung & vbCrLf & "Fügen Sie diese manuell hinzu oder kontaktieren Sie den Entwickler."
         MsgBox strMeldung, , "Fehlerhafte Verweise"
     End If
End Sub

Listing 6: Verweise aus der Tabelle erneuern

Liefert die Funktion den Wert False zurück, was bedeutet, dass ein fehlerhafter Verweis nicht repariert werden konnte, wird die Zeichenkette strMeldung um den Namen der Bibliothek in jeweils einer eigenen Zeile ergänzt. Ist mindestens ein Verweis nicht wiederherstellbar, erscheint eine Meldung wie aus Bild 7.

Ein Verweis konnte nicht wiederhergestellt werden.

Bild 7: Ein Verweis konnte nicht wiederhergestellt werden.

Prozedur beim Start der Anwendung aufrufen

Um diese Prozedur beim Start einer Anwendung aufzurufen, haben Sie zwei Möglichkeiten:

  • Sie legen das AutoExec-Makro an und fügen den Namen der Prozedur für eine neue Makroaktion namens AusführenCode hinzu. Dazu ändern Sie die Prozedur VerweiseErneuernAusTabelleAufruf in eine Funktion um (Entwurf des Makros siehe Bild 8).
  • Entwurf des AutoExec-Makros

    Bild 8: Entwurf des AutoExec-Makros

  • Oder Sie fügen einem Formular, dass Sie für die Eigenschaft Formular anzeigen in den Access-Optionen der Anwendung einstellen, eine Form_Load-Prozedur hinzu, welche die Prozedur VerweiseErneuernAusTabelleAufruf startet.
  • Downloads zu diesem Beitrag

    Enthaltene Beispieldateien:

    1906_VerweiseBeimStart.accdb

    Download

Schreibe einen Kommentar