系統工具開發常需:列舉特定進程的所有頂層視窗、取得啟動該進程的可執行檔完整路徑。挑戰在於:單一進程可能擁有多個無父視窗的頂層視窗 (如 Outlook、Explorer),單憑視窗類別名或標題無法判斷真正的「主視窗」。
封裝 EnumWindows,隱藏回呼細節,提供虛擬函式 OnWindow() 供衍生類過濾:
class CWindowIterator {
protected:
HWND* m_hwnds; DWORD m_nAlloc, m_count, m_current;
static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp);
virtual BOOL OnEnumProc(HWND hwnd);
virtual BOOL OnWindow(HWND hwnd) { return TRUE; } // 衍生類覆寫
public:
CWindowIterator(DWORD nAlloc=1024); ~CWindowIterator();
DWORD GetCount() { return m_count; }
HWND First(); HWND Next();
};
重寫 OnWindow(),僅保留可見且屬於目標進程的頂層視窗:
class CMainWindowIterator : public CWindowIterator {
protected:
DWORD m_pid;
virtual BOOL OnWindow(HWND hwnd) {
if ((GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)) {
DWORD pidwin;
GetWindowThreadProcessId(hwnd, &pidwin);
if (pidwin == m_pid) return TRUE;
}
return FALSE;
}
public:
CMainWindowIterator(DWORD pid, DWORD nAlloc=1024);
~CMainWindowIterator();
};
DWORD pid = ...; // 已知進程 ID
CMainWindowIterator itw(pid);
for (HWND hwnd = itw.First(); hwnd; hwnd = itw.Next()) {
// 處理每個主視窗
}
EnumProcessModules 回傳模組陣列,第一個即為主模組 (.exe):
DWORD count;
HMODULE hm[1];
EnumProcessModules(hProcess, hm, 1, &count); // hm[0] 為主模組
TCHAR modname[_MAX_PATH];
GetModuleFileNameEx(hProcess, hm[0], modname, _MAX_PATH);
// 列舉所有系統進程 (略過 PID=0 Idle 進程)
class CProcessIterator {
DWORD* m_pids; DWORD m_count, m_current;
public:
CProcessIterator(); ~CProcessIterator();
DWORD First(); DWORD Next(); DWORD GetCount();
};
// 列舉指定進程模組,First() 回傳主模組
class CProcessModuleIterator {
HANDLE m_hProcess; HMODULE* m_hModules; DWORD m_count, m_current;
public:
CProcessModuleIterator(DWORD pid); ~CProcessModuleIterator();
HANDLE GetProcessHandle() { return m_hProcess; }
HMODULE First(); HMODULE Next(); DWORD GetCount();
};
CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE 模組
TCHAR modname[_MAX_PATH];
GetModuleBaseName(itm.GetProcessHandle(), hModule, modname, _MAX_PATH);
// 或 GetModuleFileNameEx 取得完整路徑
需使用 ToolHelp API (CreateToolhelp32Snapshot 等),參考 MSDN Q175030「如何在 Win32 中列舉應用程式」。
整合上述類別,支援命令列參數列出進程、模組、主視窗。輸出範例見文中圖片。
