cmd.exe / conhost.exe 需強制清理。FindWindow("ConsoleWindowClass", NULL) 取得主控台視窗句柄 (Win2K/XP+)。Win9x 類別名為 "tty"。GetWindowThreadProcessId(hWnd, &pid) 取得進程 ID。OpenProcess(PROCESS_TERMINATE, FALSE, pid) 取得終止權限句柄。TerminateProcess(hProcess, -9) 強制結束進程 (退出碼 -9)。
#include
// 依視窗句柄終止所屬進程
void KillProcessByWnd(HWND hWnd) {
if (!hWnd) return;
DWORD pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid == 0) return;
// 僅要求 TERMINATE 權限,避免需完整存取權被拒
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProcess) {
TerminateProcess(hProcess, (UINT)-9); // 非零退出碼表達異常終止
CloseHandle(hProcess);
}
}
// 關閉第一個找到的主控台視窗
void CloseFirstConsoleWindow() {
// Win2K/XP/2003/Vista/7/8/10/11 主控台視窗類別名
HWND hConsole = FindWindow("ConsoleWindowClass", NULL);
// Win95/98/Me 使用 "tty" (可同時嘗試)
if (!hConsole) hConsole = FindWindow("tty", NULL);
if (hConsole) KillProcessByWnd(hConsole);
}
// 主程式進入點 (主控台應用程式)
int main() {
CloseFirstConsoleWindow();
return 0;
}
void __fastcall TForm1::BtnCloseConsoleClick(TObject *Sender) {
HWND hConsole = FindWindow("ConsoleWindowClass", NULL);
if (!hConsole) hConsole = FindWindow("tty", NULL); // 相容 9x
if (hConsole) {
DWORD pid;
GetWindowThreadProcessId(hConsole, &pid);
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProc) {
TerminateProcess(hProc, -9);
CloseHandle(hProc);
ShowMessage("已發送終止信號給主控台進程 (PID: " + IntToStr(pid) + ")");
} else {
ShowMessage("OpenProcess 失敗,錯誤碼: " + IntToStr(GetLastError()) + " (可能權限不足)");
}
} else {
ShowMessage("找不到主控台視窗");
}
}
| 議題 | 說明 |
|---|---|
| 資料遺失風險 | TerminateProcess 為**非正常終止**:不執行 DLL DLL_PROCESS_DETACH、不呼叫 C++ 解構函式、不刷新檔案緩衝區。目標程式若在寫入關鍵資料時被終止,會造成資料損毀。 |
| 權限需求 | 呼叫端需具備 PROCESS_TERMINATE 權限。針對系統服務、高完整性進程,需管理員權限 (UAC 提權) 或 SeDebugPrivilege。 |
| 視窗類別名變更 | Win2K+ 固定為 ConsoleWindowClass。Win9x 為 tty。新版 Windows Terminal / ConPTY 架構下,視窗類別可能不同,建議改用 EnumWindows + GetClassName 比對包含 "Console" 關鍵字。 |
| 多視窗處理 | 若有多個主控台視窗,FindWindow 僅回傳第一個。需用 EnumWindows 列舉所有符合類別的視窗並逐一處理。 |
| 優雅替代方案 | 若目標程式為自行開發,請改用 PostMessage(hWnd, WM_CLOSE, 0, 0) 或 GenerateConsoleCtrlEvent(CTRL_CLOSE_EVENT, pid) 讓程式正常關閉釋放資源。 |
BOOL CALLBACK EnumConsoleProc(HWND hWnd, LPARAM lParam) {
char className[256];
GetClassName(hWnd, className, sizeof(className));
if (strcmp(className, "ConsoleWindowClass") == 0 || strcmp(className, "tty") == 0) {
// 可在此加入標題比對、PID 過濾等邏輯
DWORD pid; GetWindowThreadProcessId(hWnd, &pid);
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProc) { TerminateProcess(hProc, -9); CloseHandle(hProc); }
}
return TRUE; // 繼續列舉
}
void CloseAllConsoleWindows() {
EnumWindows(EnumConsoleProc, 0);
}
雖然 FindWindow + TerminateProcess 能快速關閉主控台視窗,但屬「核彈級」手段,**極不建議用於正常應用程式關閉流程**。請優先協助目標程式實作正常關閉機制 (WM_CLOSE, Ctrl+C 事件, IPC 指令),僅在無法控制目標程式、或緊急清理殭屍進程時作為最後手段使用。