API-Prozeduren sind in speziellen Dateien enthalten, die sich zumeist im
Windowsverzeichnis befinden. Meistens handelt es sich dabei um Dateien vom Typ DLL.
So gibt beispielsweise die Funktion GetSystemDirectory
aus der Datei
kernel.dll
zurück, wo sich das Windows-Systemverzeichnis befindet.
Um diese Funktion in VBA zu nutzen, muss im Deklarationsbereich eines Moduls mit
einer Declare
-Anweisung auf sie verwiesen
werden:
Private Declare PtrSafe Function GetSystemDirectory Lib "kernel32" _ Alias "GetSystemDirectoryA" _ (ByVal lpBuffer As String, nSize As Long) As Long
Die Syntax von Declare
setzt sich wie
folgt zusammen:
[Public|Private] Declare [PtrSafe] Sub|Function Name Lib "Datei" [Alias "Aliasname"] ([Argumente]) [As Typ]
Private
oder Public
(optional) bestimmt, ob die Prozedur nur
für dieses Modul oder anwendungsweit
sichtbar ist.PtrSafe
(optional) kann erst ab Office
2010 verwendet werden, in älteren Versionen verursacht das einen Fehler.
Auf einem 64-Bit Office muss PtrSafe
enthalten sein. Auf den Zweck von PtrSafe
gehen wir später noch ein.Function
oder
Sub
angeben muss, hängt davon ab,
ob die Prozedur einen Rückgabewert hat. Je nachdem steht die Prozedur anschließend
als Sub oder Function zur Verfügung.Name
ist der Name, mit dem man in VBA die Prozedur ansprechen kann.Lib
Datei
ist der Name der
Datei. Bei DLL-Dateien muss die Dateierweiterung nicht angegeben werden.
Befindet sich die DLL nicht in einem Verzeichnis, das in der PATH-Umgebungsvariable
enthalten ist, muss der vollständige Verzeichnispfad angegeben werden.Alias
Aliasname
(optional,
casesensitiv) gibt den Prozedurnamen innerhalb der DLL an. Wird
Alias
verwendet, kann unter Name
ein beliebiger anderer Prozedurname verwendet werden, der dann stattdessen
von VBA angesprochen wird. Das ist sinnvoll, falls der Name in der DLL nicht
den erlaubten Namenskonventionen in
VBA entspricht oder der Name mit schon verwendeten Namen in Konflikt käme.
Endet der Aliasname mit einem „A“, deutet das an, dass es sich intern in der
DLL um die ANSI-Version der Prozedur handelt. Meist existiert dann auch eine
Version mit einem „W“ („Wide“ für UTF-16) am Ende. Da UTF-Strings in der Regel
für eine Nutzung in VBA mit StrConv
konvertiert werden müssen, ist in VBA meistens die ANSI-Variante einfacher nutzbar.As Any
bekommt.
Das ist eigentlich kein richtiger Datentyp, sondern so wird die Typprüfung
unterdrückt, um ein Argument beliebigen Datentyps zu übergeben. In aller
Regel gibt dann einer der anderen Parameter vor, welchen Datentyp so ein
Parameter haben muss.As
Typ
darf bei einer
Sub
nicht angegeben werden - eine
Sub hat schließlich keinen Rückgabewert.Eigentlich ist damit auch schon alles erledigt: Uns steht nun eine neue Funktion
namens GetSystemDirectory
zur Verfügung (in dieser Syntax zumindest
ab Office 2010, aber darauf gehen wir noch ein). Der Teufel liegt in zahlreichen
Details. Unter anderem, weil APIs in Programmiersprachen geschrieben sind, die
teils andere Datentypen haben. Aber auch die Art und Weise, wie Ergebnisse
zurückgegeben werden, ist im ersten Moment ungewohnt.
Bei GetSystemDirectory
interessiert uns beispielweise nicht etwa
der Rückgabewert vom Typ Long, wie man das im ersten Moment beim Lesen der
Declare-Anweisung erwarten könnte, sondern der Parameter lpBuffer
,
den man beim Aufruf der Funktion schon „leer“ übergeben muss. Die Funktion überschreibt
diesen String dann mit dem eigentlichen Rückgabewert. Mit „leerem“ String ist dabei
ein String bestimmter Länge, bestehend aus Null-Byte-Zeichen
(vbNullChar) gemeint.
Das ist notwendig, weil die Verwaltung des Arbeitsspeichers für Strings in der DLL
anders abläuft als in VBA, und deswegen ist es auch wichtig, ob die Parameter
ByRef oder ByVal übergeben werden.
Diese Art, an das Ergebnis einer API-Prozedur zu kommen, ist typisch. Der eigentliche
Rückgabewert enthält dagegen, je nach Prozedur, ganz unterschiedliche Informationen:
Manchmal bedeutet „0“ z. B., dass die Funktion erfolgreich abgearbeitet wurde,
und Werte ungleich „0“ sind Fehlernummern. Bei anderen Prozeduren gibt er an, wie
viele Zeichen der gesuchte Text enthält, oder wie lang der „leere“ String sein müsste,
um den zurückzugebenden String vollständig unterzubringen. Denn bei Strings ist
auch das typisch bei APIs: Oft wird auch die Länge des Strings an die API übergeben,
und hinterher muss man nicht benötigte vbNullChar
-Zeichen am Ende
abschneiden.
Aufgrund all dieser Besonderheiten ist es oft sinnvoll, zu einer Declare-Anweisung noch eine Prozedur zu schreiben, über die der eigentliche Aufruf erfolgt:
Private Declare PtrSafe Function GetSystemDirectoryA Lib "kernel32" _ (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Public Function GetSystemDirectory() As String Dim lngLen As Long, lpBuffer As String, nSize As Long nSize = 255 lpBuffer = String(nSize, vbNullChar) lngLen = GetSystemDirectoryA(lpBuffer, nSize) GetSystemDirectory = Left(lpBuffer, lngLen) End Function
Nun ist der eigentliche Aufruf ganz einfach:
Debug.Print GetSystemDirectory() C:\Windows\system32