Windows stellt einige API-Prozeduren zum Zugriff auf die Registry zur Verfügung. Die Registry verwaltet viele der für das System wichtigen Informationen. Hierzu gehören Informationen über das System, über die verschiedenen Anwendungen und Dateitypen und wie sie verknüpft werden und vieles mehr. Dieser Beitrag zeigt, wie Sie per VBA über die Funktionen der Windows-API auf die Registry zugreifen.
Neben den Informationen über das System finden Sie auch Informationen zu den Anwendungen selbst in der Registry. Wenn Sie zum Beispiel in den Optionen von Access den Standarddatenbankpfad ändern, wird der neue Pfad in die Registry eingetragen.
Auch wenn Sie der Datenbank einen neuen Assistenten oder ein Add-In hinzufügen, schreibt der Add-In-Manager die benötigten Informationen in die Registry. Für den Entwickler wird die Registry interessant, wenn er bestimmte Daten speichern will, die nicht in einer Tabelle untergebracht werden können oder sollen.
Die Registry ist im Prinzip wie das Dateisystem von Windows aufgebaut. Die Verzeichnisstruktur ist nahezu identisch. Statt der Dateien enthält die Registry Variablen. Wie die Dateien haben auch die Variablen einen bestimmten Inhalt.
Die Windows-API stellt einige Befehle zur Bearbeitung der Registry zur Verfügung. Im Folgenden lernen Sie Befehle, die Sie zum Hinzufügen, Bearbeiten und Entfernen von Schlüsseln benötigen, anhand eines Beispiels kennen.
Aufbau der Registry-Einträge
Die Einträge in die Registry, die Sie über den Befehl RegEdit öffnen (beispielsweise über das Suchen-Feld von Windows 10), sind nach einem bestimmten Schema aufgebaut. Auf der obersten Ebene befinden sich die Hauptpfade. Es gibt insgesamt fünf Hauptpfade, die Sie auch in Bild 1 sehen können:
Bild 1: Die Registry mit den fünf Hauptzweigen
- HKEY_CLASSES_ROOT: Speichert Informationen über die unterschiedlichen Dateitypen und die dazugehörenden Anwendungen.
- HKEY_CURRENT_USER: Speichert die Einstellungen des aktuellen Benutzers.
- HKEY_LOCAL_MACHINE: Speichert Informationen über die Hard- und Software des Systems.
- HKEY_USERS: Speichert die voreingestellten Einstellungen bezüglich Hard- und Software sowie benutzerdefinierte änderungen.
- HKEY_CURRENT_CONFIG: Speichert allgemeine Informationen über die Systemkonfiguration.
Jeder dieser Hauptpfade enthält weitere, aus unterschiedlich vielen Ebenen bestehende Unterpfade. Der unterste Pfad jeder der Ebenen enthält schließlich die eigentlichen Schlüssel. Die Schlüssel bestehen aus einem Namen und einem Wert. Mit dem Registrierungseditor, mit dem Sie die Einträge der Registry bequem einsehen, editieren und löschen sowie neue Einträge hinzufügen können, greifen Sie über die Benutzeroberfläche auf diese Schlüssel zu.
Der in Bild 2 markierte Pfad lautet beispielsweise HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Access\Menu Add-Ins\RibbonAdmin2016.
Bild 2: Die Access-Add-Ins und ihre Registrierung in der Windows-Registry
In dem Pfad finden Sie vier Schlüssel, die einige Informationen zu einem Access-Add-In beinhalten – unter anderem die Funktion, die beim Aufruf des Add-Ins gestartet werden soll, sowie der Ort der Bibliothek, in der die benötigte Funktion enthalten ist.
Praxisbeispiel: Shareware mit zeitlicher Begrenzung
Wenn Sie eine Datenbankanwendung als Shareware vertreiben, möchten Sie die Benutzung der Anwendung möglicherweise auf eine Testphase von beispielsweise 30 Tagen beschränken. Die Anwendung muss also bei jedem Start zunächst überprüfen, ob der angegebene Zeitraum schon beendet ist oder nicht. Dazu müssen Sie zunächst eine Information über das Installationsdatum oder das Datum der ersten Anwendung speichern.
Das Speichern der Daten innerhalb der Datenbank ist deshalb nicht zu empfehlen, weil der Anwender die Datenbank nach Ablauf der 30 Tage einfach neu installieren könnte. Eine weitere Möglichkeit ist das Speichern des Datums in der Registry. Wenn der Benutzer die Anwendung startet, vergleicht die Anwendung das in die Registry eingetragene Datum mit dem aktuellen Datum und soll den Benutzer gegebenenfalls auf das Ablaufen der Testphase hinweisen. Wenn der Benutzer dann die Datenbank neu installiert, findet die Datenbank den noch vorhandenen Registry-Eintrag und erkennt, dass die Testphase bereits einmal abgelaufen ist.
Zunächst einmal überlegt man sich, wo in der Registry ein solcher Wert am besten abgelegt wird. Da die Anwendung vermutlich unabhängig vom Benutzer auf dem Rechner installiert, wählt man den Hauptpfad HKEY_CURRENT_USER aus. Der Name des Pfades soll \AMVShop\Beispiele\Registry lauten. Den Schlüssel nennen Sie Installationsdatum und der Wert soll das aktuelle Datum sein.
Selbstverständlich sollten Sie die Informationen etwas besser verstecken und gegebenenfalls auch verschlüsseln, wenn Sie eine Anwendung wirksam schützen wollen. Da der vorliegende Anwendungsfall jedoch nur als Beispiel dienen soll, wird hier mit offenen Karten gespielt.
Konstanten
Im Rahmen der nachfolgend beschriebenen API-Funktionen definieren Sie einige Konstanten. Die Konstanten benötigen Sie, um innerhalb des VBA-Code statt nichtssagender Werte für den Entwickler verständliche Begriffe verwenden zu können. So definiert man beispielsweise die folgende Konstante HKEY_CLASSES_ROOT, um sie bei der Angabe eines Registryschlüssels statt des Ausdrucks &H80000003 zu verwenden:
Public Const HKEY_CLASSES_ROOT As Long = &H80000000
Damit Sie nicht zwischendurch immer wieder neue Kon-stanten definieren müssen, geben Sie direkt alle in Zusammenhang mit den Registryzugriffen benötigten Konstanten ein:
Public Const HKEY_CURRENT_USER As Long = &H80000001 Public Const HKEY_LOCAL_MACHINE As Long = &H80000002 Public Const HKEY_USERS As Long = &H80000003 Public Const HKEY_CURRENT_CONFIG As Long = &H80000005 Public Const REG_STR As Long = 1 Public Const REG_OPTION_NON_VOLATILE As Long = 0 Public Const REG_SZ As Long = 1 Public Const KEY_ALL_ACCESS As Long = &H3F Public Const StringlängeMax As Long = 200 Public Const ERROR_SUCCESS As Long = 0& Public Const ERROR_NO_MORE_ITEMS As Long = 259&
Noch praktischer ist es, wenn Sie für die fünf Konstanten für die Hauptpfade der Registry gleich eine Enumeration anlegen. Dann können Sie später, wenn Sie in Funktionen eine dieser Konstanten als Parameter übergeben wollen, ganz einfach per Intellisense auf diese Konstanten zugreifen. Dies sieht dann so aus:
Public Enum eRegistryPfade
HKEY_CLASSES_ROOT = &H80000000
HKEY_CURRENT_USER = &H80000001
HKEY_LOCAL_MACHINE = &H80000002
HKEY_USERS = &H80000003
HKEY_CURRENT_CONFIG = &H80000005
End Enum
Sie müssen die entsprechenden Konstanten dann allerdings löschen oder umbenennen, da sonst mehrere Elemente gleichen Namens im Code vorkommen, was zu Kompilierfehlern führt.
Achtung: Sie werden im Folgenden neben den Konstanten auch noch API-Funktionen deklarieren sowie VBA-Funktionen und -Prozeduren eingeben. Am besten legen Sie für die Konstanten und die API-Funktionen ein eigenes Modul an (zum Beispiel mdlAPIRegistry). Die VBA-Funktionen und -Prozeduren zum Thema Registry sollten Sie ebenso in einem eigenen Modul zusammenfassen – beispielsweise mdlRegistry.
Anlegen eines Schlüssels
Die API-Funktion RegCreateKeyEx dient zum Anlegen eines Registrierungsschlüssels. Falls der anzulegende Schlüssel bereits vorhanden ist, öffnet die Funktion den Schlüssel. Die Deklaration der Funktion lautet:
Declare Function RegCreateKeyEx _ Lib "advapi32.dll" _ Alias "RegCreateKeyExA" (_ ByVal hKey As Long, _ ByVal lpSubKey As String, _ ByVal Reserved As Long, _ ByVal lpClass As String, _ ByVal dwOptions As Long, _ ByVal samDesired As Long, _ lpSecurityAttributes As SECURITY_ATTRIBUTES, _ phkResult As Long, _ lpdwDisposition As Long ) As Long
Interessant sind vor allem die Parameter hKey und lpSubKey. Für den Parameter hKey geben Sie entweder das Handle an, das auf den entsprechenden Eintrag in der Registry zeigt, oder Sie geben einen der Hauptpfade aus der obigen Liste ein. Für den Parameter lpSubKey geben Sie den Pfad des Registry-Wertes an, den Sie öffnen möchten.
Für den Parameter lpSecurityAttributes müssen Sie noch einen Type definieren, und zwar im Modul mdlAPIRegistry:
Private Type SECURITY_ATTRIBUTES nLength As Long lpSecurityDescriptor As Long bInheritHandle As Boolean End Type
Um den Aufruf der API-Funktion ein wenig komfortabler zu gestalten, erstellen Sie eine Funktion, an die Sie einfach nur den Hauptpfad und den Pfad des Registry-Eintrages übergeben müssen:
Public Function SchluesselErstellen(lngHauptpfad As Long, _ Pfad As String) As Long ...
Als Hauptpfad würden Sie nun eine der Konstanten wie etwa HKEY_LOCAL_MACHINE eingeben. Da wir dafür aber eine Enumeration angelegt haben, können Sie diese auch als Datentyp für lngHauptpfad angeben, sodass die Funktion nun wie in Listing 1 aussieht.
Public Function SchluesselErstellen(strHauptpfad As eRegistryPfade, strPfad As String) As Long Dim lngHandle As Long Dim secAttrib As SECURITY_ATTRIBUTES RegCreateKeyEx strHauptpfad, strPfad, 0&, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, secAttrib, lngHandle, 0& SchluesselErstellen = lngHandle End Function
Listing 1: Hilfsfunktion zum Erstellen eines Schlüssels in der Registry
Sie können die Funktion zum Beispiel über das Testfenster aufrufen.
Geben Sie dort den folgenden Befehl ein, erhalten Sie Unterstützung bei der Auswahl des Hauptpfades (s. Bild 3):
Bild 3: Aufruf der Funktion SchluesselErstellen mit IntelliSense-Unterstützung
MsgBox SchlüsselErstellen(HKEY_CURRENT_USER, "SOFTWARE\Haufe\Beispiele\Test")
Das Meldungsfenster zeigt daraufhin die Nummer des Handles an, mit dem Sie auf den Eintrag in die Registry zugreifen können, ohne den kompletten Pfad eingeben zu müssen – zum Beispiel 4576.
Außerdem erstellt die Funktion den angegebenen Pfad in der Registry, wenn er nicht bereits vorhanden ist. Wenn der Pfad bereits erstellt wurde, bereitet die Funktion den Pfad auf den Zugriff vor. Mit dem Registrierungseditor können Sie schnell überprüfen, ob die Funktion den Registrierungsschlüssel wie gewünscht angelegt hat. öffnen Sie den Editor und navigieren Sie zu dem entsprechenden Pfad (s. Bild 4).
Bild 4: Der neue Eintrag in der Windows-Registry
öffnen eines Schlüssels
Wenn Sie nur auf einen Schlüssel zugreifen möchten, verwenden Sie den API-Befehl RegOpenKey. Die Funktion hat die folgende Syntax:
Declare Function RegOpenKeyEx _ Lib "advapi32.dll" _ Alias "RegOpenKeyExA" ( _ ByVal hKey As Long, _ ByVal lpSubKey As String, _ ByVal ulOptions As Long, _ ByVal samDesired As Long, _ phkResult As Long) _ As Long
Auch den Aufruf dieser API-Funktion können Sie ein wenig komfortabler gestalten, indem Sie eine Funktion erstellen, die nur die wichtigsten Werte als Parameter erfordert:
Die Funktion SchluesselOeffnen aus Listing 2 hat nur einen Unterschied im Vergleich zu der vorherigen Funktion: Sie erstellt keinen neuen Schlüssel, falls der angegebene Schlüssel nicht vorhanden ist. Beachten Sie, dass die API-Funktion keinen Fehler auslöst, wenn der zu öffnende Schlüssel nicht vorhanden ist. Sie gibt lediglich für das Handle den Wert 0 zurück.
Public Function SchluesselOeffnen(lngHauptpfad As eRegistryPfade, strPfad As String) As Long Dim lngHandle As Long RegOpenKeyEx lngHauptpfad, strPfad, 0, KEY_ALL_ACCESS, lngHandle SchluesselOeffnen = lngHandle End Function
Listing 2: Hilfsfunktion zum Ermitteln des Handles eines Registry-Eintrags
Ein Beispielaufruf sieht wie folgt aus:
SchluesselOeffnen(HKEY_CURRENT_USER, "SOFTWARE\AMVShop\Beispiele\Test") 3816
Entfernen eines Schlüssels
Bevor Sie beginnen, den neuen Schlüssel mit Werten zu füllen, erfahren Sie noch, wie Sie einen Schlüssel per API-Aufruf wieder entfernen können. Auch das ist wichtig, denn wenn Sie mit der Installation der Software in die Registry eingreifen, sollten Sie die änderung bei einer Deinstallation auch wieder rückgängig machen. Zum Löschen eines Pfades in der Registry verwendet man den API-Befehl RegDeleteKey, den Sie wie folgt deklarieren:
Declare Function RegDeleteKey _ Lib "advapi32.dll" _ Alias "RegDeleteKeyA" ( _ ByVal hKey As Long, _ ByVal lpSubKey As String _ ) As Long
Die Funktion erwartet nur den Hauptpfad und den Pfad des zu löschenden Schlüssels. Die Funktion gibt den Wert 0 zurück – es sei denn, die Operation schlägt fehl, zum Beispiel, weil der angegebene Pfad nicht vorhanden ist. Wichtig ist, dass Sie den kompletten zu entfernenden Pfad bis in die unterste Ebene angeben.
Auch für diese API-Funktion haben wir wieder eine Wrapper-Funktion programmiert, die Sie in Listing 3 finden.
Public Function SchluesselLoeschen(lngHauptpfad As eRegistryPfade, strPfad As String) As Long Dim lngHandle As Long lngHandle = RegDeleteKey(lngHauptpfad, strPfad) SchluesselLoeschen = lngHandle End Function
Listing 3: Hilfsfunktion zum Löschen eines Eintrags
Wenn Sie nun den gleichen Pfad wieder löschen wollen, den Sie soeben angelegt haben, gelingt dies nicht mit dem folgenden Aufruf der Funktion:
SchluesselLoeschen(HKEY_CURRENT_USER, "SOFTWARE\AMVShop\Beispiele\Test") 0
Dies liefert mit dem Wert 0 zwar eine Erfolgsmeldung, allerdings wird hier logischerweise nur genau das angegebene Element gelöscht, nämlich das Verzeichnis Test.
Wenn Sie alle Verzeichnisse löschen wollen, die Sie zuvor angelegt haben, sind noch zwei weitere Aufrufe nötig – Sie müssen nämlich jedes Verzeichnis vom hintersten an einzeln löschen:
SchluesselLoeschen(HKEY_CURRENT_USER, "SOFTWARE\AMVShop\Beispiele") 0 SchluesselLoeschen(HKEY_CURRENT_USER, "SOFTWARE\AMVShop") 0
Wenn Sie direkt versuchen, den Pfad SOFTWARE\AMVShop zu löschen, lösen Sie einen Fehler aus beziehungsweise erhalten einen anderen Wert als 0 zurück, in diesem Fall den Wert 5. Wenn Sie einen Pfad löschen wollen, der nicht mehr vorhanden ist, liefert die Funktion den Wert 2.
Schließen eines Schlüssels
Mit der API-Anweisung RegCloseKey schließen Sie einen geöffneten Schlüssel wieder und geben die dabei gebundenen Ressourcen wieder frei.
Der einzige Parameter der Funktion ist das Handle des zu schließenden Schlüssels, das Sie beim öffnen mit Reg-OpenKey ermittelt haben. Die Deklaration lautet folgendermaßen:
Declare Function RegCloseKey _ Lib "advapi32.dll" ( _ ByVal hKey As Long _ ) As Long
Wenn auch eigentlich nicht nötig, da ohnehin nur ein Parameter übergeben wird, haben wir dennoch auch hier eine Wrapper-Funktion erstellt. Sie liefert den Wert 0 zurück, wenn das Schließen gelungen ist, sonst den Wert 6:
Public Function SchluesselSchliessen(lngHandle As Long) As Long SchluesselSchliessen = RegCloseKey(lngHandle) End Function
Setzen eines Schlüsselwertes
Nachdem Sie nun wissen, wie Sie Registrypfade anlegen, öffnen, schließen und wieder entfernen, lernen Sie jetzt, wie Sie mit der Funktion RegSetValueEx einen Schlüssel hinzufügen und einen Wert dafür angeben. Deklarieren Sie die Funktion RegSetValueEx folgendermaßen:
Declare Function RegSetValueEx _ Lib "advapi32.dll" _ Alias "RegSetValueExA" ( _ ByVal hKey As Long, _ ByVal lpValueName As String, _ ByVal Reserved As Long, _ ByVal dwType As Long, _ lpData As Any, _ ByVal cbData As Long _ ) As Long
Wenn Sie die Deklaration aufmerksam betrachten, dass der Parameter lpData als einziger nicht ByVal, sondern ByRef übergeben wird und dass als Datentyp Any angegeben ist. Dahinter verbergen sich einige Besonderheiten.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo