2008-11-18 10 views
2

У меня труднее всего пытаться заставить это работать, надеясь, что один из вас сделал это раньше.Застрял на GenerateConsoleCtrlEvent в C# с консольными приложениями

У меня есть консольное приложение C#, на котором запущен дочерний процесс, который наследует консоль. Я хочу, чтобы ctrl-c, пойманный внешним приложением, передавался во внутреннее приложение, чтобы он мог легко закрыть его.

У меня есть очень простой код. Я запускаю процесс, а затем опросил его с помощью WaitForExit (10). У меня также зарегистрирован обработчик CancelKeyPress, который устанавливает bool в true при его возникновении. Цикл опроса также проверяет это, и когда он прав, он вызывает GenerateConsoleCtrlEvent() (который я сопоставил с помощью pinvoke).

Я пробовал много комбинаций параметров для GenerateConsoleCtrlEvent(). 0 или 1 для первого параметра и либо 0, либо идентификатор дочернего процесса для второго параметра. Ничто не работает. Иногда я получаю ложную обратную связь и Marshal.GetLastWin32Error() возвращает 0, а иногда я возвращаюсь обратно. Но ни одно из них не позволяет дочернему приложению получать ctrl-c.

Чтобы быть абсолютно уверенным, я написал тестовое приложение C# как дочернее приложение, которое выводит на экран то, что происходит с ним, и проверяет, что вручную набирать ctrl-c при запуске делает правильно заставить его выйти.

Я уже несколько часов стучал головой об этом. Может ли кто-нибудь дать мне несколько указаний о том, куда идти?

+0

У меня такая же проблема. GenerateConsoleCtrlEvent, кажется, сломан. Это не влияет на процесс, имеет ли он консольное окно или нет, и запускается ли он с CREATE_NEW_PROCESS_GROUP или нет. Я пробовал все, и, похоже, нет никакого способа очистить консольное приложение, запущенное с Process.Start или CreateProcess, если он не является частью окна консоли вызывающего процесса. – Triynko 2013-04-22 19:12:49

ответ

3

Не уверен, что это хороший подход. Это работает только в том случае, если дочерний процесс создается с флагом CREATE_NEW_PROCESS_GROUP для CreateProcess(). Класс System.Diagnostics.Process, однако, не поддерживает это.

Рассмотрите возможность использования возвращаемого значения из метода Main(). Уже существует уникальное значение, определенное в SDK Windows для прерываний Ctrl + C, STATUS_CONTROL_C_EXIT или 0xC000013A. Родительский процесс может получить этот код возврата из свойства Process.ExitCode.

+0

Трюк - мне нужен способ, чтобы сигнал дочернего процесса прерывался. Ctrl-c - стандартный способ сделать это с помощью консольных приложений. Не все подпроцессы, которые мы запускаем, находятся под нашим контролем (например, cl.exe и gcc.exe). Спасибо за информацию о CREATE_NEW_PROCESS_GROUP. Я попробую несколько хаков. – scobi 2008-11-18 17:36:42

+0

Yikes. Отражатель говорит мне, что Process.Start() очень сложный. Нужно было клонировать его, чтобы установить этот единственный флаг. Слишком много работы в это время. – scobi 2008-11-18 19:29:00

2

Вам повезло с этим? Я понимаю, что когда вы нажимаете CTRL + C на консоли, по умолчанию все процессы, подключенные к консоли, получают его, а не только родительский. Вот пример:

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."); 
    } 
} 

Выход:

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. 

Так что я бы не думал, что вам нужно делать что-то особенное. Однако, если вам действительно нужно создавать события CTRL + C самостоятельно, все может быть не так просто. Я не уверен в проблемах, которые вы описываете, но насколько я могу судить, вы можете отправлять события CTRL + C только всем процессам, прикрепленным к окну консоли. Если вы отсоедините процесс, вы не можете отправлять ему события CTRL + C. Если вы хотите быть выборочным, в каких процессах отправлять события CTRL + C, вам, похоже, нужно создать новые окна консоли для каждого. Я понятия не имею, есть ли способ сделать это без видимых окон или когда вы хотите перенаправить ввод-вывод с использованием труб.

 Смежные вопросы

  • Нет связанных вопросов^_^