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