在 .NET (C#) 應用中,實現「程序運行時自我刪除可執行文件」是一個經典需求 (如安裝程序清理、自更新替換、授權失效銷毀)。由於 Windows 禁止刪除正在運行的進程映像文件,核心思路是:**啟動獨立進程 (BAT/CMD) 延時執行刪除命令,主程序隨即退出**。本文詳細講解兩種主流方案原理、代碼實現與優缺點對比。
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
public static class SelfDeleter {
// 方案一:BAT 腳本法
public static void DeleteSelfWithBat() {
string exePath = Application.ExecutablePath; // 當前 exe 完整路徑
string batPath = Path.Combine(Path.GetDirectoryName(exePath), "DeleteSelf.bat");
// 1. 生成 BAT 內容
// :del 標籤循環
// del "exe路徑" 刪除主程序
// if exist "exe路徑" goto del 刪除失敗(仍被佔用)則跳轉循環
// del %0 刪除自身 bat 文件
string batContent = string.Format(
"@echo off\r\n" +
":del\r\n" +
"del \"{0}\"\r\n" +
"if exist \"{0}\" goto del\r\n" +
"del \"%~f0\"\r\n",
exePath.Replace("\"", "\"\"") // 轉義雙引號
);
File.WriteAllText(batPath, batContent, Encoding.Default); // 系統默認編碼 (GBK)
// 2. 隱藏啟動 BAT (WinExec 簡潔,或 Process.Start 隱藏窗口)
// WinExec 來自 kernel32.dll
WinExec(batPath, 0); // SW_HIDE = 0
// 3. 主程序立即退出
Application.Exit();
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern uint WinExec(string lpCmdLine, uint uCmdShow);
// 替代方案:用 Process.Start 隱藏窗口
/*
private static void StartBatHidden(string batPath) {
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c " + batPath) {
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(psi);
}
*/
}
@echo off
:del
del "C:\Path\YourApp.exe" // 嘗試刪除主程序
if exist "C:\Path\YourApp.exe" goto del // 若刪除失敗(文件仍被鎖定),跳轉 :del 繼續嘗試
del "%~f0" // 刪除自身 (%~f0 獲取當前 bat 完整路徑)
利用 `ping 1.1.1.1 -n 1 -w 1000 > nul` 作為 **約 1 秒延時**(ping 不存在 IP,等待超時),然後執行 `del`。無需生成 BAT 文件,極其簡潔。
public static void DeleteSelfWithCmd() {
string exePath = Application.ExecutablePath;
// cmd /c 執行命令字符串後退出
// ping 1.1.1.1 -n 1 -w 1000 > nul 延時 ~1 秒 (等待主進程退出釋放鎖)
// & 命令連接符
// del "exePath" 刪除主程序
string cmdArgs = string.Format(
"/c ping 1.1.1.1 -n 1 -w 1000 > nul & del \"{0}\"",
exePath.Replace("\"", "\"\"")
);
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", cmdArgs) {
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(psi);
Application.Exit();
}
| 維度 | BAT 腳本法 | CMD 延時法 |
|---|---|---|
| 臨時文件 | 生成 `.bat` (需寫入權限、殘留風險極低) | 無臨時文件 |
| 代碼複雜度 | 中 (生成腳本、調用 API) | 極低 (單行命令) |
| 可靠性 | 高 (循環重試直到成功) | 中 (固定延時,極端情況可能失敗) |
| 兼容性 | 極高 (所有 Windows 版本) | 高 (需 cmd.exe 支持 ping & 符號) |
| 調試可見性 | 可保留 BAT 檢查內容 | 無痕跡 |
| 推薦場景 | 正式產品、需極高可靠性、複雜路徑 | 快速原型、簡單工具、臨時需求 |
若需「主程序異常退出時自動重啟」或「雙進程互相監守防止被殺」,可採用**伴隨進程** 模式:
此模式常用於安全軟件、關鍵服務保活,**不屬於自我刪除範疇**,但技術關聯性強,供參考。
掌握這兩種方案,即可在安裝包清理、自更新替換、試用版過期銷毀等場景中靈活應用,實現 .NET 程序的「無痕離場」。