STRUCTURE d'un source ASM

et GESTION des EVENEMENTS

Tenir compte du fonctionnement de windows

Les Lignes essentielles

      .386                              

      .model flat, stdcall              ;Lignes destinées au compilateur et au linker,format de compilation

      option casemap :none      

                                        

        .const

        .data

        .code                                ;le code commence à .code

        start:                                ;L'éxécution du code commence içi (etiquette:    .......   end etiquette),

                

        end start

 

 

      .386                              

      .model flat, stdcall              ;Lignes destinées au compilateur et au linker,format de compilation

      option casemap :none      

         ;déclarations de protos non nécessaires , n'ayant pas que des avantages

        .const

        .data

        .code

        start:                                ;L'éxécution du code commence içi (etiquette:    .......   end etiquette),

          winmain proc

          winmain endp  

        end start

      .386                              

      .model flat, stdcall              ;Lignes destinées au compilateur et au linker,format de compilation

      option casemap :none      

         premier PROTO :DWORD;déclarations de protos n'ayant pas que des inconvénients

        .const

        .data

        .code

        start:                                ;L'éxécution du code commence içi (etiquette:    .......   end etiquette),

        winmain proc

        winmain endp  

        end start

STRUCTURE:

Connaitre la structure d'un source asm MASM32 est necessaire a l'écriture et au debugage

 

           Section des déclarations:  (ne génère ni code , ni data)

                                 .386
                                 .model flat, stdcall
                                 option casemap :none   ;
trois lignes importantes pour la compilation


                                ;.STACK 10000 ;par défaut fixé a 1024 octets

                                 include \masm32\include\windows.inc    ;toujours en premier

                                 include \masm32\include\user32.inc        ;contient les protos (déclarations des PROCs)
                                 includelib \masm32\lib\user32.lib            ;contient le code compilé des PROC

 

                                 GENREPROG PROTO                        ;déclaration d'un nom de PROC
                                  return MACRO arg
                                      mov eax, arg
                                      ret
                                  ENDM

 

            CONSTANTES

                                 .const
                                 CONSTANTE EQU 14

            DONNEES içi commence la génération des octets du programme éxécutable

                                 .data
                                 chaine DB "salut",0
                                 Hinstance    dd 0

            CODE

                                .code
START:
                                        INVOKE    GetModuleHandle, NULL
                                        mov       hInstance, eax
                                                        .
                                        INVOKE     WinMain,hInstance,NULL, CommandLine, SW_SHOWDEFAULT
                                                        .
                                        invoke ExitProcess,MainExit    ;FIN du programme
------------------------------------------------------------------------------------------------------------------
                ;winmain est un simple PROC défini par l'utilisateur .
                ;Son utilisation permet simplement de bénéficier de variables locales.
                ;En mettant ses variables locales en data ,on peut le supprimer
              
WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine :DWORD,CmdShow:DWORD
                                        LOCAL wc   :WNDCLASSEX
                                                        .
                                        mov wc.lpfnWndProc,    offset
WndProc    ;definition de la fenêtre
                                                        .
                                                        .
                                        StartLoop:    ;boucle d'attente
                                                        .
                                        return msg.wParam    ;ret
            
WinMain endp
            ;Le proto de WndProc est défini par windows,il n'est pas modifiable
            ;Il tire son nom de la fonction qui le termine
DefWindowProc
            
WndProc proc hWndParent:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
                                                        .
                                        .if uMsg == WM_COMMAND
                                                        .
                                                 invoke GENREPROG
                                                 return 0.
                                        .elseif uMsg == WM_CREATE
                                                        .
                                        .elseif uMsg == WM_...........
                                                        .
                                        .else
                                                        .
                                        .end if
                                        invoke
DefWindowProc,hWndParent,uMsg,wParam,lParam
                                        ret
           
 WndProc endp
            -------------------- les Proc définis par l'utilisateur et la définition d'un sub --------------------
            GENREPROG proc
                                                        .
                                        call SousProg
                                                        .

            Findegenreprog:
            ret
                     SousProg:                L'emplacement du sub , juste après le ret, a son importance
                    FindeSousProg:         Le sub accède normalement a toutes les variables du PROC
                    
retn                           Il est inutile de lui passer des variables
          GENREPROG endp

END START

 

GESTION des EVENEMENTS

            Le nom du programme declaré dans la structure wc (içi WndProc) a pour vocation la gestion des evenements.On peut en distinguer deux types,générés par le systeme (WM_........) et générés par les éléments rajoutés sur la feuille.Par exemples:
            pour les tab            TCM_........
            pour les combobox CB_......
            et ainsi de suite
            Les procédures d'événements traitées doivent retournées une valeur precise. La fonction DefWindowProc placés a la fin de WndProc s'assure que tous les évènements soient traités correctement et complète éventuellement ceux déclarés comme traités.On peut d'ailleurs créer un wndProc n'éxécutant que cette seule fonction.Lorsque DefWindowProc complète l'évènement cela est préciser dans WinHelp. Pour chaque événement traité , il faut s'assurer (winhelp.hlp)que la valeur de retour est correcte.Le plus souvent c'est zero mais pas toujours. Pour s'assurer que tous les événements sont gérés correctement on peut placer la fonction  DefWindowProc dans  le .else de la boucle if . La, seule les événements non traités passe par la fonction.Si on met la fonction en dehors du bloc IF , des événements déja traités peuvent repasser par elle.Certains comportement aléatoire du programme peuvent s'expliquer par des valeurs de retour incorrecte. Il faut alors faire un tri parmi les messages non traités .La valeur du message etant connu ,on peut retrouver sa designation litterale dans windows.inc .Cela est important l'orsqu'un événement géré en génère d'autres.

Les feuilles MDI utilisent une fonction particulière en fin de boucle d'évènements.La boucle d'évènements ne s'appelle plus WndProc mais FrameProc

 Pour les boites de dialogues,Il n'y a pas de fonction de traitement des évènements.Les retours s'écrivent comme suit:

                        .else                             ;pas de traitement
                              mov eax,FALSE    ;DialogProc si utilisation d'une classe pour boite
                              ret
                        .endif
                        mov eax,TRUE            ;l'évènement a été traité
                        ret
                        DlgProc endp    

         Excepté pour le message WM_INITDIALOG retour FALSE si on a attribué le focus (point d'insertion )

 Tout Fonctionne Normalement Mais,.....?

Vous avez eu la patience d'étudier la page et vous commencez à vous doutez qu'en assembleur on doit respecter des règles précises .La question est , mais ... qu'en est il des règles , mal traduites,pas vus , mal expliqués , mal comprises ....Là est le mais provoquant un fonctionnement plus ou moins stable de l'application.Je citerais deux exemples:

1° exemple:Les Handles de feuilles mères et filles

CreateWindowEx est la fonction permettant de créer tout et n'importe quoi.Elle renvoie un handle identifiant l'objet créer.Que se passe-t-il quand le système nous renvoie deux handles pour le même objet ?.C'est ce qui se produit à la création d'une fenêtre

Un des rôles de Winmain est de créer les feuilles principales.On appelle CreateWindowEx , la fonction crée la fenêtre et déclenche l'évènement WM_CREATE du wndproc associé à cette fenêtre.

Une chose doit nous préoccuper immédiatement , c'est que le système nous passe en premier paramètre du proc WndProg le handle de la fenêtre en question.CreateWindowEx nous en fournit un autre (comparer les valeurs).Il est bien tentant de réutiliser ce même handle à l'intérieur de WndProg et là,hélas, on commet une approximation .La tentation est d'autant plus forte que cela marche le plus souvent,mais .... En vérité,si l'on compare la valeur hexadécimale de ces deux handles ,désignant la même fenêtre, on à la surprise de constater leurs différences.Le problème étant posé , on aimerais bien pouvoir réutiliser la même déclaration de variable .Chance , une fois l'étape d'init dépassée , Winmain rentre dans une boucle et n'utilise plus ce handle.On tient donc la solution , rajouter deux lignes immédiatement après WndProg.

WndProc proc  uses ebx esi edi  hWndParent:DWORD, wmsg, wparam, lparam

                mov eax,hWndParent    ;handle en pile passé par windows

                mov HWndProc,eax     ;Handle que nous avons saugardé dans Winmain

Le choix d'utiliser le handle fourni par le WndProc s'est fait après plusieurs essais , en essayant les deux .Sous XP,on ne rencontre que des problèmes en utilisant le handle fourni par CreateWindowEx et il faut considérer comme inutile de le conserver.Dans la suite de winmain , si on doit utiliser le handle de la fenêtre nouvellement créer , on peut utiliser celui fournit par le WndProc sans soucis.

conclusion:Dans le cas précis d'une création de fenêtre , ne pas sauvegarder le handle fourni par CreateWindowEx

2° exemple:Le Multitâche:

De quoi s'agit-il ?.
Exemple :
La liaison internet est d'une extrème lenteur , pour le microprocesseur,et l'utilisateur ,encore plus lent,tape une adresse internet dans l'explorateur.Le microprocesseur va partager son temps entre ces deux tâches sans que l'on constate la moindre anomalie dans son fonctionnement.Le multitâche peut aussi être matériel en faisant travailler plusieurs microprocesseurs,mais c'est un autre problème.
L'exemple le plus simple est donné par le batch MAKE servant a produire le .lib des librairies.Le répertoire C:\masm32\M32LIB contient toutes les sources de la librairie masm32.Le batch MAKE se charge de toutes les opérations nécessaires à leur utilisation.En premier, il utilise ML pour produire les .obj.En second il utilise LINK pour réunir les .obj dans un .lib.En troisieme il efface tous les .obj devenus inutiles.Du au fonctionnement normal de windows,le link demandant un certain temps,les opérations de suppression des .obj s'éxécutent en même temps,et le link produit une librairie vide.La solution consiste a insérer "pause" dans le batch pour permettre la fin des opérations du link avant d'effacer les .obj.

Autre exemple pratique :
 Dans editmasm on a ouvert un projet (plusieurs fichiers) et on aimerait bien en ouvrir un autre.Notre PROC va bien faire les choses,et va fermer le projet ouvert avant d'en ouvrir un autre.Pour cela , il va appeler un proc spécialiser dans la fermeture des projets.Le microprocesseur se retrouve avec deux tâches à accomplir et partage son temps entre les deux .Cela donne ,Vidé un vase d'un côté et le remplir de l'autre .Résultat,sans être planté , le programme est bloqué

Solution:Utiliser un témoin (variable) pour dire si un projet est présent et interdire le chargement d'un projet lorsqu'un autre existe.

Modale ou Modeless ?:
La boite de dialogue modale joue le même rôle que pause insérer dans le fichier batch MAKE

 

Si vous voyez d'autres attrapes nigots du même genre , n'hésitez pas à m'en faire part.

Point d'entrée du code:

On a utiliser la séquence      etiquette:          end etiquette  pour définir le point d'entrée du code à etiquette.On peut aussi le définir dans une librairie.Pour cela il faut définir deux proc dans la librairie,mainCRTStartup et WinMainCRTStartup

On n'utilise plus l'étiquette.Lorsque link émet une erreur "couldn't find WinMainCRTStartup" cela veut dire qu'une librairie utilise ce type d'entrée et demande un nom de prog particulier (WinMain).

Librairie

La librairie qui suit est a créer avec LIB.EXE

.code

.........

mainCRTStartup proc c public

        ;SUBSYSTEM:CONSOLE    option de link

        invoke Init

        invoke StartupMasm            ;StartupMasm est le nom du proc ou va commençer le code dans l'éxécutable

        invoke ExitProcess,eax

mainCRTStartup endp

 

WinMainCRTStartup proc c public

        ;SUBSYSTEM:WINDOWS

        invoke Init     

        invoke StartupMasm

        invoke FreeRicheditDll

        invoke ExitProcess,eax

WinMainCRTStartup endp

..........

end

 

 

Executable

Normalement créer avec LINK.EXE

.code

.........

StartupMasm PROC

 

ret

StartupMasm ENDP

...........

end                    ;pas d'étiquette

 

Pour utiliser msvcrt.lib et la libcmt.lib

 

WinMain PROC STDCALL public uses esi edi ebx, hInst:DWORD,hPrev:DWORD,\

                                                                lpCmdLine:DWORD,nShowCmd:SDWORD

;...................................................

ret

WinMain endp

 

CONSOLE

 

main PROTO C :DWORD,  :DWORD

 

Accueil  PLAN