Windows-API per VBA nutzen

Access stellt ausreichend Bordmittel zur Programmierung von Datenbankanwendungen zur Verfügung. Dazu gehören die Benutzerschnittstellen zur Gestaltung der Datenbankobjekte wie Tabellen, Abfragen, Formulare und Berichte sowie die Möglichkeit, Abläufe ereignisgesteuert per Makro oder VBA zu automatisieren. Manchmal reichen die vorhandenen Befehle aber nicht aus. In dem Fall greifen Sie auf die Prozeduren der Windows-API (Application Programming Interface) zu. Mit API-Prozeduren können Sie Ihre Anwendungen alles machen lassen, was Windows auch kann.

Die Windows-API verfügt über eine sehr große Anzahl von Befehlen. Der vorliegende Beitrag kann Ihnen aber aus Platzgründen nur einen kleinen Einblick in die Möglichkeiten der API-Programmierung geben. Nach einer kurzen Einführung, in der die wichtigsten Begriffe und die technischen Grundlagen erklärt werden, folgt der Praxisteil mit einigen Beispielen. Die Beispiele sind so ausgewählt, dass Sie sie gut in Ihre eigenen Anwendungen übernehmen können.

VBA und API

Das Datenbanksystem Microsoft Access ist Windows-kompatibel. Daraus ergeben sich für den Entwickler große Vorteile. Er kann mit Access Datenbanken erstellen, welche die Eigenschaften von Windows wie selbstverständlich ausnutzen. Dabei muss der Entwickler sich nicht damit abmühen, das Aussehen von Formularen, Berichten und den darin enthaltenen Steuerelementen zu programmieren. Access stellt Werkzeuge zur Verfügung, mit denen die Erstellung solcher Objekte zum Kinderspiel wird. Der Entwickler muss lediglich die verschiedenen Ereignisse per VBA programmieren, mit denen die Anwendung auf die unterschiedlichen Benutzereingaben reagiert.

Streng genommen handelt es sich bei den Befehlen nicht nur um VBA-Befehle. VBA selbst enthält nur die Befehle, die von den Microsoft-Anwendungen wie zum Beispiel Word, Excel und eben Access genutzt werden können. Um eine Datenbank zu programmieren, benötigen Sie darüber hinaus mindestens noch die Bibliotheken Microsoft Access x.0 Object Library und eine Datenzugriffsbibliothek wie in den neueren Versionen von Access die Bibliothek Microsoft Office x.0 Access Database Engine Object Library. Die beiden Bibliotheken enthalten die Befehle zur Steuerung der Datenbankobjekte von Access und zum Zugriff auf die in der Datenbank gespeicherten Daten.

Windows selbst kennt über die Befehle der drei genannten Bibliotheken hinaus noch viel mehr Befehle. Diese sogenannten API-Befehle können Sie auch von Access aus aufrufen. In den folgenden Abschnitten erfahren Sie, wie Sie unterschiedliche Befehle der Windows-API aufrufen können und welche Vorraussetzungen dazu erfüllt sein müssen.

Die Prozedurbibliotheken von Windows

Die wesentlichen zum Betrieb von Windows notwendigen Prozeduren sind auf einige wenige Bibliotheken verteilt. Die folgenden drei sind die wichtigsten: Kernel32.dll, User32.dll und GDI32.dll.

Die Bibliothek Kernel32.dll macht den eigentlichen Kern von Windows aus. Zu den Aufgaben der Prozeduren dieser Bibliothek gehören die Auswertung von Tastatureingaben, die Ausgabe auf dem Bildschirm, die Verwaltung der laufenden Anwendungen, die Verwaltung des Dateisystems und andere, die aber für den Einsatz im Zusammenhang mit Access eine untergeordnete Bedeutung haben.

Die Prozeduren der Dynamic Link Library User32 dienen hauptsächlich der Bereitstellung der Benutzerschnittstelle, das heißt der Fenster, des Mauszeigers, des Ribbons und der Menüs und so weiter. Das öffnen, Schließen und Verschieben der Fenster gehört zu den Aufgaben der User32.dll.

Das Graphics Device Interface (GDI32.dll) dient der Ausgabe von grafischen Elementen wie Grafiken, Text, Farben et cetera. Es dient praktisch als Schnittstelle zwischen dem Benutzer und dem Ausgabegerät. Als Ausgabegeräte kommen dabei alle möglichen Geräte infrage – sowohl unterschiedliche Monitore als auch Drucker und andere Ausgabegeräte. Windows stellt für alle möglichen Formate einen Treiber zur Verfügung.

Neben den genannten Bibliotheken gibt es noch einige weitere, wie etwa die COMDLG32.dll, die unter anderem die Dialoge zum öffnen und Speichern von Dateien und zur Auswahl von Farben und von Zeichensätzen zur Verfügung stellt.

Wie hier zu erkennen ist, sind die zum Betrieb von Windows notwendigen Prozeduren nach Aufgaben geordnet auf unterschiedliche Bibliotheken aufgeteilt. Durch diese modulare Bauweise ist Windows leicht erweiterbar. Dementsprechend sind im Laufe der Zeit noch einige weitere Bibliotheken hinzugekommen. Sie stellen zum Beispiel neue Steuerelemente zur Verfügung (COMCTL32.dll), ermöglichen den Austausch von E-Mail (MAPI32.dll) oder dienen zur Verwaltung von Netzwerken (NETAPI32.dll).

Wo finde ich die API-Prozedur für meine Zwecke

Ohne entsprechende Dokumentation der Prozeduren der Windows-API ist es sehr schwer, bestimmte Aufgaben mit Hilfe der API zu lösen. Sie müssen also zunächst eine geeignete API-Prozedur für Ihre Aufgabe finden. Das zweite Problem ist, dass die meisten Prozeduren der API-Bibliotheken in C programmiert sind. Dementsprechend sind sie auch für den Aufruf von C-Programmen ausgelegt. Vor allem wegen der unterschiedlichen Variablentypen in Visual Basic und in C kann der Aufruf einer solchen Funktion manchmal Probleme bereiten. Es gibt aber genügend Quellen, die den Aufruf von API-Funktionen aus Visual Basic heraus beschreiben. Neben diversen Fachzeitschriften, in denen immer wieder Beiträge zum Thema API auftauchen, soll an dieser Stelle auf ein Buch hingewiesen werden, das zwar leider englischsprachig ist, aber von vielen als API-Bibel bezeichnet wird: Dan Appleman”s “Visual Basic Programmer”s Guide to the Win32 API”. Wenn Sie also Gefallen an der Integration von API-Funktionen in Ihre Anwendungen finden, erfahren Sie dort mehr.

Deklaration von API-Funktionen

Sie können API-Funktionen nicht wie gewöhnliche VBA-Prozeduren aufrufen. Sie müssen die gewünschte Prozedur zunächst deklarieren. Strenggenommen werden die VBA-Befehle und die Befehle zur Verwaltung der Datenbankobjekte auch deklariert – allerdings funktioniert das auf eine andere Weise und wird normalerweise direkt beim öffnen von Access erledigt. Die Deklaration dieser und anderer Bibliotheken nehmen Sie vor, indem Sie mit einem Verweis direkt die ganze Bibliothek verfügbar machen. Um einen solchen Verweis zu setzen, öffnen Sie ein beliebiges Modul in der Entwurfsansicht und wählen den Menübefehl Extras|Verweise. Im Dialog Verweise (s. Bild 1) können Sie durch Markieren der Kontrollkästchen Verweise auf die einzelnen Bibliotheken setzen.

Die Funktionen einiger Bibliotheken können per Verweis referenziert werden.

Bild 1: Die Funktionen einiger Bibliotheken können per Verweis referenziert werden.

Die Deklaration von API-Prozeduren ist nicht ganz so einfach. Sie müssen jede API-Prozedur separat deklarieren. Bevor Sie mit dem ersten Beispiel beginnen, soll hier kurz die Syntax der Deklaration einer API-Prozedur erläutert werden.

Syntax der Deklaration einer API-Prozedur

Allgemein sieht die Syntax folgendermaßen aus:

[Public|Private] Declare Function|Sub name Lib "libname" _ [Alias "aliasname"]([argumentlist])] [As type] 

Mit dem ersten Parameter, Public oder Private, geben Sie an, ob die Funktion nur innerhalb des Moduls Gültigkeit hat, oder ob sie anwendungsweit aufgerufen werden kann. Lassen Sie den ersten Parameter weg, hat die Funktion anwendungsweite Gültigkeit.

Die Declare-Anweisung weist darauf hin, dass eine externe Funktion deklariert wird.

Als nächstes Schlüsselwort geben Sie wie bei der Programmierung einer VBA-Prozedur entweder das Schlüsselwort Function oder Sub an – je nachdem, ob die Prozedur einen oder mehrere Werte zurückgibt oder nicht. In der Regel bekommen Sie es aber mit Funktionen zu tun.

Unter Name geben Sie den Namen der API-Prozedur an. Unter dem hier angegebenen Namen rufen Sie die Prozedur von Ihren eigenen Prozeduren aus auf. In der Regel ist das auch der Name, unter dem die Prozedur in der jeweiligen DLL abgelegt ist. Es gibt aber manche API-Prozeduren, deren Name nicht den VBA-Konventionen für Prozedurnamen entspricht. In dem Fall wird der eigentliche Name der API-Prozedur hinter dem Schlüsselwort Alias als aliasname angegeben. Zum Aufruf der API-Prozedur benutzen Sie aber die unter Name angegebene Bezeichnung.

Nach dem Schlüsselwort Lib folgt der Name der Bibliothek, in der die Prozedur abgelegt ist. Es gibt drei unterschiedliche Arten, die Bibliothek anzugeben. Bei den drei Bibliotheken Kernel32, User32 und GDI32 reicht die Angabe des Namens ohne Dateinamenendung. Bei allen anderen Bibliotheken geben Sie die Dateinamenendung an. Manchmal müssen Sie zusätzlich den Pfad der Bibliothek angeben. Das ist der Fall, wenn sich die Bibliothek nicht in den folgenden Verzeichnissen befindet:

  • Anwendungsverzeichnis
  • aktuelles Verzeichnis
  • Windows-Systemverzeichnis
  • Windows-Verzeichnis
  • Verzeichnisse, die in der Umgebungsvariablen Path angegeben sind

Für den Parameter ArgumentList geben Sie die Argumente an, die beim Aufruf der Prozedur übergeben werden. Die übergabe von Argumenten kann auf zwei Arten erfolgen. Welche der beiden Arten zu wählen ist, gibt die jeweilige Prozedur vor. Entweder Sie übergeben den Parameter als Wert und setzen dem Parameter das Schlüsselwort ByVal voran, oder Sie übergeben die Speicheradresse des Parameters. Geben Sie dann entweder das Schlüsselwort ByRef oder gar kein Schlüsselwort an.

übergeben Sie den Parameter als Wert, erhält die DLL nur eine Kopie des Parameters. Nachdem der Parameter bearbeitet wurde, wird die Kopie über das Original geschrieben. Wenn Sie hingegen eine Referenz übergeben, also einen Verweis auf die Adresse des Parameters, kann die DLL direkt auf den Parameter zugreifen.

Wann man welche Art der Parameterübergabe wählt und warum, wird erst deutlich, wenn man sich eingehender mit den unterschiedlichen Variablenarten in Visual Basic und C beschäftigt. In den später vorgestellten Beispielen wird die Art der Parameterübergabe jeweils angegeben. Zu der Parameterübergabe in weiteren API-Prozeduren erfahren Sie mehr in der einschlägigen Fachliteratur.

Hinter dem Schlüsselwort As geben Sie schließlich den Datentyp an. Mehr über die in API-Aufrufen verwendeten Datentypen erfahren Sie im nächsten Abschnitt.

Datentypen beim Aufruf von API-Prozeduren

Die zu verwendenden Datentypen werden ähnlich wie die Art der Parameterübergabe durch die aufzurufende Prozedur festgelegt. üblicherweise finden hier die in VB üblichen Datentypen Verwendung.

Eine Ausnahme ist der Datentyp Any. Er wird nur in Zusammenhang mit dem Aufruf von API-Prozeduren eingesetzt. Ein Parameter des Datentyps Any kann unterschiedliche Datentypen annehmen, zum Beispiel String und Long. Wenn Ihnen ein solcher Datentyp begegnet, ist meist ein weiterer Parameter nicht weit, in dem der für den Parameter gültige Datentyp übergeben wird.

Eine weitere Ausnahme sind benutzerdefinierte Datentypen. Parameter eines benutzerdefinierten Datentyps bestehen meist aus mehreren Parametern, die sich auf ein einziges Objekt beziehen. Solche Datentypen müssen im Deklarationsteil eines Moduls deklariert werden. Anschließend müssen Sie den Namen des benutzerdefinierten Datentyps der gewünschten Variablen zuweisen.

Wo deklariere ich API-Prozeduren

Es gibt zwei sinnvolle Möglichkeiten, API-Prozeduren zu deklarieren. Entweder Sie nehmen die Deklaration aller API-Funktionen und benutzerdefinierten Datentypen in einem eigens dafür angelegten Modul vor. Auf diese Weise ist es ab einer gewissen Menge Deklarationen leichter, die übersicht zu behalten. Wenn Sie hingegen wissen, dass Sie eine bestimmte API-Funktion nur in einer Prozedur aufrufen, sollten Sie die Deklaration und die aufrufende Prozedur in einem Modul unterbringen. So können Sie die Komponenten im Paket kopieren und in anderen Anwendungen verwenden.

Praxisbeispiele zur Benutzung der Windows-API mit Access

Leider sind die Kenntnisse einiger theoretischer Grundlagen bei der Benutzung der Windows-API unumgänglich. Da die API weit über 1.000 Prozeduren kennt, können Sie sich vorstellen, dass nicht alles Wichtige in den vorangegangenen Abschnitten untergebracht werden konnte. In den folgenden Beispielen zum praktischen Umgang mit den Prozeduren der Windows-API werden sich deshalb immer wieder kleine Abschnitte mit den theoretischen Hintergründen beschäftigen.

Da der vorliegende Beitrag nicht alle API-Prozeduren vorstellen kann, finden Sie hier nur eine Auswahl von Prozeduren.

Name des Computers und des Benutzers ermitteln

Die API-Funktionen zur Bestimmung des Computernamens und des aktuellen Benutzers des Computers sollen als erstes Beispiel dienen. Die entsprechenden API-Prozeduren heißen GetComputerName und GetUserName.

Sie müssen die Prozeduren vor dem Aufruf in geeigneter Weise deklarieren. Damit Sie die im Rahmen des vorliegenden Beitrags erstellten Prozeduren mit ihren API-Aufrufen gut in Ihre eigenen Datenbanklösungen integrieren können, legen Sie jeweils ein neues Modul für jedes Beispiel an.

Wenn Sie ein neues Standardmodul angelegt haben, speichern Sie es unter dem Namen mdlSystemInformation. Anschließend deklarieren Sie die erste der beiden Funktionen wie folgt:

Declare Function GetComputerName Lib "kernel32" _
     Alias "GetComputerNameA" (ByVal lpBuffer As _
     String, nSize As Long) As Long

Der Deklaration können Sie entnehmen, dass die Funktion GetComputerName zur Dynamic Link Library Kernel32 gehört und dort unter dem Namen GetComputerNameA bekannt ist. Die Funktion hat zwei Parameter, die Zeichenkette lpBuffer wird als Wert übergeben, während die Länge der Zeichenkette nSize als Referenz übergeben wird. Der Rückgabewert hat den Datentyp Long.

Der Rückgabewert enthält bei vielen Funktionen nicht die Informationen, die Sie eigentlich abrufen möchten. In der vorliegenden Funktion GetComputerName wird etwa der Zahlenwert 1 zurückgegeben, wenn es einen Computernamen gibt, und der Wert 0, wenn kein Computername gefunden wurde.

Die gewünschte Information packt die API-Funktion in die Parameter. Sie weist dem Parameter lpBuffer den Namen des Computers als String und dem Parameter nSize die Länge der übergebenen Zeichenkette als Long zu.

Es ist sehr wichtig, dass Sie String-Parametern vor der übergabe an eine DLL eine Zeichenkette zuweisen, die mehr Zeichen enthält als der erwartete Wert haben kann. Ist der zurückgegebene String länger als der übergebene String, löst das einen Fehler aus.

In der Funktion aus Listing 1 können Sie die API-Funktion nun endlich einsetzen.

Public Function Computername() As String
     Dim strComputerName As String
     Dim lngAnzahlZeichen As Long
     Dim lngTemp As Long
     lngAnzahlZeichen = 256
     strComputerName = Space$(lngAnzahlZeichen)
     lngTemp = GetComputerName(strComputerName, lngAnzahlZeichen)
     Computername = Trim$(strComputerName)
End Function

Listing 1: Funktion zum Ermitteln des Computernamens per API

Zunächst deklarieren Sie dort die benötigten Variablen für den zu übergebenden Text sowie die Länge des Textes.

Der Variablen lngTemp weisen Sie den Rückgabewert der Funktion zu. Dem Parameter strComputerName weisen Sie mit der Space$-Funktion einen String mit 256 Leerzeichen zu. Nach dem Aufruf der Funktion benutzen Sie die Funktion Trim$, um die überflüssigen Leerzeichen des zurückgegebenen Wertes zu entfernen.

Testen Sie die Funktion mit Hilfe des Testfenster (zu öffnen mit Strg + G). Lassen Sie sich einfach den Computernamen in einem Meldungsfenster ausgeben:

  Computername
WIN7OFF13IND 

Benutzername per API ermitteln

Die Ausgabe des Benutzernamens können Sie in ähnlicher Weise vornehmen. Die Deklaration des entsprechenden API-Aufrufs lautet:

Declare Function GetUserName Lib "advapi32.dll" _
     Alias "GetUserNameA" (ByVal lpBuffer As String, _
     nSize As Long) As Long

Die Vorgehensweise zum Ermitteln des Namens des aktuell eingeloggten Benutzers ist prinzipiell mit dem Ermitteln des Computernamens identisch. Die Funktion zum Aufruf der API-Prozedur GetUserNameA ist allerdings etwas anders gestaltet, um Sie auf eine Besonderheit beim Aufruf von API-Funktionen aufmerksam zu machen (s. Listing 2).

Public Function Benutzername() As String
     Dim strBenutzername As String
     Dim lngAnzahlZeichen As Long
     lngAnzahlZeichen = 256
     strBenutzername = Space$(lngAnzahlZeichen)
     GetUserName strBenutzername, lngAnzahlZeichen
     Benutzername = Trim$(strBenutzername)
End Function

Listing 2: Funktion zum Ermitteln des Benutzernamens per API

Wie Sie erkennen können, gibt es in der Funktion keine Variable namens lngTemp, um den Rückgabewert der API-Funktion zu speichern. Die Funktion wird auch gar nicht in Form einer Wertzuweisung aufgerufen, wie es üblicherweise bei Funktionen der Fall ist, sondern wie eine Prozedur. Da es in den meisten Fällen nicht auf den Rückgabewert ankommt, sondern auf die geänderten Parameter, kann man sich hier die Deklaration einer Variablen und damit Zeit und Speicherplatz sparen.

Die beiden Funktionen können Sie nun zum Beispiel benutzen, um den Anwender beim Start der Datenbank mit seinem Namen zu begrüßen.

Zugriff auf Fenster und andere Objekte per Handle

Den Begriff Handle werden Sie sicher bereits einmal gehört haben. Ein Handle ist eine Möglichkeit, Objekte unter Windows eindeutig zu kennzeichnen. Dadurch, dass Windows mitunter Objekte aus dem Arbeitsspeicher temporär auf die Festplatte oder in andere Speicherbereiche verbannt, sind die Objekte teilweise nicht mehr unter der angegebenen Speicheradresse anzutreffen.

Dies erscheint zunächst wie ein Windows-internes Problem – da Sie aber per API Windows direkt steuern, erweisen sich Handles für den Entwickler als sehr nützlich. Der Inhalt eines Handles, also der Verweis auf ein Objekt, wird immer im Arbeitsspeicher gehalten – auch wenn das Objekt selbst zwischenzeitlich auf die Festplatte verbannt wurde.

Wenn Sie also per API auf ein Objekt zugreifen möchten, ermitteln Sie zunächst dessen Handle. Zur Ermittlung eines Handles gibt es unterschiedliche Möglichkeiten, von denen einige später vorgestellt werden. Wenn Sie das Handle einmal kennen, können Sie über das Handle auf das entsprechende Objekt zugreifen.

Deutlicher wird dies an einem Beispiel. Mit der Funktion GetWindowText soll der Titel des aktuellen Access-Hauptfensters ermittelt werden. Die API-Prozedur hat die folgende Deklaration:

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

Schreibe einen Kommentar