Screenmate boulinator

Description

Un utilisateur, une balle, un bureau et des rebonds : une recette simple pour un programme pas compliqué ! Boulinator est une application gadget parfaitement inutile? Mais il me fallait une idée-support pour m?essayer à l?assembleur Win32. Voilà qui est fait !

Pour information : si vous décider de lancer ce petit programme, sachez qu?une icône va s?ajouter en bas à droite dans la barre des tâches, ce qui vous permet d?accéder à un menu à tout moment. Avec un clic droit sur la balle vous aurez le même résultat. Pour le reste : cliquez gauche sur la balle, déplacez la souris et lâchez tout !

Dans ce code vous trouverez une touche de « région », un soupçon de « thread » et une larme de « floating point ».
Tout ça en assembleur MASM32.

Puisant régulièrement dans les sources de www.asmfr.fr pour apprendre les rudiments de la programmation Win32, il m?a semblé correct d?y déposer une humble participation. Voici donc Boulinator, un inoffensif petit ScreenMate.

Remarques, commentaires et optimisations bienvenu !

mov eax, salut_!
mov a_tous,eax

Source / Exemple :


Title   BOULINATOR  Version MASM32
    
    .486                   
    .model  flat, stdcall      
    option  casemap :none       
 
    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\shell32.inc 
    include \masm32\include\winmm.inc

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\shell32.lib
    includelib \masm32\lib\winmm.lib
    
    WinMain         PROTO   :DWORD,:DWORD,:DWORD,:DWORD
    InfoDlgProc     PROTO   :DWORD,:DWORD,:DWORD,:DWORD
    ParamDlgProc    PROTO   :DWORD,:DWORD,:DWORD,:DWORD
    ErrMsg          PROTO   :DWORD,:DWORD
    
.const

    ID_icon         equ 20
    ID_bonk         equ 30
    IDR_MENU        equ 10000
    IDM_stopper     equ 10001
    IDM_continuer   equ 10002
    IDM_apropos     equ 10003
    IDM_quitter     equ 10004
    IDM_parametre   equ 10005
    DlgInfo         equ 1000
    IDC_BTN1        equ 1001
    DlgParam        equ 2000
    IDC_vitesse     equ 2001
    IDC_rebond      equ 2002
    IDC_gravit      equ 2003
    IDC_diam        equ 2004
    IDC_son         equ 2005
    IDC_annuler     equ 2006
    IDC_ok          equ 2007
    IDC_textson     equ 2018
    THREADMSG       equ WM_USER+1
    ICONMSG         equ WM_USER+2
    
.data

    ClassName   db  "Boulinator",0
    AppName     db  "Boulinator",0
    szvitesse   db  "La vitesse doit être comprise entre 0 et %u     ",0
    szrebond    db  "Le rebond doit être compris entre 0 et %u     ",0
    szgravit    db  "La gravité doit être comprise entre 0 et %u     ",0
    szdiam      db  "Le diamètre doit être compris entre 5 et %u     ",0
    szon        db  "on",0
    szoff       db  "off",0
    dragflag    dd  0
    threadflag  dd  0
    stopflag    dd  0
    sonflag     dd  1
    valpause    dd  10
    diam        dd  35
    fposx       REAL8   0.0
    fposy       REAL8   0.0
    vectx       REAL8   0.0
    vecty       REAL8   0.0
    rebond      REAL8   0.94
    frotte      REAL8   0.97
    gravit      REAL8   2.0
    ajust       REAL8   0.4
    cent        REAL8   100.0
    dix         REAL8   10.0
    
.data?

    n           NOTIFYICONDATA <>
    hInstance   HINSTANCE   ?
    hwnd        HWND    ?   
    hicon       HWND    ?
    hmenu       HWND    ?
    hthread     HWND    ?
    maxx        dd  ?
    maxy        dd  ?
    posx        dd  ?
    posy        dd  ?
    IDthread    dd  ?
    sourx1      dd  ?
    soury1      dd  ?
    sourx2      dd  ?
    soury2      dd  ?
    xdiff       dd  ?
    ydiff       dd  ?
    vectxinit   dd  ?
    vectyinit   dd  ?
    oldx1       dd  ?
    oldx2       dd  ?
    oldx3       dd  ?
    oldy1       dd  ?
    oldy2       dd  ?
    oldy3       dd  ?
    
.code

start:

    invoke  GetModuleHandle,NULL
    mov     hInstance,eax
    invoke  WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT
    invoke  ExitProcess,eax
    
WinMain     PROC hInst:HINSTANCE,hPrevinst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD

    LOCAL   wc:WNDCLASSEX
    LOCAL   msg:MSG
    
    invoke  GetSystemMetrics,SM_CYSCREEN
    mov     maxy,eax    ; recuperer les dimensions de l'écran
    invoke  GetSystemMetrics,SM_CXSCREEN
    mov     maxx,eax    ; pour fixer les limites
    shr     eax,1
    mov     ecx,diam                         
    shr     ecx,1
    sub     eax,ecx
    mov     posx,eax    ; et pour positionner la balle au milieu et en bas               
    mov     eax,maxy            
    sub     eax,diam
    mov     posy,eax                       
    mov     wc.cbSize,SIZEOF WNDCLASSEX
    mov     wc.style,CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS ; double clic OK
    mov     wc.lpfnWndProc,OFFSET WndProc           
    mov     wc.cbClsExtra,NULL
    mov     wc.cbWndExtra,NULL
    push    hInstance
    pop     wc.hInstance
    invoke  CreateSolidBrush,000000FFh  ; couleur balle = couleur de fond
    mov     wc.hbrBackground,eax
    mov     wc.lpszMenuName,NULL                        
    mov     wc.lpszClassName,OFFSET ClassName
    invoke  LoadIcon,hInstance,ID_icon
    mov     hicon,eax
    mov     wc.hIcon,eax
    mov     wc.hIconSm,eax
    invoke  LoadCursor,NULL,IDC_ARROW          
    mov     wc.hCursor,eax
    invoke  RegisterClassEx,addr wc ; fenetre avec styles adaptées :
    invoke  CreateWindowEx,WS_EX_TOPMOST+WS_EX_TOOLWINDOW,\; tjrs au dessus
            ADDR ClassName,ADDR AppName,\   ; pas de barre d'icône
            WS_POPUP,\  ; pas de barre de titre
            posx,posy,\                   
            maxx,maxy,\
            NULL,NULL,hInstance,NULL
    mov     hwnd,eax
  
boucle_message :                 

    invoke  GetMessage,ADDR msg,NULL,0,0
    cmp     eax,0
    je      fin_boucle_message
    invoke  TranslateMessage,ADDR msg
    invoke  DispatchMessage,ADDR msg
    jmp     boucle_message
    
fin_boucle_message:

     mov     eax,msg.wParam
     ret

WinMain     ENDP

WndProc     PROC hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

LOCAL   pt:POINT
LOCAL   rect:RECT

    .IF     uMsg == WM_CREATE   ; creation ?
        invoke  LoadMenu,hInstance,IDR_MENU ; on load le menu
        invoke  GetSubMenu,eax,NULL ; qu'on passe en submenu
        mov     hmenu,eax                           
        invoke  CreateEllipticRgn,0,0,diam,diam ; creation d'une rgn ronde
        invoke  SetWindowRgn,hWnd,eax,1 ; pour y associer la fenetre
        invoke  ShowWindow,hWnd,SW_SHOWNORMAL   ; et la rendre visible
        invoke  UpdateWindow,hWnd   
        mov     n.cbSize,SIZEOF NOTIFYICONDATA  ; pour être "joignable"...
        push    hWnd
        pop     n.hwnd 
        mov     n.uID,0 
        mov     n.uFlags,NIF_ICON+NIF_MESSAGE+NIF_TIP 
        mov     n.uCallbackMessage,ICONMSG  ; ( le message de retour )
        mov     eax,hicon 
        mov     n.hIcon,eax  
        invoke  lstrcpy,ADDR n.szTip,ADDR AppName 
        invoke  Shell_NotifyIcon,NIM_ADD,ADDR n ; création d'un tray icon
      
    .ELSEIF uMsg == WM_DESTROY  ; c'est fini ?
        invoke  DestroyMenu,hmenu   ; menu...   
        invoke  Shell_NotifyIcon,NIM_DELETE,ADDR n  ; tray icon...
        invoke  PostQuitMessage,NULL
        
    .ELSEIF uMsg == WM_KEYDOWN && wParam == VK_ESCAPE   ; touche Escape ?
        invoke  DestroyWindow,hwnd  
                                        ; clic droit ou dblclic gauche ?
    .ELSEIF uMsg == WM_RBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK
        invoke  GetCursorPos,ADDR pt    ; recuperer la pos du curseur
        invoke  SetForegroundWindow,hwnd    ; et afficher le menu
        invoke  TrackPopupMenu,hmenu,TPM_HORIZONTAL,pt.x,pt.y,NULL,hwnd,NULL
                             ; clic gauche et thread off ?
    .ELSEIF uMsg == WM_LBUTTONDOWN && dragflag == 0 && threadflag == 0
        mov     dragflag,1  ; drag commence
        invoke  GetCursorPos,ADDR pt
        mov     eax,pt.x
        mov     ecx,pt.y    ; recuperer la position de la souris
        mov     sourx1,eax
        mov     sourx2,eax
        mov     soury1,ecx  ; initialiser l'historique 
        mov     soury2,ecx  ; des deux  dernières positions souris
        mov     posx,eax
        mov     posy,ecx    ; initialiser la position de la balle
        mov     xdiff,eax
        mov     ydiff,ecx       
        invoke  GetWindowRect,hwnd,ADDR rect
        mov     eax,rect.left   ; recuperer la position de la fenetre
        mov     ecx,rect.top
        sub     xdiff,eax
        sub     ydiff,ecx   ; calculer le decalage souris-fenetre
        invoke  SetCapture,hwnd ; garder le lien avec la souris
        invoke  SetTimer,hwnd,1,50,NULL ; pour suivre les mvts de souris
                                    ; clic gauche et thread on ?
    .ELSEIF uMsg == WM_LBUTTONDOWN && dragflag == 0 && threadflag == 1  
        mov     stopflag,1  ; demander au thread de s'arreter
        invoke  PostMessage,hwnd,WM_LBUTTONDOWN,wParam,lParam   ; drag
                            ; drag on et relachement clic gauche ?
    .ELSEIF uMsg == WM_LBUTTONUP && dragflag == 1   
        mov     dragflag,0
        invoke  KillTimer,hwnd,1    ; plus besoin de suivre la souris
        mov     eax,sourx2
        sub     eax,sourx1
        mov     ecx,soury2
        sub     ecx,soury1  ; deux dernières positions de souris
        mov     vectxinit,eax   ; pour les vecteurs de deplacements
        mov     vectyinit,ecx       
        invoke  ReleaseCapture  ; on peut libèrer la souris
        .IF threadflag == 0 ; pas déjà un thread en cours ?
            mov     stopflag,0
            mov     eax,OFFSET MonThread
            invoke  CreateThread,NULL,NULL,eax,NULL,NULL,ADDR IDthread
            mov     hthread,eax
            mov     threadflag,1    ; alors on le creer
        .ENDIF
                            ; drag on et mvt de souris ?
    .ELSEIF uMsg == WM_MOUSEMOVE && dragflag == 1   
        invoke  GetCursorPos,ADDR pt
        mov     eax,pt.x
        mov     ecx,pt.y    ; recuperer la position de la souris
        sub     eax,xdiff
        sub     ecx,ydiff   ; decalage avec la fenetre
        mov     posx,eax    ; mettre à jour position de la balle
        mov     posy,ecx    ; et deplacer la fenetre
        invoke  SetWindowPos,hwnd,HWND_TOPMOST,eax,ecx,NULL,NULL,SWP_NOSIZE
   
    .ELSEIF uMsg == WM_TIMER    ; timer ?
        invoke  GetCursorPos,ADDR pt
        mov     eax,pt.x
        mov     ecx,pt.y    ; recuperer la position de la souris
        push    sourx2              
        pop     sourx1  ; la dernière devient l'avant dernière
        push    soury2
        pop     soury1
        mov     sourx2,eax  ; et l'actuelle devient la dernière
        mov     soury2,ecx          

    .ELSEIF uMsg == WM_COMMAND  ; commande du menu ?
        mov     eax,wParam
        .IF     ax == IDM_quitter   ; quitter : on sort
            invoke  DestroyWindow,hwnd
        .ELSEIF ax == IDM_parametre ; paramètres : boite de dialogue
            invoke  DialogBoxParam,hInstance,DlgParam,hwnd,ADDR ParamDlgProc,NULL   
        .ELSEIF ax == IDM_apropos   ; a propos : boite de dialogue
            invoke  DialogBoxParam,hInstance,DlgInfo,hwnd,ADDR InfoDlgProc,NULL
        .ELSEIF ax == IDM_stopper && threadflag == 1
            mov     stopflag,1  ; on demande au thread de s'arreter
        .ENDIF

    .ELSEIF uMsg == THREADMSG   ; message "j'ai fini" du thread ?
        invoke  WaitForSingleObject,hthread,INFINITE
        invoke  CloseHandle,hthread
        mov     threadflag,0    ; on l'attend avant de continuer                    
    
    .ELSEIF uMsg == ICONMSG ; message tray icon + clic souris ?
        .IF lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN 
            invoke  GetCursorPos,ADDR pt    ; recuperer la pos de la souris
            invoke  SetForegroundWindow,hwnd    ; pour afficher le menu
            invoke  TrackPopupMenu,hmenu,TPM_RIGHTALIGN,pt.x,pt.y,NULL,hwnd,NULL
        .ENDIF
 
    .ELSE   ; sinon c'est windows qui gère
     invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
     ret

    .ENDIF                      
     xor     eax,eax
     ret

WndProc     ENDP

MonThread   PROC

LOCAL   tempx:DWORD
LOCAL   tempy:DWORD
LOCAL   bonk:DWORD

    mov     oldx1,0 ; initialisation de l'historique 
    mov     oldx2,0 ; des trois dernières positions de la balle
    mov     oldx3,0
    mov     oldy1,0
    mov     oldy2,0
    mov     oldy3,0
    
    fild    posx    ; posx et posy -> convertis en floating point
    fstp    fposx
    fild    posy
    fstp    fposy
    
    fild    vectxinit   ; idem pour vectxinit et vectyinit
    fmul    ajust   ; Ajuster pour eviter des vecteurs hors de proportion
    fstp    vectx
    fild    vectyinit
    fmul    ajust
    fstp    vecty
    
.REPEAT
    
    mov     bonk,0  ; initialiser le flag pour le son d'impact
    finit

    fld     fposx
    fadd    vectx
    fstp    fposx   ; posx = posx +vectx

    fld     fposx
    fistp   tempx
    mov     eax,maxx
    sub     eax,diam
    cmp     tempx,eax   
    jl      @f  ; posx > maxx ?

    mov     tempx,eax   
    fild    tempx
    fstp    fposx   ; oui : posx = maxx
    fld     vectx       
    fchs
    fmul    rebond
    fstp    vectx   ; et vectx = -vectx X rebond
    mov     bonk,1
    jmp     @suite
    
@@: mov     eax,1
    cmp     tempx,eax
    jg      @suite  ; posx < minix ?
    
    mov     tempx,eax   
    fild    tempx
    fstp    fposx   ; oui : posx = minix
    fld     vectx       
    fchs
    fmul    rebond
    fstp    vectx   ; et vectx = -vectx X rebond
    mov     bonk,1
    
@suite:
    fld     fposy       
    fadd    vecty
    fstp    fposy   ; posy = posy +vecty

    fld     fposy
    fistp   tempy
    mov     eax,maxy
    sub     eax,diam
    cmp     tempy,eax   
    jl      @f      ; posy > maxy ?

    mov     tempy,eax   
    fild    tempy
    fstp    fposy   ; oui : posy = maxy
    fld     vecty
    fchs
    fmul    rebond
    fstp    vecty   ; et vecty = -vecty X rebond
    mov     bonk,1
    jmp     @suite2
    
@@: mov     eax,1
    cmp     tempy,eax
    jg      @suite2 ; posy < miniy ?
    
    mov     tempy,eax   
    fild    tempy
    fstp    fposy   ; oui : posy = miniy
    fld     vecty       
    fchs
    fmul    rebond
    fstp    vecty   ; et vecty = -vecty X rebond
    mov     bonk,1

@suite2:
    fld     vecty       
    fadd    gravit
    fstp    vecty   ; vecty = vecty + gravité
    
    push    oldx2   ; mettre à jour l'histo des 3 dernières positions
    pop     oldx1
    push    oldx3
    pop     oldx2
    mov     eax,tempx
    mov     oldx3,eax   ; x1 <- x2 <- x3 <- nouveau x 
    
    push    oldy2       
    pop     oldy1
    push    oldy3
    pop     oldy2
    mov     ecx,tempy
    mov     oldy3,ecx   ; y1 <- y2 <- y3 <- nouveau y
;                       ; plus de mvt ? 
    .IF eax==oldx1 && eax==oldx2 && ecx==oldy1 && ecx==oldy2    
        mov     stopflag,1  ; alors stop
        mov     bonk,0
        
    .ELSE
        mov     edx,maxy
        sub     edx,diam
        .IF ecx==oldy1 && ecx==oldy2 && ecx==edx    ; ça roule en bas ?
            fld     vectx
            fmul    frotte  ; vectx = vectx X frotte ( ralentissement )
            fstp    vectx
            mov     bonk,0
        .ENDIF
        
    .ENDIF
                    ; deplacer la balle-fenetre à sa nouvelle position
    invoke  SetWindowPos,hwnd,HWND_TOPMOST,tempx,tempy,NULL,NULL,SWP_NOSIZE
    
    .IF bonk==1 && sonflag==1   ; il faut produire un son ?
        invoke  PlaySound,ID_bonk,hInstance,SND_RESOURCE or SND_ASYNC
    .ENDIF
    
    invoke  Sleep,valpause  ; faire un pause bien méritée ;-)
    
.UNTIL  stopflag==1 ; et on recommence jusqu'à ce qu'un STOP soit annoncé

    fld     fposx               
    fistp   posx
    fld     fposy
    fistp   posy    ; mettre à jour posx et posy ( les non floating point )
    invoke  PostMessage,hwnd,THREADMSG,NULL,NULL    ; et prevenir
    ret

MonThread endp

InfoDlgProc PROC hdlg:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

    .IF     uMsg==WM_INITDIALOG ; c'est l'initialisation ?
        mov     eax,maxy
        shr     eax,2   ;  on positionne la boite en haut à gauche
        invoke  SetWindowPos,hdlg,HWND_TOPMOST,eax,eax,NULL,NULL,SWP_NOSIZE
                        ; c'est vu ?
    .ELSEIF uMsg==WM_CLOSE || (uMsg==WM_COMMAND && wParam==IDC_BTN1)
        invoke  EndDialog,hdlg,NULL ; bye bye...        
     
    .ENDIF
     xor    eax,eax
     ret

InfoDlgProc ENDP

ParamDlgProc PROC hdlg:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

LOCAL   temp:DWORD
LOCAL   errflag:DWORD

    .IF     uMsg==WM_INITDIALOG
        ; positionner la boite en haut à gauche
        mov     eax,maxy                                                        
        shr     eax,2
        invoke  SetWindowPos,hdlg,HWND_TOPMOST,eax,eax,NULL,NULL,SWP_NOSIZE
        ; imposer des limites aux edits
        invoke  SendDlgItemMessage,hdlg,IDC_vitesse,EM_SETLIMITTEXT,3,0 
        invoke  SendDlgItemMessage,hdlg,IDC_rebond,EM_SETLIMITTEXT,3,0
        invoke  SendDlgItemMessage,hdlg,IDC_gravit,EM_SETLIMITTEXT,3,0
        invoke  SendDlgItemMessage,hdlg,IDC_diam,EM_SETLIMITTEXT,3,0
        ; initialiser les items pour le son
        .IF     sonflag == 1
            invoke  SendDlgItemMessage,hdlg,IDC_son,BM_SETCHECK,BST_CHECKED,0 ; check on
            invoke  SetDlgItemText,hdlg,IDC_textson,ADDR szon   ; text "on"
        .ELSE
            invoke  SetDlgItemText,hdlg,IDC_textson,ADDR szoff  ; text "off"
        .ENDIF
        ; initialiser les items pour la vitesse, le rebond et la gravité
        mov     eax,101 ; valpause comprise entre 1 et 101
        sub     eax,valpause    ; et inversement proportionnelle a 
        invoke  SetDlgItemInt,hdlg,IDC_vitesse,eax,FALSE    ; la vitesse
        fld     rebond
        fmul    cent    ; convertir rebond en pourcent
        fistp   temp
        invoke  SetDlgItemInt,hdlg,IDC_rebond,temp,FALSE    ; et transmettre
        fld     gravit
        fmul    dix ; gravité entre 0 et 10
        fistp   temp    ; à convertir en pourcent
        invoke  SetDlgItemInt,hdlg,IDC_gravit,temp,FALSE
        invoke  SetDlgItemInt,hdlg,IDC_diam,diam,FALSE  ; le diametre
            ; annuler ?
    .ELSEIF uMsg==WM_CLOSE || (uMsg==WM_COMMAND && wParam==IDC_annuler) 
        invoke  EndDialog,hdlg,NULL ; on ferme
     
    .ELSEIF uMsg==WM_COMMAND && wParam==IDC_ok  ; clic sur ok ?
        mov     errflag,0   ; au depart pas d'erreur
        invoke  GetDlgItemInt,hdlg,IDC_vitesse,NULL,FALSE   ; la vitesse
        .IF eax>100 ; si depassement de valeur
            invoke  ErrMsg,100,ADDR szvitesse   ; on affiche msg erreur
            mov     errflag,1   ; et on signale l'erreur
        .ELSE
            mov     ecx,101 ; sinon on convertit
            sub     ecx,eax ; et on met à jour
            mov     valpause,ecx
        .ENDIF
        invoke GetDlgItemInt,hdlg,IDC_rebond,NULL,FALSE ; idem rebond
        .IF eax>100 
            invoke  ErrMsg,100,ADDR szrebond
            mov     errflag,1
        .ELSE
            mov     temp,eax
            fild    temp
            fdiv    cent
            fstp    rebond
        .ENDIF
        invoke  GetDlgItemInt,hdlg,IDC_gravit,NULL,FALSE    ; idem gravité
        .IF eax>100 
            invoke  ErrMsg,100,ADDR szgravit
            mov     errflag,1
        .ELSE
            mov     temp,eax
            fild    temp
            fdiv    dix
            fstp    gravit
        .ENDIF
        invoke  GetDlgItemInt,hdlg,IDC_diam,NULL,FALSE  ; le diàmetre...
        .IF eax>maxy || eax <5
            invoke  ErrMsg,maxy,ADDR szdiam
            mov     errflag,1
        .ELSE
            mov     diam,eax    ; si pas d'erreur
            invoke  CreateEllipticRgn,0,0,diam,diam ; rgn au format
            invoke  SetWindowRgn,hwnd,eax,1 ; et on y associe la fenetre
            mov eax,posx
            add eax,diam    ; la balle sort de l'écran ?
            .IF eax>maxx    ; à droite ?
                mov eax,maxx    ; alors on ajuste
                sub eax,diam
                mov posx,eax
            .ENDIF
            mov eax,posy    ; idem pour en bas
            add eax,diam
            .IF eax>maxy
                mov eax,maxy
                sub eax,diam
                mov posy,eax
            .ENDIF  ; on change le format de la fenetre
            invoke  SetWindowPos,hwnd,HWND_TOPMOST,posx,posy,NULL,NULL,SWP_NOSIZE
        .ENDIF
     
        .IF errflag == 0    ; pas d'erreur ?
            invoke  EndDialog,hdlg,NULL ; alors on ferme la boite
        .ENDIF  ; sinon on reste...
     
    .ELSEIF uMsg==WM_COMMAND && wParam==IDC_son ; check "son" ?
        invoke  SendDlgItemMessage,hdlg,IDC_son,BM_GETCHECK,0,0 ; état  ?
        .IF eax == BST_CHECKED  ; checké ?
            mov     sonflag,1   ; oui :texte "on"
            invoke  SetDlgItemText,hdlg,IDC_textson,ADDR szon   
        .ELSE
            mov     sonflag,0   ; non : texte "off"
            invoke  SetDlgItemText,hdlg,IDC_textson,ADDR szoff  
        .ENDIF
     
    .ENDIF
     xor eax,eax
     ret

ParamDlgProc ENDP

ErrMsg      PROC valmax:DWORD,lpmsg:DWORD

LOCAL   buffer[64]:BYTE

    invoke  wsprintf,ADDR buffer,lpmsg,valmax   ; on complète le texte
    invoke  MessageBox,hwnd,ADDR buffer,ADDR AppName,MB_OK+MB_ICONERROR 
    ret ; et on affiche

ErrMsg      ENDP

end start

Conclusion :


SACHEZ LE : Si vous déplacer un dossier sur votre bureau ( drag ) en même temps que la balle est en mouvement, la trace de celle-ci reste à l?écran. Le simple passage d?une fenêtre sur cette trace suffit à l?effacer? rien de grave donc, mais c?est un bug quand même ! Je n?ai pas encore trouvé la parade et suis preneur si quelqu?un à des pistes !
Boulinator

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.