|
Seit Visual Basic 6 können Sie zwar den Inhalt
eines Arrays direkt einem anderen Array zuweisen und brauchen nicht
in einer Schleife alle Elemente von einem Array in das andere zu
kopieren. Doch zum Kopieren von einem bestimmten Teil eines Arrays
in ein anderes sind Sie weiterhin auf Schleifen angewiesen. Und in
früheren Versionen vor Visual Basic 6 müssen Sie auch
komplette Arrays weiterhin per Schleife kopieren.
Mit Hilfe der API-Funktion CopyMemory können Sie beliebig lange
Byte-Folgen im Arbeitsspeicher kopieren. Eigentlich heißt die
Funktion "RtlMoveMemory" - sie wird aber meistens der
leichteren Merkbarkeit als "CopyMemory" deklariert.
Außerdem werden von ihr die Bytes nicht tatsächlich verschoben,
sondern lediglich kopiert - der Speicherinhalt von der Quelle werden
nicht verändert.
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal Dest As Long, ByVal Source As Long, _
ByVal Bytes As Long)
Da bei Arrays (ausgenommen sind String- und Variant-Arrays) die
Elemente als durchgehende Byte-Folge in einem Block im Speicher
vorliegen, können Sie mit CopyMemory auch Teilbereiche eines Arrays
kopieren. Als Dest (Ziel - Speicheradresse, an die kopiert werden
soll) und Source (Quelle - Speicheradresse, von der ab kopiert
werden soll) geben Sie einen Zeiger auf das jeweilige Element an.
Die Zeiger auf die Elemente liefert Ihnen die (undokumentierte)
Visual Basic-Funktion VarPtr. Schließlich geben Sie noch die Anzahl
Bytes an, die kopiert werden sollen. Die Anzahl der Bytes ergibt
sich aus der Anzahl der Elemente, multipliziert mit der Byte-Länge
eines Elements entsprechend dem Datentyp der Arrays.
Dim ArraySource() As Long
Dim ArrayDest() As Long
Dim i As Integer
ReDim ArraySource(0 to 99)
For i = 0 To 99
ArraySource(i) = i
Next ' i
ReDim ArrayDest(0 To 9)
CopyMemory VarPtr(ArraySource(50)), VarPtr(ArrayDest(0)), 10 * 4
For i = 0 To 9
Debug.Print ArrayDest(i)
Next ' i
Verpacken Sie den Aufruf von CopyMemory in eine Hilfsfunktion,
können Sie das Kopieren sicherer gestalten. Denn falls Sie
versehentlich über die Obergrenze des Ziel-Arrays hinaus Bytes
kopieren sollten, wird der auf das Ziel-Array folgende
Speicherbereich überschrieben - in der Regel führt das zu schweren
Ausnahmefehlern und damit zu Totalabstürzen Ihrer Anwendung. Die
Hilfsfunktion verhindert automatisch, dass Sie einen Start- oder
Ziel-Index angeben können, der die Untergrenzen der Arrays
unterschreitet, und löst gegebenenfalls einen Laufzeitfehler aus.
Setzen Sie den optionalen Parameter ForceUBound, der auf True
voreingestellt ist, auf False, wird ebenfalls ein Laufzeitfehler
ausgelöst, wenn die Obergrenze eines der beiden Arrays durch die
angegebene Anzahl der Elemente überschritten würde. Bei der
Voreinstellung True sorgt die Funktion dagegen automatisch dafür,
dass das Kopieren auf die Obergrenzen beider Arrays beschränkt
bleibt.
Public Sub CopyArrayPartLong(Source() As Long, Dest() As Long, _
ByVal SourceStartIndex As Long, ByVal CountElements As Long, _
ByVal DestStartIndex As Long, _
Optional ByVal ForceUBound As Boolean = True)
Dim nPtrSourceStart As Long
Dim nPtrDestStart As Long
Dim nCountElements As Long
If SourceStartIndex < LBound(Source) Then
Err.Raise 9, "CopyArrayPartLong", "SourceStartIndex"
End If
If DestStartIndex < LBound(Dest) Then
Err.Raise 9, "CopyArrayPartLong", "SourceDestIndex"
End If
nCountElements = CountElements
If SourceStartIndex + nCountElements - 1 > UBound(Source) Then
If ForceUBound Then
nCountElements = UBound(Source) - SourceStartIndex + 1
Else
Err.Raise 9, "CopyArrayLong", "CountElements > SourceUBound"
End If
End If
If DestStartIndex + nCountElements - 1 > UBound(Dest) Then
If ForceUBound Then
nCountElements = UBound(Dest) - DestStartIndex + 1
Else
Err.Raise 9, "CopyArrayLong", "CountElements > DestUBound"
End If
End If
nPtrSourceStart = VarPtr(Source(SourceStartIndex))
nPtrDestStart = VarPtr(Dest(DestStartIndex))
CopyMemory nPtrDestStart, nPtrSourceStart, nCountElements * 4
End Sub
Der Aufruf dieser Hilfsfunktion sähe entsprechend dem
obenstehenden Beispiel folgendermaßen aus:
Dim ArraySource() As Long
Dim ArrayDest() As Long
Dim i As Integer
ReDim ArraySource(0 to 99)
For i = 0 To 99
ArraySource(i) = i
Next ' i
ReDim ArrayDest(0 To 9)
CopyArrayPartLong ArraySource, ArrayDest, 50, 10, 0
For i = 0 To 9
Debug.Print ArrayDest(i)
Next ' i
Die Hilfsfunktionen für Arrays anderer Datentypen finden Sie im
Modul modCopyArrayPart.bas, das Sie zu diesem Artikel
herunterladen können. Sie unterschieden sich lediglich in der
Deklaration der Datentypen als Parameter übergeben Quell- und
Ziel-Arrays, im Faktor, mit dem die Anzahl der zu kopierenden
Elemente zur Bestimmung der zu kopierenden Bytes multipliziert wird,
und in den Source-Angaben, die dem Error-Objekt übergeben werden.
|