Processクラス

プロパティ

プロパティ 内容
System.IO.StreamWriter StandardInput 標準入力ストリームへ書き込めるStreamWriter
System.IO.StreamReader StandardOutput 標準出力ストリームを読み込めるStreamReader
System.IO.StreamReader StandardError 標準エラー ストリームを読み込めるStreamReader
System.Diagnostics.ProcessStartInfo StartInfo プロセスの起動情報。Start()で情報を渡さないときに指定する
bool HasExited trueならば、プロセスが終了している
bool EnableRaisingEvents trueならば、プロセスが終了するときExitedイベントが発生する
int ExitCode 終了コード
ProcessModule MainModule 関連付けられたプロセスの、メイン モジュール
ProcessModuleCollection Modules 関連付けられたプロセスに読み込まれた、モジュール
IntPtr MainWindowHandle 関連付けられたプロセスの、メイン ウィンドウのウィンドウ ハンドル

次のような場合に、IntPtr.Zeroとなることがある

  • メイン ウィンドウがない
  • タスクバーに表示されず、隠されている。これは通知領域のアイコンとして表示されている場合
     
プロパティ - Process Class (System.Diagnostics) | Microsoft Learn

StartInfo

プロセスの起動情報を指定します。

ProcessStartInfoクラス
プロパティ 内容 既定値
string FileName 起動するアプリケーションの名前、またはアプリケーションに関連付けられたドキュメントの名前 ""
string Arguments コマンドライン引数 ""
string Verb アプリケーションやドキュメントを開くときに使用する動詞 (verb)

(動詞とは、エクスプローラのファイルのコンテキストメニューに表示される、開く (Open)、編集 (Edit)、印刷 (Print) などのこと)

""
bool RedirectStandardInput trueならば、入力をStandardInputから読み込む false
bool RedirectStandardOutput trueならば、出力をStandardOutputへ書き込む false
bool RedirectStandardError trueならば、エラー出力をStandardErrorへ書き込む false
bool UseShellExecute trueならば、プロセスの起動にOSのシェルを使用する。falseならば、プロセスは実行ファイルから直接作成される。 true
bool CreateNoWindow trueならば、プロセスは新しいウィンドウを作成せずに起動する

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

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

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

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

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

MainModule

ProcessModuleクラス
プロパティ 内容
string ModuleName プロセスのモジュール名
FileVersionInfo FileVersionInfo モジュールのバージョン情報
     
プロパティ - ProcessModule クラス (System.Diagnostics) | Microsoft Learn

メソッド

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

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

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

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

BeginOutputReadLine() リダイレクトされたStandardOutputから、非同期読み込みを開始する
BeginErrorReadLine() リダイレクトされたStandardErrorから、非同期読み込みを開始する
   
メソッド - Process Class (System.Diagnostics) | Microsoft Learn
静的メソッド
戻り値の型 メソッド 機能
Process[] GetProcesses() ローカル コンピューター上の、すべてのプロセスを取得できる
Process[] GetProcessesByName(String) ローカル コンピューター上の、指定のプロセス名を共有するすべてのプロセスを取得できる
Process GetProcessById(Int32) ローカル コンピューター上の、指定のプロセスIDのプロセスを取得できる
Process GetCurrentProcess() 現在アクティブなプロセスを取得できる
     

Start()

プロセス リソースを起動し、それをProcessコンポーネントに関連付けられます。

public bool Start ();
Start() - Process.Start メソッド (System.Diagnostics) | Microsoft Learn

起動するプロセスの情報はStartInfoプロパティで設定しておくか、Process.Start()の引数で渡します。

Process process = new Process();
process.StartInfo.FileName = "notepad.exe";
process.Start();

既存のプロセスが再利用されるなどして、新しいプロセスが起動されなかったならばfalseが返されます。

StartInfo.FileNameで指定したアプリケーションが存在しないと、「指定されたファイルが見つかりません。」としてWin32Exceptionが投げられます。そのときHRESULTは、E_FAIL (0x80004005) です。

ファイルを指定してプロセスを起動

特定のファイルやアプリケーションを開くだけならば、それを指定します。

public static Process Start(
    string fileName, // プロセスで実行する文書、またはアプリケーション ファイルの名前
)
Start(String) - Process.Start メソッド (System.Diagnostics) | Microsoft Learn

たとえば次のように、ファイルを指定してプロセスを起動できます。

Process.Start("sample.txt");

このように起動したプロセスの情報は、次のように得られます。

Process process = Process.Start("notepad.exe");
foreach (ProcessModule module in process.Modules)
{
    string name = module.ModuleName;

    FileVersionInfo info = module.FileVersionInfo;
    string str1 = info.CompanyName;
    string str2 = info.FileDescription;
}

WaitForExit(Int32)

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

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

BeginOutputReadLine()

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

[System.Runtime.InteropServices.ComVisible(false)]
public void BeginOutputReadLine ();
Process.BeginOutputReadLine Method (System.Diagnostics) | Microsoft Learn

次のように処理します。

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

イベント

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

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

出力の取得

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

process.StartInfo.FileName = "where";
process.StartInfo.Arguments = "notepad";

process.Start();
string output = process.StandardOutput.ReadToEnd();
Examples - Process.StandardOutput Property (System.Diagnostics) | Microsoft Learn

この処理はオブジェクト初期化子を用いて次のようにも記述できます。

ProcessStartInfo startInfo = new ProcessStartInfo("where", "notepad")
{
    UseShellExecute = false,
    RedirectStandardOutput = true,
};

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

出力が空文字列となる場合には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 Learn

名前付きパイプ (Named pipes)

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