Windows 不直接提供「進程 CPU %」API。標準做法:
Process_CPU_% = ( (Proc_T2 - Proc_T1) / (Sys_T2 - Sys_T1) ) * 100%typedef struct _THREAD_INFO {
LARGE_INTEGER CreateTime;
DWORD dwUnknown1;
DWORD dwStartAddress;
DWORD StartEIP;
DWORD dwOwnerPID;
DWORD dwThreadId;
DWORD dwCurrentPriority;
DWORD dwBasePriority;
DWORD dwContextSwitches;
DWORD Unknown;
DWORD WaitReason;
} THREADINFO, *PTHREADINFO;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaxLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef struct _PROCESS_INFO {
DWORD dwOffset; // 到下一個 PROCESS_INFO 的偏移
DWORD dwThreadsCount;
DWORD dwUnused1[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime; // 用戶態 CPU 時間 (100ns)
LARGE_INTEGER KernelTime; // 核心態 CPU 時間 (100ns)
UNICODE_STRING ProcessName;
DWORD dwBasePriority;
DWORD dwProcessID;
DWORD dwParentProcessId;
DWORD dwHandleCount;
DWORD dwUnused3[2];
DWORD dwVirtualBytesPeak;
DWORD dwVirtualBytes;
ULONG dwPageFaults;
DWORD dwWorkingSetPeak;
DWORD dwWorkingSet;
DWORD dwQuotaPeakPagedPoolUsage;
DWORD dwQuotaPagedPoolUsage;
DWORD dwQuotaPeakNonPagedPoolUsage;
DWORD dwQuotaNonPagedPoolUsage;
DWORD dwPageFileUsage;
DWORD dwPageFileUsagePeak;
DWORD dCommitCharge;
THREADINFO ThreadSysInfo[1]; // 變長數組
} PROCESSINFO, *PPROCESSINFO;
| 方法 | API | 優點 | 缺點 |
|---|---|---|---|
| 文檔化 API | OpenProcess + GetProcessTimes | 穩定、有簽名、支援遠程進程 | 需 PROCESS_QUERY_LIMITED_INFORMATION 權限;頻繁調用開銷大 |
| 系統信息類 | NtQuerySystemInformation(SystemProcessInformation, ...) | 一次調用獲取**所有進程/線程**完整信息,極快 | 非公開 API (但極穩定)、需動態載入 ntdll、結構體對齊敏感 |
#include
#include // 需 Windows SDK 10+ 或自行定義上述結構
#pragma comment(lib, "ntdll.lib")
typedef NTSTATUS (NTAPI *PNtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
double GetProcessCpuPercent(DWORD pid) {
static PNtQuerySystemInformation pNtQSI = nullptr;
if (!pNtQSI) pNtQSI = (PNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");
// 兩次採樣
auto snap = [&](ULONGLONG& procTime, ULONGLONG& sysTime) {
ULONG len = 0; pNtQSI(SystemProcessInformation, nullptr, 0, &len);
std::vector buf(len);
pNtQSI(SystemProcessInformation, buf.data(), len, &len);
ULONGLONG totalSys = 0;
PPROCESSINFO p = (PPROCESSINFO)buf.data();
while (true) {
ULONGLONG ut = p->UserTime.QuadPart;
ULONGLONG kt = p->KernelTime.QuadPart;
totalSys += ut + kt; // 累加所有進程時間 = 系統總 CPU 時間
if (p->dwProcessID == pid) {
procTime = ut + kt;
}
if (p->dwOffset == 0) break;
p = (PPROCESSINFO)((BYTE*)p + p->dwOffset);
}
sysTime = totalSys;
};
ULONGLONG proc1, sys1, proc2, sys2;
snap(proc1, sys1);
Sleep(500); // 採樣間隔
snap(proc2, sys2);
ULONGLONG dProc = proc2 - proc1;
ULONGLONG dSys = sys2 - sys1;
if (dSys == 0) return 0.0;
return (double)dProc / dSys * 100.0; // 已包含多核心 (系統總時間 = 核心數 * 實時)
}
GetSystemInfo / GetLogicalProcessorInformation)。NtQuerySystemInformation 可能較慢,建議啟動時預熱一次。PdhAddCounter("\\Process(*)\\% Processor Time") 封裝好但延遲較大;WMI Win32_PerfFormattedData_PerfProc_Process 適合腳本/低頻查詢。掌握 NtQuerySystemInformation + 時間差分算法,即可在 C++ 中以極低開銷實現即時、準確的進程 CPU 監控,適用於任務管理器、性能分析器、資源限制守護進程等場景。