Visual Basic und Assembler - Seite 5
von Udo Schmidt
Beispiel
Nachfolgend ein Beispiel, das die Verwendung der oben aufgeführten Makros und der Einbindung des Codes in VB verdeutlichen soll.
HEX-Umwandlung
Zwar ist VB in der Lage, Hex-Code zu erzeugen, jedoch nur bis zu 8 Zeichen, da die Funktion auf Longs begrenzt ist. Wer ganze Zeichenketten oder ein Long-Array in HexCode umwandeln möchte, kann dies nur in einem Loop tun. Ein sehr alter recht geschickter ASM-Algorithmus ermöglicht dies in sehr kurzer Zeit unter Verwendung des Befehls DAA (DezimalAnpassung nach Addition zweier binary coded decimals =BCD).
.386 ; Keine "neuen" Pentium-Befehle .MODEL FLAT ; 32-Bit-Modus .CODE ; Codesection _run: ; Programmcode-Beginn include stdparas.inc ; Einfügen der Makros... ; *********************** src EQU <PA1> ; PA1 = source (Herkunft) tgt EQU <PA2> ; PA2 = target (Ziel) cnt EQU <PA3> ; PA3 = count (Anzahl) ; ************************ CHR2HEX PROC NEAR ; Prozedurbeginn init: mac SAVE ; Einfügen INT3, Sichern der Register mov esi,src ; SourceIndex <= source mov edi,tgt ; TargetIndex <= target mov ecx,cnt ; Counter <= count chr_loop: mov al,[esi] ; AL = nächstes Byte shr al,4 ; AL = AL / 16 = „high nibble“ ) add al,90h ; AL = AL + 90h daa ; high nibble = Zehner, low nibble=Einer adc al,40h ; AL = AL + 40h + Carry daa ; high nibble = Zehner, low nibble=Einer mov [edi],al ; [TargetIndex] <= Ergebnis inc edi ; TargetIndex += 1 mov al,[esi] ; dasselbe für das „low nibble“ and al,0Fh ; AL = low nibble add al,90h daa adc al,40h daa inc esi ; SourceIndex += 1 mov [edi],al inc edi dec ecx ; Counter -= 1 jnz chr_loop ; wenn nicht 0 => nächstes Byte stc ; Carry setzen (True zurückgeben) mac REST ; Register wiederherstellen CHR2HEX ENDP ; Prozedurende END _run ; Programmende
Die Kombination aus ADD-, ADC- und DAA-Befehlen ist wirklich trickreich und stellt bestimmt eine gute Übung dar, Assemblercode und Flags nachzuvollziehen! Um die Funktion nutzen zu können, bedarf es in VB des folgenden Rahmens:
Option Explicit Private Declare Function ASM_cdLong Lib "user32" _ Alias "CallWindowProcA" _ (ByRef adr As Long, _ ByVal PA1 As Long, _ ByVal PA2 As Long, _ ByVal PA3 As Long, _ ByVal PA4 As Long) As Long Function CNV2HEX(ptr As Long, LN As Long) As String Static asm(14) As Long If asm(0) = 0 Then asm(0) = &HEC8B5590: asm(1) = &H8B575653 asm(2) = &H7D8B0875: asm(3) = &H104D8B0C asm(4) = &HE8C0068A: asm(5) = &H27900404 asm(6) = &H88274014: asm(7) = &H68A4707 asm(8) = &H90040F24: asm(9) = &H27401427 asm(10) = &H46470788: asm(11) = &HF9E17549 asm(12) = &H5E5FC01B: asm(13) = &H10C25D5B asm(14) = &H0 End If ' ******************************************** Dim bar() As Byte ReDim bar(LN * 2 - 1) ASM_cdLong asm(0), ptr, VarPtr(bar(0)), LN, 0 CNV2HEX = StrConv(bar, vbUnicode) End Function
Im Deklarationsteil wird der Aufruf von CallWindowProc definiert. In diesem Fall als ASM_cdLong, da die Parameter etwas vom Standard abweichen. Dann wird die Funktion CNV2HEX erstellt, die zwei Parameter erwartet: Einen Pointer auf den umzuwandelnden Text, also z.B. StrPtr(MyText), sowie dessen Länge in Bytes.
Sicher wäre es möglich, die Funktion als CHR2HEX o.ä. zu deklarieren. Der Vorteil dieser bloß "formalen" Deklaration liegt in der Flexibilität: Die Funktion konvertiert ebenso Text
Debug.Print CNV2HEX(StrPtr(StrConv(<text>, vbFromUnicode)), Len(<text>))
wie sie ein ganzes Long-Array konvertieren kann:
Debug.Print CNV2HEX(VarPtr(arr(0)), UBound(arr) * 4 + 4)
Für beides ließen sich natürlich weitere VB-Funktionen erstellen, um den Aufruf übersichtlicher zu gestalten. Weitere Beispiele können auf der ActiveVB-Seite in der Rubrik Assembler und VB eingesehen werden.