2008-11-18 5 views
2

Je vais avoir du mal à faire fonctionner ça, en espérant que l'un d'entre vous l'ait déjà fait.Bloqué sur GenerateConsoleCtrlEvent en C# avec les applications de la console

J'ai une application de console C# qui exécute un processus enfant qui hérite de sa console. Je veux qu'un ctrl-c attrapé par l'application externe soit passé à l'application intérieure afin qu'il puisse avoir une chance de fermer bien.

J'ai un code très simple. Je démarre un processus, puis l'interroge avec WaitForExit (10). J'ai également un gestionnaire CancelKeyPress enregistré, qui définit un booléen à vrai quand il se déclenche. La boucle d'interrogation vérifie également cela, et quand c'est vrai, il appelle GenerateConsoleCtrlEvent() (que j'ai mappé à travers pinvoke).

J'ai essayé beaucoup de combinaisons de paramètres avec GenerateConsoleCtrlEvent(). 0 ou 1 pour le premier param, et 0 ou l'ID du processus enfant pour le second param. Rien ne semble fonctionner. Parfois, je reçois un faux retour et Marshal.GetLastWin32Error() renvoie 0, et parfois je reçois vrai retour. Mais aucun ne provoque l'application enfant à recevoir un ctrl-c. Pour être absolument sûr, j'ai écrit une application de test C# pour être l'application enfant qui imprime ce qui se passe avec elle et vérifié que taper manuellement ctrl-c quand il s'exécute le fait correctement quitter. Je me suis cogné la tête contre ce pour quelques heures. Quelqu'un peut-il me donner des indications sur où aller avec cela?

+0

J'ai le même problème. GenerateConsoleCtrlEvent semble être rompu. Cela n'affecte pas le processus, qu'il dispose ou non d'une fenêtre de console, et qu'il ait démarré avec CREATE_NEW_PROCESS_GROUP ou non. J'ai tout essayé, et il semble qu'il n'y ait aucun moyen de fermer proprement une application console démarrée avec Process.Démarrer ou CreateProcess lorsqu'il ne fait pas partie de la fenêtre de console du processus appelant. – Triynko

Répondre

3

Pas si sûr que ce soit une bonne approche. Cela ne fonctionne que si le processus enfant est créé avec l'indicateur CREATE_NEW_PROCESS_GROUP pour CreateProcess(). La classe System.Diagnostics.Process ne supporte cependant pas cela. Envisagez d'utiliser la valeur de retour de la méthode Main(). Il existe déjà une valeur unique définie dans le SDK Windows pour les interruptions Ctrl + C, STATUS_CONTROL_C_EXIT ou 0xC000013A. Le processus parent peut obtenir ce code retour à partir de la propriété Process.ExitCode.

+0

L'astuce est - J'ai besoin d'un moyen de signaler le processus de l'enfant à abandonner. Ctrl-c est la manière standard de faire cela avec les applications console. Tous les sous-processus que nous exécutons ne sont pas sous notre contrôle (tels que cl.exe et gcc.exe). Merci pour les informations sur CREATE_NEW_PROCESS_GROUP. Je vais essayer quelques hacks. – scobi

+0

Yikes. Reflector me dit que Process.Start() est très complexe. Je devrais le cloner juste pour définir ce seul drapeau. Trop de travail en ce moment. – scobi

+0

GenerateConsoleCtrlEvent ne fonctionne même pas lorsque CREATE_NEW_PROCESS_GROUP est défini. Ça ne marche pas du tout. Période. Il ne fonctionne même pas si vous créez ou non une nouvelle console, que vous spécifiiez CREATE_NO_WINDOW, CREATE_NEW_CONSOLE ou DETATCHED_PROCESS ... le nouveau processus ne répond jamais à aucun des signaux générés par GenerateConsoleCtrlEvent, malgré le fait que le processus (tel que 7-zip [7z.exe] par exemple) est connu pour se fermer proprement en réponse à un signal de rupture ctrl + c ou ctrl +. GenerateConsoleCtrlEvent est inutile. – Triynko

2

Avez-vous eu de la chance avec ça? Ma compréhension est que lorsque vous appuyez sur CTRL + C dans une console, par défaut tous les processus attachés à la console le reçoivent, pas seulement le parent. Voici un exemple:

Child.cs:

using System; 

public class MyClass 
{ 
    public static void CtrlCHandler(object sender, ConsoleCancelEventArgs args) 
    { 
     Console.WriteLine("Child killed by CTRL+C."); 
    } 
    public static void Main() 
    { 
     Console.WriteLine("Child start."); 
     Console.CancelKeyPress += CtrlCHandler; 
     System.Threading.Thread.Sleep(4000); 
     Console.WriteLine("Child finish."); 
    } 
} 

Parent.cs:

using System; 

public class MyClass 
{ 
    public static void CtrlCHandler(object sender, ConsoleCancelEventArgs args) 
    { 
     Console.WriteLine("Parent killed by CTRL+C."); 
    } 
    public static void Main() 
    { 
     Console.CancelKeyPress += CtrlCHandler; 
     Console.WriteLine("Parent start."); 
     System.Diagnostics.Process child = new System.Diagnostics.Process(); 
     child.StartInfo.UseShellExecute = false; 
     child.StartInfo.FileName = "child.exe"; 
     child.Start(); 
     child.WaitForExit(); 
     Console.WriteLine("Parent finish."); 
    } 
} 

Sortie:

Y:\>parent 
Parent start. 
Child start. 
Parent killed by CTRL+C. 
Child killed by CTRL+C. 
^C 
Y:\>parent 
Parent start. 
Child start. 
Child finish. 
Parent finish. 

Je ne l'aurais pas pensé que vous auriez besoin faire quelque chose de spécial. Cependant, si vous avez vraiment besoin de générer des événements CTRL + C vous-même, les choses pourraient ne pas être si faciles. Je ne suis pas sûr des problèmes que vous décrivez, mais autant que je peux dire que vous pouvez seulement envoyer des événements CTRL + C à tous les processus attachés à une fenêtre de console. Si vous détachez un processus, vous ne pouvez pas lui envoyer d'événements CTRL + C. Si vous voulez être sélectif dans les processus pour envoyer les événements CTRL + C, vous devez créer de nouvelles fenêtres de console pour chacun. Je ne sais pas s'il existe un moyen de le faire sans fenêtres visibles ou lorsque vous voulez rediriger les E/S en utilisant des tuyaux.

+0

Je n'ai pas travaillé sur cela depuis - n'a pas été un problème ces derniers temps. Mais si je me souviens bien du problème, je voulais pouvoir dire à un processus enfant d'abandonner, et pour beaucoup d'applications en ligne de commande, cela signifiait envoyer un ctrl-c, ou un signal, ou quoi que ce soit. GenerateConsoleCtrlEvent() est apparemment la fonction à appeler, mais cela ne fonctionnait pas. Il semble que CREATE_NEW_PROCESS_GROUP soit ce que j'ai besoin de définir, mais la classe Process ne le supporte pas. – scobi

Questions connexes