
VB-Inline-ASM ist ein Plugin für Visual Basic 6 welches es ermöglicht ASM-Code direkt in Visual Basic einzugeben. Dies funktioniert so, dass der ASM-Code als Kommentar deaktiviert in den VB-Code eingegeben wird. Beim Kompilieren fängt ein Hook den ASM vom VB-Compiler ab, sucht nach den auskommentierten ASM-Codes, reaktiviert diese und deaktiviert gleichzeitig VB-Code der ersatzweise eingefügt werden kann. Der modifizierte ASM-Code wird dann vom MASM-Compiler (welcher auf dem System ebenfalls installiert sein muß) in den endgültigen Binärcode kompiliert.
Über diesen Trick ist es möglich ASM doch in VB einzubinden, obwohl VB selbst diese Möglichkeit nicht bietet. Der Nachteil ist dabei offensichtlich, dass Debugging für ASM-Codes im VB-Editor nicht möglich ist, Fehler führen meistens zu einem harten Absturz des Programms. Der Programmierer muß also genau wissen was er macht und der eingefügte ASM-Code muß fehlerfrei sein. Der ASM-Code sollte also am besten zuerst in einem ASM-Compiler entwickelt werden und erst dann wenn dieser fehlerfrei funktioniert, in bestehende VB-Codes integriert werden.
Damit Debugging der VB-Codes möglich ist, müssen die Codes doppelt geschrieben werden, einmal in VB und einmal in ASM. Dies bietet auch die Möglichkeit Geschwindigkeitsvergleiche und Code-Tests durchzuführen.
VB löscht normalerweise die ASM-Codes beim Kompilieren, mit VB-Inline-ASM ist es möglich, den von VB kompilerten ASM-Code zu analysieren und möglicherweise auch zu optimieren. Oder man kann ihn verwenden um zu lernen wie VB zu ASM wird.
Hinweis
VB-Inline-ASM funktioniert natürlich nur mit kompiliertem ASM-Code (System-Code, Native-Code), nicht mit P-Code. (P-Code, Primitiv-Code ist kein echter Maschinen-Code sondern nur eine in Binärform umgewandelter VB-Code der von einem Interpreter ausgeführt wird. Dies muß in den Compileroptionen eingestellt sein.)
VB-Inline-ASM basiert auf einem Code der auf Planet-Source-Code veröffentliche wurde, aber mittlerweile da nicht mehr zu finden ist. VBFibre da ist der Original-Code noch verfügbar.
Das hier veröffentlichte AddIn wurde verbessert und ist nicht mehr identisch mit dem Original.
Das Programm ist Freeware und liegt im Download.
Ab der Version 0.15 hat VbInlineAsm nun ein Installer.
WICHTIG:
Das Add-In wird nun in das "Programme" Verzeichnis installiert. Falls eine ältere Versionen noch im "..\VB98\Wizards\" liegt, müssen alle Dateien von VbInlineAsm Manuell entfernt werden. Dazu müssen alle Visual-Basic Instanzen beendet werden, und wenn eigene Templates erstellt wurden, müssen diese nach der Installation ins neue "VbInlineAsm-Templates" Verzeichnis verschoben werden.
oder
VbInlineAsm_Deinstaller_Version_0.01_bis_0.14.exe Löscht alle VbInlineAsm-Dateien aus dem Verseichnis
"..\VB98\Wizards\"
"..\VB98\Wizards\VbInlineAsm-Templates\"
"..\VB98\Wizards\VbInlineAsm\"
"..\VB98\Wizards\VbInlineAsm\VbInlineAsm-Templates\"
Alle Visual-Basic Instanzen beenden
(Alte VbInlineAsm Version aus "..\VB98\Wizards\" entfernen, wenn vorhanden)
VbInLineAsm_Installer.exe ausführen
Add-In in Visual-Basic aktiviert, unter Menü -> Add-Ins -> AddIn-Manager -> VbInlineAsm , Laden
Danach taucht ein neues Icon auf der Symbolleiste und ein Eintrag im Menü Add-Ins auf, über diese können die Einstellungen von VbInlineAsm geändert werden. In den Optionen kann das Umleiten und Bearbeiten des
ASM-Codes aktiviert oder deaktiviert werden.
Konfiguration anpassen, Pfad für MASM eintragen (zB. C:\MASM32\BIN\ML.exe)
Im Template-Verzeichnis können Codes als TXT gespeichert werden die im
VB-Editor über Kontektmenü oder Optionen in den Code eingefügt werden können. (..\VbInlineAsm\Templates\*.txt)
Bei einer Kompilierung mit VbInlineAsm werden alle Dateien im Verzeichnis des Projekts in "\..Projekt..\_VbInlineAsm\" gespeichert.
Zum Updaten einer bestehenden Installation ist es nicht notwendig die Alte erst zu deinstallieren, es können die neuen Dateien über die alten installiert werden.
Es können weitere Sprachen installiert werden indem eine Sprachdatei ???.lng erstellt wird die im Verzeichnis "Language" bei VbInLineAsm.dll liegen muß. (??? ist der Platzhalter für den Namen der Sprache in Englisch.) Am besten eine Bestehende Datei kopieren, den Dateinamen anpassen und die Texte ändern. Im Moment werden Deutsch und Englisch unterstützt. Falls Benutzer weitere Sprachen erstellen, werden diese in kommenden Versionen enthalten sein.
Im Bug-Report können Fehler gemeldet werden.
| Option | Beschreibung |
|---|
| |
| Optionen | |
|---|
| InLineAsm Aktiv | Aktiviert/Deaktiviert die InlineASM Kompilierung |
| |
| CFG speichern | Speichert Options-Einstellungen individuell für dieses Projekt |
| Compiler-Hilfe | Zeigt die Hilfe der Compiler-Programme an |
| Schliessen | Verbirgt das Options-Fenster |
| |
| Build Optionen | |
|---|
| DOS-Konsole App | DOS-Konsolen App Linker-Schalter setzen |
| Std Dll | Erzeugt DEF-Datei und modifiziert Kommandozeile für Std C++ DLL |
| Listings für alle Module | Generiert VB C2 LST-Listings für alle Dateien |
| OBJ-Dateien speichern | Speichern OBJ-Dateien ins Listing-Verzeichnis |
| Compiler Pfad | Pfad für Assembler-Compiler setzten (ML.exe für MASM) |
| Editor Pfad | Pfad für ein ASM-Editor setzten (NotePad.exe) |
| |
| Compile Kontrolle | |
|---|
| Pause vor dem Kompilieren | Pause vor dem Ausführen des Compilers (zu ASM) |
| Pause vor dem Linken | Pause vor dem Ausführen des Linkers |
| Cmd-Zeile ändern | Ermöglicht das Anpassen der KomandoZeile für dem Kompilieren |
| Linken überspringen | OBJ-Dateien werden nicht gelinkt (zu EXE oder DLL) |
| |
| Debug Optionen | |
|---|
| Debug MsgBox anzeigen | Alle Debug-Nachrichten zeigen eine MsgBox |
| DebugLog speichern | Debug Nachrichten in DebugLog speichern |
| Log erzwingen | DebugLog Ausgabe für alle Kompilierungen erzwingen |
| DebugLog löschen vor dem Kompilieren | Löscht DebugLog vor jeder Kompilierung |
| Assembler Nachrichten in Log speichern | Speichert Assembler Nachrichten in das DebugLog |
| Detaillierte MASM und LINK Map-Datei speichern | Assembler und Linker Schalter für MAP-Dateien Ausgabe setzen |
| |
| Allgemeine Optionen | |
|---|
| Sprache | |
| Laden beim Start | Laden des Add-In beim IDE-Editor Start |
| Fenster über andere | Add-In Fenster über alle anderen setzen |
| Code-Beispiele Kontext Menü | Ermöglicht über Kontext-Menu Beispiel-Codes einzufügen |
| ComboBox verwenden | Benutzt ComboBox für das Kontext-Menu für Templates |
| |
| Aufräum Optionen | |
|---|
| DbgLog | Alle Log-Dateien löschen |
| *.LST | Alle LST-Dateien löschen |
| *.ASM | Alle ASM-Dateien löschen |
| Log löschen | Löscht die LOG-Dateien |
| |
| Code-Beispiele Templates | |
|---|
| Einfügen | Fügt das ausgewählte Code-Beispiel im Editor ein |
| Marker | Beschreibung |
|---|
| '#ASM_VB | VB-Code Variante während der Entwicklungs-Zeit verwendbar, wird bei Kompilierung aus dem Code entfernt und durch ASM ersetzt |
|
| '#ASM_STARTALL | Löscht den kompletten Code in der Prozedur außerhalb des #ASM_ Blocks (ein ASM_STARTALL in der Prozedur überschreibet alle ASM_START) |
| '#ASM_START | Bearbeitet den ASM_ Block, aber beläßt Codes außerhalb des ASM_ Blocks |
|
| '#ASM_END | Ende der Ersetzung |
Es ist empfohlen ASM_STARTALL zu verwenden um die volle Kontrolle über den Code zu haben. Wird ASM_START verwendet muß unbedingt der Code in der LST-Datei geprüft werden um die Funktion korrekt übersetzt wurde. Der Compiler führt Optimierungen durch die möglicherweise nicht beabsichtigt oder unvorhergesehen sind.
Alle ASM-Codes müssen mit ' auskommentiert werden, da natürlich der VB-Editor mit ASM nichts anfangen kann und Fehler melden würde. Die ASM-Codes werden erst beim kompilieren aktiviert. Deshalb muß ein Programm mit solchen ASM Inline-Codes als native EXE und nicht als P-Code kompiliert werden. Dies kann eingestellt werden über Menü -> Projekt -> Eigenschaften von... -> Kompilieren -> Kompilieren zu System-Code (Native Code).
Tip:
Um herauszufinden wie der eigene ASM Code am besten in die Routinen integriert werden kann, sollten die Codes erst mal in VB kompiliert werden um zu erkennen wie VB den Code in ASM kompiliert. Danach kann dies als Grundlage verwendet werden um die eigenen ASM-Codes einzufügen.
Es können Codes auch kompiliert werden um sie nachträglich zu Verbessern, ohne das der gesamte ASM-Code neu geschrieben werden muß.
Und natürlich können die ASM-Codes die VB erzeugt auch genutzt werden um zu lernen wie aus VB-Codes ASM-Codes werden, oder welche Änderungen bestimmte Compiler Optionen zur Optimierung den ASM-Code verändern.
'#ASM_VB
'<-- VB-Code
'#ASM_STARTALL
'
' ;<-- ASM-Code
'
'#ASM_END oder
'#ASM_VB
'<-- VB-Code
'#ASM_START
'
' ;<-- ASM-Code
'
'#ASM_ENDPublic Function ShiftLeftAsm(ByVal Par1 As Long, ByVal Par2 As Long) As Long
'#ASM_VB
'<-- VB-Code
ShiftLeftAsm = (Par1 * 2 ^ Par2)
'#ASM_STARTALL
' Par1 EQU[EBP+4] ; Parameter deklarieren
' Par2 EQU[EBP+8]
'
' PUSH EBP ; Sichert EBP auf Stack
' MOV EBP, ESP ; EBP = ESP, um auf den Stack zugreifen und Parameter lesen zu können
'
' PUSH ECX ; In Code manipulierte Register auf Stack sichern
' PUSH EBX ; In Klassen/Betriebssystem manipulierte Register auf Stack sichern
' PUSH ESI
' PUSH EDI
'
' ;<-- ASM-Code
' MOV EAX, Par1 ; EAX = Par1
' MOV ECX, Par2 ; ECX = Par2
'
' SHL EAX, CL ; EAX = EAX << CL
'
' POP EDI ; Gesicherte Register aus dem Stack lesen
' POP ESI
' POP EBX
' POP ECX
'
' MOV ESP, EBP ; ESP = EBP, Gesicherter EBP aus dem Stack lesen
' POP EBP ; (MOV,POP ist viel schneller als LEAVE (ENTER) auf 486 und Pentium)
'
' RET 8 ; Return mit Resultat auf EAX, der RET Wert muß der Summe der Byte aller Parameter entsprechen ( 8 = 2 * Long(4Byte) )
'#ASM_END
End Function
Par1 EQU[EBP+4]
Par2 EQU[EBP+8]
Deklariert ein Parameterame damit man über diesen einfacher auf den Stack zugreifen kann. Par1 ist dann identisch mit [EBP+4] usw.
Es beginnt mit +4 weil in den ersten 4 Bytes die Rücksprungadresse steht.
Die Stack Elemente haben eine feste Länge, in einem 32-Bit Programm sind dies 4 Byte. Es ist also egal ob über den Stack Byte Integer Long oder Single übergeben werden, es werden immer 4 Byte Pro Parameter verwendet. Ist der Wert größer als 4 Byte zB. bei Double, wird er aus mehreren Elementen zusammengesetzt. Die ungenutzten Bytes bleiben leer.
PUSH EBP
MOV EBP, ESP
EBP wird als Indexregister verwendet da ESP nicht als Indexregister verwendet werden kann. Dazu wird der aktuelle Wert in EBP auf den Stack gesichert und dann EBP = ESP gesetzt.
PUSH ECX
PUSH EBX
PUSH ESI
PUSH EDI
Wenn notwendig können zusätzlich weitere Werte auf den Stack in Registern gesichert werden. EDI ESI EBX sind Register die von Klassen und Windows API Befehlen manipuliert werden. Falls diese wichtige Werte enthalten müssen sie gesichert werden bevor in eine Klasse oder ein API gecallt wird. (Hier eigentlich unnötig)
MOV EAX, Par1
MOV ECX, Par2
SHL EAX, CL
Danach ist die Prozedur bereit für den Code.
EAX ist das Standardregister für Rückgabewerte, das Resultat muß also am Ende in EAX Register stehen.
POP EDI
POP ESI
POP EBX
POP ECX
Nach dem Code müssen alle gesicherten Register in umgekehrter Reihenfolge wie sie auf den Stack geschrieben wurden, wieder von diesem zurück kopiert werden.
MOV ESP, EBP
POP EBP
Danach wird noch ESP EBP rekonstruiert.
RET 8
Return um aus der Prozedur zurück zu springen, der Wert bei RET muß der Summe der Byte aller Parameter entsprechen in 4-Byte Schritten ( 8 = 2 * 4 Byte (2 Long Parameter) )
Der Vollständigkeit halber sei noch erwähnt, es gibt auch noch eine andere Möglichkeit Assembler Code in VisualBasic Programme einzubauen, in dem ein ASM-Code zuerst in ein Binärcode compiliert wird, dieser dann als ein Array in das VB-Programm eingebunden wird und im Programmlauf über CallWindowProcA in diesen Code gesprungen wird. CallWindowProcA führt dann den Inhalt des Array aus als wäre es ein normaler Programmocde, da er dieses ja eigentlich auch ist und CallWindowProcA nicht interessierst das an dieser Speicherstelle eigentlich der Inhalt eines Arrays und nicht eines normalen compilierten Codes liegt. Dieser Weg ist aber umständlicher als den Code direkt als Kommentartext in das VB-Programm einzufügen und das Compilieren VbInlineAsm und Masm zu überlassen. Über VbInlineAsm eingefügter Code läßt sich im Editor bearbeiten.
Ein solcher CallWindowProc-Code würde ungefähr so aussehen (Das ist nur ein Pseudocode ohne Funktion):
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByRef Adr As Long, ByVal Par1 As Long, ByVal Par2 As Long, ByVal Par3 As Long, ByVal Par4 As Long) As Long
Function TestAsm(ByRef Ptr As Long, ByRef DataLen As Long) As String
Static ASM(20) As Long
If ASM(0) = 0 Then
<- Hier der HexCode des ASM-Programms im ASM() Array
ASM(0) = &H01020304: ASM(1) = &H....
...
ASM(20) = &H0
End If
ReDim Data(DataLen - 1)
Call CallWindowProc (ASM(0), Ptr, VarPtr(Data(0)), DataLen, 0)
End Function
...
Call TestAsm(VarPtr(Scr(0)), UBound(Scr) - LBound(Scr) + 1)