| Vorheriges Kapitel (Ermittlung der Windows-Version) | Nächstes Kapitel (Menüs) |
Das Thema Kommandozeilenparameter oder -argumente kommt vielleicht, verglichen mit sonstigen Tutorials, etwas früh, aber da in späteren Beispielen mit diesen Argumenten gearbeitet wird, kommt die Erklärung schon jetzt und nicht später mittendrin. Zumal dieses Thema ohne Fenster und sonstiges grafisches Beiwerk auskommt.
Kommandozeilenparameter sind bei Windows-GUI-Programmen (Programme mit grafischer Bedienoberfläche) etwas in den Hintergrund getreten, da Dateien und Programmoptionen meist durch entsprechende Dialoge ermittelt werden können.
In Hochsprachen werden Kommandozeilenparameter auf verschiedene Weise bereit
gestellt. Aus C kennen sie vielleicht die Programmhauptfunktion int
main(int argc, char *argv[])
oder aus Pascal die beiden Funktionen
ParamCount und ParamStr aus der Unit System. In Windows-C-Programmen gibt es die
Funktion int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow).
In den C-Programmen wird bei Erzeugung der exe-Datei Programmcode eingefügt, der die Funktionen main() oder WinMain() aufruft. Dieser Code führt Initialisierungen aus, ermittelt die Kommandozeile und übergibt im Fall von main() die Anzahl der Argumente als Parameter argc und die Argumente selbst als Zeiger argv auf ein Zeichenarray. Im Falle von WinMain() wird nur der Zeiger auf die Zeichenkette übergeben.
In Assembler für Windows gibt es diese main- oder WinMain-Funktion nicht.
Um an die Kommandozeile zu kommen, kann die API-Funktion GetCommandLine()
verwendet werden. Damit entfällt schonmal das hantieren mit dem PSP wie
unter DOS. GetCommandLine() wird durch kernel32.dll bereit gestellt, die
Funktionsdefinition in MASM32 durch die Includedatei kernel32.inc. In
kernel32.inc wird durch GetCommandLine equ <GetCommandLineA>
erreicht, dass beim kompilieren des Quellcodes die ANSI-Variante der Funktion
verwendet wird.
In den Nachfolgern von Windows NT 3.5 (also NICHT Windows 95/98/Me) gibt es die
Funktion CommandLineToArgvW(), exportiert von shell32.dll. Das "W" am Ende sagt
schon aus, dass es sich um eine Funktion handelt, die mit Unicode arbeitet. Die
Definition in C sieht so aus:
LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine,int *pNumArgs).
lpCmdLine ist dabei die Kommandozeile im
Unicode-Format, *pNumArgs die Adresse einer dWord-Variablen, in die die Anzahl
der Parameter geschrieben wird. Als Ergebnis liefert die Funktion die Adresse
eines Arrays, in dem wiederum die Adressen der einzelnen Argumente enthalten
sind. pNumArgs sollte nach dem Funktionsaufruf mindestens den Wert 1 enthalten,
da der Programmname immer mitzählt. Der Programmname wurde u. U. auf den
kompletten Verzeichnispfad erweitert.
Um diese Funktion nutzen zu können, muss die Kommandozeile also in der Unicode-Variante geliefert werden. Dies erledigt GetCommandLineW().
Das Array, das GetCommandLineToArgvW() erzeugt und dessen Adresse die Funktion liefert, kann man sich so vorstellen:
ArrayAdr = GetCommandLineToArgvW(pCmdLine,pArgv) ArrayAdr + 0 = Adresse der Zeichenkette für Parameter 0 (Programmname) ArrayAdr + 4 = Adresse der Zeichenkette für Parameter 1 usw.
In einem Programm sieht es dann folgendermaßen aus.
;cmdlnarg - Kommandozeilenargumente .586 .MODEL flat,stdcall OPTION casemap:none include c:\masm32\include\windows.inc include c:\masm32\include\user32.inc include c:\masm32\include\kernel32.inc include c:\masm32\include\shell32.inc includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\shell32.lib .DATA cArgument db "A",0,"r",0,"g",0,"u",0,"m",0,"e",0,"n",0,"t",0,0,0 cParamTitle db "Parameterfehler",0 cParamFehler db "Unzureichende Anzahl Parameter",0 .DATA? ;uninitialisierte Daten hInstance HINSTANCE ? pCmdline LPSTR ? pArgs dword ? ;Zeiger auf ein Array iArgs dword ? ;Anzahl Argumente .CODE start: call mymain invoke LocalFree,pArgs invoke ExitProcess,0 mymain PROC invoke GetModuleHandle,NULL mov hInstance,eax invoke GetCommandLineW ;Verwendung der Unicode-Version mov pCmdline,eax invoke CommandLineToArgvW,eax, ADDR iArgs mov pArgs,eax cmp iArgs,2 ;gibt es mindestens ein Programmargument jge @@weiter invoke MessageBox,0,ADDR cParamFehler,ADDR cParamTitle,MB_OK ret ;wenn nicht, dann Abbruch mit Meldung @@weiter: mov eax,pArgs ;Startadresse des Arrays nach EAX mov ebx,[eax + 4] ;Startadresse des ersten Programmarguments ermitteln invoke MessageBoxW,0,ebx,ADDR cArgument,MB_OK dec iArgs add pArgs,4 cmp iArgs,1 jne @@weiter ret mymain ENDP END start |
Dieses Programm führt keine Prüfung der Windows-Version durch,
läuft also gnadenlos in die Falle, wenn CommandLineToArgvW() nicht
vorhanden ist. Sie können es in einer DOS-Box z. B. so starten:
cmdlnarg 134 fa2 aasdf ds3 asdf4.
Probieren sie auch was passiert, wenn sie kein Argument angeben oder ein
Argument in Anführungszeichen einschließen.
Da natürlich die Ergebnisse von CommandLineToArgvW() ebenfalls als
Unicode-Zeichenketten vorliegen, muss auch MessageBox() in der Unicode-Variante
aufgerufen werden. Und aus dem gleichen Grund liegt der Titel der Messagebox im
Unicode-Format vor (beachten sie das doppelte Null-Byte am Ende).
Alternativ wäre die Umwandlung in ANSI-Zeichenketten zu erwägen.
Befragen sie hierzu am besten ihre API-Dokumentation unter
WideCharToMultiByte().
CommandLineToArgvW() reserviert intern Speicher für das Argumentarray. Dieser Speicher ist nach Beendigung der Auswertung wieder frei zu geben. Dazu wurde hier im Hauptprogramm LocalFree() verwendet.
Die Auswertung der einzelnen Parameter ist wieder eine Sache für sich. Die Komplexität steigt hier mit der Anzahl und Art der Parameter sowie deren Kombinationsmöglichkeit. Wenn sie ein fest definiertes Parameterformat haben, dann reicht obiger Code. Ansonsten ist die Verwendung von Toolfunktionen zu empfehlen, die es mit Sicherheit irgendwo zu finden gibt. Ähnlich sieht es aus, wenn diese Funktionalität auch unter den Nicht-NT-Nachfolgern geboten werden soll.
| Vorheriges Kapitel (Ermittlung der Windows-Version) | Nach oben | Nächstes Kapitel (Menüs) |
| Zum Inhaltsverzeichnis | ||
| Zur Startseite |