|
Eine ganze Reihe von API-Funktionen erfordert die Übergabe von
so genannten Zeigern ("Pointern") anstelle des Wertes
einer Variablen. Die Zeiger auf Visual Basic-Variablen (ein Zeiger
ist nichts weiter als die Adresse einer Variable im Arbeitsspeicher)
erhalten Sie über die versteckten und nicht offiziell
dokumentierten VB-Funktionen StrPtr (für Variablen des Datentyps
String), ObjPtr (Objekt-Variablen) und VarPtr (für alle übrigen
Datentypen).
Doch es gibt auch API-Funktionen, die umgekehrt einen Zeiger
zurückgeben. Damit Sie auf den Inhalt zugreifen können, der an der
Speicherstelle abgelegt ist, auf die der Zeiger verweist, bräuchten
Sie die Umkehrung der genannten Funktionen. Diese Funktionen stellt
Visual Basic leider nicht zur Verfügung.
Auch mit API-Funktionen gibt es keine Möglichkeit, auf direktem
Wege an den an der Speicheradresse abgelegten Wert zu gelangen. Sie
können jedoch mit Hilfe der API-Funktion CopyMemory
(die eigentlich RtlMoveMemory heißt) den Speicherinhalt von dieser
Adresse in eine vorab deklarierte Variable des betreffenden
Datentyps kopieren. Dabei sind je nach Datentyp des Inhalts
unterschiedlich viele Bytes zu kopieren. Die Deklaration von
CopyMemory lautet:
Public Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (Dest As Any, Src As Any, _
ByVal Length As Long)
Recht einfach ist das Kopieren von Inhalten der
"einfachen" Datentypen Integer, Long, Single, Double,
Byte, Currency und Date. Zahlen dieses Datentyps belegen eine
jeweils eindeutig definierte Anzahl an Bytes im Arbeitsspeicher.
Daher steht die Anzahl der zu kopierenden Bytes fest, so dass Sie
die Kopiererei in die folgenden Hilfsfunktionen verlagern können:
Public Function PtrInt(ByVal Pointer As Long) As Integer
Dim nDest As Integer
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 2
PtrInt = nDest
End Function
Public Function PtrLng(ByVal Pointer As Long) As Long
Dim nDest As Long
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 4
PtrLng = nDest
End Function
Public Function PtrSng(ByVal Pointer As Long) As Single
Dim nDest As Single
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 4
PtrSng = nDest
End Function
Public Function PtrDbl(ByVal Pointer As Long) As Double
Dim nDest As Double
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 8
PtrDbl = nDest
End Function
Public Function PtrByte(ByVal Pointer As Long) As Byte
Dim nDest As Byte
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 1
PtrByte = nDest
End Function
Public Function PtrCur(ByVal Pointer As Long) As Currency
Dim nDest As Currency
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 8
PtrCur = nDest
End Function
Public Function PtrDate(ByVal Pointer As Long) As Date
Dim nDest As Date
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 8
PtrDate = nDest
End Function
Die entsprechende Funktion für Variant-Variablen gibt es
natürlich auch. Sie sieht genau so aus wie die voranstehenden
Funktionen, nur dass hier 16 Bytes zu kopieren sind. Da aber
Variant-Variablen in sich die verschiedensten Datentypen enthalten
können, ist nicht immer gesagt, dass Sie mit dem kopierten Inhalt
auch tatsächlich etwas anfangen können. Ich will hier auf die
verschiedenen Unwägbarkeiten nicht weiter eingehen und überlasse
es Ihnen, die folgenden Hilfsfunktion auf ihre Tauglichkeit in einem
gegebenen Kontext zu prüfen und sie zu verwenden
Public Function PtrVar(ByVal Pointer As Long) As Variant
Dim nDest As Variant
CopyMemory ByVal VarPtr(nDest), ByVal Pointer, 8
PtrVar = nDest
End Function
Bei Variablen des Datentyps String ist es nicht ganz so einfach.
Die Länge eines Strings ist ja nicht per Definition festgelegt,
sondern variabel. Einer entsprechenden Hilfsfunktion müssen Sie
daher zusätzlich die Länge des Strings übergeben. In der Regel
liefern die API-Funktionen, die String-Zeiger zurückgeben, auch die
Anzahl der Zeichen des Strings (sehr oft über den Rückgabewert der
API-Funktion). Ich will hier nicht näher auf die Umstände
eingehen, die das Thema Unicode betreffen - wenn Sie die jeweiligen
Ascii-Versionen der betreffenden API-Funktionen (der Funktionsname
im Alias-Teil der Deklaration endet mit einem "A")
verwenden, greift Visual Basic selbst im Hintergrund zur Anpassung
ein. Da aber Visual Basic selbst wiederum Strings intern im
Unicode-Format speichert, jedes Zeichen also zwei Bytes belegt, ist
die Anzahl der zu kopierenden Zeichen doppelt so groß wie die
Anzahl der Zeichen.
Die Kopierfunktion für Strings berücksichtigt diese
Verdoppelung und legt auch vorab einen leeren String(-Puffer
aus Ascii-0-Zeichen) an, in den die Zeichen kopiert
werden:
Public Function PtrStr(ByVal Pointer As Long, ByVal Size As Long) _
As String
Dim nString As String
Dim nPos As Long
nString = String$(Size, 0)
CopyMemory ByVal StrPtr(nString), ByVal Pointer, Size * 2
nPos = InStr(nString, Chr(0))
If nPos Then
PtrStr = Mid$(nString, 1, nPos - 1)
Else
PtrStr = nString
End If
End Function
|