J'aimerais terminer un process cree avec CreateProcess avec ExitProcess et non TerminateProcess.
ExitProcess termine le process appelant. Comment utiliser dans ExitProcess le HANDLE retourne par CreateProcess ?
merci
J'aimerais terminer un process cree avec CreateProcess avec ExitProcess et non TerminateProcess.
ExitProcess termine le process appelant. Comment utiliser dans ExitProcess le HANDLE retourne par CreateProcess ?
merci
Il y a un moyen, mais c'est crade.
Mais paradoxalement, moins crade que TerminateProcess().
Néanmoins, ni l'un ni l'autre ne sont recommandés. La bonne méthode, c'est de dire à l'autre processus de se terminer (par un message Windows ou un autre mécanisme d'IPC).
2 points me genent:
* la doc de msdn dit explicitement d'utiliser ExitProcess(). C'est tres bizarre qu'on ne puisse pas l'utiliser
* dans la mesure ou CreateProcess() peut lancer n'importe quelle application, je ne peux pas savoir comment l'appli se termine (je fais un wrapper autour de CreateProcess, donc la commande qu'on lui passe n'est pas connue a l'avance)
Ben non, c'est pour quitter le processus courant. Elle recommande sans doute que le processus destination utiliser ExitProcess() pour quitter, c'est son droit (même si personnellement je trouve ça sale: Dans le cas idéal, un processus se termine quand tous ses threads se sont terminés, mais de nos jours il y a tellement de fonctions qui créent un thread en arrière-plan que ça n'est plus réaliste, et le code appelle automatiquement ExitProcess() quand la fonction main() retourne).
Et pourtant, tu autorises à tuer le processus créé? Ben tu ne peux pas avoir le beurre et l'argent du beurre, ni être sâle et propre à la fois. D'un autre côté, tu peux essayer plusieurs méthodes successives, comme le fait le gestionnaire de tâches: Envoyer des messages de fin à ses fenêtres, puis si ça ne marche pas, à son thread principal, puis si ça ne marche toujours pas, tuer le processus...* dans la mesure ou CreateProcess() peut lancer n'importe quelle application, je ne peux pas savoir comment l'appli se termine (je fais un wrapper autour de CreateProcess, donc la commande qu'on lui passe n'est pas connue a l'avance)
le thread principal, c'est celui qui se trouve dans le PROCESS_INFORMATION rempli par CreateProcess ?
Oui.
Disons que c'est le premier thread créé, et que c'est généralement celui utilisé pour l'interface utilisateur (je pense notamment que ça n'est pas le cas pour les applications Java).
C'est surtout que si ce thread principal se termine, ton process se termine également. Donc, les autres threads du processus se font flinguer au passage...
En règle générale, pour qu'il ne se termine pas sans prévenir, on y met justement la boucle de messages Windows, ça occupe utilement le thread principal justement.
Seulement s'il se termine par un retour du main.
On peut explicitement le terminer avec ExitThread() pour éviter cela, mais ça n'est pas recommandé parce que certains composants du systême (comme COM) peuvent créer des threads sur lesquels tu n'as aucun contrôle, et qui empêchent le processus de se terminer naturellement quand tous les threads "à toi" sont terminés.
Edit: En bonus, l'article du lendemain. Quand je disais que ExitProcess() était sale...
Le thread principal, c'est celui exécutant le main, justement...
Faudrait essayer pour le fun, mais je doute fortement que flinguer le thread principal (via TerminateThread, tant qu'à faire soyons crades jusqu'au bout) depuis un thread / processus à part permette au processus de continuer à tourner.
Je l'ai déjà fait: Thread principal lance un second thread, second thread fait un truc (comme afficher des messages toutes les secondes pendant dix secondes), premier thread appelle ExitThread() au lieu de sortir du main()...
PS: Doc à l'appui
"ExitThread()", c'est "propre" (enfin... c'est relatif, hein) par rapport à "TerminateThread()"... Enfin, ça reste juste de la curiosité quoi qu'il en soit vu que cela reste du code "crade" si ce n'est pas fait correctement, avec la coopération propre du processus que l'on veut terminer.
donc pour résumer, j'appelle CreateProcess. Si pi est la structure PROCESS_INFORMATION remplie par CreateProcess, j'appelle CloseHandle sur pi.hProcess (je n'en ai pas besoin). Puis si plus tard je veux arreter l'application lancee par CreateProcess:
- J'appelle CloseHandle(pi.hThread)
- Si ca foire, J'appelle TerminateProcess(pi.ProcessId, 0)
c'est ca ? Notez que j'appelle CloseHandle et pas ExitThread car c'est ce qui est indique dans la doc de CreateProcess
Non.
Vous demandez au process que vous avez créé de se terminer. Le canal de communication avec le process créé est fonction de celui-ci.
On ne "demande" pas à un programme de se terminer par un TerminateThread() sur son premier thread. Entre autres, c'est une des choses qui laissera tourner les autres threads, puisque le premier thread n'aura pas appelé ExitProcess().
La méthode que je propose, c'est plus:
- EnumWindows() + GetWindowThreadProcessId() + PostMessage(WM_CLOSE)
- et si ça ne marche pas, PostThreadMessage(WM_QUIT)
- si ça ne marche pas, et si tu en as la volonté, on peut tester plus sournois: CreateRemoteThread(ExitProcess) mais ça a tendance à planter certaines applications, et donc à lancer DrWatson. Étrangement, comme ça prévient les DLLs, je me demande parfois si ça n'est pas plus propre que TerminateProcess()...
- Quand tout le reste a échoué, TerminateProcess().
PS: TerminateProcess() nécessite un handle, pas un ID.
Un code comme ceci pour le callback ?
Je ne suis pas sur si il faut que je passe NULL pour les attributs de securite de CreateRemoteThread.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 static DWORD WINAPI _ecore_exe_thread_procedure(LPVOID data) { ExitProcess(0); return 1; } static BOOL CALLBACK _ecore_exe_enum_windows_procedure(HWND window, LPARAM data) { Ecore_Exe *exe; DWORD thread_id; exe = (Ecore_Exe *)data; thread_id = GetWindowThreadProcessId(window, NULL); if (thread_id == exe->thread_id) { if (PostMessage(window, WM_CLOSE, 0, 0)) return FALSE; if (PostThreadMessage(thread_id, WM_QUIT, 0, 0)) return FALSE; if (CreateRemoteThread(exe->process, NULL, 0, _ecore_exe_thread_procedure, NULL, 0, NULL)) return FALSE; } return TRUE; }
Concernant l'utilisation de TerminateProcess(), comme je fais un port Windows d'une bibliotheque Linux et que celle-ci utilise les signaux d'interruption, je ne sais pas s'il faut que je l'utilise tout le temps ou pas. Je demanderai au developpeur principal.
Au passage, j'ai utilise OpenProcess() apres CreateProcess pour modifier les attributs du processus. Dois-je toujours appeler CloseHandle sur le HANDLE retourne par cette donction ? Ou bien ceci est gerer par certains appels du code ci-dessus ?
merci en tout cas !
Non, la Callback doit être directement ExitProcess().
Et normalement, il faudrait regarder où se trouve la fonction dans la DLL (calculer son offset) et où se trouve la DLL dans le processus destination. Mais bon, comme il s'agit de Kernel32, on peut s'en passer (du moins sous XP).
Note aussi que cette tactique, peut-être même avec le calcul d'offset, peut être invalidée par l'introduction de mécanismes d'ASLR (Address Space Layout Randomization) sous Windows Vista.
Edit: Apparemment, l'ASLR de Vista ne change que l'emplacement des DLLs en mémoire, donc un calcul d'offset devrait contourner la protection.
Pour calculer l'offset, ceci devrait suffire:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part ptrdiff_t offsetExit = (char const*)GetModuleHandle("kernel32.dll") - (char const*)&ExitProcess;
Ensuite, il faut trouver la DLL dans l'autre processus. À l'époque, j'avais utilisé CreateToolHelp32Snapshot() et Module32First()/Module32Next(), mais EnumProcessModules() suffit peut-être.
Heu, je veux peut-être dire une connerie mais si la version Linux fait des Kill -9 sur ces fils, il peut faire aussi crade sous Windows.
Si c'est des signaux USR1 ou USR2, pourquoi ne pas câbler les routines d'interruption sur signal sous Linux dans la pompe à message de la fenêtre principale sur les messages WM_APP et WM_APP+1 ?
C'est juste pour faire aussi basic que sous Linux.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager