Downloadez l'exemple ici. Attention en fait cet exemple est dans un *.ZIP et il ne marchera pas si vous le laissez dedans, donc dézipez-le.
"Un 'process' est une application (un programme) qui sert à exécuter un autre programme. C'est un espace d'adresses virtuel privé, de code, de données et d'autres ressources du système d'exploitation, comme les fichiers, ou la synchronisation d'objets qui sont visibles pour le process.."Comme vous pouvez le voir dans la définition ci-dessus, process "possède" plusieurs objets : l'espace d'adresse, le(s) module(s) (les autres programmes) à exécuter et tout ce que ces programmes créent ou ouvrent. Au minimum, process doit consister en l'exécution d'un seul module, avec un espace d'adresse privé et un lien. Chaque process doit avoir au moins un lien. Qu'est ce qu'un lien ? Un lien est en réalité une suite d'instructions d'exécution en attente. Lorsque Windows crée d'abord un process, il crée seulement un lien de process. D'habitude, ce lien fait en sorte d'exécuter la première instruction dans le module (dans le programme ciblé). Si le process à besoins de plusieurs autres liens par la suite, il peut les créer.
CreateProcess
proto lpApplicationName:DWORD,\
lpCommandLine:DWORD,\
lpProcessAttributes:DWORD,\
lpThreadAttributes:DWORD,\
bInheritHandles:DWORD,\
dwCreationFlags:DWORD,\
lpEnvironment:DWORD,\
lpCurrentDirectory:DWORD,\
lpStartupInfo:DWORD,\
lpProcessInformation:DWORD
Ne soyez pas effrayez par le nombre de paramètres. Nous pouvons ignorer la plupart d'entre eux.
LpApplicationName est le nom du fichier exécutable avec ou sans nom de chemin que vous voulez exécuter. Si ce paramètre est nul, vous devez mettre le nom du fichier exécutable dans le paramètre lpCommandLine.
LpCommandLine sont les arguments de la ligne de commande du programme que vous voulez exécuter. Notez que si lpApplicationName est NUL, ce paramètre doit en plus contenir le nom du fichier exécutable. Comme cela : "notepad.exe readme.txt". (LpCommandLine c'est aussi l'argument qu'on écrit dans W32Dasm quand on fait 'DebugàLoad Process [argument]àLoad' , mais c'est très rare qu'on écrive quelque chose en tant qu'argument!)
LpProcessAttributes et lpthreadAttributes Spécifient les attributs de sécurité pour process et le lien primaire. S'ils sont NULS, les attributs de sécurité par défaut sont employés.
BInheritHandles est un flag qui indique si vous voulez qu'un autre process hérite du contrôle de toutes les manipulations ouvertes par votre process.
DwCreationFlags représente Plusieurs flags qui déterminent le comportement du process que vous voulez créé, comme : voulez-vous qu'un process soit créés, mais suspendu immédiatement pour que vous puissiez l'examiner ou le modifier avant qu'il ne reparte ? Vous pouvez aussi spécifier la classe de priorité du lien(s) dans un nouveau process. Cette classe de priorité est employée pour déterminer la priorité de planification des liens du process. Normalement nous employons le flag NORMAL_PRIORITY_CLASS.
LpEnvironment est le pointer du bloc d'environnement qui contient plusieurs instructions pour un nouveau process. Si ce paramètre est NUL, le nouveau process hérite de l'environnement du bloc process précédent.
LpCurrentDirectory est le pointer qui est sur la chaîne de caractères lequel indique l'actuel 'Lecteur ' (Drive) ainsi que le répertoire (Directory) du Child Process. Il est NULL si vous voulez que le 'Child Process' succède au 'Parent Process'.
LpStartupInfo pointe sur une structure STARTUPINFO laquelle dit comment doit apparaître la fenêtre principale du nouveau process. La structure STARTUPINFO contient beaucoup de membres servants à définir l'affichage de la fenêtre principale du 'Child Process'. Si vous ne voulez rien de spécial, vous pouvez remplir la structure STARTUPINFO avec les valeurs du 'Parent Process' en appelant la fonction GetStartupInfo.
LpProcessInformation pointe sur la structure PROCESS_INFORMATION laquelle reçoit l'information d'identification du nouveau process. La structure de PROCESS_INFORMATION est la suivante :
PROCESS_INFORMATION STRUCTL'handle du process et l'ID du process sont deux choses différentes. L'ID est un identificateur unique du process dans le système. L'handle est une valeur renvoyée par Windows pour qu'on puisse l'utiliser avec d'autres process rapportés de fonctions API. L'handle du process ne peut pas être employé pour identifier un process puisque il n'est pas unique.
hProcess HANDLE ? ; Handle du 'Child Process'
hThread HANDLE ? ; Handle du premier lien du 'Child Process'
dwProcessId DWORD ? ; ID du 'Child Process'
dwThreadId DWORD ? ; ID du premier lien du 'Child Process'
PROCESS_INFORMATION ENDS
Après l'appel à CreateProcess, un nouveau process est créé et on retourne (au prog principa) immédiatement après cet appel à CreateProcess. Vous pouvez vérifier si le nouveau process est toujours actif en appelant la fonction GetExitCodeProcess qui a la syntaxe suivante :
GetExitCodeProcess proto hProcess:DWORD, lpExitCode:DWORD
Si cet appel est couronné de succès, lpExitCode contient le statut de terminaison du process en question. Si la valeur dans lpExitCode est égale à STILL_ACTIVE, alors ce process est toujours en cours.
Vous pouvez force le process à se terminer en appelant la fonction TerminateProcess. Voici sa syntaxe :
TerminateProcess proto hProcess:DWORD, uExitCode:DWORD
Vous pouvez spécifier le code de sortie désiré pour votre process, n'importe quelle valeur que vous souhaitez. TerminateProcess n'est pas une façon très propre de terminaison d'un process puisque chaque dll rattaché à ce process ne sera pas informé que le process a été fermé.
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.const
IDM_CREATE_PROCESS equ 1
IDM_TERMINATE equ 2
IDM_EXIT equ 3
.data
ClassName db "Win32ASMProcessClass",0
AppName db "Win32 ASM Process Example",0
MenuName db "FirstMenu",0
processInfo PROCESS_INFORMATION <>
programname db "msgbox.exe",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu HANDLE ?
ExitCode DWORD ?
; Contient le statut 'exitcode du process' servant à l'appel de GetExitCodeProcess.
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,300,200,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
invoke GetMenu,hwnd
mov hMenu,eax
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL startInfo:STARTUPINFO
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_INITMENUPOPUP
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.if lParam==0
.if ax==IDM_CREATE_PROCESS
.if processInfo.hProcess!=0
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.endif
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
invoke CloseHandle,processInfo.hThread
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.else
invoke DestroyWindow,hWnd
.endif
.endif
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
.ELSEIF uMsg==WM_INITMENUPOPUP
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if eax==TRUE
.if ExitCode==STILL_ACTIVE
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_GRAYED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_ENABLED
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
.else
invoke EnableMenuItem,hMenu,IDM_CREATE_PROCESS,MF_ENABLED
invoke EnableMenuItem,hMenu,IDM_TERMINATE,MF_GRAYED
.endif
Pourquoi utilisons-nous ce message dans notre process? Parce que nous souhaitons préparer les sous-menus dans le menu popup avant que l'utilisateur ne puisse les voir. Dans notre exemple, lorsque le process n'est pas encore lancé, nous activons le sous-menu "Start Process" et désactivons "Terminate Process" (il est grisé). On fait le contraire quand le nouveau process est déjà actif.
Nous vérifions d'abord si le nouveau process dirige (a encore la main sur MsgBox.exe) toujours en appelant la fonction GetExitCodeProcess avec l'handle du process qui a été renvoyé par la fonction CreateProcess. Si les retours de GetExitCodeProcess sont FALSE(FAUX), alos ça signifie que notre process n'est pas encore commencé, donc nous grisons (désactivons) le sous-menu "Terminate Process". Si les retours de GetExitCodeProcess sont TRUE(VRAIS), nous savons que notre nouveau process a été lancé, mais nous devons vérifier plus loin s'il est toujours en court. Donc nous comparons la valeur dans ExitCode à la valeur STILL_ACTIVE. S'ils sont égaux,c'est que notre process en encore en court : nous devons alors désactiver la sous-menu "Start Process" puisque nous ne souhaitons pas lancer plusieurs processus en même temps.
.if ax==IDM_CREATE_PROCESS
.if processInfo.hProcess!=0
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
.endif
invoke GetStartupInfo,ADDR startInfo
invoke CreateProcess,ADDR programname,NULL,NULL,NULL,FALSE,\
NORMAL_PRIORITY_CLASS,\
NULL,NULL,ADDR startInfo,ADDR processInfo
invoke CloseHandle,processInfo.hThread
Quand l'utilisateur choisit le menu item "Start Process", nous vérifions d'abord si le membre hProcess de la structure PROCESS_INFORMATION est déjà fermé. Si c'est la première fois, la valeur d'hProcess sera toujours zéro puisque nous définissons la structure de PROCESS_INFORMATION dans la section '.data'. Si la valeur du membre hProcess n'est pas 0, ça signifie que le Child Process est sorti mais nous n'avons pas fermé son handle process encore. Donc c'est maintenant qu'il le faire.
Nous appelons la fonction GetStartupInfo pour récupérer la valeur startupinfo pour pouvoir ensuite la passer à la fonction CreateProcess. Après ça nous appelons la fonction CreateProcess pour commencer nouveau process. Notez que je n'ai pas vérifié la valeur de retour de CreateProcess parce que ça aurait encore compliqué cet exemple. En réalité, vous devriez vérifier cette valeur de retour (de CreateProcess). Immédiatement après CreateProcess, nous fermons l'handle du premier lien, lequel est renvoyé par la structure processInfo. La fermeture du handle ne veut pas dire que est le lien terminé, mais seulement que nous ne voulons pas employer cet handle pour nous référer au lien de notre programme. Si nous ne le fermons pas, il provoquera une fuite des ressources.
.elseif ax==IDM_TERMINATE
invoke GetExitCodeProcess,processInfo.hProcess,ADDR ExitCode
.if ExitCode==STILL_ACTIVE
invoke TerminateProcess,processInfo.hProcess,0
.endif
invoke CloseHandle,processInfo.hProcess
mov processInfo.hProcess,0
Quand l'utilisateur choisit le sous-menu (le menu item) "Terminate Process", nous vérifions si le nouveau process est toujours actif en appelant la fonction GetExitCodeProcess. Si il est toujours actif, nous appelons la fonction TerminateProcess pour détruire notre process. Aussi nous fermons l'handle du Child Process puisque désormais nous n'en avons plus besoin.