基礎用法
using System.Diagnostics;
// 最簡單
Process.Start("notepad.exe");
Process.Start("calc.exe");
// 開啟檔案/網址 (關聯預設程式)
Process.Start("https://example.com");
Process.Start(@"C:\Docs\report.pdf");
Process.Start(@"D:\Projects\MyApp.sln");
進階控制:ProcessStartInfo
var psi = new ProcessStartInfo
{
FileName = "notepad.exe",
Arguments = @"C:\Temp\readme.txt", // 傳遞參數
WorkingDirectory = @"C:\Temp", // 工作目錄
Verb = "runas", // 以管理員身分執行 (需 UAC 提權)
WindowStyle = ProcessWindowStyle.Maximized, // 視窗狀態
UseShellExecute = true, // true: Shell 執行 (支援 Verb/關聯), false: 直接建立進程
CreateNoWindow = false, // 不建立視窗 (僅 UseShellExecute=false 時有效)
RedirectStandardInput = false, // 重導向標準輸入/輸出/錯誤
RedirectStandardOutput = false,
RedirectStandardError = false,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
Process.Start(psi);
關鍵屬性決策表
| 需求 | UseShellExecute | RedirectStandardOutput | CreateNoWindow | 備註 |
| 啟動 GUI 應用程式 (記事本、瀏覽器) | true | false | false | 預設行為 |
| 啟動 CLI 工具並捕獲輸出 | false | true | true | 必須搭配 UseShellExecute=false |
| 以管理員身分執行 | true | false | false | Verb="runas" 觸發 UAC |
| 隱藏主控台視窗 (背景服務) | false | true/false | true | 無視窗閃爍 |
| 開啟網址/文件關聯 | true | false | false | FileName 為 URL/路徑 |
捕獲輸出完整範例
public static (int ExitCode, string Output, string Error) RunCli(string fileName, string args, int timeoutMs = 30000)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
using (var proc = Process.Start(psi))
{
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
bool exited = proc.WaitForExit(timeoutMs);
if (!exited) proc.Kill();
return (proc.ExitCode, output, error);
}
}
// 使用
var (code, out, err) = RunCli("dotnet", "--version");
Console.WriteLine($"Exit: {code}, Out: {out.Trim()}");
非同步事件式讀取 (避免死結)
public static async Task<(int ExitCode, string Output, string Error)> RunCliAsync(string fileName, string args)
{
var tcs = new TaskCompletionSource<(int, string, string)>();
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (var proc = new Process { StartInfo = psi, EnableRaisingEvents = true })
{
var outBuf = new StringBuilder();
var errBuf = new StringBuilder();
proc.OutputDataReceived += (s, e) => { if (e.Data != null) outBuf.AppendLine(e.Data); };
proc.ErrorDataReceived += (s, e) => { if (e.Data != null) errBuf.AppendLine(e.Data); };
proc.Exited += (s, e) => tcs.TrySetResult((proc.ExitCode, outBuf.ToString(), errBuf.ToString()));
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
return await tcs.Task;
}
}
常見陷阱與解決
| 問題 | 原因 | 解決 |
| 死結 | 同步 `ReadToEnd` + 大量輸出填滿管道緩衝區 | 非同步事件讀取 / 交錯讀取雙管道 / 增加緩衝區 |
| Verb="runas" 不生效 | UseShellExecute=false | 必須 UseShellExecute=true |
| 檔案關聯不生效 | UseShellExecute=false | true 或明確指定關聯程式路徑 |
| 中文參數亂碼 | 編碼不匹配 | StandardOutputEncoding = Encoding.UTF8 / 系統預設編碼 |
| 等待逾時未結束 | 子程式卡住/等待輸入 | 設定 Timeout + Kill / 標準輸入寫入結束訊號 |
總結
`Process.Start` 看似簡單,實則藏著 **Shell vs 直接建立、重導向管道死結、UAC 提權、編碼、視窗風格** 等關鍵決策。掌握 `ProcessStartInfo` 完整屬性矩陣,依需求選擇正確組合,並善用非同步事件式讀取避免死結,即能穩健啟動並控制任何外部程式。
- 上一篇文章: C# 實作 SOCKS5 代理用戶端協議完整解析與程式碼
- 下一篇文章: C# 主控台應用程式隱藏自身視窗並啟動新程式技巧
Copyright ©
程式碼之家 All Rights Reserved