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

C語言實現進程管理器:Toolhelp32 與 PSAPI 兩種枚舉技術詳解

     編輯:關於C語言

前言

在 Windows 系統程式開發中,獲取當前系統運行的進程資訊是基礎且關鍵的需求。本文將詳細介紹兩種主流的 C 語言實現方案:基於 Toolhelp32 API 的快照遍歷法,以及基於 PSAPI 的 EnumProcesses 介面。文中包含完整、可編譯的程式碼範例,並解析關鍵步驟與常見坑點。

方案一:使用 Toolhelp32 API 建立進程快照

CreateToolhelp32Snapshot 能將當前系統所有進程的狀態「拍照」成一個快照,隨後配合 Process32First/Process32Next 即可逐一枚舉。此法不需額外連結庫,標頭檔 <tlhelp32.h> 即可使用,適合輕量級工具。

核心程式碼

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

int main() {
    PROCESSENTRY32 pe32 = {0};
    pe32.dwSize = sizeof(pe32);

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE) {
        printf("CreateToolhelp32Snapshot 失敗,錯誤碼:%lu\n", GetLastError());
        return 1;
    }

    printf("%-20s %10s\n", "進程名", "PID");
    printf("==============================\n");

    BOOL bMore = Process32First(hSnap, &pe32);
    int count = 0;
    while (bMore) {
        printf("%-20s %10u\n", pe32.szExeFile, pe32.th32ProcessID);
        ++count;
        bMore = Process32Next(hSnap, &pe32);
    }

    printf("\n共枚舉到 %d 個進程。\n", count);
    CloseHandle(hSnap);
    return 0;
}

關鍵點解析

  • 結構體初始化:pe32.dwSize = sizeof(pe32) 必須在呼叫 Process32First 前完成,否則 API 會拒絕服務。
  • 錯誤處理:檢查 INVALID_HANDLE_VALUE 並呼叫 GetLastError() 取得詳細錯誤碼。
  • 資源釋放:迴圈結束後務必 CloseHandle(hSnap),避免句柄洩漏。

方案二:使用 PSAPI 的 EnumProcesses 介面

EnumProcesses 直接回傳所有進程 ID 陣列,再以 OpenProcess 取得句柄,配合 EnumProcessModules/GetModuleFileNameEx 可獲取完整路徑。此法需連結 psapi.lib(或透過 #pragma comment(lib, "psapi.lib"))。

核心程式碼

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#pragma comment(lib, "psapi.lib")

BOOL EnableDebugPrivilege() {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp = {1, {{0}, SE_PRIVILEGE_ENABLED}};
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
        return FALSE;
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
    BOOL ok = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
    CloseHandle(hToken);
    return ok;
}

int main() {
    EnableDebugPrivilege(); // 取得查詢系統進程所需權限

    DWORD pids[1024], cbNeeded, count;
    if (!EnumProcesses(pids, sizeof(pids), &cbNeeded)) {
        printf("EnumProcesses 失敗:%lu\n", GetLastError());
        return 1;
    }
    count = cbNeeded / sizeof(DWORD);

    for (DWORD i = 0; i < count; ++i) {
        HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pids[i]);
        if (!hProc) {
            printf("PID %5u : 無法開啟(權限不足)\n", pids[i]);
            continue;
        }

        HMODULE hMod;
        DWORD cbMod;
        char path[MAX_PATH] = {0};
        if (EnumProcessModules(hProc, &hMod, sizeof(hMod), &cbMod))
            GetModuleFileNameExA(hProc, hMod, path, MAX_PATH);

        printf("PID %5u : %s\n", pids[i], path[0] ? path : "(無法取得路徑)");
        CloseHandle(hProc);
    }
    return 0;
}

權限提升細節

系統進程(如 csrss.exe、services.exe)預設拒絕一般權限的 OpenProcess。範例中的 EnableDebugPrivilege() 會為當前執行緒加上 SE_DEBUG_NAME 特權,讓後續呼叫能穿透大多數防護。實務上建議僅在必要時啟用,用畢即以 AdjustTokenPrivileges 關閉。

進階主題:枚舉指定進程的模組(DLL)

若需列出某進程載入的所有模組,可使用 CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid) 搭配 Module32First/Module32Next。以下為簡化版封裝函式:

int ListModules(DWORD pid) {
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
    if (hSnap == INVALID_HANDLE_VALUE) return 1;

    MODULEENTRY32 me = {0};
    me.dwSize = sizeof(me);

    if (Module32First(hSnap, &me)) {
        do {
            printf("%-30s %s\n", me.szModule, me.szExePath);
        } while (Module32Next(hSnap, &me));
    }
    CloseHandle(hSnap);
    return 0;
}

進程終止:ExitProcess vs TerminateProcess

API適用場景特性
ExitProcess當前進程正常退出會執行 DLL 的 DLL_PROCESS_DETACH、釋放資源、刷新 I/O 緩衝區
TerminateProcess強制結束任意進程(需權限)立即終止,**不**執行清理程式碼,可能導致資料遺失或資源洩漏

編寫管理工具時,優先嘗試發送 WM_CLOSE 或呼叫 ExitProcess(若為自身);唯有進程無回應時才退而求其次使用 TerminateProcess。

總結與建議

  • Toolhelp32:API 簡潔、無額外依賴、適合快速原型與輕量工具。
  • PSAPI:功能更豐富(可取得模組完整路徑、記憶體計數器等),適合需深度診斷的場景。
  • 無論選哪套,**務必檢查回傳值、妥善關閉句柄、注意權限提升的安全性**。

掌握這兩套機制,即可在 C/C++ 中靈活實作進程監控、診斷與管理功能,為後續開發系統級工具打下堅實基礎。

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