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
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
char WPARAM 20h ; Le caractère que le programme reçoit du clavier.
; 20h est la valeur pour obtenir un espace.
; Ainsi rien ne sera affiché à l'écran au moment de son ouverture.
.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,NULL
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,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,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
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CHAR
push wParam
pop char
invoke InvalidateRect, hWnd,NULL,TRUE
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
invoke TextOut,hdc,0,0,ADDR char,1
invoke EndPaint,hWnd, ADDR ps
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
char
WPARAM 20h
; Le caractère que le programme reçoit du clavier
C'est la variable qui stockera le caractère envoyé par le clavier. Puisque le caractère est envoyé dans le paramètre WPARAM (appartenant à la procédure de fenêtre). La valeur initiale de WPARAM est 20h pour afficher un 'espace' au moment où notre fenêtre régénère son secteur client la toute première fois, quand il n'y a aucune entrée clavier. Donc au commencement, nous voulons afficher 'espace'.
.ELSEIF uMsg==WM_CHAR
push wParam
pop char
invoke InvalidateRect, hWnd,NULL,TRUE
Ceci a été rajouté à la procédure de fenêtre pour manipuler le message WM_CHAR. Il met seulement le caractère dans la variable nommée "char" et appelle ensuite InvalidateRect. InvalidateRect fait apparaître le 'rectangle invalide' dans le secteur client et force ainsi Windows à envoyer le message WM_PAINT à la procédure de fenêtre. Sa syntaxe est la suivante :
InvalidateRect proto hWnd:HWND,\
lpRect:DWORD,\
bErase:DWORD
lpRect est un indicateur sur le rectangle qui se trouve dans le secteur client que nous voulons déclarer comme étant invalide. Si ce paramètre est nul, le secteur client entier deviendra invalide.
bErase est un drapeau (un flag) indiquant à Windows s'il a besoin d'effacer le fond (background). Si ce drapeau est VRAI, alors Windows effacera le background du rectangle invalide dès que BeginPaint sera appelé.
Ainsi la stratégie que nous avons employé ici est que : nous stockons toute l'information nécessaire touchant à la peinture du secteur client et fabriquons ensuite le message WM_PAINT pour repeindre le secteur client. Bien sûr, les codes dans la section WM_PAINT doivent savoir à l'avance ce que l'on attend d'eux. On pourrait croire qu'on tourne en rond mais c'est la méthode utilisée par Windows.
En réalité nous pouvons repeindre (réactualiser) le secteur client pendant le traitement du message WM_CHAR en appelant la paire GetDC - ReleaseDC. A ce niveau, il n'y a aucun problème. Mais ça commence à être intéressant quand notre fenêtre a besoin de repeindre son secteur client. Puisque les codes qui peignent (affichent) le caractère sont dans la section WM_CHAR, la procédure de fenêtre ne sera plus capable de repeindre notre caractère sur le secteur client. Donc la ligne suivante sert à mettre toutes les données et les codes nécessaires à peinture dans WM_PAINT. Vous pouvez envoyer le message WM_PAINT n'importe où dans votre code dès que vous voulez repeindre le secteur client.
invoke TextOut,hdc,0,0,ADDR char,1
Quand InvalidateRect est appelé, il envoie un message WM_PAINT à la procédure de fenêtre en retour. Donc les codes dans la section WM_PAINT sont appelés. Il appelle BeginPaint comme d'habitude pour obtenir l'handle du contexte de dispositif et appelle ensuite TextOut qui dessine notre caractère dans le secteur de client à x=0, y=0. Quand vous exécutez le programme et appuyez sur une touche, vous verrez que le caractère se répercute dans le coin supérieur gauche de la fenêtre. Et quand la fenêtre est rétrécie au maximum puis réagrandie de nouveau, le caractère est toujours présent puisque tous les codes et toutes les données essentielles pour repeindre sont tous réunis dans la section WM_PAINT.