首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

如何獲取進程主視窗與啟動程式路徑:C++ 完整實作方案

     編輯:關於VC++

問題背景

系統工具開發常需:列舉特定進程的所有頂層視窗、取得啟動該進程的可執行檔完整路徑。挑戰在於:單一進程可能擁有多個無父視窗的頂層視窗 (如 Outlook、Explorer),單憑視窗類別名或標題無法判斷真正的「主視窗」。

核心解決方案:兩大迭代器類別

1. CWindowIterator - 通用視窗列舉基類

封裝 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();
};

2. CMainWindowIterator - 列舉指定進程主視窗

重寫 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()) {
    // 處理每個主視窗
}

取得進程啟動模組路徑

Windows NT/2000/XP 環境:使用 PSAPI

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);

封裝類別:CProcessIterator & CProcessModuleIterator

// 列舉所有系統進程 (略過 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 取得完整路徑

Windows 9x/Me 環境

需使用 ToolHelp API (CreateToolhelp32Snapshot 等),參考 MSDN Q175030「如何在 Win32 中列舉應用程式」。

實戰應用:lp.exe 控制台工具

整合上述類別,支援命令列參數列出進程、模組、主視窗。輸出範例見文中圖片。

lp.exe 執行畫面

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved