调用不同目录下批处理文件时C#控制台程序崩溃
基础代码错误修复
你的代码存在几个明显问题,先修正这些基础错误:
路径转义错误:字符串中的
\是C#的转义字符,直接写"C:\Temp\batfile.bat"会被解析错误,需要用逐字字符串(加@前缀)或者双反斜杠:// 正确写法二选一 var batPath = @"C:\Temp\batfile.bat"; // 或者 var batPath = "C:\\Temp\\batfile.bat";WorkingDirectory占位符未替换:你写的
"location of batfile.bat"是占位符,实际应该设置为批处理文件所在的目录,比如:processInfo.WorkingDirectory = @"C:\Temp";进程null检查:
Process.Start()可能返回null(比如启动失败),直接调用WaitForExit()会引发空引用异常,需要先判断:var process = Process.Start(processInfo); if (process != null) { process.WaitForExit(); // ...后续逻辑 }
核心崩溃原因:更新程序强制终止原进程
你的批处理是启动更新exe来替换当前应用,这种场景下,更新程序需要替换当前C#进程正在占用的文件,如果原进程不退出,更新程序通常会强制终止原进程,这就导致你的C#程序直接崩溃,且无法进入catch块(因为进程被外部强制终止,不是托管代码异常)。
针对性解决方案
根据更新场景的特性,你需要让原C#进程在启动批处理后立即退出,让更新程序在无进程占用的情况下完成更新:
方案一:启动批处理后直接退出当前程序
try { var batPath = @"C:\Temp\batfile.bat"; var processInfo = new ProcessStartInfo("cmd.exe", $"/c \"{batPath}\"") { CreateNoWindow = true, WorkingDirectory = Path.GetDirectoryName(batPath), UseShellExecute = false }; // 启动批处理,不等待其完成 Process.Start(processInfo); // 立即退出当前C#进程,给更新程序释放文件占用 Environment.Exit(0); } catch (Exception ex) { // 记录日志 }
方案二:让批处理等待原进程退出后再执行更新
修改你的批处理文件,先等待原C#进程退出,再启动更新exe(假设原进程名为YourConsoleApp.exe):
@echo off :: 等待原进程退出 :WAIT tasklist /FI "IMAGENAME eq YourConsoleApp.exe" 2>NUL | find /I /N "YourConsoleApp.exe">NUL if "%ERRORLEVEL%"=="0" ( timeout /t 1 /nobreak > NUL goto WAIT ) :: 启动更新exe start "" "path/to/your/update.exe"
然后C#代码启动批处理后立即退出,这样批处理会等原进程结束后再执行更新,避免强制终止。
额外注意事项
如果必须等待批处理完成,且更新程序不会替换当前进程的文件,那需要检查批处理中是否有其他会导致进程崩溃的操作(比如输出大量内容未重定向,导致缓冲区溢出),可以添加重定向输出的代码:
processInfo.RedirectStandardOutput = true; processInfo.RedirectStandardError = true; // 启动后读取输出,避免缓冲区满导致进程挂起 process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { /* 处理输出 */ } }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { /* 处理错误输出 */ } }; process.BeginOutputReadLine(); process.BeginErrorReadLine();
内容的提问来源于stack exchange,提问作者Harsh Bhadoria

