Dies ist ein 32-bit-Nachbau des 16-bit-Programms FRAGE.COM.
Beide Versionen leisten etwa das gleiche. Allerdings unterscheiden sie sich etwas im Format des Aufrufs. Die hier gezeigte 32-bit-Version verwendet die im MASM32-SDK empfohlene Methode der Parameterabfrage mittels „GetCL”. Das 32-bit-Programm Frage.exe ist 2569 Byte groß. Wenn es für die Fehlersuche mit eingeschaltetem DEBUG assembliert wurde, ist es 4608 Bytes groß. Die 16-Bit Version FRAGE.COM ist mit 216 Bytes Größe deutlich kleiner. Für eine weiteren Vergleich habe ich ein funktionsähnliches Programm in der Programmiersprache Pure Basic erstellt. Das daraus erstellte ausführbare 32-bit-Programm Frage.exe kommt auf 12899 Bytes Größe. Die Funktion von Frage.exe lässt sich anhand der Steuerdatei Ask.bat demonstrieren: |
@echo off if %1 == 3 goto:frage3 if %1 == 2 goto:frage2 if %1 == 1 goto:frage1 echo Stapeldatei: Parameter 1, 2 oder 3 eingeben! goto raus :frage1 frage "Bitte 'j' zur Antwort Ja (jn)" nj goto returncode :frage2 frage "Umlaute: abcÄäÖöÜüßz" goto returncode :frage3 frage :returncode if errorlevel 99 goto aufruffehler if errorlevel 2 goto ja if errorlevel 1 goto nein echo Aufruf mit nur einem Parameter goto raus :aufruffehler echo Der Aufruf war fehlerhaft goto raus :ja echo Die Antwort war "Ja" goto raus :nein echo Die Antwort war "Nein" :raus | AblaufbeispielLinks wird die Scriptdatei Ask.bat gezeigt. Unterhalb sind die etwas abgeschnittenen Bildschirmanzeigen von vier Durchläufen zu sehen. |
C:\masm32\Uebung\Konsole>fragetest 1 Bitte 'j' zur Antwort Ja (jn)> Die Antwort war "Ja" | |
C:\masm32\Uebung\Konsole>fragetest 1 Bitte 'j' zur Antwort Ja (jn)> Die Antwort war "Nein" | |
C:\masm32\Uebung\Konsole> C:\masm32\Uebung\Konsole>fragetest 2 Umlaute: abcÄäÖöÜüßz Aufruf mit nur einem Parameter | |
C:\masm32\Uebung\Konsole>fragetest 3 Der erste Parameter 'prompt' fehlt! Aufruf nur mit einem oder zwei Parametern möglich! Aufruf: FRAGE.exe prompt [key-list] Beispiel: frage.exe "Weitermachen (jn)" jn Ohne key-list kann mit einer beliebigen Taste |
Befehlsbeschreibung von GetCL gemäß MASM32 Library referenceGetCL proc ArgNum:DWORD, ItemBuffer:DWORDGetCL übergibt das in seinem Aufruf spezifizierte Kommandozeilenargument im spezifizierten Pufferbereich (buffer). Name und Pfad des aufrufenden Programms haben dabei die Argumentennummer 0. Der erste Parameter hat die Nummer 1. In Gänsefüßchen eingekleidete Kommandozeilenargumente werden ohne Gänsefüßchen in den Pufferbereich übertragen. Parameter: Rückgabewerte: Hinweis:
Der Pufferbereich sollte mit einer Länge von 128 Bytes angelegt werden. Dies ist gleichzeitig seine zugelassene Maximallänge. Beispiel zur Übertragung des ersten Arguments in den angegebenen Puffer: invoke GetCl, 1, ADDR buffer |
Das Quellprogramm für MASM32-SDKEine kurze Interpretation steht unterhalb des Quellprogrammtextes.; ----------------------------------------------- ; Build this with the "Project" menu using ; "Console Assemble and Link" ; ----------------------------------------------- ; Versuche mit Verarbeitung der Kommandozeile ; mymasm32rt.inc - siehe fredriks.de/8086asm/masm321.php?f=2#mymasm32rt ; ----------------------------------------------- debugFT equ FALSE include c:\masm32\include\mymasm32rt.inc .LIST .data buffer1 db 128 dup(0) buffer2 db 128 dup(0) cParamFehler db "Aufruf nur mit einem oder zwei Parametern m",oe,"glich!",cr,lf,lf ;Hilfstextanzeige wenn Aufruf ohne Parameter hilfe db "Aufruf: FRAGE.exe prompt [key-list]",cr,lf db 'Beispiel: frage.exe "Weitermachen (jn)" jn',cr,lf db "Ohne key-list kann mit einer beliebigen Taste geantwortet werden",cr,lf db "Prompt ggf. in G",ae,"nsef",ue,sz,"chen!",lf crlf db cr,lf,0 ;Zeilenwechsel ;ergaenzt hilfe prompt db '>',0 ;fast ein Promptzeichen comment # Umlauttabelle, enthält Winddows- und MS-Dosumlaute äöüßÄÖÜ jeweils nebeneinander zuerst Windows, dann Notepad, dann MS-DOS ä ö ü Ä Ö Ü ß Windows: e4 f6 fc c4 d6 dc df notepad: f5 f7 b3 2d cd 5f af MS-DOS: 84 94 81 8e 99 9a e1 # umlaute db 0f5h,ae,0f7h,oe,0b3h,ue ;äöü Notepad db 02dh,Ae,0cdh,Oe,05fh,Ue,0afh,sz ;ÄÖÜß Notepad db 0e4h,ae,0f6h,oe,0fch,ue ;äöü Windows db 0c4h,Ae,0d6h,Oe,0dch,Ue,0dfh,sz ;ÄÖÜß Windows db 0,0 ;garantiertes Tebellenende .DATA? ;uninitialisierte Daten iArgs dword ? ;Anzahl Argumente +1 iArgszaehler dword ? ;Schleifenzaehler Anzahl Argumente .code ; Tell MASM where the code starts ; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« start: SetConsoleCaption "Frage ergibt Returncode" ; The CODE entry point to the program call main ; branch to the "main" procedure push eax ; sichert den ermittelten Errorlevel ; inkey ; keinen Tastendruck abwarten bei Programmende pop eax exit eax ; Errorlevel wurde in eax mitgegeben ; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« main proc DumpMem offset umlaute, 32, "Umlauttabelle bei Programmstart" invoke GetCL,1,ADDR buffer1 cmp eax, TRUE je @F print chr$("Der erste Parameter 'prompt' fehlt!",13,10) call help ret @@: mov iArgs,2 ;iArgs enthält Parameteranzahl +1 DumpMem offset iArgs,8, "1.Argument" invoke GetCL,2,ADDR buffer2 cmp eax, TRUE jne @F mov iArgs,3 ;iArgs enthält Parameteranzahl +1 @@: DumpMem offset iArgs, 8, "2.Argument" mov eax,iArgs ;iArgs enthält Parameteranzahl +1 dec eax DumpMem offset buffer1, 32, "buffer1 vor Codewandlung" mov iArgszaehler,eax ;Schleifenzaehler, Inhalt 1 oder 2 codewandlung_parameter: mov ebx,offset buffer2 ;Startadresse des Arrays nach EAX cmp iArgszaehler,1 jne T1 mov ebx,offset buffer1 ;Startadresse des Arrays nach EAX T1: mov esi,ebx ;von = nach T2: mov al,[esi] ;fertig konvertiert ? cmp al,0 je T3 ;fertig konvertiert ! call todos ;wandelt äöüÄÖÜß von Windwos- in DOS-ASCII mov [esi],al inc esi jmp T2 T3: dec iArgszaehler ;Stringende erkannt cmp iArgszaehler,0 jne codewandlung_parameter ;zur Codewandlung des nächsten Parameters DumpMem offset umlaute, 32, "Umlauttabelle nach Codewandlung" DumpMem offset buffer1, 32, "buffer1 nach Codewandlung" ;Codewandlung ist beendet. Der erste Parameter (der Text) wird angezeigt print offset buffer1 ;Falls nur ein Aufrufparameter angegeben war, nun Ende mit Errorlevel 0 DumpMem offset iArgs, 8, "Argumente plus 1" cmp iArgs,3 je antw5 ;Sprung, wenn key-list angegeben war print offset crlf ;Ein Zeilenvorschub mov eax,0 ;Es war nur ein Parameter! ret antw5: mov ebx, offset buffer2 ;Startadresse der Antwortmoeglichkeiten write ">" ;> als Prompt. Das print-macro ; invoke StdOut,offset prompt ;verträgt print ">" nicht. deshalb write ; ;oder direktes invoke StdOut call ret_key ;wait for a keystroke and return its scancode in EAX mov ecx,1 ;Errorlevel 1 fuer 1. Zeichen der key-list antw6: cmp al,cr je antw5 ;cr wird ignoriert ; and al,5fh ;al enth. das Zeichen in Grossschrift mov ah,[ebx] ;Ende des Vergleichsstring erreicht? cmp ah,0 je antw5 ;ja, aber Eingabe war unpassend cmp [ebx],al ;passt die Eingabe? je antw9 ;ja inc ebx ;nein. Dann Einstellen auf nächsten Vergleich inc ecx jmp antw6 antw9: push ecx ;ecx enthaelt nun den Errorlevel print offset crlf ;Zeilenvorschub pop eax ;eax enthaelt nun den Errorlevel ret main endp ; Unterprogramme ; --------------------------------------------------- ;Unterprogramm Codewandlung Umlaut von Windows- in DOS-Codierung (ASCII) ;Das zu untersuchende Zeichen steht in al ; ----- todos proc mov cx,14 ;Tabelle Umlaute ist 2*14 Zeichen lang mov ebx, offset umlaute todos1: cmp byte ptr[ebx],al je todos9 inc ebx ;adressieren naechsten Tabellenplatz inc ebx dec cx jnz todos1 ret ;Unterprogrammende ohne Wandlung todos9: inc ebx ;Codewandlung des Zeichen und mov byte ptr al,[ebx] ;Unterprogrammende mit Wandlung ret todos endp ; ----- ; Unterprogramm Hilfstext ausgeben ; ----- help proc ;Parameteranzahl muss 1 oder 2 sein print offset cParamFehler ;falsche Parameteranzahl mov eax,99 ;Errorlevel 99 und Schluss! ret help endp end start ; Tell MASM where the program ends |
Interpretation des QuellprogrammsKonstanten: Die Symbolisierungen für die deutschen Umlaute in DOS-ASCII verbessern die Lesbarkeit des Quellprogramms. buffer1, buffer2: Die beiden Pufferbereiche zur Aufnahme der Kommandozeilenparameter sind bei Programmstart mit hexadezimal 00 vorbelegt. Dadurch wird ein Markierung des Stringendes sichergestellt. Hilfe: Der zur Anzeige bestimmte Text wurde angepasst. Umlauttabelle: Das Programm wurde unter Windows 10 Version 1809 entwickelt. Dabei zeugte sich, dass zwei Umschlüsselungen erforderlich sind. Beim Programmaufruf vom Konsolfenster (CMD) aus, wirkt die Umschlüsselung Windows auf MS-DOS. Beim Aufruf von einer mit dem Editor NOTEPAD.EXE erstellten Stapeldatei (.BAT) beinhaltet die Stapeldatei den erwarteten Code gemäß Windows 1252. Bei Ablauf kommt jedoch ein davon abweichender Code für die Umlaute im Frage-Programm an. Die Entdeckung dieser Eigenschaft hat mir bei der Programmentwicklung erhebliche Schwierigkeiten gebracht. Deshalb sind die verschiedenen Aufrufe von DumpMem als Überreste von der Programmentwicklung im Programmtext enthalten. Sie alle werden durch zwei Zeilen DBGWIN_DEBUG_ON = 0 und DBGWIN_EXT_INFO = 0 bei der Assemblierung als Kommentare behandelt. Bei start unter .code wird nun vor der Anforderung zur Tastenbetätigung beim Programmende der Inhalt von eax gesichert und nach der Eingabe wieder hervorgeholt. Grund: Vom Unterprogramm main wird der Errorlevel dem Hauptprogramm in eax übergeben. Für den Ablauf des Frageprogramms unter einer Stapeldatei ist die Tastenbestätigung eher störend. Sie ist deshalb auskommentiert. invoke GetCL,1,ADDR buffer1 Mit der in iArgszaehler eingestellten Anzahl der Aufrufparameter wird bewirkt, dass nur der bzw. die vorhandenen Aufrufparameter eine Codewandlung erfahren. ;Codewandlung ist beendet: Die Programmzeilen print offset buffer1 hinter diesem Kommentar zeigt den Prompt auf dem Bildschirm an. Falls nur ein Aufrufparameter angegeben war, wird ein Zeilenvorschub ausgegeben und das Unterprogramm wird mit Errorlevel 0 beendet. antw5 bis zum ret hinter antw6: Diese Zeilen sind an 32-bit-Programmierung angepasste Zeilen aus dem oben genannten 16-bit-Programm. Statt print ">" steht write ">". Das print-Makro kommt mit dem > nicht klar. Alternativ kann der nachfolgende auskommentierte invoke-Aufruf anstelle von write verwendet werden. Der auskommentierte Befehl and al,5fh würde bei seiner Aktivierung eine Wandlung der eingetippten Buchstaben a bis z in Großschrift durchführen. Ob man es macht, ist Entscheidungssache. Wenn man es ordentlich machen möchte, müsste man sich auch um äöü kümmern. |
Eine individuelle Überschrift für das KonsolfensterMit der Zeilestart: SetConsoleCaption "Frage ergibt Returncode"kann man dem Konsolfenster die angegebene Überschrift geben: |
![]() |
Dazu sind jedoch weitere Schritte erforderlich. Welche es sind, wird unter SetConsoleCaption in der Hilfestellung des MASM32-SDK beschrieben. Hier ist der Weg zur Beschreibung von der MASM32-SDK Entwicklungsumgebung aus:
|
Das Frageprogramm mit PureBasicFür einen weiteren Vergleich habe ich ein funktionsgleiches Programm in der Programmiersprache Purebasic erstellt. Das daraus ertellte ausführbare 32-bit-Programm Frage.exe kommt auf 12800 Bytes Größe. Dessen Quellprogramm ist allerdings kürzer und deutlich übersichtlicher als das in Assembler geschriebene Quellprogramm:OpenConsole("Frage ergibt Returncode") ;Zähle Parameter AnzahlParameter.i = CountProgramParameters() ;Add all command line parameters to a linked list Global NewList Parameter.s() ;PrintN("Anzahl Aufrufparameter: " + StrU(AnzahlParameter)) Select AnzahlParameter Case 1 AddElement(Parameter()) : a$=ProgramParameter() : PrintN (a$) ExitCode=0 ;Errorlevel 0 wenn Aufruf mit nur einem Parameter Case 2 AddElement(Parameter()) : prompt$=ProgramParameter() : Print(prompt$ + "> ") AddElement(Parameter()) : antworten$=ProgramParameter() ;PrintN ("ExitCode=" + StrU(ExitCode)) Repeat ;Vergleich der Eingabe ohne Beachtung der Groß-/Kleinschreibung KeyPressed$ = Inkey() If KeyPressed$ <> "" Position = FindString(antworten$, KeyPressed$,1,#PB_String_NoCase) Debug position Else Delay(100) ; Wir verbrauchen nicht die gesamte ; CPU-Leistung, da wir in einem Multitasking-OS ; laufen EndIf If KeyPressed$ = Chr(27) ;Abbruch mit ESC-Taste wird ermoeglicht Position=99 EndIf Until Position<>0 ;Bis gültige Eingabe oder ESC-Taste ExitCode=Position ;Errorlevel 99 kennzeichnet Fehler oder Abbruch Default PrintN ("Aufruf: FRAGE.exe prompt [key-List]") PrintN ("") PrintN ("Beispiel: frage.exe " + Chr(34) + "Weitermachen (jn)" + Chr(34) + " jn") PrintN ("Ohne key-List kann mit einer beliebigen Taste geantwortet werden") PrintN ("Prompt ggf. in Gänsefüßchen!") ExitCode=99 ;Errorlevel 99 kennzeichnet Fehler EndSelect ;PrintN ("ExitCode=" + StrU(ExitCode)) PrintN("") PrintN("Press any key To Continue ...") Input() End ExitCode Als Reste von der Programmentwicklung enthält das Quellprogramm an zwei Stellen auskommentierte Anzeigebefehle für den erzeugten Rückgabecode:
;PrintN ("ExitCode=" + StrU(ExitCode)) Weiterhin ist der Befehl Debug positionvorhanden. Dieser ruft eine eingebaute Testhilfe auf. Bei der Compilierung in das ausführbaren Program Frage.exe wird dieser Befehl wie ein Kommentar behandelt. Somit verlängert er das ausführbare Programm nicht. Laut der Produktbeschreibung für PureBasic soll der erzeugte ausführbare Programmcode verhältnismäßig kompakt sein. In diesem Fall ist er jedoch gut viermal umfangreicher als sein mit purem Assembler erzeugtes Gegenstück. |