4

これを機能させるのに最も苦労しています。あなたの誰かが以前にこれを行ったことがあることを願っています。

コンソールを継承する子プロセスを実行している C# コンソール アプリがあります。外側のアプリでキャッチされた ctrl-c を内側のアプリに渡して、適切にシャットダウンできるようにしたいと考えています。

私はいくつかの非常に単純なコードを持っています。Process を開始し、WaitForExit(10) でポーリングします。CancelKeyPress ハンドラーも登録しており、起動時に bool を true に設定します。ポーリング ループもこれをチェックし、それが true の場合、GenerateConsoleCtrlEvent() を呼び出します (pinvoke を介してマップしました)。

GenerateConsoleCtrlEvent() に対して多くのパラメーターの組み合わせを試しました。最初のパラメーターは 0 または 1、2 番目のパラメーターは 0 または子プロセスの ID。何も機能していないようです。時々私は偽を返し、Marshal.GetLastWin32Error() は 0 を返し、時には真を返します。ただし、子アプリが ctrl-c を受け取る原因はありません。

確実にするために、テスト用の C# アプリを子アプリとして作成し、その子アプリで何が起こっているかを出力し、実行時に ctrl-c を手動で入力すると正しく終了することを確認しました。

私はこれに数時間頭を悩ませてきました。これでどこに行くべきかについて、誰かが私にいくつかの指針を教えてもらえますか?

4

3 に答える 3

3

これが良いアプローチかどうかはわかりません。これは、子プロセスが の CREATE_NEW_PROCESS_GROUP フラグで作成されている場合にのみ機能しCreateProcess()ます。ただし、System.Diagnostics.Process クラスはこれをサポートしていません。

Main() メソッドからの戻り値の使用を検討してください。Windows SDK には、Ctrl+C による中止、STATUS_CONTROL_C_EXIT または 0xC000013A 用に定義された一意の値が既に存在します。親プロセスは、プロパティからそのリターン コードを取得できProcess.ExitCodeます。

于 2008-11-18T02:04:04.283 に答える
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.");
    }
}

親.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 をリダイレクトしたい場合に何か方法があるかどうかはわかりません。

于 2009-11-26T10:37:20.833 に答える