Home > Artikel > Ausgabe 8/2014 > Registry-Zugriff per VBA

Registry-Zugriff per VBA

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Die Windows Registrierungsdatenbank, kurz Registry, ist die zentrale Sammelstelle für Einstellungsdaten aller Art. Die Konfiguration des gesamten Systems und fast aller Anwendungen hängt von ihr ab. Ob lesend oder schreibend, auch als Access-Entwickler hätte man gern eine Programmierschnittstelle für den Zugriff auf die Registry. Weil VBA hier nur eingeschränkte Möglichkeiten bietet, ist dem Thema dieser Beitrag gewidmet.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1408_Registry.mdb.

Eingebaute Zugriffsmethoden

Im Beitrag Anwendungseinstellungen abspeichern dieser Ausgabe wurde deutlich, dass die Werte von Eigenschaftsvariablen, die über die aktuelle Access-Sitzung hinaus Bestand haben sollen, außerhalb der Datenbank selbst gespeichert werden müssen. Statt dafür eine externe verknüpfte Tabelle zu verwenden, könnte man ebenso Variablen in der Registry unterbringen.

Genau dieser Zweck schwebte den VBA-Entwicklern wohl vor, als sie die vier Methoden zum Zugriff auf die Registry in die VBA-Bibliothek einbauten. Sie lauten

GetSettingGetAllSettingsSaveSettingDeleteSetting

GetSetting liest einen Registry-Wert aus, GetAllSettings liest alle Werte eines Schlüssels auf einmal, SaveSetting schreibt einen Wert in die Registry, und DeleteSetting löscht einen solchen wieder. Der Haken an der Sache ist, dass all diese Methoden nur einen ganz kleinen reservierten Bereich der Registry ansprechen können, nämlich den Schlüssel

HKEY_CURRENT_USER\Software\

VB and VBA Program Settings

Unterhalb dieses Schlüssels kann man walten, wie man will, aber von allen anderen Bereichen der Registry ist man ausgesperrt. Dass dieser Schlüssel unter HKEY_CURRENT_USER liegt, ist nicht verwunderlich, denn für alle anderen Root-Schlüssel benötigt man schreibend Administratorrechte – und Access wird normalerweise nicht mit diesen Rechten gestartet.

Die Schlüsselstruktur unterhalb dieses Hauptschlüssels ist immer dieselbe. Sie wird in Bild 1 ersichtlich. Dort ist ein Zweig abgebildet, der über die Routinen der Beispieldatenbank erstellt wurde. AB_Registry als Unterschlüssel ist quasi der Generalschlüssel und Anwendungsname, und darunter kann ein oder können mehrere Bereichsschlüssel liegen. Im Beispiel ist es nur einer mit dem Namen General. Werte können außerdem nur im untersten Schlüssel gespeichert werden, also nicht etwa unter AB_Registry. Sie können eine beliebige Anzahl von Werten unterbringen. Bei größerem Umfang ist der Übersicht halber aber die Anlage mehrerer Unterschlüssel überlegenswert. Zum General-Schlüssel könnte etwa noch ein Printer-Schlüssel kommen, der Werte für die Steuerung von Druckern aufnähme.

Der von VBA aus zugängliche Bereich der Registry

Bild 1: Der von VBA aus zugängliche Bereich der Registry

Wie kommt nun der Test-Eintrag zustande? Die Syntax der Code-Zeile sieht so aus:

SaveSetting "AB_Registry", "General", "Test0", "Sascha"

Als Parameter werden also Hauptschlüssel, Unterschlüssel, Wertname und Wert übergeben. Die Schlüssel müssen zuvor nicht erst angelegt worden sein, wie das etwa bei Routinen, die das Windows-API benutzen, der Fall ist. Die SaveSetting-Anweisung macht alles auf einen Schlag: Hauptschlüssel, Unterschlüssel anlegen, Wert speichern. Als Wert können Sie einen beliebigen Variant-Typ übergeben und das selbstredend auch über eine Variable. Erlaubt sind alle Standarddatentypen, nicht jedoch Arrays oder Objekte. Es spielt keine Rolle, welchen Datentyp Sie verwenden, denn alle werden automatisch in Strings verwandelt. In Bild 1 wird das aus der Typ-Spalte des Editors ersichtlich, wo alle Werte als REG_SZ aufgeführt sind, dem Pendant zu vbString.

Mit GetSetting lesen Sie den Wert über diese Syntax aus:

GetSetting ("AB_Registry", "General", "Test0", "nix")

Die Parameter sind also Hauptschlüssel, Unterschlüssel, Wertname, und die Rückgabe ist immer vom Typ String. Ganz hinten können Sie optional noch einen weiteren Parameter anschließen. Das ist ein Wert, der immer dann als Resultat der Funktion zurückgegeben wird, wenn entweder der Registry-Wert leer ist, der Wertname nicht existiert, oder es den Schlüssel selbst nicht gibt. VBA löst nämlich keine Fehler aus, wenn die Namensparameter ungültig sind!

Im Modul mdlRegistryBeispiele der Beispieldatenbank finden Sie mehrere Prozeduren, die den Umgang mit den vier VBA-Methoden vereinfachen. Einen Ausschnitt daraus zeigt Listing 1. Statt etwa GetSetting immer mit allen fünf Parametern bestücken zu müssen, nehmen Sie einfach die kürzere Variante SaveVarToRegistry, welche nur einen Parameter erwartet: den Wertnamen.

Public Const cMainRegKey = "AB_Registry"

Public Const cSubRegKey = "General"

Sub SaveVarToRegistry(ByVal KeyName As String, Value As Variant)

     SaveSetting cMainRegKey, cSubRegKey, KeyName, Value

End Sub

Function GetVarFromRegistry(ByVal KeyName) As Variant

     GetVarFromRegistry = GetSetting(cMainRegKey, _

         cSubRegKey, KeyName, "LEER")

End Function

Sub RemoveVarFromRegistry(ByVal KeyName As String)

     DeleteSetting cMainRegKey, cSubRegKey, KeyName

End Sub

Function GetVarsFromRegistry() As Variant

     GetVarsFromRegistry = GetAllSettings(cMainRegKey, _

         cSubRegKey)

End Function

Listing 1: Ausschnitt aus dem Modul zum Bearbeiten von Registry-Werten

Die Prozedur enthält nur eine Zeile mit der GetSetting-Funktion, der ihrerseits als Parameter aber zwei Konstanten übergeben werden, die oben im Kopf des Moduls global deklariert wurden: die Namen der Haupt- und Unterschlüssel. Denn diese dürften für die Datenbank konstant bleiben. Wenn Sie das Modul in eine andere Datenbank importieren, so ändern Sie dort nur diese zwei Konstanten. Das erspart Ihnen, überall im Code die Schlüsselnamen neu manuell einzufügen.

Die weiteren drei Prozeduren des Moduls arbeiten ähnlich und sind wohl selbsterklärend. Lediglich der GetVarsFromRegistry wäre gesonderte Aufmerksamkeit zu schenken. Sie verwendet die GetAllSettings-Funktion von VBA. Die Rückgabe ist ein Variant. Was sich hinter dieser Rückgabe verbirgt, macht die Prozedur TestGetAllVars deutlich:

Sub TestGetAllVars()

Dim i As Long

Dim V As Variant

V = GetVarsFromRegistry

For i = 0 To UBound(V, 1)

Debug.Print _

V(i, 0) & " = " & V(i, 1)

Next i

End Sub

Die Schleife zeigt, dass es sich bei der Variant-Rückgabe um ein zweidimensionales Array handelt. Die erste Dimension entspricht der Zahl der zurückgegebenen Registry-Werte. Die zweite hat immer zwei Elemente und enthält entweder den Namen oder den Wert des Registry-Eintrags. V(0,0) wäre der Name des ersten Eintrag, V(0,1) sein Wert. und so weiter.

Probleme mit den eingebauten Methoden

Wie erwähnt wandelt VBA jeglichen Datentyp beim Speichern in die Registry in einen String um. Beim Auslesen erhält man infolgedessen immer einen String. Das kann zu Problemen führen, wenn etwa ein Boolean-Wert abgespeichert wurde, in der Registry dann der String Wahr steht und beim Auslesen wieder einer Boolean-Variablen zugewiesen werden soll. Zwar ist VBA in der Regel intelligent genug, auch hier die Rückkonvertierung zu gewährleisten. Doch möchten Sie den Boolean-Wert einer Long-Variablen zuweisen, so geht die Sache schief. VBA kann den String-Ausdruck Wahr nicht in einen Long-Wert verwandeln, während der direkte Weg von Boolean zu Long (-1) problemlos funktioniert. Ähnliche Konvertierungsprobleme stehen mit dem Datumstyp an. Kann man normal einen vbDate-Typ einer Double-Variablen übergeben, funktioniert dies nicht, wenn der Ausgangswert ein String der Form 1.09.2014 ist.

Daraus folgt, dass beim Auslesen von Registry-Werten grundsätzlich der gleiche Variablentyp verwendet werden sollte, wie beim Speichern. Nur dann kommt VB mit der zweifachen Konvertierung klar.

Komplettzugriff auf die Registry

Wenn Sie mehr wollen, als nur den beschränkten Bereich, den Ihnen VBA anbietet, dann brauchen Sie entweder aufwändige API-Lösungen, oder zusätzliche Bibliotheken, die in die Verweise des Projekts aufgenommen werden. Die API-Variante folgt im nächsten Abschnitt. Hier zunächst die Lösung per zusätzlicher Bibliothek. Davor jedoch noch der Hinweis, dass mit beiden Varianten zwar der lesende Zugriff auf fast alle Bereiche der Registry möglich ist, der schreibende aber nur auf die Schlüssel unter HKEY_CURRENT_USER.

Die wahrscheinlich einfachste Bibliothek, welche Methoden zum Zugriff auf die Registry ermöglicht, ist das Windows Scripting Host Object Model, kurz WSHOM. Die DLL dazu findet sich auf allen Windows-Plattformen im Systemverzeichnis und lautet wshom.ocx. Nachdem Sie die Bibliothek in die Verweise des VBA-Projekts aufgenommen haben, finden Sie in der Objektklasse WshShell die drei auf die Registry bezogenen Methoden RegDelete, RegRead und RegWrite (siehe Bild 2). Deren Syntax ist verblüffend simpel. So erwartet die RegRead-Funktion lediglich die Angabe des Schlüssels/Wertnamen-Strings:

Das WshShell-Objekt und seine Methoden zum Zugriff auf die Registy

Bild 2: Das WshShell-Objekt und seine Methoden zum Zugriff auf die Registy

RegRead ("HKEY_CURRENT_USER\Software\VB and VBA Program Settings\AB_Registry\General\Test0")

Im Unterschied zu den VBA-Methoden ereignet sich ein Fehler, wenn Schlüssel- oder Wertnamen nicht gültig sind. Im Modul mdlWSHOM der Beispieldatenbank ist deshalb eine Fehlerbehandlung in die entsprechenden Prozeduren zum Lesen und Schreiben eingebaut. Bei ungültigen Namensparametern zeigt sich eine MsgBox mit der Meldung "Ungültiger Registry Key". Die Prozedur SetVarWSHOM des Moduls zum Schreiben von Registry-Werten ist etwas aufwändiger gestaltet. Sie macht sich zunutze, dass die RegWrite-Methode des WshShell-Objekts neben Schlüssel/Wertname-Kombination und dem Wert auch noch den Datentyp erwartet. Allerdings nicht VB-Datentypen, mit denen die Registry nichts anfangen kann, sondern deren eigene Typen. Für uns sind dabei nur die beiden Typen REG_SZ und REG_DWORD von Belang. Ein DWORD entspricht dem VB-Typ Long. Damit lassen sich hier immerhin die VB-Typen Long, Integer und Boolean von den restlichen absetzen und als DWORD speichern. Beim Auslesen kommt dann eben auch ein Long-Wert heraus und die Konvertierungsprobleme sind geringer, als bei den VBA-Methoden. Die Prozedur SetVarWSHOM verzweigt also je nach übergebenem Datentyp und speichert entweder einen REG_SZ- oder einen REG_DWORD-Eintrag.

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!