Iczelion - 10 - Dialog-Box als Hauptfenster

Tutorial 10: Dialog-Box als Hauptfenster


Nun kommt der wirklich interessante Part über GUI, die Dialog Box. In diesem Tutorial (und dem nächsten), werden wir lernen, wie wir eine Dialog Box als unser Haupt-Fenster benutzen können.

Laden Sie hier das erste Beispiel herunter und das zweite Beispiel hier.

Theorie:

Wenn Sie lange genug mit den Beispielen aus den vorherigem Tutorial herumspielen, werden Sie herausfinden, dass Sie den Eingabefokus von einem Child-Fenster Steuerelements zu einem anderen nicht mit der Tab-Taste wechseln können. Die einzige Möglichkeit das zu machen, ist ein Klick auf das Steuerelement, dem Sie den Eingabefokus geben wollen. Diese Situation ist ziemlich eigenartig. Eine weitere Sache die Sie vielleicht bemerkt haben, ist, dass ich die Hintergrundfarbe des Eltern-Fensters in grau geändert habe, statt des normalen Weiss, wie in den vorherigen Beispielen. Das wurde gemacht, damit die Farbe der Child-Fenster Steuerelemente nahtlos mit der Farbe der Client-Area des Eltern-Fensters übergehen kann. Es gibt einen Weg dieses zu umgehen, aber der ist nicht einfach. Sie müssen alle Child-Fenster-Steuerelemente in ihrem Eltern-Fenster ableiten.

Der Grund warum eine solche Unbequemlichkeit existiert ist, dass Child-Fenster-Steuerelemente ursprünglich für die Arbeit mit Dialog Boxen designed wurden und nicht für normale Fenster. Die Standard-Farbe der Child-Fenster-Steuerelemente, wie Buttons, ist Grau, weil die Client Area einer Dialog Box normalerweise grau ist, so dass sie ineinander übergehen ohne Bemühungen des Programmierers.

Bevor wir ins Detail gehen, sollten wir als erstes wissen, was eine Dialog Box ist. Eine Dialog Box ist nicht anderes als ein normales Fenster, was designed wurde um mit Child-Fenster-Steuerelementen zu arbeiten. Windows betreibt interne "Dialog Box Manager", welche für die Tastatureingaben, wie das Wechseln des Eingabe-Fokus, wenn der Benutzer Tab drückt, das drücken des Standard-Buttons wenn Enter gedrückt wird, etc., verantwortlich ist, so das der Programmierer sich darum nicht mehr kümmern braucht. Dialog Boxen werden in erster Linie als Ein-/Ausgabe-Geräte benutzt. So betrachtet kann man eine Dialog Box als "Black Box" bezeichnen, da Sie nicht wissen müssen, wie eine Dialog Box intern funktioniert, um sie benutzen zu können, Sie müssen nur wissen, wie Sie mit ihr interagieren. Das ist ein Prinzip der objektorientierten Programmierung (OOP) names 'information hiding'. Wenn die Black Box *perfekt* designed wurde, kann der Benutzer sie benutzen ohne jegliches Wissen, wie sie operiert. Das Problem ist, dass die Black Box perfekt sein muss, was schwer machbar ist in der realen Welt. Das Win32 API wurde auch als Black Box designed.

Nun denn, es sieht so aus, als ob wir abschweifen würden. Kommen wir zurück zum Thema. Dialog Boxen wurden designed um Programmieren etwas Arbeit abzunehmen. Normalerweise müssen Sie, wenn Sie ein Child-Fenster-Steuerelement in einem normalen Fenster plazieren, es ableiten und die Tastatursteuerung selbst schreiben. Wenn Sie sie aber in einer Dialog Box plazieren, wird Ihnen diese Aufgabe abgenommen. Sie müssen nur wissen, wie Sie die Benutzereingaben aus der Dialog Box bekommen oder wie Sie Kommandos an sie senden.

Eine Dialog Box ist wie ein Menü als Ressource definiert. Sie schreiben ein Dialog Box Template, das die Charakteristika der Dialog Box und seiner Steuerelemente beschreibt und compilieren dann das Ressource-Skript mit einem Ressource-Editor.

Beachten Sie, dass alle Ressourcen in einer Ressource-Skript-Datei stehen. Sie können jeglichen Text-Editor benutzen um ein Dialog-Box Template zu schreiben, aber ich empfehle es nicht. Sie sollten einen Ressource-Editor benutzen, um diese Arbeit visuell zu tun, da das plazieren von Child-Fenster-Steuerelementen in einer Dialog Box ziemlich hart ist, wenn man es manuell probiert. Mehrere exzellente Ressource-Editoren sind verfügbar. Die meisten größeren IDEs haben ihren eigenen Ressource-Editor. Sie können sie benutzen, um ein Ressource-Skript für ihr Programm zu erzeugen und dann alle nicht relevanten Zeilen, wie welche die für MFC sind, herauslöschen.

Es gibt zwei Haupttypen von Dialog Boxen: modale und nicht modale. Eine nicht modale Dialog Box erlaubt es ihnen, den Fokus auf ein anderes Fenster zu setzen. Als Beispiel der Suchen-Dialog von MS Word. Es gibt zwei Unterarten von modalen Dialog Boxen: Applikations-modal und System-modal. Eine Applikations-modale Dialog Box, lässt Sie nicht den Eingabe-Fokus auf ein anderes Fenster innerhalb der Applikation wechseln, aber Sie können den Eingabefokus auf ein Fenster einer ANDEREN Applikation setzen. Eine System-modale Dialog Box erlaubt es ihnen nicht den Eingabe-Fokus zu irgend einem anderen Fenster zu wechseln, bis Sie auf sie reagiert haben.

Eine nicht modale Dialog Box wird erzeugt, indem die CreateDialogParam-API-Funktion aufgerufen wird. Eine modale Dialog Box wird durch den Aufruf von DialogBoxParam erzeugt. Der einzige Unterschied zwischen einer Applikations-modalen Dialog Box und einer System-modalen ist der DS_SYSMODAL-Stil. Wenn Sie den DS_SYSMODAL Stil in einem Dialog Box Template einfügen, wird die Dialog Box eine System-modale.

Sie können mit jedem Child-Fenster Steuerelement einer Dialog Box kommunizieren, indem Sie die SendDlgItemMessage-Funktion benutzen. Die Syntax ist wie folgt:

SendDlgItemMessage proto hwndDlg:DWORD,\ idControl:DWORD,\ uMsg:DWORD,\ wParam:DWORD,\ lParam:DWORD


Dieser API Aufruf ist unglaublich nützlich für's interagieren mit einem Child-Fenster Steuerelement. Wenn Sie zum Beispiel den Text aus einem Edit-Steuerelement ermitteln wollen, können Sie folgendes tun:

call SendDlgItemMessage, hDlg, ID_EDITBOX, WM_GETTEXT, 256, ADDR text_buffer
Um zu wissen, welche Nachricht gesendet werden muss, sollten Sie ihre Win32 API-Referenz konsultieren.

Windows stellt auch verschiedene Steuerelement-spezifische API-Funktionen zu Verfügung um Daten schnell auszulesen und zu setzen, z.B. GetDlgItemText, CheckDlgButton, etc. Diese Steuerelement-spezifischen Funktionen werden zu Verfügung gestellt, um den Programmierern das Leben zu erleichtern, so dass dieser nicht immer die Bedeutungen von lParam und wParam bei jeder Nachricht nachschauen muss. Normalerweise sollten Sie Steuerelement-spezifische API-Aufrufe verwenden, soweit sie verfügbar sind, da sie den Source Code einfacher machen. Greifen Sie nur auf SendDlgItemMessage zurück, wenn keine entsprechende Steuerelement-spezifischen API-Aufrufe verfügbar sind.

Der Windows Dialog Box Manager sendet einige Nachrichten an eine spezielle Callback-Funktion names Dialog Box Prozedur welches folgendes Format hat:

DlgProc proto hDlg:DWORD ,\ iMsg:DWORD ,\ wParam:DWORD ,\ lParam:DWORD
Die Dialog Box Prozedur ist sehr ähnlich der Fenster-Prozedur außer für die Typen des Rückgabewerts, welche TRUE/FALSE anstatt von LRESULT ist. Der interne Dialog Box Manager in Windows IST die wirklich Fenster-Prozedur für die Dialog Box. Sie ruft unsere Dialog Box Prozedur mit einigen Nachrichten auf, die sie erhält. Deshalb folgende Regel: wenn unsere Dialog Box Prozedur eine Nachricht abarbeiten, MUSS sie TRUE in EAX zurückliefern und wenn sie die Nachricht nicht bearbeitet, muss sie FALSE in EAX zurückliefern. Beachten Sie, dass die Dialog Box Prozedur nicht abgearbeitete Nachrichten nicht weiter an die DefWindowProc reicht, da es keine richtige Fenster-Prozedur ist.

Es gibt zwei verschiedene Benutzungen einer Dialog Box. Sie können sie als Hauptfenster ihrer Applikation oder als Eingabegerät benutzen. Wir werden erste Anname in diesem Tutorial untersuchen.

"Eine Dialog Box als Hauptfenster zu benutzen" kann in zwei verschiedenen Weisen verstanden werden.

  1. Sie können das Dialog Box Template als ein Klassen-Templaten benutzen, welche sie mit einem RegisterClasseEx-Aufruf registrieren. In diesem Fall benimmt sich die Dialog Box wie ein "normales" Fenster: es empfängt Nachrichten via einer Fenster-Prozedur, welche mittels dem lpfnWndProc-Element in der Fenster-Klasse referiert wird, nicht über eine Dialog Box Prozedur. Der Vorteil dieser Vorgehensweise ist, dass Sie die Child-Fenster-Steuerlemente nicht selbst erzeugen müssen, Windows erzeugt sie für Sie, wenn die Dialog Box erzeugt wird. Auch kümmert sich Windows um die Tastaturbedienung für Sie, wie Tab-Reihenfolge, etc. Zusätzlich können Sie den Cursor und das Icon ihres Fensters in der Fenster-Klassen Struktur spezifizieren.
  2. Ihr Programm erzeugt nur eine Dialog Box ohne ein Eltern-Fenster zu erzeugen. Diese Vorgehensweise macht eine Message-Loop unnötig, da Nachrichten direkt an die Dialog Box Prozedur gesendet werden. Sie müssen nicht einmal die Fenster-Klasse registrieren!
Dieses Tutorial wird ein langes. Ich präsentiere ihnen erst die erste Vorgehensweise und danach die zweite.

Beispiele:




dialog.asm





.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 includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib .data ClassName db "DLGCLASS",0 MenuName db "MyMenu",0 DlgName db "MyDialog",0 AppName db "Our First Dialog Box",0 TestString db "Wow! I'm in an edit box now",0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? buffer db 512 dup(?) .const IDC_EDIT equ 3000 IDC_BUTTON equ 3001 IDC_EXIT equ 3002 IDM_GETTEXT equ 32000 IDM_CLEAR equ 32001 IDM_EXIT equ 32002 .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 hDlg: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,DLGWINDOWEXTRA push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_BTNFACE+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 CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL mov hDlg,eax invoke ShowWindow, hDlg,SW_SHOWNORMAL invoke UpdateWindow, hDlg invoke GetDlgItem,hDlg,IDC_EDIT invoke SetFocus,eax .WHILE TRUE invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke IsDialogMessage, hDlg, ADDR msg .IF eax ==FALSE invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDIF .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 lParam==0 .IF ax==IDM_GETTEXT invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512 invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK .ELSEIF ax==IDM_CLEAR invoke SetDlgItemText,hWnd,IDC_EDIT,NULL .ELSE invoke DestroyWindow,hWnd .ENDIF .ELSE mov edx,wParam shr edx,16 .IF dx==BN_CLICKED .IF ax==IDC_BUTTON invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString .ELSEIF ax==IDC_EXIT invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0 .ENDIF .ENDIF .ENDIF .ELSE invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .ENDIF xor eax,eax ret WndProc endp end start





Dialog.rc




#include "resource.h" #define IDC_EDIT 3000 #define IDC_BUTTON 3001 #define IDC_EXIT 3002 #define IDM_GETTEXT 32000 #define IDM_CLEAR 32001 #define IDM_EXIT 32003 MyDialog DIALOG 10, 10, 205, 60 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Our First Dialog Box" CLASS "DLGCLASS" BEGIN EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13, WS_GROUP END MyMenu MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Get Text", IDM_GETTEXT MENUITEM "Clear Text", IDM_CLEAR MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/ MENUITEM "E&xit", IDM_EXIT END END


Analyse:

Lassen Sie uns das erste Beispiel analysieren.
Dieses Beispiel zeigt, wie ein Dialog-Template als eine Fenster-Klasse registriert und ein Fenster von dieser Klasse erzeugt wird. Es vereinfacht ihr Programm, da Sie ihre Child-Fenster Steuerelemente nicht selbst erzeugen müssen.

Lassen Sie uns als erstes das Dialog-Template analysieren.

MyDialog DIALOG 10, 10, 205, 60


Deklariert den Namen eines Dialogs, in diesem Fall, "MyDialog" gefolgt von dem Schlüsselwort "DIALOG". Die folgenden vier Ziffern sind: x, y, Breite und Höhe der Dialog Box in Dialog Box Einheiten (nicht das Selbe wie Pixel).

STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK


Deklariert die Stile der Dialog Box.

CAPTION "Our First Dialog Box"


Dieser Text wird in der Titelleiste der Dialog Box erscheinen.

CLASS "DLGCLASS"


Diese Zeile ist entscheidend. Es ist das Schlüsselwort CLASS das uns erlaubt das Dialog Box Template als eine Fenster-Klasse zu benutzen. Dem Schlüsselwort folgt der Name der "Fenster Klasse"

BEGIN EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13 END


Der obere Block definiert die Child-Fenster Steuerelemente in der Dialog Box. Sie werden zwischen den Schlüsselwörtern BEGIN und END definiert. Generell ist die Syntax wie folgt:

Steuerelement-Typ  "text"   ,controlID, x, y, Breite, Höhe [,Stile]


Steuerelement-Typ sind Ressource Compiler-Konstanten, so dass Sie ihr Handbuch befragen müssen.

Nun kommen wir zum Assembler Source Code. Der interessante Teil ist in der Fenster-Klassen-Struktur:

mov wc.cbWndExtra,DLGWINDOWEXTRA mov wc.lpszClassName,OFFSET ClassName


Normalerweise ist dieses Element NULL, wenn wir aber ein Dialog Box Template als Fenster-Klasse registrieren wollen, müssen wir dieses Element auf den Wert DLGWINDOWEXTRA setzen. Beachten Sie, dass der Name der Klasse mit dem, der dem Schlüsselwort CLASS im Dialog Box Template folgt, identisch sein muss. Die übrigen Elemente werden wie gewöhnlich initialisiert. Nachdem Sie die Fenster-Klassen-Struktur gefüllt haben, registrieren Sie sie mit RegisterClassEx. Kommt ihnen das bekannt vor? Das ist die selbe Routine, die Sie machen müssen, als wenn Sie eine normale Fenster-Klasse registrieren wollen.

invoke CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL


Nachdem die "Fenster Klasse" registriert wurde, erzeugen wir unsere Dialog Box. In diesem Beispiel erzeuge ich eine nicht modale Dialog Box mit der CreateDialogParam-Funktion. Diese Funktion erwartet 5 Parameter, aber Sie müssen nur die ersten beiden ausfüllen: das Instanz Handle und den Pointer auf den Namen des Dialog Box Templates. Beachten Sie, dass der 2. Parameter kein Zeiger auf den Klassen-Name ist.

Zu diesem Zeitpunkt wird die Dialog Box und ihre Child-Fenster-Steuerelemente von Windows erzeugt. Ihre Fenster-Prozedur wird eine WM_CREATE-Nachricht wie gewöhnlich empfangen.

invoke GetDlgItem,hDlg,IDC_EDIT invoke SetFocus,eax


Nachdem die Dialog Box erzeugt wurde, setze ich den Eingabe-Fokus auf das Edit-Steuerelement. Wenn ich diese Code in der WM_CREATE Sektion plazieren würde, würde GetDlgItem Aufruf fehlschlagen, da zu diesem Zeitpunkt die Child-Fenster Steuerelemente noch nicht erzeugt wurden. Der einzige Weg um das zu machen, ist, sie nachdem die Dialog Box und all ihre Steuerelemente erzeugt wurden, aufzurufen. Deswegen plaziere ich diese beiden Zeilen nach dem UpdateWindow-Aufruf. Der GetDlgItem-Funktion wird die Controll-ID übergeben und liefert das zugehörige Steuerelement Fenster Handle zurück. Auf diese Weise können Sie ein Fenster-Handle ermitteln, wenn Sie die Controll-ID kennen.

invoke IsDialogMessage, hDlg, ADDR msg .IF eax ==FALSE invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDIF


Das Programm tritt in die Message-Loop ein und bevor wir die Nachrichten translaten und dispatchen, rufen wir die IsDialogMessage-Funktion auf, damit der Dialog Box Manager die Tastatureingaben unserer Dialog Box für uns händelt. Wenn diese Funktion TRUE zurückliefert, bedeutet das, dass die Nachricht für die Dialog Box bestimmt ist und wird vom Dialog Box Manager bearbeitet. Beachten Sie einen weiteren Unterschied zum vorherigen Tutorial. Wenn die Fenster-Prozedur den Text aus dem Edit-Steuerelement auslesen will, ruft es die GetDlgItemText-Funktion statt GetWindowText auf. GetDlgItemText akzeptiert eine Controll-ID statt eines Fenster-Handles. Das macht den Aufruf einfacher für den Fall, dass Sie eine Dialog Box benutzen.





Kommen wir zur zweiten Vorgehensweise, eine Dialog Box als Haupt-Fenster zu benutzen. In dem nächsten Beispiel erzeuge ich eine Applikation modale Dialog Box. Sie werden keine Message-Loop oder Fenster-Prozedur finden, weil diese nicht nötig sind!




dialog.asm (part 2)




.386 .model flat,stdcall option casemap:none DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib .data DlgName db "MyDialog",0 AppName db "Our Second Dialog Box",0 TestString db "Wow! I'm in an edit box now",0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? buffer db 512 dup(?) .const IDC_EDIT equ 3000 IDC_BUTTON equ 3001 IDC_EXIT equ 3002 IDM_GETTEXT equ 32000 IDM_CLEAR equ 32001 IDM_EXIT equ 32002 .code start: invoke GetModuleHandle, NULL mov hInstance,eax invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL invoke ExitProcess,eax DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .IF uMsg==WM_INITDIALOG invoke GetDlgItem, hWnd,IDC_EDIT invoke SetFocus,eax .ELSEIF uMsg==WM_CLOSE invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0 .ELSEIF uMsg==WM_COMMAND mov eax,wParam .IF lParam==0 .IF ax==IDM_GETTEXT invoke GetDlgItemText,hWnd,IDC_EDIT,ADDR buffer,512 invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK .ELSEIF ax==IDM_CLEAR invoke SetDlgItemText,hWnd,IDC_EDIT,NULL .ELSEIF ax==IDM_EXIT invoke EndDialog, hWnd,NULL .ENDIF .ELSE mov edx,wParam shr edx,16 .if dx==BN_CLICKED .IF ax==IDC_BUTTON invoke SetDlgItemText,hWnd,IDC_EDIT,ADDR TestString .ELSEIF ax==IDC_EXIT invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0 .ENDIF .ENDIF .ENDIF .ELSE mov eax,FALSE ret .ENDIF mov eax,TRUE ret DlgProc endp end start





dialog.rc (part 2)




#include "resource.h" #define IDC_EDIT 3000 #define IDC_BUTTON 3001 #define IDC_EXIT 3002 #define IDR_MENU1 3003 #define IDM_GETTEXT 32000 #define IDM_CLEAR 32001 #define IDM_EXIT 32003 MyDialog DIALOG 10, 10, 205, 60 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Our Second Dialog Box" MENU IDR_MENU1 BEGIN EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13 PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13 END IDR_MENU1 MENU BEGIN POPUP "Test Controls" BEGIN MENUITEM "Get Text", IDM_GETTEXT MENUITEM "Clear Text", IDM_CLEAR MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/ MENUITEM "E&xit", IDM_EXIT END END





Die Analyse folgt:

    DlgProc proto :DWORD,:DWORD,:DWORD,:DWORD


Wir deklarieren den Funktionsprototypen für DlgProc, so dass wir sie mit dem addr Operator in der nächsten Zeile referenzieren können:

    invoke DialogBoxParam, hInstance, ADDR DlgName,NULL, addr DlgProc, NULL


Die obige Zeile ruft die DialogBoxParam Function auf, welche 5 Parameter benötigt: das Instanz-Handle, den Namen des Dialog Box Templates, dasEltern-Fenster Handle, die Adresse der Dialog-Box Prozedur und die Dialog-spezifischen Daten. DialogBoxParam erzeugt eine modale Dialog Box. Sie wird nicht zurückkehren, bis die Dialog Box zerstört wird.

.IF uMsg==WM_INITDIALOG invoke GetDlgItem, hWnd,IDC_EDIT invoke SetFocus,eax .ELSEIF uMsg==WM_CLOSE invoke SendMessage,hWnd,WM_COMMAND,IDM_EXIT,0


Die Dialog Box Prozedur sieht aus wie die Fenster-Prozedur, mit dem Unterschied, dass sie keine WM_CREATE Nachricht erhält. Die erste Nachricht, die sie erhält, ist WM_INITDIALOG. Normalerweise können Sie hier ihren Initialisierungscode platzieren. Beachten Sie, dass Sie den Wert TRUE in EAX zurückgeben müssen, wenn die Nachricht bearbeitet wurde.

Der interne Dialog Box Manager sendet unserer Dialog Box Prozedur nicht automatisch die WM_DESTROY-Nachricht, wenn WM_CLOSE an unsere Dialog Box gesendet wurde. So müssen wir die WM_CLOSE Nachricht bearbeiten, wenn wir wir darauf reagieren wollen, wenn der Benutzer auf den Schließen Button der Dialog Box klickt. In unserem Beispiel sendet wir eine WM_COMMAND Nachricht mit IDM_EXIT als Wert in wParam. Das hat den selben Effekt, als wenn der Benutzer das Exit Menü-Element anwählt. EndDialog wird als Antwort auf IDM_EXIT aufgerufen. Die Bearbeitung der WM_COMMAND-Nachricht bleibt die selbe.

Wenn Sie die Dialog Box zerstören wollen, gibt's nur die Möglichkeit die EndDialog-Funktion aufzurufen. Versuchen Sie nicht DestroyWindow! EndDialog zerstört die Dialog Box nicht unverzüglich. Es setzt nur ein Flag für den internen Dialog Box Manager und fährt mit dem nächsten Befehl fort.

Lassen Sie uns nun die Ressourcedatei unter die Lupe nehmen. Die auffälige Veränderung ist, dass wir statt einem String als Menünamen den Wert IDR_MENU1 benutzen. Das ist nötig, wenn Sie ein Menü einer Dialog Box die mit DialogBoxParam erzeugt wird, hinzufügen wollen. Beachten Sie, dass Sie in dem Dialog Box Template das Schlüsselwort MENU gefolgt von der Menü-Ressource ID einfügen müssen.

Ein Unterschied den Sie zwischen den beiden Beispielen beobachten können, ist das fehlen des Icons in dem letzten Beispiel. Wie auch immer, Sie können das Icon hinzufügen, indem Sie eine WM_SETICON-Nachricht an die Dialog Box senden während WM_INITDIALOG.


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