首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# Process 類完整指南:啟動外部程式、隱藏視窗、同步等待與參數傳遞

     編輯:關於C語言

System.Diagnostics.Process 是 .NET 啟動、控制、監控作業系統進程的核心 API。無論是呼叫 CLI 工具、轉檔程式、瀏覽器,還是啟動另一個 .NET 應用程式,掌握 Process 與 ProcessStartInfo 的關鍵屬性,就能處理「隱藏黑框、傳遞參數、捕獲輸出、同步/非同步等待」等實務需求。

最簡單啟動:一行式

using System.Diagnostics;

Process.Start("notepad.exe"); // 系統路徑下的 exe 可直接用檔名
Process.Start(@"C:\Tools\MyTool.exe", "arg1 arg2"); // 帶參數

此為 Fire-and-Forget,呼叫端不等待子進程結束。

同步等待子進程結束

var p = Process.Start("notepad.exe");
p.WaitForExit(); // 封鎖當前執行緒,直到記事本關閉
Console.WriteLine($"Exit code: {p.ExitCode}");

進階控制:ProcessStartInfo 完整設定

var psi = new ProcessStartInfo
{
    FileName = @"C:\Tools\ffmpeg.exe",          // 完整路徑或 PATH 內指令
    Arguments = "-i input.mp4 -vn output.mp3",  // 命令列參數
    UseShellExecute = false,                    // 關鍵:false 才能重導向 IO、隱藏視窗
    CreateNoWindow = true,                      // 不建立視窗(無黑框閃爍)
    RedirectStandardOutput = true,              // 捕獲標準輸出
    RedirectStandardError = true,               // 捕獲錯誤輸出
    RedirectStandardInput = true,               // 向子進程寫入輸入
    WorkingDirectory = @"C:\Work",              // 工作目錄
    Verb = "runas"                              // 需管理員權限(UAC 提升)
};

using (var proc = Process.Start(psi))
{
    // 非同步讀取輸出避免死鎖
    string output = await proc.StandardOutput.ReadToEndAsync();
    string error = await proc.StandardError.ReadToEndAsync();
    await proc.WaitForExitAsync();              // .NET 6+ 非同步等待
    Console.WriteLine($"ExitCode: {proc.ExitCode}");
    Console.WriteLine(output);
}

關鍵屬性對照表

屬性用途備註
FileName可執行檔路徑或指令若 UseShellExecute=true 可為網址、文件關聯
Arguments命令列參數字串含空白路徑請用雙引號包裹
UseShellExecute是否用 Shell 執行false 才能重導向 IO、隱藏視窗、設定 Verb
CreateNoWindow不建立主控台視窗僅 UseShellExecute=false 生效
RedirectStandardOutput/Error/Input重導向標準串流需 UseShellExecute=false
WorkingDirectory子進程工作目錄相對路徑解析基準
Verb動詞runas 觸發 UAC,open 等
StandardOutputEncoding輸出編碼.NET 6+,解決中文亂碼

常見實務場景

1. 呼叫 CLI 工具並即時處理輸出

var psi = new ProcessStartInfo("dotnet", "build --verbosity quiet")
{
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    CreateNoWindow = true
};

using (var p = Process.Start(psi))
{
    p.OutputDataReceived += (s, e) => { if (e.Data != null) Console.WriteLine($"[OUT] {e.Data}"); };
    p.ErrorDataReceived += (s, e) => { if (e.Data != null) Console.Error.WriteLine($"[ERR] {e.Data}"); };
    p.BeginOutputReadLine();
    p.BeginErrorReadLine();
    await p.WaitForExitAsync();
}

2. 以管理員權限重啟自身(自我提權)

if (!IsRunAsAdmin())
{
    var psi = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName)
    {
        UseShellExecute = true,
        Verb = "runas"
    };
    Process.Start(psi);
    Environment.Exit(0);
}

bool IsRunAsAdmin()
{
    using var id = WindowsIdentity.GetCurrent();
    var principal = new WindowsPrincipal(id);
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}

3. 跨平台啟動預設瀏覽器/編輯器


// .NET Core 3.0+ 跨平台開啟 URL 或檔案
Process.Start(new ProcessStartInfo("https://example.com") { UseShellExecute = true });
Process.Start(new ProcessStartInfo(@"README.md") { UseShellExecute = true });

避坑指南

  1. 大量輸出導致死鎖:同步 ReadToEnd() 可能填滿管道緩衝區 → 改用事件式 OutputDataReceived 或非同步 ReadToEndAsync()。
  2. 中文亂碼:設定 StandardOutputEncoding = Encoding.UTF8(.NET 6+)或 proc.StandardOutput.CurrentEncoding = Encoding.GetEncoding(950)(繁中環境)。
  3. 路徑含空白:Arguments = "\"C:\\Program Files\\Tool.exe\" arg1\"。
  4. 忘記 Dispose:Process 實作 IDisposable,務必 using 或手動釋放,否則句柄洩漏。
  5. UseShellExecute=true 時無法重導向:需二擇一:要隱藏視窗/捕獲輸出 → false;要開啟網址/文件關聯/提權 → true。

.NET 6+ 現代化 API

  • WaitForExitAsync(CancellationToken):可取消的非同步等待。
  • Process.StartAsync(ProcessStartInfo, CancellationToken):非同步啟動。
  • Process.GetProcessesByName、Process.GetCurrentProcess() 等查詢 API 維持不變。

熟練運用 ProcessStartInfo 的三大核心組合——UseShellExecute=false + CreateNoWindow=true + RedirectStandardOutput=true——即能優雅地在後台執行任何命令列工具,並完整掌控其生命週期與輸出。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved