Une première fenêtre simple
Page 1 sur 1
Une première fenêtre simple
Les boites de dialogues nous ont permis d'entrevoir les possibilités d'affichage et de saisie des informations par l'utilisateur.
Dans cette partie, nous allons voir les différentes possibilités des fenêtres de windows. Nous commençons par une fenêtre simple où nous afficherons une ligne de texte.
Dans le segment .data, après la définitions des zones de texte, nous définissons 3 structures nécessaires à la création d'une fenêtre : la classe des fenêtres : WNDCLASSEX, une structure pour le dessin et l'écriture dans la fenêtre PAINTSTRUCT et une structure MSG pour la gestion des évènements.
Dans la partie code, il nous faut alimenter la structure WNDCLASS avant de la passer à une fonction de création de la classe de le fenêtre : RegisterClassExA. Il faut donc renseigner la taille de la structure, le style de la fenêtre, le nom de la procèdure qui va gérer les événements de la souris : ici nous l'appelons WndProc. Ensuite nous alimentons le handle de l'instance du programme que nous avons récupéré en début de programme, puis nous chargeons l'image du pointeur de la souris et nous définissons la couleur d'arrière plan et le nom de classe des fenêtres.
Après l'appel de la fonction, nous creeons la fenêtre par appel de la fonction CreateWindowExA à laquelle nous devons passer 12 paramètres :
Les plus importants sont la position et la taille de la fenêtre, les handles des instances mères, le nom de la classe de la fenêtre et qui doit être identique au nom de la classe créee par la fonction précédente et le titre de la fenêtre.
Après la création, nous affichons la fenêtre par ShowWindow et nous appelons la fonction UpdateWindow qui generera un message WM_PAINT qui va nous permetre d'afficher ce que nous voulons dans la fenêtre.
Ensuite, et comme pour la boite de dialogue personalisée, nous avons une boucle de gestion des messages dans laquelle nous appelons les fonctions GetMessageA, TranslateMessage et DispatchMessageA. Lorsque GetMessageA rencontra le message de fermeture de la fenêtre, la boucle se terminera ainsi que le programme (Nous affichons un message de bonne fin qui bloquera le programme au cas où la mise au point serait difficile.).
Dans la procèdure de gestion des évenements de la fenêtre WndProc qui sera appelée par Windows, nous commençons par récupérer 4 paramètres : le handle de la fenêtre, le type de message reçu, et 2 paramètres dont le contenu est variable suivant le type de message.
Ici, nous allons gérer les messages WM_CREATE,WM_PAINT et WM_DESTROY. Les autres messages seront gérés par l'appel à une fonction par défaut DefWindowProcA (Attention cette procèdure a besoin des mêmes 4 paramètres que ceux reçus et donc il faudra veiller à ne pas les altérer).
Lors de la création, nous ne faisons rien de plus qu'afficher dans la console le vidage des registres.
Dans la partie paint, nous commençons par initialiser un contexte d'affichage standard par la fonction BeginPaint, puis nous préparons l'affichage d'une ligne de texte à la position voulue par la fonction TextOutA et nous terminons en refermant le contexte d'affichage par la fonction EndPaint.
Dans la partie destroy, nous envoyons un message de fin pour terminer la boucle de gestion des message par la fonction PostQuitMessage.
Ce programme servira donc de squelette pour les améliorations à venir.
Dans cette partie, nous allons voir les différentes possibilités des fenêtres de windows. Nous commençons par une fenêtre simple où nous afficherons une ligne de texte.
Dans le segment .data, après la définitions des zones de texte, nous définissons 3 structures nécessaires à la création d'une fenêtre : la classe des fenêtres : WNDCLASSEX, une structure pour le dessin et l'écriture dans la fenêtre PAINTSTRUCT et une structure MSG pour la gestion des évènements.
Dans la partie code, il nous faut alimenter la structure WNDCLASS avant de la passer à une fonction de création de la classe de le fenêtre : RegisterClassExA. Il faut donc renseigner la taille de la structure, le style de la fenêtre, le nom de la procèdure qui va gérer les événements de la souris : ici nous l'appelons WndProc. Ensuite nous alimentons le handle de l'instance du programme que nous avons récupéré en début de programme, puis nous chargeons l'image du pointeur de la souris et nous définissons la couleur d'arrière plan et le nom de classe des fenêtres.
Après l'appel de la fonction, nous creeons la fenêtre par appel de la fonction CreateWindowExA à laquelle nous devons passer 12 paramètres :
Les plus importants sont la position et la taille de la fenêtre, les handles des instances mères, le nom de la classe de la fenêtre et qui doit être identique au nom de la classe créee par la fonction précédente et le titre de la fenêtre.
Après la création, nous affichons la fenêtre par ShowWindow et nous appelons la fonction UpdateWindow qui generera un message WM_PAINT qui va nous permetre d'afficher ce que nous voulons dans la fenêtre.
Ensuite, et comme pour la boite de dialogue personalisée, nous avons une boucle de gestion des messages dans laquelle nous appelons les fonctions GetMessageA, TranslateMessage et DispatchMessageA. Lorsque GetMessageA rencontra le message de fermeture de la fenêtre, la boucle se terminera ainsi que le programme (Nous affichons un message de bonne fin qui bloquera le programme au cas où la mise au point serait difficile.).
Dans la procèdure de gestion des évenements de la fenêtre WndProc qui sera appelée par Windows, nous commençons par récupérer 4 paramètres : le handle de la fenêtre, le type de message reçu, et 2 paramètres dont le contenu est variable suivant le type de message.
Ici, nous allons gérer les messages WM_CREATE,WM_PAINT et WM_DESTROY. Les autres messages seront gérés par l'appel à une fonction par défaut DefWindowProcA (Attention cette procèdure a besoin des mêmes 4 paramètres que ceux reçus et donc il faudra veiller à ne pas les altérer).
Lors de la création, nous ne faisons rien de plus qu'afficher dans la console le vidage des registres.
Dans la partie paint, nous commençons par initialiser un contexte d'affichage standard par la fonction BeginPaint, puis nous préparons l'affichage d'une ligne de texte à la position voulue par la fonction TextOutA et nous terminons en refermant le contexte d'affichage par la fonction EndPaint.
Dans la partie destroy, nous envoyons un message de fin pour terminer la boucle de gestion des message par la fonction PostQuitMessage.
- Code:
;programme fenetre windows en 64 bits
;fenetresimple.asm
%include "../windowsinc64.inc"
global Main
; tous les noms des fonctions de l'API sont mis dans le fichier include ci dessus
extern afferreur,affmessageP,affconsoleP,afftoutregistreP,afftoutreg8a15P,affmemoireP
;=============================================================================
section .data
;=============================================================================
szTitreFen: db 'Fenêtre 1', 0
szMsg: db "Début programme", 0
szMsgFin: db 'Fin programme!', 0
szClasseFen db "Classe1",0
szTexte1 db "Ceci est ma première fenêtre.",0
ILGTEXTE1 equ $ - szTexte1
;instance de la classe des fenetres
wcexa: align 8
wcex:
istruc WNDCLASSEX
iend
LGWCEX equ $ - wcex
; instance contexte dessin
ipainta: align 8
ipaint istruc PAINTSTRUCT
iend
;instance message
msga: align 8
msg: istruc MSG
at MSG.fin, db "<<< "
iend
;=============================================================================
section .bss
;=============================================================================
hCons resq 1
hInst resq 1
hdc resq 1
hMainWnd resq 1
;=============================================================================
section .text
;=============================================================================
Main:
sub rsp, 28h ; alignement pile et reserve paramètres
xor rcx,rcx
call GetModuleHandleA ; récuperation handle du programme
mov r9,__LINE__
cmp eax,NULL
je .erreur
mov [hInst],rax
; préparation de la structure de classe des fenêtres
mov dword[wcex+WNDCLASSEX.cbSize], LGWCEX ;taille de la structure de la classe de la fenetre
mov dword[wcex+WNDCLASSEX.style],CS_HREDRAW | CS_VREDRAW ; style des fenetres
mov qword[wcex+WNDCLASSEX.lpfnWndProc], WndProc ; nom de la procedure qui va gerer les évenements de la fenetre
xor rax,rax
mov dword[wcex+WNDCLASSEX.cbClsExtra], eax ;raz de ces zones
mov dword[wcex+WNDCLASSEX.cbWndExtra], eax
mov qword rax, [hInst]
mov qword[wcex+WNDCLASSEX.hInstance], rax ;handle du parent
mov qword[wcex+WNDCLASSEX.hIcon], NULL
;chargement image curseur souris
mov rcx,NULL
mov rdx,IDC_ARROW
call LoadCursorA
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
mov qword[wcex+WNDCLASSEX.hCursor], rax
mov qword[wcex+WNDCLASSEX.hbrBackground], COLOR_WINDOW + 1 ; couleur d'arrière plan
mov qword [wcex+WNDCLASSEX.lpszMenuName], NULL
mov qword [wcex+WNDCLASSEX.lpszClassName], szClasseFen
;creation de la classe de la fenetre (c'est obligatoire)
mov rcx,wcex
call RegisterClassExA
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
;creation de la fenetre
add rsp,20h
;8 parametres donc pas d'alignement à respecter
push NULL ; pas de données complémentaires
push qword[hInst] ;handle de l'instance du programme
push NULL ;fenetre non identifiée
push NULL ; pas de fenetre parent
push 180h ; hauteur de la fenetre
push 1A0H ; largeur de la fenetre
push 0 ; position verticale de la fenetre
push 0 ;position horizontale de la fenetre
;
sub rsp,20h ; reservation de la place pour les 4 parametres suivants
mov rcx,NULL ; pas de style complémentaire
mov rdx,szClasseFen ; classe de la fenetre doit être identique à la classe crée par RegisterClassExA
mov r8,szTitreFen ; titre de la fenetre
mov r9,WS_OVERLAPPEDWINDOW ; fenetre standard avec menu système
;
call CreateWindowExA
add rsp,40h ;liberation de la place pour les 8 paramètres push
mov r9,__LINE__ - 2
cmp eax,NULL
je .erreur
mov [hMainWnd],eax ; conserve le handle de la fenetre
mov rcx,[hMainWnd]
mov rdx,SW_SHOWDEFAULT ; affichage de la fenetre
call ShowWindow
; ici on ne teste pas le code erreur (voir la doc microsoft)
mov rcx,[hMainWnd]
call UpdateWindow ;genere le message WM_PAINT qui dessinera dans la fenêtre
mov r9,__LINE__ - 1
cmp eax,NULL
je .erreur
;
.boucle_commande:
mov rcx,msg
mov rdx,NULL
mov r8,0
mov r9,0
call GetMessageA ;récuperation des messages
cmp eax,0 ; fin de boucle l'utilisateur a fermé la fenetre
jz .fin_commande
mov rcx,msg
call TranslateMessage ; convertit les actions clavier en message (voir la doc)
mov rcx,msg
call DispatchMessageA ; envoie le message à la procédure de gestion de la fenetre
jmp .boucle_commande
.fin_commande:
; cet affichage pour verifier la bonne fin du programme
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx,[szMsgFin] ; LPCSTR lpText
lea r8,[szTitreFen] ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
mov r9,__LINE__
cmp eax,NULL
je .erreur
mov rcx,0 ; code retour OK
jmp .fin
.erreur:
call afferreur
mov rcx,1 ; code retour erreur
.fin:
; code retour positionné avant
call ExitProcess
;===========================================================
;Procédure de gestion des évenements de la fenetre
;===========================================================
WndProc:
%define hWnd rbp+16 ; pour simplifier l'ecriture dans les instructions suivantes
%define uMsg rbp+24
%define wParam rbp+32
%define lParam rbp+40
;recuperation des parametres handle de la fenetre, type du message, wparam, lparam
;----- save home register in the shadow space -------
mov [rsp+8],rcx ; handle fenêtre
mov [rsp+16],rdx ; type de message
mov [rsp+24],r8 ; wparam
mov [rsp+32],r9 ; lparam
enter 0,0 ; eventuellement reserver de la place pour variables locales
;ici il faut sauver les registres rbx,rdi,rsi r12 à r15 s'ils sont utilisés
;attention si nombre impair il faut aligner la pile
sub rsp,20h ; reservation pour les autres appels
;traitement des messages
cmp rdx,WM_CREATE
jz .creation
cmp rdx,WM_PAINT
jz .paint
cmp rdx,WM_DESTROY
jz .destroy
jmp .retourdefaut ; pour les messages non traités appel fonction defaut
.creation:
mov rax,[hWnd] ; normalement egal à rcx
push __LINE__
call afftoutregistreP
jmp .retourproc
.paint:
;pas d'alimentation de rcx car normalement il contient le handle de la fenêtre
mov rdx, ipaint ; structure
call BeginPaint ; debut du dessin
mov [hdc], rax ; retoune un handle vers un display device context (contexte d'affichage)
;5 parametres à passer
add rsp,20h
sub rsp,8h ;aligne pile
push ILGTEXTE1 ; longueur du texte a afficher
sub rsp,20h
mov rcx,qword[hdc]
mov rdx,20 ; position horizontale du texte
mov r8,100 ; position verticale du texte
mov r9,szTexte1 ; adresse du texte
call TextOutA
add rsp,10h ; dépile le 5ieme parametre et l'alignement pile
mov rcx,[hWnd] ;handle de la fenetre
mov rdx, ipaint ; structure
call EndPaint ; fin du dessin
jmp .retourproc
.destroy:
xor rcx,rcx
call PostQuitMessage
jmp .retourproc
.retourdefaut: ; appel par defaut pour tous les autres messages
call DefWindowProcA
.retourproc:
add rsp,20h
;ici il faut restaurer les registres sauvegardés
;attention si nombre impair il faut aligner la pile
leave ; restaure
ret
Ce programme servira donc de squelette pour les améliorations à venir.
Sujets similaires
» Une fenêtre complète
» Dessin dans une fenêtre
» Ajout de controles et menus à une fenêtre
» Affichage simple dans la console
» Dessin dans une fenêtre
» Ajout de controles et menus à une fenêtre
» Affichage simple dans la console
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|