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
En fonction de la position des proc par rapport a start,on peut ou non s'abstenir de déclarer des PROTOS
------------------------------------------------------------------------------------------------
.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
premier Proc argument:DWORD
premier endp
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),
premier Proc argument:DWORD
premier endp
winmain proc
winmain endp
end start
Le point d'entrée du code peut se trouver dans une librairie
Connaitre la structure d'un source asm MASM32 est necessaire a l'écriture et au debugage
.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
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.
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).
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
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