Processクラス

プロパティ

プロパティ  
System.IO.StreamWriter StandardInput 標準入力ストリームへ書き込めるStreamWriter
System.IO.StreamReader StandardOutput 標準出力ストリームを読み込めるStreamReader
System.IO.StreamReader StandardError 標準エラー ストリームを読み込めるStreamReader
System.Diagnostics.ProcessStartInfo StartInfo プロセスの起動情報。Start()で情報を渡さないときに指定する
bool EnableRaisingEvents trueならば、プロセスが終了するときExitedイベントが発生する
プロパティ - Process Class (System.Diagnostics) | Microsoft Docs

StartInfo

ProcessStartInfoクラス
プロパティ 内容
string FileName 起動するアプリケーションの名前、またはアプリケーションに関連付けられたドキュメントの名前
string Arguments コマンドライン引数
bool RedirectStandardInput trueならば、入力をStandardInputから読み込む
bool RedirectStandardOutput trueならば、出力をStandardOutputへ書き込む
bool RedirectStandardError trueならば、エラー出力をStandardErrorへ書き込む
bool UseShellExecue trueならば、プロセスの起動にOSのシェルを使用する。falseならば、プロセスは実行ファイルから直接作成される。
bool CreateNoWindow trueならば、プロセスは新しいウィンドウを作成せずに起動する

UseShellExecuteがtrue、またはUserNameとPasswordがnullでなければ、この指定は無視される

bool ErrorDialog trueならば、プロセスを起動できなかったときにエラーダイアログボックスを表示する

これをtrueとするときには、UseShellExecueもtrueでなければならない

Encoding StandardOutputEncoding 標準出力に適切なエンコーディング
Encoding StandardErrorEncoding エラー出力に適切なエンコーディング
     
プロパティ - ProcessStartInfo Class (System.Diagnostics) | Microsoft Docs

出力が適切にデコードされないときには、StandardOutputEncodingやStandardErrorEncodingを設定します。一方で入力が問題のときにはConsole.InputEncodingを設定します。

メソッド

メソッド 機能
Start() プロセスを起動し、コンポーネントに関連付ける
WaitForExit() プロセスが終了するまで、無期限に待機する
WaitForExit(Int32) プロセスが終了するまで、指定時間まで待機する
Close() コンポーネントに関連付けられたすべてのリソースを解放する

Dispose()はClose()を呼ぶため、usingブロックなどでDispose()を呼ぶならば、Close()を呼ぶ必要はない

CloseMainWindow() クローズ メッセージを送ることで、UIを持つプロセスを終了する。これはユーザーがシステムメニューからウィンドウを閉じることと同一で、アプリケーションが即座に終了することを要求しない
Kill() 関連付けられたプロセスを、即座に終了する

これは非同期で実行されるため、実際の終了はWaitForExit()で待つか、HasExitedで確認する

BeginOutputReadLine() リダイレクトされたStandardOutputから、非同期読み込みを開始する
BeginErrorReadLine() リダイレクトされたStandardErrorから、非同期読み込みを開始する
   
メソッド - Process Class (System.Diagnostics) | Microsoft Docs

Start()

プロセス リソースを起動し、それをProcessコンポーネントに関連付けられます。引数を取らない定義では、情報をStartInfoプロパティで事前に設定しておきます。

public bool Start ();
public static Process Start(
    string fileName, // プロセスで実行する文書、またはアプリケーション ファイルの名前
)
Process.Start メソッド (String) (System.Diagnostics) | MSDN
public static Process Start(
    string fileName, // プロセスで実行するアプリケーション ファイルの名前
    string arguments // プロセスに渡すコマンドライン引数
)
Process.Start メソッド (String, String) (System.Diagnostics) | MSDN
Process.Start("sample.txt");
Process.Start("notepad.exe");

WaitForExit(Int32)

public bool WaitForExit (int milliseconds);
WaitForExit(Int32) - Process.WaitForExit Method (System.Diagnostics) | Microsoft Docs

OutputDataReceivedイベントのハンドラは別スレッドで呼ばれるため、このメソッドがtrueを返してもそこでの処理が完了していないことがあります。

BeginOutputReadLine()

アプリケーションのリダイレクトされたStandardOutputから、非同期読み込みを開始できます。

[System.Runtime.InteropServices.ComVisible(false)]
public void BeginOutputReadLine ();
Process.BeginOutputReadLine Method (System.Diagnostics) | Microsoft Docs
  1. UseShellExecute プロパティをfalseにする
  2. RedirectStandardOutput プロパティをtrueにする
  3. OutputDataReceived イベントのハンドラを追加する
  4. Processを開始する
  5. BeginOutputReadLine()を呼ぶ
Remarks - Process.BeginOutputReadLine Method (System.Diagnostics) | Microsoft Docs

イベント

イベント 発生タイミング
Exited プロセスが終了したとき。ただしEnableRaisingEventsプロパティがtrueの場合に限られる
ErrorDataReceived アプリケーションがStandardErrorに書き込むとき
OutputDataReceived アプリケーションがStandardOutputに行を書き込むたび

ハンドラではDataReceivedEventArgs.Dataから書き込まれた文字列を受け取れるが、そこには改行文字は含まれていない。それらを連結していくと改行文字が失われた状態となるため、それが不都合ならば改行文字を追加する。

出力の取得

Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;

process.StartInfo.FileName = "sample.exe";
process.StartInfo.Arguments = "/all";

process.Start();
string output = process.StandardOutput.ReadToEnd();

Console.Write(output);
例 - Process.StandardOutput プロパティ (System.Diagnostics) | MSDN

出力が空文字列となる場合にはStartInfo.RedirectStandardErrorをtrueとして、標準エラー出力を確認します。

プロセスが接続を閉じないとき、ReadToEnd()で出力を読み込むと無期限にブロックされます。

非同期 読み込み

StandardOutputから同期で読み込む場合、プロセスが書き込みを完了するまで処理は戻りません。これに対しOutputDataReceivedイベントにハンドラを設定し、BeginOutputReadLine()で読み込みを開始すると、呼び出し元へすぐに処理が返されるようにできます。

Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.EnableRaisingEvents = true;

process.OutputDataReceived += (sender, e) =>
{
    string output = e.Data;
    Console.Write(output);
};

process.Exited += delegate
{
    // プロセスが終了した
};

process.StartInfo.FileName = filename;
process.StartInfo.Arguments = arguments;

process.Start();
process.BeginOutputReadLine();

bool hasProcessExited = process.WaitForExit(1000);
process.Close();

意図せずタイムアウトするときは、BeginErrorReadLine()でエラーも読み込みます。

プロセスが接続を閉じないとき、引数なしのWaitForExit()で待機すると無期限にブロックされます。c# - ProcessStartInfo hanging on "WaitForExit"? Why? - Stack Overflow

プロセス間通信 (inter-process communication)

  • 匿名パイプ (Anonymous pipes)
    • ローカル コンピューターでの、プロセス間通信
    • 一方向であり、ネットワーク経由では使用できない
    • 名前付きパイプと比較してオーバーヘッドは小さいが、提供するサービスも限定
    • 1つのサーバー インスタンスのみをサポート
    • スレッド間または親子のプロセス間での通信に有用
  • 名前付きパイプ (Named pipes)
    • パイプ サーバーとパイプ クライアントとの間での、プロセス間通信
    • 一方向または双方向のパイプを使用できる
    • メッセージ ベースの通信をサポートし、複数のクライアントが同じパイプ名を使用してサーバーに対して同時に接続できる
    • 偽装をサポートし、プロセス間接続においてリモート サーバー上で独自のアクセス許可を使用できる

匿名パイプ (Anonymous pipes)

Client側

static void Main(string[] args)
{
    if (args.Length == 0) return;

    using (PipeStream pipeClient
        = new AnonymousPipeClientStream(PipeDirection.In, args[0]))
    {
        using (StreamReader sr = new StreamReader(pipeClient))
        {
            string data = sr.ReadLine();
            Console.WriteLine(data);
        }
    }
}

Server側

static void Main(string[] args)
{
    Process pipeClient = new Process();
    pipeClient.StartInfo.FileName = "Client.exe";

    using (AnonymousPipeServerStream pipeServer
        = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
    {
        // このプロセスへのハンドルを、クライアントに渡す
        pipeClient.StartInfo.Arguments = pipeServer.GetClientHandleAsString();
        pipeClient.StartInfo.UseShellExecute = false;
        pipeClient.Start();

        pipeServer.DisposeLocalCopyOfClientHandle();

        using (StreamWriter sw = new StreamWriter(pipeServer))
        {
            sw.AutoFlush = true;
            sw.WriteLine("TEST");

            pipeServer.WaitForPipeDrain();
        }
    }

    pipeClient.WaitForExit();
    pipeClient.Close();
}
方法: ローカルのプロセス間通信で匿名パイプを使用する | Microsoft Docs

名前付きパイプ (Named pipes)

方法: ネットワークのプロセス間通信で名前付きパイプを使用する | Microsoft Docs
MSDN (Microsoft Developer Network) から検索