Downloadez le fichier en example ici.
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 "SimpleWinClass",0
AppName
db "Our First Window",0
MenuName
db "FirstMenu",0
ButtonClassName
db "button",0
ButtonText
db "My First Button",0
EditClassName
db "edit",0
TestString
db "Wow! I'm in an edit box now",0
.data?
hInstance
HINSTANCE ?
CommandLine
LPSTR ?
hwndButton
HWND ?
hwndEdit
HWND ?
buffer
db 512 dup(?)
; Buffer pour stocker le texte qu'on inscrit dans la boîte d'édition.
.const
ButtonID
equ 1
; The control ID of the button control
EditID
equ 2
; The control ID of the edit control
IDM_HELLO
equ 1
IDM_CLEAR
equ 2
IDM_GETTEXT
equ 3
IDM_EXIT
equ 4
.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_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 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_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,35,200,25,hWnd,8,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc
endp
end
start
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
Rappelez-vous bien qu'un menu envoie lui aussi des messages WM_COMMAND vers la fenêtre parente pour l'informer de son propre état. Comment pouvez-vous faire la différence entre des messages WM_COMMAND, émis par un menu (Child Window) ou par un contrôle (effectué par la Parent Window) ? Voici ci-dessous la réponse :
Low word of wParam | High word of wParam | lParam | |
Menu | Menu ID | 0 | 0 |
Control | Control ID | Notification code | Child Window Handle |
Vous pouvez voir que vous devez vérifier lParam. Si c'est zéro, l'actuel message WM_COMMAND provient d'un menu. Vous ne pouvez pas employer wParam pour faire la différence entre un menu et un contrôle, puisque le 'menu ID' et 'control ID' peuvent être identique et le code de notification peut être zéro.
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
Vous pouvez écrire une chaîne de caractère (du texte) dans la boîte d'édition en appelant la fonction SetWindowText. Vous pouvez aussi effacez le contenu de cette boîte d'édition en appelant SetWindowText avec le NULL. SetWindowText une fonction API d'usage flexible. Vous pouvez employer SetWindowText pour modifier du titre dans une fenêtre ou pour changer le texte inscrit sur un bouton.
Pour importer du texte dans une boîte d'édition, vous employez GetWindowText. (Comprenez seulement que, dans ce cas on écrit pas manuellement le texte dans la boîte d'édition (de saisie), mais on le fait s'inscrire dans la zone de saisie comme on aurait pu faire s'inscrire un texte dans une MessageBox).
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
Ce petit bout de code réagit à la seule condition que l'utilisateur presse le bouton. D'abord, il vérifie le mot bas (ou de poids faible) de wParam pour voir si le 'control ID' correspond à celui du bouton. S'il l'est, il vérifie le haut mot (ou de poids fort) de wParam pour savoir si on a bien l'indication BN_CLICKED, qui est envoyée quand le bouton est cliqué.
La partie qui est intéressante, c'est après qu'on soit certain que le code de notification soit BN_CLICKED. Nous voulons récupérer le texte qu'on vient d'écrire dans la boîte d'édition et le montrer dans une boîte de message (une MessageBox). Nous pourrions faire un double du code de la section IDM_GETTEXT ci-dessus mais ça n'a pas de sens. Si d'une façon ou d'une autre nous pouvions envoyer un message WM_COMMAND avec le mot bas de wParam, alors la valeur contenue dans IDM_GETTEXT serait transmise à notre propre procédure de fenêtre, nous pouvons donc éviter la duplication de ce code et simplifier notre programme. La solution, c'est la fonction SendMessage. Cette fonction envoie n'importe quel message à n'importe quelle fenêtre avec n'importe quel wParam et lParam. Ainsi au lieu de recopier du code, nous appelons SendMessage avec : 1- l'Handle de la fenêtre parente, 2- WM_COMMAND, 3- IDM_GETTEXT et 4- 0. Ceci a le même effet que de sélectionner le menu Item "Get Text" (un de nos sous-menu) du menu. La procédure de fenêtre ne voit aucune différence entre les deux. (La procédure de fenêtre = la procédure qui s'occupe du fonctionnement de notre fenêtre, comme la détection d'un appui sur un bouton ou bien une inscription de texte dans une zone de saisie)
Vous devez essayer d'employer cette technique le plus possible pour organiser votre code au mieux.
Dernier point mais non le moindre, n'oubliez pas d'utiliser la fonction TranslateMessage à l'intérieur de la boucle de message. Puisque vous devez taper du texte dans la boîte d'édition, votre programme doit traduire des entrées clavier brutes en un texte lisible. Si vous omettez cette fonction, vous ne serez incapables de taper quoique ce soit dans votre boîte d'édition.