2

コマンドライン インタープリターを持つプロセスを生成するアプリを作成しています。別のマシンからこの CLI にコマンドを提供する必要があります。ここで、コマンドがいつ終了したかを検出する必要があるため、作成中のプロセスの標準出力に CLI のプロンプトがいつ表示されるかを確認しています。コードのスニペットを次に示します。

private string StartProcess(string input)
{
try
{
    StringBuilder output = new StringBuilder();
    StringBuilder error = new StringBuilder();

    AutoResetEvent commandFinished = new AutoResetEvent(false);

    ProcessStartInfo startInfo = new ProcessStartInfo()
    {
        FileName = "myprocess.exe",
        Arguments = "",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        RedirectStandardInput = true,
        UserName = System.Environment.UserName
    };

    Process myProcess = new Process()
    {
        StartInfo = startInfo,
        EnableRaisingEvents = true
    };

    myProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
    {
        if (e.Data != null)
        {
            string prompt = "user >";

            if (e.Data.Substring(e.Data.Length - prompt.Length).Equals(prompt))
            {
                Console.WriteLine("Received prompt! Sending CommandFinished signal!");
                commandFinished.Set();
                Console.WriteLine("CommandFinished signal set!");
            }
            else
            {
                output.AppendLine(e.Data);
            }
        }
        else
        {
            // Data finished
            Console.WriteLine("StdOut data finished! Sending CommandFinished signal!");
            commandFinished.Set();
            Console.WriteLine("CommandFinished signal set!");
        }
    });


    myProcess.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
    {
        if (e.Data != null)
        {
            Console.WriteLine("Error Data received: " + e.Data.ToString());
            error.AppendLine(e.Data);
        }
    });

    myProcess.Start();
    myProcess.BeginOutputReadLine();
    myProcess.BeginErrorReadLine();

    Console.WriteLine("Executing input command: " + input);
    myProcess.StandardInput.WriteLine(input);

    Console.WriteLine("Waiting for input command to complete...");

    commandFinished.WaitOne();

    Console.WriteLine("Command complete!");

    return output.ToString();
}
catch (Exception ex)
{
    Console.WriteLine("EXCEPTION: " + ex.ToString());
    throw ex;
}
}

現在、コードは WaitOne() の呼び出しでハングしています。OutputDataReceived理由について混乱しています-出力でCLIプロンプトを検出せず、イベントでプロンプトが受信されたこと、または受信したデータがnullであることを通知するWriteLinesを取得しません。つまりOutputDataReceived、前のコマンドが完了してプロンプトが表示されたときにイベントが発生していません。

私が提供している入力コマンドはしばらく時間がかかりますが、完了します。ここで AutoResetEvent を間違って使用していますか?

4

1 に答える 1

2

優れた最小限完全なコード例がなければ、コードの何が問題なのかを確実に知ることは不可能です。しかし、明らかな説明が 1 つあります。

このイベントは、受信した出力のOutputDataReceivedごとに発生します。つまり、改行文字で終了する文字列です。

外部プロセスに関する詳細がなければ、確かなことは言えません。ただし、ほとんどの CLI タイプのシナリオでは、改行文字のないプロンプトが表示されます。つまり、プロンプトがコンソールに書き込まれ、次の行ではなく、プロンプトの直後にユーザー入力がコンソールにエコーされることが期待されます。

これがシナリオの場合、プロンプトだけではイベントが発生しないため、ほぼ確実にプロンプ​​トの検出に失敗しています。前のコマンドの操作からの出力の最終行の後、次にイベントが発生するのは、コマンドが標準入力を介してプロセスに送信された後です。これは、そのコマンドをいつ送信するかを知るのに役立つには明らかに遅すぎます。:)

これを機能させるには、行ベースではない他の使用可能なメカニズムのいずれかを介して、プロセスから入力を読み取る必要があります。

于 2015-10-29T23:01:57.847 に答える