J'ai (dans le passé) les applications multi-plateformes (Windows / Unix) écrit qui, lorsqu'il est lancé depuis la ligne de commande, un utilisateur-traitées dactylographié Ctrl- Ccombinaison de la même manière ( par exemple pour arrêter l'application proprement).
Est-il possible sous Windows d'envoyer un Ctrl- C/ SIGINT / équivalent à un processus à partir d'un autre processus (non lié) pour demander qu'il se termine proprement (lui donnant la possibilité de ranger les ressources, etc.)?
jstack
puisse être utilisé de manière fiable à la place pour cette question spécifique: stackoverflow.com/a/47723393/603516Réponses:
L' application tierce SendSignal est la solution la plus proche que je connaisse . L'auteur répertorie le code source et un exécutable. J'ai vérifié qu'il fonctionne sous Windows 64 bits (fonctionnant comme un programme 32 bits, tuant un autre programme 32 bits), mais je n'ai pas compris comment incorporer le code dans un programme Windows (soit 32 bits ou 64 bits).
Comment ça fonctionne:
(Faites-le précéder de
start
si vous l'exécutez dans un fichier batch.)la source
J'ai fait des recherches sur ce sujet, qui s'est avéré être plus populaire que prévu. La réponse de KindDragon a été l'un des points cruciaux.
J'ai écrit un article de blog plus long sur le sujet et créé un programme de démonstration fonctionnel, qui démontre l'utilisation de ce type de système pour fermer une application de ligne de commande dans quelques modes. Cet article répertorie également les liens externes que j'ai utilisés dans mes recherches.
En bref, ces programmes de démonstration font ce qui suit:
Edit: La solution modifiée de KindDragon pour ceux qui sont intéressés par le code ici et maintenant. Si vous prévoyez de démarrer d'autres programmes après avoir arrêté le premier, vous devez réactiver la gestion Ctrl-C, sinon le processus suivant héritera de l'état désactivé du parent et ne répondra pas à Ctrl-C.
[DllImport("kernel32.dll", SetLastError = true)] static extern bool AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern bool FreeConsole(); [DllImport("kernel32.dll")] static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); // Enumerated type for the control messages sent to the handler routine enum CtrlTypes : uint { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); public void StopProgram(Process proc) { //This does not require the console window to be visible. if (AttachConsole((uint)proc.Id)) { // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); //Moved this command up on suggestion from Timothy Jannace (see comments below) FreeConsole(); // Must wait here. If we don't and re-enable Ctrl-C // handling below too fast, we might terminate ourselves. proc.WaitForExit(2000); //Re-enable Ctrl-C handling or any subsequently started //programs will inherit the disabled state. SetConsoleCtrlHandler(null, false); } }
En outre, prévoyez une solution d'urgence si
AttachConsole()
ou le signal envoyé doit échouer, par exemple dormir alors ceci:if (!proc.HasExited) { try { proc.Kill(); } catch (InvalidOperationException e){} }
la source
wait()
j'ai supprimé le Re-enable Ctrl-C (SetConsoleCtrlHandler(null, false);
). J'ai fait quelques tests (appels multiples, également sur des processus déjà terminés) et je n'ai trouvé aucun effet secondaire (encore?).Je suppose que je suis un peu en retard sur cette question, mais j'écrirai quand même quelque chose pour quiconque a le même problème. C'est la même réponse que j'ai donnée à cette question.
Mon problème était que j'aimerais que mon application soit une application graphique, mais les processus exécutés doivent être exécutés en arrière-plan sans aucune fenêtre de console interactive attachée. Je pense que cette solution devrait également fonctionner lorsque le processus parent est un processus console. Vous devrez peut-être supprimer l'indicateur "CREATE_NO_WINDOW".
J'ai réussi à résoudre ce problème en utilisant GenerateConsoleCtrlEvent () avec une application wrapper. La partie la plus délicate est simplement que la documentation n'est pas vraiment claire sur la manière dont elle peut être utilisée et les pièges qui l'accompagnent.
Ma solution est basée sur ce qui est décrit ici . Mais cela n'a pas vraiment expliqué tous les détails non plus et avec une erreur, voici donc les détails sur la façon de le faire fonctionner.
Créez une nouvelle application d'assistance "Helper.exe". Cette application se situera entre votre application (parent) et le processus enfant que vous souhaitez pouvoir fermer. Cela créera également le processus enfant réel. Vous devez avoir ce processus "intermédiaire" ou GenerateConsoleCtrlEvent () échouera.
Utilisez une sorte de mécanisme IPC pour communiquer du parent au processus d'assistance que l'aide doit fermer le processus enfant. Lorsque l'assistant obtient cet événement, il appelle "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)" qui se ferme lui-même et le processus enfant. J'ai utilisé un objet événement pour cela moi-même que le parent complète lorsqu'il souhaite annuler le processus enfant.
Pour créer votre Helper.exe, créez-le avec CREATE_NO_WINDOW et CREATE_NEW_PROCESS_GROUP. Et lors de la création du processus enfant, créez-le sans indicateur (0), ce qui signifie qu'il dérivera la console de son parent. Si vous ne le faites pas, il ignorera l'événement.
Il est très important que chaque étape se fasse ainsi. J'ai essayé toutes sortes de combinaisons, mais cette combinaison est la seule qui fonctionne. Vous ne pouvez pas envoyer d'événement CTRL_C. Il renverra le succès mais sera ignoré par le processus. CTRL_BREAK est le seul qui fonctionne. Cela n'a pas vraiment d'importance puisqu'ils appelleront tous les deux ExitProcess () à la fin.
Vous ne pouvez pas non plus appeler GenerateConsoleCtrlEvent () avec un ID groupd de processus de l'ID de processus enfant permettant directement au processus d'assistance de continuer à vivre. Cela échouera également.
J'ai passé une journée entière à essayer de faire fonctionner cela. Cette solution fonctionne pour moi, mais si quelqu'un a autre chose à ajouter, veuillez le faire. Je suis allé partout sur le net pour trouver beaucoup de gens avec des problèmes similaires, mais sans solution définitive au problème. Le fonctionnement de GenerateConsoleCtrlEvent () est également un peu étrange, donc si quelqu'un connaît plus de détails, veuillez le partager.
la source
Éditer:
Pour une application GUI, la manière «normale» de gérer cela dans le développement Windows serait d'envoyer un message WM_CLOSE à la fenêtre principale du processus.
Pour une application console, vous devez utiliser SetConsoleCtrlHandler pour ajouter un fichier
CTRL_C_EVENT
.Si l'application ne respecte pas cela, vous pouvez appeler TerminateProcess .
la source
En quelque sorte,
GenerateConsoleCtrlEvent()
renvoie une erreur si vous l'appelez pour un autre processus, mais vous pouvez vous attacher à une autre application de console et envoyer un événement à tous les processus enfants.la source
Voici le code que j'utilise dans mon application C ++.
Points positifs:
Points négatifs:
Exemple d'utilisation:
la source
la source
Cela devrait être clair car pour le moment, ce n'est pas le cas. Il existe une version modifiée et compilée de SendSignal pour envoyer Ctrl-C (par défaut, il n'envoie que Ctrl + Break). Voici quelques binaires:
J'ai également mis en miroir ces fichiers au cas où:
version 32 bits: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0 version
64 bits: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0
Avertissement: je n'ai pas construit ces fichiers. Aucune modification n'a été apportée aux fichiers originaux compilés. La seule plate-forme testée est la version 64 bits de Windows 7. Il est recommandé d'adapter la source disponible sur http://www.latenighthacking.com/projects/2003/sendSignal/ et de la compiler vous-même.
la source
En Java, en utilisant JNA avec la bibliothèque Kernel32.dll, similaire à une solution C ++. Exécute la méthode principale CtrlCSender en tant que processus qui obtient simplement la console du processus à laquelle envoyer l'événement Ctrl + C et génère l'événement. Comme il s'exécute séparément sans console, l'événement Ctrl + C n'a pas besoin d'être désactivé et réactivé.
CtrlCSender.java - Basé sur les réponses de Nemo1024 et KindDragon .
Étant donné un ID de processus connu, cette application console attachera la console du processus ciblé et générera un événement CTRL + C dessus.
Application principale - Exécute CtrlCSender en tant que processus de console séparé
la source
Oui. Le
windows-kill
projet fait exactement ce que vous voulez:la source
Une solution que j'ai trouvée à partir d'ici est assez simple si vous avez python 3.x disponible dans votre ligne de commande. Tout d'abord, enregistrez un fichier (ctrl_c.py) avec le contenu:
Puis appelez:
Si cela ne fonctionne pas, je vous recommande d'essayer le projet windows-kill: https://github.com/alirdn/windows-kill
la source
Un de mes amis a suggéré une manière complètement différente de résoudre le problème et cela a fonctionné pour moi. Utilisez un vbscript comme ci-dessous. Il démarre et l'application, laissez-le fonctionner pendant 7 secondes et fermez-le en utilisant ctrl + c .
'Exemple VBScript
la source
Je trouve tout cela trop compliqué et utilisé SendKeys pour envoyer une CTRL- Cséquence de touches à la fenêtre de ligne de commande (fenêtre c. -à- cmd.exe) comme solution de contournement.
la source
la source
SIGINT peut être envoyé au programme en utilisant windows-kill , par syntaxe
windows-kill -SIGINT PID
, oùPID
peut être obtenu par la pslist de Microsoft .En ce qui concerne la capture des SIGINT, si votre programme est en Python, vous pouvez implémenter le traitement / capture SIGINT comme dans cette solution .
la source
Sur la base de l'identifiant du processus, nous pouvons envoyer le signal au processus pour qu'il se termine de manière forcée ou gracieuse ou tout autre signal.
Lister tous les processus:
Pour tuer le processus:
Détails:
http://tweaks.com/windows/39559/kill-processes-from-command-prompt/
la source