卡住C#中的控制台应用程序中的GenerateConsoleCtrlEvent

问题描述:

我最困难的时间试图让这个工作,希望你们之前做过这个。卡住C#中的控制台应用程序中的GenerateConsoleCtrlEvent

我有一个C#控制台应用程序正在运行继承其控制台的子进程。我想要一个由外部应用程序捕获的ctrl-c传递给内部应用程序,以便它可以很好地关闭。

我有一些非常简单的代码。我开始一个Process,然后用WaitForExit(10)轮询它。我还有一个注册的CancelKeyPress处理程序,它在触发时将bool设置为true。轮询循环也会检查它,如果它是真的,它会调用GenerateConsoleCtrlEvent()(我已通过pinvoke映射)。

我已经尝试了很多组合的参数GenerateConsoleCtrlEvent()。 0或1表示第一个参数,0或第二个参数的子进程ID。似乎没有任何工作。有时我得到一个错误的回来,Marshal.GetLastWin32Error()返回0,有时我会回到真实。但是没有一个导致子应用程序接收到ctrl-c。要绝对确定,我写了一个测试C#应用程序作为子应用程序,它打印出它正在发生的事情,并验证当它运行时手动输入ctrl-c确实会导致它退出。

我几个小时一直对我的头撞。任何人都可以给我一些指向哪里去与此?

+0

我遇到同样的问题。 GenerateConsoleCtrlEvent似乎被破坏。它不影响进程,不管它是否具有控制台窗口,也不影响它是否以CREATE_NEW_PROCESS_GROUP开头。我试过了所有的东西,似乎没有办法彻底关闭一个以Process启动的控制台应用程序。如果它不是调用进程的控制台窗口的一部分,则启动或CreateProcess。 – Triynko 2013-04-22 19:12:49

不太确定这是一个好方法。这只适用于如果使用CREATE_NEW_PROCESS_GROUP标志为CreateProcess()创建子进程。但System.Diagnostics.Process类不支持这一点。

考虑使用Main()方法的返回值。在Windows SDK中已经为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

是的。 Reflector告诉我Process.Start()非常复杂。将不得不克隆它只是为了设置单个标志。在这个时候工作太多了。 – scobi 2008-11-18 19:29:00

你有没有这方面的运气?我的理解是,当您在控制台中按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事件,你似乎需要为每一个创建新的控制台窗口。我不知道是否有办法在没有可见窗口的情况下执行此操作,或者您想要使用管道重定向I/O。