2008-11-18 178 views
2

我最困難的時間試圖讓這個工作,希望你們之前做過這個。卡住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

回答

3

不太確定這是一個好方法。這隻適用於如果使用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

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事件,你似乎需要爲每一個創建新的控制檯窗口。我不知道是否有辦法在沒有可見窗口的情況下執行此操作,或者您想要使用管道重定向I/O。