在 GUI 應用程式中啟動控制台子進程,或需以無訊息方式終止現有控制台視窗。挑戰在於:
void __fastcall KillProcess(HWND hWnd) {
DWORD dwPid = 0;
DWORD result = GetWindowThreadProcessId(hWnd, &dwPid);
if (result && dwPid) {
// 取得進程控制代碼 (PROCESS_TERMINATE = 0x0001)
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwPid);
if (hProcess) {
TerminateProcess(hProcess, -9); // 退出碼 -9 (自訂)
CloseHandle(hProcess);
}
}
}
改進點:原始碼使用 `GlobalAlloc`/`GlobalLock` 配置 PID 緩衝區屬過度設計,直接使用區域變數 `DWORD dwPid` 即可;`OpenProcess` 權限應用 `PROCESS_TERMINATE` (0x0001) 而非數值 `1`;錯誤檢查需更完善。
void __fastcall CloseDosWindow() {
// Windows 2000/XP/2003/Vista/7/8/10/11
HWND hWnd = FindWindow("ConsoleWindowClass", NULL);
// Windows 95/98/Me
// HWND hWnd = FindWindow("tty", NULL);
if (hWnd) {
KillProcess(hWnd);
}
}
BOOL CALLBACK EnumConsoleWindows(HWND hWnd, LPARAM lParam) {
char className[256];
GetClassName(hWnd, className, sizeof(className));
if (strcmp(className, "ConsoleWindowClass") == 0 || strcmp(className, "tty") == 0) {
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
// 可選:檢查進程名稱、命令列參數決定是否終止
KillProcess(hWnd);
}
return TRUE; // 繼續列舉
}
// 使用方式
EnumWindows(EnumConsoleWindows, 0);
| API | 用途 | 關鍵參數 | 常見錯誤 |
|---|---|---|---|
| FindWindow | 依類別名/標題查找視窗 | lpClassName="ConsoleWindowClass" | 類別名稱因 OS 版本不同 |
| GetWindowThreadProcessId | 視窗 -> 進程 ID | lpdwProcessId 輸出參數 | 傳入 NULL 導致崩潰 |
| OpenProcess | 取得進程控制代碼 | dwDesiredAccess=PROCESS_TERMINATE | 權限不足 (非管理員/受保護進程) |
| TerminateProcess | 強制結束進程 | uExitCode 退出碼 | 資源洩漏 (DLL 未正確卸載) |
// 發送 CTRL_CLOSE_EVENT 讓控制台程式處理清理邏輯
BOOL GenerateConsoleCtrlEvent(DWORD dwCtrlEvent, DWORD dwProcessGroupId);
// 附加至控制台
AttachConsole(dwPid);
GenerateConsoleCtrlEvent(CTRL_CLOSE_EVENT, 0);
FreeConsole();
HANDLE hJob = CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0};
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
// 建立進程時指定 hJob,主進程結束時自動終止所有子進程
AssignProcessToJobObject(hJob, hProcess);
// 任務管理員命令列
taskkill /IM cmd.exe /F
taskkill /FI "WINDOWTITLE eq *Console*" /F
// PowerShell
Stop-Process -Name "cmd" -Force
Get-Process | Where-Object {$_.MainWindowTitle -like "*Console*"} | Stop-Process -Force
程式化關閉控制台視窗涉及視窗查找、進程識別、權限管理等核心 Windows API。現代開發應優先採用優雅關閉 (Ctrl Event)、Job Object 管理子進程,僅在必要時使用 `TerminateProcess`。完善的錯誤處理、目標驗證與最小權限原則是構建穩健工具的關鍵。