VB6 und COM Spezialitäten

20 Jahre liegen meine VB6 Zeiten zurück und trotzdem denke ich immer wieder gerne an damals zurück.
Die einfache Möglichkeit UIs mit Freude zu erstellen, konnte mir bis heute kein noch so moderner dotNet Editor wiederbringen.

Doch an die Limitierungen dieser Programmiersprache erinnere ich mich auch noch … und auch, wie man sie “kreativ” umgehen musste.


64 Bit Rechnungen mit Currency

Das VB6 Datentypensystem basierte 1:1 auf COM VARIANT Datentypen, die wegen ihres Ursprungs unter Windows 3.x noch sehr 16-bit lastig waren.

Nachdem Integer in VB (wie auch int im ursprünglichen C) nur 16-bit breit ist, fasst Long unglaubliche 32 bit aus.
Dass irgendjemand mal 64-bit zum Rechnen braucht, war damals nicht vorstellbar, also gab es kein LongerInt, LongLong oder BigInt.

Eine Zielgruppe gab es aber dennoch und zwar die förmlichen Menschen in Banken und Finanzabteilungen. Die hatten kein Vertrauen in Double in Bezug auf Rundungen und brauchten eine Festkommastellen Zahl, die Milliarden und Billiarden abbilden konnte.

Dim i64 As Currency war die Lösung, denn dieser Typ fasste 64 Bit und ist eine Festkommazahl dessen 64-Bit Wert fix durch 10 000 dividiert wird. Die binäre Zahl 123 456 wird dann als 12.3456 dargestellt.

LSet als memcpy() Ersatz

Das LSet Statement kopiert den Inhalt eines Datentyps in einen anderen und macht das ohne zu hinterfragen, ob die Typen stimmen. So habe ich gerne Bytes herumkopiert

 1Private Type UI32
 2  Value As Long
 3End Type
 4Private Type UI32Bytes
 5  Value0  As Byte
 6  Value1  As Byte
 7  Value2  As Byte
 8  Value3  As Byte
 9End Type
10
11Private Sub MemCpyUI32(ByRef src As UI32, ByRef dst As UI32Bytes)
12  LSet dst = src
13End Sub

Leere Arrys

Um Arrays auf eine bestimmte Größe zu setzen, nutzt man

1Dim strArray As String()
2ReDim strArray(count - 1)

Wer glaubt, dass ein einfaches Dim var As String() ohne ReDim ein leeres String-Feld erzeugt, der irrt leider. Es kommt nämlich eine nicht initialisierte Variable heraus, mit der Funktionen wie UBound oder LBound fehlschlagen.

Ruft man aber Split mit einem leeren String auf, kommt ein typisiertes String-Array heraus, das kein Element beinhaltet, wo Ubound also ohne Fehler -1 liefert.

1Function EmptyStringArray() As String()
2  EmptyStringArray = Split(vbNullString)
3End Function

Leere Byte-Arrays sind ebenso ein Problem, doch hier reicht die implizite Konvertierung eines leeren Strings aus

1Function EmptyByteArray() As Byte()
2    EmptyByteArray = vbNullString
3End Function

Globale Variablen als Funktionen

Klassen können mit Property Get/Let/Set Routinen um Eigenschaften erweitert werden, wo man syntaktisch glaubt, man würde eine Member-Variable setzen, aber in Wahrheit läuft eine Funktion, die Werte validieren und manipulieren kann.

Wenn man ein “Modul” in VB6 anfügt und dort Property Routinen implementiert, erscheinen dieses Properties wie globale Variablen in allen anderen Modulen und Klassen. Und das ist echt nett beim Debuggen.

 1Private secretX As String
 2
 3Public Property Let GlobalX(ByVal value As String)
 4    secretX = value + "_patch_added"
 5End Property
 6
 7Public Property Get GlobalX() As String
 8    GlobalX = secretX
 9End Property
10
11Public Sub Main()
12    GlobalX = "Hello-World"
13    MsgBox GlobalX
14End Sub

Fazit

Ich trauere ein bisschen um diese alten VB-Minihacks. Es hat mich damals viel Zeit gekostet, sie herauszufinden … und heute sind sie wirtschaftlich leider wertlos.

Und trotzdem erinnere ich mich noch gerne daran zurück, als man quasi im Abenteuer-Modus durch VB durchlief und immer wieder was Neues entdeckte. Das musste dann gleich in irgend einem Web-Forum gepostet werden, auch wenn es sonst niemand interessiert hat, aber man war glücklich dabei.