Tutorial 10: Boîte de Dialogue
Comme Fenêtre Principale

Vient maintenant un objet vraiment intéressante du GUI (NdT : Graphic User Interface), à savoir : la boîte de dialogue. Dans ce Tutorial (et le suivant), nous apprendrons comment se servir d'une boîte de dialogue comme fenêtre principale.

Downloadez le premier exemple ici, le second .

Théorie:

Si vous avez joué assez longtemps avec les exemples des Tutorials précédants, vous avez dû découvrir que la touche TAB ne permettait pas de changer de centre d'entrée d'un 'Child Window Control' à un autre (EX : si vous avez un bouton et une zone de saisie, la touche TAB sert à activer puis à passer de l'un à l'autre. Essayez sur les exemples de ce TUT) . Dans les Tutorials précédents, le seul moyen d'activer le centre d'entrée d'un des 'Child Wondow Control' était de simple-cliquer sur l'un d'eux. C'est une situation un peu lourde. Une nouvelle chose à remarquer, c'est que j'ai changé la couleur du fond de la fenêtre parente, elle est grise maintenant au lieu de blanche comme dans des exemples précédents. C'est fait pour que la couleur des 'child window controls' puisse se mélanger sans différence avec la couleur du 'secteur client' de la fenêtre parente. Il y a une autre façon de contourner ce problème mais ce n'est pas facile. Vous devez sous-classer tous les 'child window controls' de votre fenêtre parente.
La raison pour laquelle un tel inconvénient existe, c'est qu'à l'origine les 'Child Window Controls' ont étés conçus pour travailler avec une boîte de dialogue, et non pas une simple fenêtre. La couleur par défaut des 'Child Window Controls' tel qu'un bouton est grise parce que le 'secteur client' d'une boîte de dialogue est normalement gris. Donc ils se marient l'un avec l'autre sans que le programmeur ne se casse encore plus la tête sur un détail comme ça.
Avant que nous n'allions plus profondément dans les détails, nous devons d'abord comprendre ce qu'est une boîte de dialogue. Une boîte de dialogue n'est rien de plus d'une fenêtre normale qui est conçue pour travailler avec des'child window controls'. Windows possède aussi son propre ''administrateur de boîte de dialog'' lequel est responsable de la majeure partie de la logique du clavier, comme par exemple le changement du centre d'entrée quand l'utilisateur presse 'TAB' (= activer un autre Child Window Control avec TAB), ou bien en 'Validant' la touche dont son centre d'entrée est sélectionné si la touche ENTER est pressée (=quand vous avez 2 boutons dans une fenêtre, un OK l'autre NON, si c'est OK qui est sélectionné en cadre pointillé, en appuyant sur ENTER c'est comme si on avait cliqué sur OK ), etc… donc avec ça, les programmeurs peuvent traiter des tâches de plus haut niveau. Les boîtes de dialogue sont principalement employées comme des dispositifs d'Entrée / Sorties. Puisqu'une telle boîte de dialogue peut être considérée comme une "boîte noire" d' Entrée / Sortie, vous n'avez pas besoin de savoir comment travaille intérieurement cette boîte de dialogue pour pouvoir l'employer. Vous devez seulement savoir comment elle agir. C'est le principe d'OBJET ORIENTÉ PROGRAMMÉ (OOP) qui fait en sorte que l'information est dissimulée (tout n'est pas apparent dans son fonctionnement). Si la boîte noire était *parfaitement* conçue, l'utilisateur devrait pouvoir s'en servir sans aucune connaissance de son fonctionne. Le hic c'est que la boîte noire doit être parfaite, et en réalité c'est difficile à réaliser car les API Win32 sont aussi conçues comme des boîtes noire.
Bien, il semble que nous dévions de notre chemin. On va revenir à notre sujet. Les boîtes de dialogue sont conçues pour réduire le travail du programmeur. Normalement si vous utilisez des 'Child Window Controls' sur une fenêtre normale, vous devez les sous-classer et écrire (définir) la logique du clavier vous-même. Mais si vous les mettez sur une boîte de dialogue, tout ceci sera manipulé pour vous. Vous devez seulement savoir comment s'utilisent vos Child Window dans la boîte de dialogue ou comment envoyer des commandes.
Une boîte de dialogue est définie comme une ressource (un objet qu'on défini pour pouvoir l'utiliser parmi d'autres) un peu de la même façon qu'un menu. Vous décrivez les caractéristiques de votre boîte de dialogue et de ses commandes, puis ensuite vous compilez le scénario de ressources avec un éditeur de ressources.
Remarquez que toutes les ressources sont réunies dans le même fichier de scénario de ressource. Vous pouvez employer n'importe quel éditeur de texte pour écrire un calibre de boîte de dialogue mais je ne le recommande pas. Vous vaut mieux employer un éditeur de ressources pour faire le travail visuellement puisque l'arrangement des 'child window controls' sur une boîte de dialogue est difficile à faire manuellement. Plusieurs éditeurs de ressources excellents sont disponibles. La plupart des Packs de compilateurs incluent aussi leurs propres éditeurs de ressources. Vous pouvez les employer pour créer un scénario de ressources pour votre programme et couper ensuite les lignes sans rapport comme celles liés à MFC.
Il y a deux principaux types de boîte de dialogue : 'modale' et 'sans modèle'. Une boîte de dialogue sans modèle vous laisse changer son centre d'entrée pour une autre fenêtre. Le meilleur exemple c'est la boîte de dialogue 'RECHERCHER' de WORD. Il y a deux sous-types de boîte de dialogue modale : l'application modale et le système modal. Une boîte de dialogue d'application modale ne vous laisse pas changer son centre d'entrée pour aller vers une autre fenêtre dans la même application. Par contre vous pouvez changer le centre d'entrée de la fenêtre pour aller vers d'AUTRES applications. Le système de la boîte de dialogue modale ne vous permet pas de changer son centre d'entrée pour une autre fenêtre avant que vous ne répondiez d'abord.
On créé une 'boîte de dialogue sans modèle' en appelant la fonction API CreateDialogParam. On créé une boîte de dialogue modale en appelant DialogBoxParam. La seule différence entre une boîte de dialogue d'application modale et un système modal est le style DS_SYSMODAL. Si vous incluez le style DS_SYSMODAL dans un calibre de boîte de dialogue, cette boîte de dialogue sera un système modale.
Vous pouvez communiquer avec n'importe quel 'child window control' dans une boîte de dialogue en employant la fonction SendDlgItemMessage. Sa syntaxe est la suivante :
 
SendDlgItemMessage proto hwndDlg:DWORD,\
                                             idControl:DWORD,\
                                             uMsg:DWORD,\
                                             wParam:DWORD,\
                                             lParam:DWORD
Cet appel d'API est super utile pour l'action réciproque avec les 'child window control'. Par exemple, si vous voulez récupérer le texte d'un contrôle d'édition, vous pouvez faire ceci :
call SendDlgItemMessage, hDlg, ID_EDITBOX, WM_GETTEXT, 256, ADDR text_buffer
Pour savoir quel message (quelle commande) vous devez utiliser, vous devez consulter votre référence Win32 API.
Windows fournit aussi plusieurs fonctions API de contrôle-spécifiques pour récupérer et transmettre des données rapidement, par exemple, GetDlgItemText, CheckDlgButton etc. Ces fonctions de contrôle-spécifiques sont mis à la disposition du programmeur. Donc il ne doit pas rechercher les significations de wParam et lParam pour chaque message. Normalement, vous devez utiliser les appels d'API de contrôle-spécifiques quand ils sont disponibles puisque ils servent à vous faciliter l'écriture de votre code source. On recours seulement à SendDlgItemMessage si aucun des appels d'API de contrôle-spécifiques n'est disponible.
L'administrateur de boîte de dialogue de Windows envoie quelques messages à une fonction de rappel de service spécialisée, laquelle est appelée 'procédure de boîte de dialogue' et qui a le format suivant :
DlgProc  proto hDlg:DWORD ,\
                        iMsg:DWORD ,\
                        wParam:DWORD ,\
                        lParam:DWORD
La 'procédure de boîte de dialogue' est très semblable à une 'procédure de fenêtre' à part le type de valeur de retour qui est TRUE / FAULSE au lieu de LRESULT. L'administrateur de boîte de dialogue interne à Windows EST la vraie procédure de fenêtre pour la boîte de dialogue. Il appelle notre procédure de boîte de dialogue avec les messages qu'il a reçu. Donc la règle générale en vigueur consiste en ce que : si notre procédure de boîte de dialogue traite un message, il DOIT retourner la valeur TRUE (VRAIE) dans eax et s'il ne traite pas le message, il doit retourner FAULSE (FAUX) dans eax. Remarquez qu'une procédure de boîte de dialogue ne transmet pas les messages et elle ne traite pas l'appel de DefWindowProc puisque ce n'est pas une procédure de fenêtre réelle (normale).
Il y a deux utilisations distinctes d'une boîte de dialogue. Vous pouvez l'employer en tant que fenêtre principale de votre application ou l'employer comme un dispositif d'entrée. Nous allons examiner la première approche dans ce tutorial.
""L'utilisation d'une boîte de dialogue comme fenêtre principale" peut être interprétée dans deux sens différents.
  1. Vous pouvez calibrer une boîte de dialogue comme un calibre de classe que vous déclarez avec l'appel de RegisterClassEx. Dans ce cas, la boîte de dialogue se comporte comme une fenêtre "normale" : elle reçoit des messages via une procédure de fenêtre mentionnée par le membre lpfnWndProc de la classe de fenêtre, et non pas par une procédure de boîte de dialogue. L'avantage de cette approche est que vous n'avez pas à créer vous-même de 'child window controls'. Windows les crée pour vous lorsque la boîte de dialogue est créée. Ainsi Windows gère la logique du clavier pour vous. De plus vous pouvez choisir le curseur et l'icône de votre fenêtre dans la structure de classe de fenêtre.

  2. Votre programme crée seulement une boîte de dialogue sans créer aucune fenêtre parente. Cette approche fait une boucle de message inutile puisque les messages sont envoyés directement à la procédure de boîte de dialogue. Vous n'avez même pas besoin d'enregistrer une classe de fenêtre!
Ce Tutorial va être long. Je présenterai la première approche suivie par le deuxième.

Exemples:


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! Je suis dans une boîte d'édition maintenant",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   "Dis Bonjour", 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:

On va analyser ce premier exemple.
Cet exemple montre comment créer un calibre de dialogue comme une classe de fenêtre, et créer "une fenêtre" avec cette classe. ça simplifie notre programme puisque on n'a pas besoin de créer de 'child window controls' soi-même.
On va d'abord analyser le calibre de dialogue.

MyDialog DIALOG 10, 10, 205, 60

On déclare le nom d'un dialogue, dans ce cas, "MyDialog" suivi du mot-clé "DIALOG". Les quatre nombres suivants sont : x, y, largeur et hauteur de la boîte de dialogue, ce sont des unités propres aux DialogBox (C'est pas des pixels).

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

Déclare les styles de la boîte de dialogue.

CAPTION "Our First Dialog Box"

C'est le texte qui apparaîtra dans la barre de titre de la boîte de dialogue.

CLASS "DLGCLASS"

Cette ligne est cruciale. C'est ce mot-clé CLASS qui nous permet d'employer le calibre de boîte de dialogue comme une 'Window Class' (classe de fenêtre). Puis, suivant le mot-clé on trouve le nom de la "Window Class"

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

Le susdit bloc définit les 'child window controls' de la boîte de dialogue. Ils sont définis entre les mots-clés BEGIN et END. Généralement la syntaxe est la suivante :

Les 'types' de contrôle sont propre au compilateur de ressource, donc vous devez consulter le manuel.
Maintenant nous voyons le code de source assembleur. La partie intéressante est dans la structure de la 'Window Class ' : Normalement, ce membre est le NULL, mais si nous voulons enregistrer un calibre de boîte de dialogue comme une Window Class (classe de fenêtre), nous devons mettre ce membre à la valeur DLGWINDOWEXTRA. Notez que le nom de la classe doit être identique à celui qui est après le mot-clé CLASS pour le calibre de boîte de dialogue. Les membres restants sont initialisés comme d'habitude. Après que vous ayez remplis la structure de classe de fenêtre, déclarez-la avec RegisterClassEx. Ça vous semble familier ? C'est la même routine que pour enregistrer une classe de fenêtre normale. Après avoir définit notre "Window Class", nous créons notre boîte de dialogue. Dans cet exemple, je la crée comme une boîte de dialogue sans modèle grâce à la fonction CreateDialogParam. Cette fonction prend 5 paramètres, mais en réalité, vous n'avez besoin que des deux premier : l'instance handle et le pointeur qui justement pointe sur 'le nom du calibre de DialogBox'. Notez que le 2ème paramètre n'est pas un pointeur sur le nom de class.
À ce point, la boîte de dialogue et ses 'child window controls' sont créés par Windows. Votre procédure de fenêtre recevra comme d'habitude le message WM_CREATE. Maintenant que la boîte de dialogue est créée, j'aimerai mettre le centre d'entrée au contrôle d'édition (= on veut que la zone de saisie de texte soit active). Si je met ces codes dans la section WM_CREATE, l'appel GetDlgItem échouera jusqu'à ce que les 'child window controls' ne soient créés. La seule façon pour faire cela est de l'appeler après que la boîte de dialogue et tous ses 'child window controls' soient créés. C'est pour ça que j'ai mis ces deux lignes après l'appel à UpdateWindow. la fonction GetDlgItem obtient le contrôle ID et renvoie le contrôle du 'Window Handle' associé. C'est de cette manière que vous pouvez récupérer un 'Window Handle' lorsque vous connaissez son 'contrôle ID'.

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

Le programme entre dans la boucle de message et avant que nous traduisions et expédiions des messages, nous appelons la fonction IsDialogMessage pour que l'administrateur de boîte de dialogue puisse s'occuper de la logique du clavier à notre place. Si ces retours de fonction sont TRUES(VRAIS), alors ça signifie que le message est destiné à la boîte de dialogue et est traité par l'administrateur de la boîte de dialogue. Remarquez une autre différence par rapport Tutorial précédent. Quand la procédure de fenêtre veut récupérer le texte qui est inscrit dans la zone d'édition, elle appelle la fonction GetDlgItemText au lieu de GetWindowText. GetDlgItemText accepte un contrôle ID au lieu d'un 'Window Handle'. Ceci rend l'appel plus facile dans le cas vous employez une boîte de dialogue.



Maintenant on va voir à la deuxième approche, à savoir : l'utilisation d'une boîte de dialogue comme fenêtre principale. Dans l'exemple suivant, je vais créer une boîte de dialogue d'application modale. Vous ne trouverez pas de boucle de message ou de procédure de fenêtre parce qu'elles ne sont pas nécessaires!
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! Je suis dans une zone d'édition",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 (partie 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   "Dis Bonjour", 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



The analysis follows:

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

Nous déclarons le prototype de fonction de DlgProc ,ainsi nous pouvons lui attribuer l'opérateur addr à la ligne ci-dessous :

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

la susdite ligne appelle la fonction DialogBoxParam qui prend 5 paramètres : l'Instance handle', le 'nom du calibre de boîte de dialogue', l'handle de la fenêtre parente', l'adresse de la procédure de la de boîte de dialogue et des données dialogue-spécifiques. DialogBoxParam crée une boîte de dialogue modale. Rien ne sera retourné tant que la boîte de dialogue ne sera pas détruite.

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

La procédure de boîte de dialogue ressemble à une procédure de fenêtre sauf qu'elle ne reçoit pas le message WM_CREATE. Le premier message qu'elle reçoit est WM_INITDIALOG. Normalement vous pouvez mettre le code d'initialisation ici. Remarquez que vous devez renvoier la valeur TRUE (VRAIE) dans eax si vous traitez le message.
L'administrateur interne de boîte de dialogue n'envoie pas à notre procédure de boîte de dialogue par défaut le message WM_DESTROY quand WM_CLOSE est envoyé à notre boîte de dialogue. Ainsi si nous voulons réagir quand l'utilisateur presse le bouton proche sur notre boîte de dialogue, nous devons traiter le message WM_CLOSE. Dans notre exemple, nous envoyons le message WM_COMMAND avec la valeur IDM_EXIT dans wParam. Ça a le même effet que lorsque l'utilisateur choisit l'article de menu de Sortie (le sous-menu : EXIT). EndDialog est appelé dans la réponse à IDM_EXIT.
Le traitement du messages WM_COMMAND reste le même.
Quand vous voulez détruire la boîte de dialogue, il faut appeler la fonction EndDialog. N'essayez pas DestroyWindow! EndDialog ne détruit pas la boîte de dialogue immédiatement. Il met seulement un drapeau(Flag) pour l'administrateur de la boîte de dialogue et continue à exécuter les instructions suivantes.
Maintenant on va examiner le fichier de ressources. Un changement notable est qu'au lieu de l'utilisation d'une chaîne de texte pour le nom de menu nous employons une valeur, IDR_MENU1. C'est nécessaire si vous voulez attacher un menu à une boîte de dialogue créée avec DialogBoxParam. Notez que dans le calibre de boîte de dialogue, vous devez ajouter le mot-clé MENU suivi de la ressource du menu ID.
La différence entre les deux exemples de ce Tutorial est le manque d'une icône dans le dernier exemple. Cependant, vous pouvez mettre l'icône en envoyant le message WM_SETICON à la boîte de dialogue pendant WM_INITDIALOG.


[Iczelion's Win32 Assembly Homepage]


Traduit par Morgatte