Rubrik: Variablen/Strings · Arrays | VB-Versionen: VB6 | 28.06.05 |
Übergabe eines Array an eine Prozedur: ByVal ByVal-Übergabe eines Array an eine Prozedur durch einen Variant-Parameter | ||
Autor: Manfred Bohn | Bewertung: | Views: 36.828 |
ohne Homepage | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Übergibt man eine Variable an eine 'Function' oder 'Sub' mit dem Schlüsselwort 'ByRef' wird ein Verweis auf die Variable übergeben. Die Änderung der Variable innerhalb der Prozedur wirkt sich auch auf die Variable im rufenden Programm aus.
Verwendet man statt dessen das Schlüsselwort 'ByVal', wird intern eine Kopie der Variable erstellt, auf die die Prozedur zugreifen kann. Veränderungen des Wertes der Variable innerhalb der Prozedur wirken sich auf das 'Original' im rufenden Programm nicht aus.
Versucht man ein ARRAY mit dem Schlüsselwort 'ByVal' zu übergeben, meldet die VB-IDE sofort einen Fehler: Array-Argument muss als Verweis 'ByRef' übergeben werden.
DAS IST EIN BLUFF !!
Verwendet man statt dessen einen Variant-Parameter mit dem Schlüsselwort 'ByVal' in der Deklarationszeile der 'Function' bzw. 'Sub', kann man auch ein Array 'ByVal' an diesen Parameter übergeben. Es wird eine lokale Kopie des gesamten Array zur Verwendung in der gerufenen Routine erstellt.
Zu beachten ist allerdings, dass ein Variant-Parameter alles mögliche enthalten kann. Man sollte sich deshalb innerhalb der Prozedur stets zunächst davon überzeugen, dass tatsächlich ein Array übergeben worden ist und aus welchem Datentyp die Elemente dieses Array bestehen.
Von Interesse ist ferner, dass dieses lokale Array sich stets wie ein dynamisch deklariertes Array verhält - unabhängig von der Art der Deklaration im rufenden Programm. Der Datentyp des lokalen Array entspricht dem Datentyp, mit dem es im rufenden Programm deklariert worden ist. Das gilt auch für Anzahl und Grenzen der Dimensionen.
Die Übergabe eines Array an eine Prozedur durch einen Variant-Parameter funktioniert bei allen internen VB-Datentypen, ausser bei Strings fester Länge. Bei Arrays, deren Elemente benutzerdefinierte Datentypen sind, muss die COM-Unterstützung vorhanden sein. (Zur Erzeugung solcher UDTs siehe Tipp: UDT als Parameter einer Klassen-Prozedur II).
' ===================================================================== ' Demonstration der Übergabe eines Array ' an eine Prozedur 'ByVal' ' ===================================================================== Option Explicit ' schnelle API-Kopierfunktion für Bytefolgen Private Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" ( _ Ziel As Any, _ Quelle As Any, _ ByVal Anzahl_Bytes As Long) ' Teil des 'SafeArray', ... Private Type udtSafeArray Dimensionen As Integer ' Zahl der Dimensionen Features As Integer ' Attribute (Bitfolge) Bytes_Pro_Feld As Long ' Anzahl der Bytes pro Element Locks As Long ' Anzahl der gesetzten Array-Sperren Data_Pointer As Long ' bei Strings: Varptr --> Deskriptor End Type
Sub main() ' statisches Integer Array deklarieren Dim iarr(1 To 100, 1 To 10) As Integer Dim i As Long, k As Long ' Loop ' Array mit Werten füllen For i = 1 To 100 For k = 1 To 10 iarr(i, k) = i * 100 + k Next k Next i ' Aufruf einer Funktion (BYVAL-Parameter) Test1 iarr() ' Ist das Array tatsächlich unverändert geblieben? For i = 1 To 100 For k = 1 To 10 If iarr(i, k) <> i * 100 + k Then Stop ' Nanu! Next k Next i ' Aufruf einer Funktion (BYVAL-Parameter) Test2 iarr() ' Ist das Array tatsächlich unverändert geblieben? For i = 1 To 100 For k = 1 To 10 If iarr(i, k) <> i * 100 + k Then Stop ' Nanu! Next k Next i End Sub
Private Function Test1(ByVal iarr As Variant) As Boolean ' Die Routine demonstriert die Ermittlung der ' Informationen zu einem Array, das ByVal durch ' einen Variant-Parameter übergeben worden ist Dim i As Long, k As Long ' Loop Dim typname As String ' Datentyp des Array Dim vt As VbVarType ' VarType der Elemente des Array Dim sa As udtSafeArray ' Variable für SafeArray-Struktur Dim ptr As Long ' Zeiger auf SafeArray-Struktur ' Liegt überhaupt ein Array in 'iArr' vor If Not IsArray(iarr) Then Exit Function ' Datentyp der Array-Elemente feststellen typname = TypeName(iarr) If UCase(typname) <> "INTEGER()" Then Stop ' NANU ' Vartype der Elemente des Array ermitteln vt = VarType(iarr) - vbArray If Not vt = vbInteger Then Stop ' NANU ' Zeiger auf SafeArray-Struktur besorgen Call CopyMemory(ptr, ByVal VarPtr(iarr) + 8, 4&) Call CopyMemory(sa, ByVal ptr, LenB(sa)) ' Es müssten 2 Dimensionen sein .... If sa.Dimensionen <> 2 Then Stop ' Nanu ' Es müssten 2 Bytes/Feld sein (wg. Integer) If sa.Bytes_Pro_Feld <> 2 Then Stop ' Nanu! ' Array-Inhalt prüfen und dann ' explizit zurücksetzen (nur lokal!) For i = LBound(iarr, 1) To UBound(iarr, 1) For k = LBound(iarr, 2) To UBound(iarr, 2) If iarr(i, k) <> i * 100 + k Then Stop ' Nanu! iarr(i, k) = 0 Next k Next i ' Am Ende der Routine wird das lokale Array ' automatisch freigegeben Test1 = True End Function
Private Function Test2(ByVal iarr As Variant) As Boolean ' Lokales (dynamisch deklariertes) Array ' übergeben 'BYVAL' ' innerhalb der Prozedur neu deklarieren ' nur 1 Dimension, andere Grenzen ' Das lokale Array ist dynamisch deklariert!! ReDim iarr(-100 To 100) Dim i As Long ' Lokales Array füllen For i = -100 To 100 iarr(i) = i Next i ' Am Ende der Routine wird das lokale Array ' automatisch freigegeben Test2 = True End Function