Assembleur 64 avec le compilateur nasm
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Le Deal du moment :
Xiaomi Mi Smart Camera 2K Standard Edition (design ...
Voir le deal
11.39 €

Une première fenêtre simple

Aller en bas

Une première fenêtre simple Empty Une première fenêtre simple

Message par Admin Lun 12 Déc - 21:02

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.
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
A l’exécution, nous avons bien une fenêtre simple !! avec un titre, un menu système qui permet de fermer la fenêtre, et un pointeur de souris qui permet d'agrandir, réduire la fenêtre, de la déplacer dans l'écran et de la fermer.
Ce programme servira donc de squelette pour les améliorations à venir.
Admin
Admin
Admin

Messages : 38
Date d'inscription : 28/11/2016

https://assembleur64.kanak.fr

Revenir en haut Aller en bas

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum