Tutorial 11: Encore Plus à Propos
Des Boîtes de Dialogue

Dans ce Tutorial, nous allons en apprendre encore plus sur la boîte de dialogue. Plus spécialement, nous allons voir comment employer les boîtes de dialogue en tant que dispositifs d'entrée-sortie. Si vous avez lu le tutorial précédent, celui-ci ne sera qu'une brise. Il s'agit ici d'une une modification mineure pour pouvoir utiliser les boîtes de dialogue comme des adjonctions à notre fenêtre principale. Aussi dans ce tutorial, nous allons apprendre à utiliser les boîtes de dialogue comme elles sont utilisées normalement.

Downloadez les exemples de DialogBox ici et ici. Downloadez l'exemple de DialogBox couramment utilisée ici.

Théorie:

Vite fait, voici ce qui doit être dit à propos de l'emploi des boîtes de dialogue en tant que dispositifs d'entrée-sortie de notre programme. Comme d'habitude, notre programme crée la fenêtre principale puis quand vous voulez montrer la DialogBox, appelez juste CreateDialogParam ou bien DialogBoxParam. Avec l'appel de DialogBoxParam, vous n'avez rien de plus à faire, traitez seulement les messages dans la procédure de la boîte de dialogue. Avec CreateDialogParam, vous devez insérer un 'Call IsDialogMessage' dans la boucle de message pour permettre à l'administrateur de la boîte de dialogue de gérer la navigation du clavier dans votre boîte de dialogue à votre place. Puisque ces deux cas sont rares, je ne mettrai pas le code source ici. Vous pouvez télécharger les exemples et les examiner vous-même, ici et ici.
Continuons avec les boîtes de dialogue communes (habituellement utilisées). Windows possède des DialogBox prédéterminées pour que vos applications puissent les utiliser. Ces boîtes de dialogue existent pour servir d'interface utilisateur standardisée. Il s'agit des fichiers comme, l'imprimante, la couleur, la fonte et des boîtes de dialogue de recherche. Vous devez les employer autant que possible. Ces boîtes de dialogue prédéfinies résident dans comdlg32.dll. Pour les employer, vous devez vous lier avec comdlg32.lib. Vous créez ces boîtes de dialogue en appelant des fonctions appropriées dans la bibliothèque de DialogBox communes. Pour ouvrir le fichier de dialogue, c'est GetOpenFileName, pour le sauvegarder en tant que dialogue on se sert de GetSaveFileName, pour la boîte de dialogue de l'imprimante c'est PrintDlg et cetera. Chacune de ces fonctions utilise un pointeur comme paramètre dans sa structure. Vous devez les regarder dans la référence Win32 API. Dans ce Tutorial, je on va voir comment créer et employer une DialogBox servant à ouvrir des fichiers.
Voici ci-dessous le prototype de fonction de GetOpenFileName :
 
GetOpenFileName proto lpofn:DWORD
Vous pouvez voir qu'il ne reçoit qu'un seul paramètre, un pointeur sur la structure OPENFILENAME. La valeur de retour TRUE(VRAI) signifie que l'utilisateur vient de choisi un fichier pour l'ouvrir, sinon la valeur en retour est FALSE(FAUX). Voyons la structurent d'OPENFILENAME maintenant.
 
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
On va voir la signification des membres fréquemment employés.
 
lStructSize Taille de la structure d'OPENFILENAME, en octets.
hwndOwner handle de la boîte de dialogue qui sert à ouvrir des fichiers.
hInstance Instance Handle de l'application qui crée la 'boîte de dialogue qui sert à ouvrir des fichiers'.
lpstrFilter Sert à filtrer le type de chaînes de caractères à ouvrir. Il faut 2 NULL pour terminer cette instruction. La première chaîne de caractères est la description (donc le texte). La deuxième c'est le type de filtre. Par exemple, dans un répertoire on peut sélectionner tous les dossiers ou bien que les .exe ou bien seulement les .zip……etc:
     FilterString   db "All Files (*.*)",0, "*.*",0
                        db "Text Files (*.txt)",0,"*.txt",0,0
Remarquez bien que c'est la deuxième chaîne de caractères (pour chaque ligne) qui en réalité sert à Windows à filtrer les fichiers. Donc vous êtes obligés de mettre un 0 supplémentaire à la fin de la chaîne de caractères du filtre pour en indiquer sa fin.
nFilterIndex Indique quelle [paire de chaîne de caractères de] filtre sera utilisée par défaut dans la DialogBox qui sert à ouvrir les fichiers. Ce sera le 1, pour la première paire "All Files (*.*)", le 2 pour la deuxième paire "Text Files (*.txt)" etc. Ainsi dans notre exemple, si nous spécifions nFilterIndex en tant que 2, le deuxième modèle, "*.txt" sera employé.
lpstrFile Le pointeur du buffer qui contient le nom de fichier qu'on a l'habitude d'initialiser dans la boîte d'édition de notre DialogBox (ici c'est le pointeur qui pointe sur le texte " ALL FILES ". Le pointeur doit avoir une longueur d'au moins 260 octets. 
Après que l'utilisateur ait choisit un fichier pour l'ouvrir, le nom de ce fichier ainsi que le chemin (Patch) complète où il est stocké, sont gardés dans ce buffer pstrFile. Vous pourrez en extraire l'information plus tard.
nMaxFile La taille de buffer lpstrFile.
lpstrTitle Pointeur du titre de la DialogBox qui sert à ouvrir les fichiers. (donc c'est le titre).
Flags Détermine le style et les caractéristiques de la boîte de dialogue.
nFileOffset Après que l'utilisateur ait choisi un fichier pour l'ouvrir, ce membre contient le n° du premier caractère du nom du fichier réel. Par exemple, si le nom complète avec son chemin est "c:\Windows\system\lz32.dll", ce membre contiendra la valeur 18.
nFileExtension Après que l'utilisateur ait choisi un fichier pour l'ouvrir, ce membre contient le numéro du premier caractère de l'extension du fichier. Ici c'est 23

Exemple:

Le programme suivant montre une boîte de dialogue servant à ouvrir des fichiers. Pour en ouvrir un, l'utilisateur doit choisir le Fichier avec le sous-menu 'OPEN'. Quand l'utilisateur choisit un fichier dans la DialogBox, le programme affiche une MessageBox montrant le nom complet, à savoir le nom du fichier avec l'extension de ce fichier.

.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 "All Files",0,"*.*",0
             db "Text Files",0,"*.txt",0,0
buffer db MAXSIZE dup(0)
OurTitle db "-=Our First Open File Dialog Box=-: Choose the file to open",0
FullPathName db "The Full Filename with Path is: ",0
FullName db "The Filename is: ",0
ExtensionName db "The Extension is: ",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

Nous remplaçons les membres ordinaires par des structures ofn.

            mov  ofn.lpstrFilter, OFFSET FilterString

Ce FilterString est le filtre du nom de fichier que nous définissons comme suit :

FilterString db "All Files",0,"*.*",0
             db "Text Files",0,"*.txt",0,0
Remarquez que les quatre chaînes de caractères sont terminées par un Zéro. La première chaîne est la description de la chaîne suivante (EX : ''ALL FILES est la description de *.*''). Le modèle réel est la 2e chaîne de caractères, dans notre cas ce sont *. * et *.txt. En réalité nous pouvons prendre n'importe quel modèle d'extension. exemple : *.wavwav . Nous DEVONS mettre un zéro supplémentaire après la dernière chaîne de caractères pour à montrer que c'est la fin de la chaîne du filtre. N'oubliez surtout pas ça, sinon votre DialogBox se comportera étrangement.

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

Nous indiquons où la boîte de dialogue mettra le nom du fichier que l'utilisateur vient de choisir. Notez que nous devons spécifier sa taille dans le membre nMaxFile. Plus tard, nous pourrons extraire le nom du fichier contenu dans ce buffer.

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

Flags indique les caractéristiques de la boîte de dialogue.
Les 'flags' (les drapeaux) OFN_FILEMUSTEXIST et OFN_PATHMUSTEXIST exigent que le nom du fichier et le chemin que l'utilisateur tape dans la zone d'édition DOIVENT exister.
le 'flag' OFN_LONGNAMES dit à la boîte de dialogue de montrer des noms de fichier longs. (et non pas des trucs du genre 'nomtropl~1.exe')
Le flag OFN_EXPLORER indique que l'apparition de la boîte de dialogue doit être semblable à celle de l'Explorer Windows.
Le flag OFN_HIDEREADONLY cache la 'case à cocher : read-only ' de la boîte de dialogue.
Il y a beaucoup encore d'autres flags que vous pouvez employer. Consultez votre référence Win32 API.

            mov  ofn.lpstrTitle, OFFSET OurTitle

C'est le titre de la boîte de dialogue qui sert à ouvrir des fichiers.

            invoke GetOpenFileName, ADDR ofn

Appelle la fonction GetOpenFileName. Il passage le pointer à la structure 'ofn' en tant que son paramètre.
À partir d'ici, la boîte de dialogue qui ouvre les fichiers, est affichée à l'écran. La fonction ne retournera pas avant que l'utilisateur ne choisisse un fichier pour l'ouvrir ou bien qu'il ne presse le bouton ANNULER ou FERMER de la boîte de dialogue.
Il renverra la valeur TRUE(VRAI) dans eax si l'utilisateur choisit un fichier pour l'ouvrir. Sinon, il retournera FALSE(FAUX).

            .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

Dans le cas où l'utilisateur choisit un fichier pour l'ouvrir, nous préparons une chaîne de caractère pour qu'elle soit affichée dans une MessageBox. Nous réservons un bloc de mémoire dans la variable OutputString puis ensuite nous employons la fonction API, lstrcat, pour enchaîner ensembles les chaîne de caractères . Pour faire apparaître les chaînes sur plusieurs lignes, nous devons séparer chaque ligne avec un retour chariot.

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

Les susdites lignes exigent quelques explications. nFileOffset contient le n° dans l'ofn.lpstrFile (ce n° c'est son positionnement). Mais vous ne pouvez pas les ajouter ensemble directement puisque nFileOffset est une variable de TAILLE 'WORD' et lpstrFile est de TAILLE 'DWORD'. Il faut donc mettre la valeur de nFileOffset dans le mot bas (le mot de poids faible) de ebx et l'ajouter à la valeur de lpstrFile.

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

Nous affichons la chaîne de caractères dans la MessageBox (boîte de message).

                invoke RtlZerolMemory,offset OutputString,OUTPUTSIZE

Nous devons *effacer* l'OutputString avant que nous ne puissions remplir une autre chaîne de caractères. Donc nous employons la fonction RtlZeroMemory pour faire le travail.


[Iczelion's Win32 Assembly HomePage]


Traduit par Morgatte