You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C语言枚举Windows全量进程(含用户进程)及资源统计问题

解决Windows下C语言枚举所有进程资源使用的问题

我之前做类似需求时也踩过同样的坑,你遇到的“无法获取非系统进程”的问题,90%以上是权限不足导致的——毕竟Windows的进程权限模型比Linux要严格得多,普通用户权限根本碰不到其他用户的进程、系统服务进程这类资源。下面给你几个具体的解决思路,亲测有效:

1. 先给程序加上管理员权限

这是最常见的原因,很多用户进程(比如其他用户启动的程序、系统后台服务)只有管理员权限才能打开访问。你可以先右键以“管理员身份运行”你的测试程序,如果能正常获取到那些进程的信息,那就是权限的问题。

要让程序默认请求管理员权限,可以给它添加UAC清单:在项目里新建一个manifest文件,内容如下,然后编译时链接进去:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

2. 检查OpenProcess的权限参数是否正确

你调用OpenProcess时,传递的权限掩码可能不够。要获取进程的时间、资源使用情况,至少需要PROCESS_QUERY_LIMITED_INFORMATION(Windows Vista及以后推荐使用,比PROCESS_QUERY_INFORMATION更安全)或者PROCESS_QUERY_INFORMATION权限。

如果还要获取内存、线程等其他资源,可能需要额外添加PROCESS_VM_READ、PROCESS_QUERY_INFORMATION等权限。比如正确的调用方式:

HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);

每次调用OpenProcess失败后,一定要用GetLastError()查看错误码:如果是ERROR_ACCESS_DENIED,那就是权限问题;如果是ERROR_INVALID_PARAMETER,可能是PID无效或者系统不支持该权限。

3. 换用CreateToolhelp32Snapshot枚举进程

EnumProcesses虽然简单,但有时候会漏掉一些进程,或者获取的信息不全。CreateToolhelp32Snapshot是更可靠的枚举方式,能拿到进程的名称、PID、父进程ID等更多元数据,配合Process32First/Process32Next遍历,基本不会漏掉进程。

我给你写了个极简的示例代码,涵盖枚举+获取进程时间的逻辑:

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

void GetProcessResourceInfo(DWORD pid) {
    HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    if (!hProc) {
        printf("PID %d: 无法打开进程,错误码: %d\n", pid, GetLastError());
        return;
    }

    FILETIME createTime, exitTime, kernelTime, userTime;
    if (GetProcessTimes(hProc, &createTime, &exitTime, &kernelTime, &userTime)) {
        // 这里可以把FILETIME转换成可读格式,比如用FileTimeToSystemTime
        printf("PID %d: 内核态时间/用户态时间获取成功\n", pid);
    } else {
        printf("PID %d: 获取进程时间失败,错误码: %d\n", pid, GetLastError());
    }

    CloseHandle(hProc);
}

int main() {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        printf("创建进程快照失败,错误码: %d\n", GetLastError());
        return 1;
    }

    PROCESSENTRY32 pe = {0};
    pe.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnapshot, &pe)) {
        printf("遍历第一个进程失败,错误码: %d\n", GetLastError());
        CloseHandle(hSnapshot);
        return 1;
    }

    do {
        printf("进程名称: %s | PID: %d\n", pe.szExeFile, pe.th32ProcessID);
        GetProcessResourceInfo(pe.th32ProcessID);
        printf("-------------------------\n");
    } while (Process32Next(hSnapshot, &pe));

    CloseHandle(hSnapshot);
    return 0;
}

4. 处理32位/64位兼容性问题

如果你的程序是32位的,在64位Windows系统上枚举64位进程可能会出现权限问题或者枚举不全的情况。这种情况下,建议直接编译成64位程序,或者调用Wow64相关的API(比如Wow64DisableWow64FsRedirection)来兼容,但前者是更简单的解决方案。

最后补充

如果还是有部分进程无法访问,大概率是系统的受保护进程(比如Windows的核心进程、带防篡改的安全软件进程),这类进程即使是管理员权限也无法打开,除非你拥有系统级调试权限或者驱动级权限——但一般统计用户进程和普通系统进程的需求,前面的方法完全足够。

内容的提问来源于stack exchange,提问作者roee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 07:27:44