Iczelion - 11 - Mehr über Dialog Boxen

Tutorial 11: Mehr über Dialog Boxen


Wir werden mehr über Dialog Boxen in diesem Tutorial lernen. Insbesondere werden wir uns dem Thema widmen, wie wir Dialog Boxen als unsere Eingabe-Ausgabe Geräte benutzen können. Wenn Sie das vorherige Tutorial gelesen haben, wird dieses Tutorial ein Kinderspiel, da nur eine kleine Modifikationen nötig ist, um unsere Dialog Boxen als Beigabe unseres Hauptfensters zu benutzen. Wir werden in diesem Tutorial auch lernen, wie Standard Dialog Boxen benutzt werden.

Laden Sie die Dialog Box Beispiele hier und hier herunter. Laden Sie das gebräuchliche Dialog Box Beispiele hier herunter.

Theorie:

Sehr wenig wurde darüber gesagt, wie man Dialog Boxen als Eingabe-Ausgabe Geräte unseres Programms verwenden kann. Ihr Programm erzeugt das Hauptfenster und wenn Sie eine Dialog Box anzeigen wollen, rufen Sie einfach CreateDialogParam oder DialogBoxParam auf. Beim Aufruf von DialogBoxParam müssen Sie nichts mehr machen, nur noch die Nachrichten in der Dialog-Box Prozedur bearbeiten. Bei CreateDialogParam müssen Sie einen IsDialogMessage Aufruf in der Message-Loop einfügen, um den Dialog Box Manager die Tastatur-Navigation in ihrer Dialog Box für Sie zu händeln. Da beide Fälle ziemlich trivial sind, werde ich den Source Code hier nicht angeben. Sie können die Beispiele herunterladen und selbst betrachte, hier und hier.
Kommen wir zu den Standard-Dialog-Boxen. Windows hat einige vordefinierte Dialog Boxen, die von Ihren Applikationen gebraucht werden können. Diese Dialog Boxen existieren, um ein Standardisiertes Interface zu bieten. Sie bestehen aus, Datei, Druck, Farbe, Schriftart und Such Dialog-Boxen. Sie sollten sie so häufig wie möglich verwenden. Die Dialog-Boxen befinden sich in der comdlg32.dll. Um sie zu benutzen, müssen Sie comdlg32.lib hinzulinken. Sie erzeugen diese Dialog-Boxen indem Sie vorgefertigte Funktionen aus der Standard-Dialog-Library aufrufen. Für einen Datei-öffnen-Dialog ist es GetOpenFileName, für einen Speichern unter-Dialog ist es GetSaveFileName, für einen Drucken-Dialog ist es PrintDlg und so weiter. Jede dieser Funktion wird ein Zeiger auf eine Struktu als Parameter übergeben. Sie sollten sie in der Win32 API Referenz nachschlagen. In diesem Tutorial werde ich ihnen demonstrieren, wie man einen Datei-öffnen-Dialog erzeugt und benutzt.

Unten ist der Funktions-Prototyp der GetOpenFileName-Funktion:

GetOpenFileName proto lpofn:DWORD


Wie Sie sehen können, wird nur ein Parameter übergeben, ein Zeiger auf eine OPNFILENAME-Struktur. Der Rückgabewert TRUE bedeutet, dass der Benutzer eine Datei zum öffnen ausgewählt hat, ansonsten ist er FALST. Wir werfen als nächstes einen Blick auf die OPENFILENAME-Struktur. 

OPENFILENAME STRUCT lStructSize DWORD ? hwndOwner HWND ? hInstance HINSTANCE ? lpstrFilter LPCSTR ? lpstrCustomFilter LPSTR ? nMaxCustFilter DWORD ? nFilterIndex DWORD ? lpstrFile LPSTR ? nMaxFile DWORD ? lpstrFileTitle LPSTR ? nMaxFileTitle DWORD ? lpstrInitialDir LPCSTR ? lpstrTitle LPCSTR ? Flags DWORD ? nFileOffset WORD ? nFileExtension WORD ? lpstrDefExt LPCSTR ? lCustData LPARAM ? lpfnHook DWORD ? lpTemplateName LPCSTR ? OPENFILENAME ENDS


Schauen wir uns die Bedeutung der am häufig genutzten Elemente an.

lStructSize Die Größe der OPENFILENAME Struktur , in Bytes
hwndOwner Das Fenster-Handle der Datei-öffnen Dialog Box.
hInstance Instanz Handle der Applikation, die die Datei-öffnen Dialog Box erzeugt.
lpstrFilter Die Filter-Strings im Format gepaarter nullterminierter Strings. Der erste String in jedem Paar ist die Beschreibung. Der zweite String ist das Filter-Pattern. Zum Beispiel:

     FilterString   db "Alle Dateien (*.*)",0, "*.*",0
                            db "Text Dateien (*.txt)",0,"*.txt",0,0

Beachten Sie, dass nur das Pattern im zweiten String in jedem Paar von Windows wirklich benutzt wird, um Dateien auszufiltern. Beachten Sie auch, dass Sie eine extra 0 am Ende der Filter-Strings plazieren müssen, um das Ende zu kennzeichnen.
nFilterIndex Spezifiziert welches Paar der Filter-Strings zur Initialisierung benutzt wird, wenn der Datei-öffnen Dialog das erste Mal angezeigt wird. Der Index beginnt bei 1, das heißt, dass erste Paar ist 1, das zweite Paar ist 2, usw. In dem obigen Beispiel, würde, wenn wir nFilterIndex gleich 2 setzen, das zweite Pattern benutzt werden, also "*.txt".
lpstrFile Zeiger auf den Buffer, der den Dateinamen enthält, welcher benutzt wird um das Dateiname-Edit-Steuerelement zu initialisieren. Der Buffer sollte mindestens 260 Bytes groß sein.

Nachdem der Benutzer eine Datei zum öffnen ausgewählt hat, wird der Dateiname mit dem kompletten Pfad in diesem Buffer gespeichert. Sie können die Informationen später hieraus extrahieren.
nMaxFile Die Größe des lpstrFile Buffer.
lpstrTitle Zeiger auf den Titel der Datei-Öffnen Dialog Box.
Flags Bestimmt die Stile und Charakteristika der Dialog Box.
nFileOffset Nachdem der Benutzer eine Datei zum Öffnen ausgewählt hat, enthält dieses Element den Index des ersten Buchstabens, des aktuellen Dateinnamen. Wenn der volle Name zum Beispiel "c:\windows\system\lz32.dll lautet, dann enthält dieses Element den Wert 18.
nFileExtension Nachdem der Benutzer eine Datei zum Öffnen ausgewählt hat, enthält dieses Element den Index des ersten Buchstabens, der Datei-Extension.


Beispiel:

Das folgende Programm zeigt eine Datei-öffnen Dialog box an, wenn der Benutzer Datei - öffnen aus dem Menü auswählt. Wenn der Benutzer eine Datei in der Dialog Box auswählt, zeigt das Programm eine MessageBox an, die den kompletten Namen, Dateinamen und Extension der selektierten Datei enthält.

.386 .model flat,stdcall option casemap:none WinMain proto :DWORD,:DWORD,:DWORD,:DWORD include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\comdlg32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\comdlg32.lib .const IDM_OPEN equ 1 IDM_EXIT equ 2 MAXSIZE equ 260 OUTPUTSIZE equ 512 .data ClassName db "SimpleWinClass",0 AppName db "Our Main Window",0 MenuName db "FirstMenu",0 ofn OPENFILENAME FilterString db "Alle Dateien",0,"*.*",0 db "Text Dateien",0,"*.txt",0,0 buffer db MAXSIZE dup(0) OurTitle db "-=Unser erster Datei öffnen Dialog =-: Wählen Sie eine Datei zum öffnen ",0 FullPathName db "Der komplette Dateiname mit Pfad ist: ",0 FullName db "Der Dateiname ist: ",0 ExtensionName db "Die Extension ist: ",0 OutputString db OUTPUTSIZE dup(0) CrLf db 0Dh,0Ah,0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? .code start: invoke GetModuleHandle, NULL mov hInstance,eax invoke GetCommandLine mov CommandLine,eax invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT invoke ExitProcess,eax WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW+1 mov wc.lpszMenuName,OFFSET MenuName mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_APPLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,300,200,NULL,NULL,\ hInst,NULL mov hwnd,eax invoke ShowWindow, hwnd,SW_SHOWNORMAL invoke UpdateWindow, hwnd .WHILE TRUE invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDW mov eax,msg.wParam ret WinMain endp WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_DESTROY invoke PostQuitMessage,NULL .ELSEIF uMsg==WM_COMMAND mov eax,wParam .if ax==IDM_OPEN mov ofn.lStructSize,SIZEOF ofn push hWnd pop ofn.hwndOwner push hInstance pop ofn.hInstance mov ofn.lpstrFilter, OFFSET FilterString mov ofn.lpstrFile, OFFSET buffer mov ofn.nMaxFile,MAXSIZE mov ofn.Flags, OFN_FILEMUSTEXIST or \ OFN_PATHMUSTEXIST or OFN_LONGNAMES or\ OFN_EXPLORER or OFN_HIDEREADONLY mov ofn.lpstrTitle, OFFSET OurTitle invoke GetOpenFileName, ADDR ofn .if eax==TRUE invoke lstrcat,offset OutputString,OFFSET FullPathName invoke lstrcat,offset OutputString,ofn.lpstrFile invoke lstrcat,offset OutputString,offset CrLf invoke lstrcat,offset OutputString,offset FullName mov eax,ofn.lpstrFile push ebx xor ebx,ebx mov bx,ofn.nFileOffset add eax,ebx pop ebx invoke lstrcat,offset OutputString,eax invoke lstrcat,offset OutputString,offset CrLf invoke lstrcat,offset OutputString,offset ExtensionName mov eax,ofn.lpstrFile push ebx xor ebx,ebx mov bx,ofn.nFileExtension add eax,ebx pop ebx invoke lstrcat,offset OutputString,eax invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK invoke RtlZeroMemory,offset OutputString,OUTPUTSIZE .endif .else invoke DestroyWindow, hWnd .endif .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .ENDIF xor eax,eax ret WndProc endp end start





Analyse:

mov ofn.lStructSize,SIZEOF ofn push hWnd pop ofn.hwndOwner push hInstance pop ofn.hInstance


Wir füllen in der Routine Element der ofn-Struktur.

           mov  ofn.lpstrFilter, OFFSET FilterString


Dieser FilterString ist der Dateinamen-Filter, den wir wie folgt spezifizieren:

FilterString db "All Files",0,"*.*",0 db "Text Files",0,"*.txt",0,0


Beachten Sie, dass alle vier String nullterminiert sind. Der erste String ist die Beschreibung des folgenden Strings. Das aktuelle Pattern ist der gradzahlige Sting, in diesem Fall "*.*" und "*.txt". Wir können hier jeden Pattern spezifizieren, den wir wollen. Wir MÜSSEN eine extra Null hinter dem letzten Pattern plazieren um das Ende des String Filter zu markieren. Vergessen Sie das nicht, ansonsten benimmt sich ihre Dialog Box eigenartig.

mov ofn.lpstrFile, OFFSET buffer mov ofn.nMaxFile,MAXSIZE


Wir spezifizieren wo die Dialog Box den Dateinamen hintut, den der Benutzer ausgewählt hat. Beachten Sie, dass wir die Größe im nMaxFile-Element spezifizieren müssen. Später können wir den Dateinamen aus diesem Buffer wieder extrahieren.

mov ofn.Flags, OFN_FILEMUSTEXIST or \ OFN_PATHMUSTEXIST or OFN_LONGNAMES or\ OFN_EXPLORER or OFN_HIDEREADONLY


Die Flags spezifizieren die Charakteristika der Dialog Box.

OFN_FILEMUSTEXIST und das OFN_PATHMUSTEXIST Flag verlangen, dass der Dateiname und der Pfad, den der Benutzer in das Edit-Steruerelement eintippt existieren MÜSSEN.
OFN_LONGNAMES teilt der Dialog Box mit, dass lange Dateiname angezeigt werden.
OFN_EXPLORER spezifiziert, dass das Aussehen der Dialog Box Explorer-mäßig ist.
OFN_HIDEREADONLY versteckt die nur-lesen Checkbox in der Dialog Box.
Es gibt viel mehr Flags, die Sie benutzen können. Konsultieren Sie ihre Win32 API Referenz.

            mov  ofn.lpstrTitle, OFFSET OurTitle


Spezifiziert den Titel der Dialog Box.

            invoke GetOpenFileName, ADDR ofn


Rufen Sie die GetOpenFileName-Funktion auf. Den Zeiger auf die ofn-Struktur übergeben Sie als Parameter.

Zu diesem Zeitpunkt, wird die Datei-öffnen-Dialog-Box auf dem Bildschirm angezeigt. Die Funktion wird solange nicht zurückkehren, bis der Benutzer eine Datei zum öffnen anwählt oder den Abbrechen-Button anklickt oder die Dialog Box schließt.

Sie wird TRUE in EAX zurückliefern, wenn der Benutzer eine Datei zum öffnen ausgewählt hat. Ansonsten wird FALSE zurückgeliefert.

.if eax==TRUE invoke lstrcat,offset OutputString,OFFSET FullPathName invoke lstrcat,offset OutputString,ofn.lpstrFile invoke lstrcat,offset OutputString,offset CrLf invoke lstrcat,offset OutputString,offset FullName


Für den Fall, dass der Benutzer eine Datei zum öffnen ausgewählt hat, bereiten wir einen Ausgabe-String vor, der in einer Message-Box angezeigt wird. Wir alloziieren einen SpeicherBlock in der OutputString-Variable und benutzen dann die API Funktion lstrcat um die Strings miteinander zu verbinden. Um die Strings in verschriedene Zeilen zu schreiben, müssen wir jede Zeile mit einem Carriage Return-Zeilenvorschub Paar seperieren.

mov eax,ofn.lpstrFile push ebx xor ebx,ebx mov bx,ofn.nFileOffset add eax,ebx pop ebx invoke lstrcat,offset OutputString,eax


Die oberen Zeilen benötigen einige Erklärungen. nFileOffset enthält den Index auf ofn.lpstrFile. Aber Sie können sie nicht direkt zusammenfügen, da nFileOffset eine WORD-Variable und lpstrFile eine DWORD-Variable ist. Deswegen muss ich den Wert von nFileOffset in das untere Word von EBX speichern und ihn zum Wert von lpstrFile addieren.

                invoke MessageBox,hWnd,OFFSET OutputString,ADDR AppName,MB_OK


Wir zeigen den String in einer Message Box an.

                invoke RtlZerolMemory,offset OutputString,OUTPUTSIZE


Wir müssen den OutputString *löschen* bevor wir sie mit einem weiteren String füllen können. Deswegen benutzen wir die RtlZeroMemory-Funktion um das zu erledigen.


Deutsche Übersetzung: Joachim Rohde
Die original Win32Asm-Tutorials stammen von Iczelion's Win32 Assembly HomePage