NtQuerySystemInformation 返回 STATUS_INVALID_INFO_CLASS 主因是误用已禁用的 SystemHandleInformation(24),应改用 SystemExtendedHandleInformation(64)并动态加载、提权后两次调用获取 HandleCount 总数。
为什么
返回
直接调用
查询句柄总数时,最常见错误是用了已废弃或未公开的
(即
)。Windows 10 1809+ 和 Server 2019 起,该信息类默认被禁用,即使你正确声明了
结构体,也会触发
。这不是权限问题,也不是函数没导出——而是系统策略层面限制了该接口的直接使用。
真正可用且稳定的替代方案是:
(
),它返回带进程名的句柄列表,结构体更宽但兼容性好;或者改用
等间接方式(不推荐)。实战中应优先尝试
。
必须用
动态加载
,不能静态链接
调用前需启用
权限,否则部分进程句柄无法枚举(尤其是系统进程)
返回的
字段才是当前系统总句柄数,不是数组长度
如何安全获取
并统计总数
Windows SDK 不提供
定义,必须手动声明。注意:该结构体在不同 Windows 版本中字段对齐可能变化,不能直接按旧版
复用。
关键点在于两次调用模式:第一次传
获取所需缓冲区大小,第二次分配足够内存再调用。失败时检查
,而非直接报错退出。
立即学习
“
C++免费学习笔记(深入)
”;
C知道
CSDN推出的一款AI技术问答工具
下载
缓冲区大小建议初始分配 64KB,多数场景够用;若失败则按返回的
重新分配
字段位于结构体开头,类型为
,不是数组元素个数,而是系统级总计数
每个句柄条目(
)的
可用于过滤(如只算
或
类型)
用
只能查单个进程,别误当系统总数
是 Win32 API,只能返回**调用者自身进程**的句柄数(即当前程序打开了多少句柄),和系统全局句柄总数完全无关。很多开发者看到函数名里有 “HandleCount” 就以为是系统级接口,结果调试半天发现数值始终在几百徘徊——那只是你自己的进程。
它不需要提权,也不依赖 ntdll,但作用域严格限定为当前进程
返回值是
,但实际受进程句柄表限制(默认上限约 16,777,216,但极少达到)
若需监控多个进程句柄数,必须用
+
枚举匹配 PID 的条目,不能靠累加
权限、符号与调试器干扰的真实影响
即使代码逻辑完全正确,仍可能拿不到准确总数:一是权限不足导致跳过某些进程(如
、
),二是启用内核调试器(如 WinDbg 启用本地内核调试)会强制禁用
,此时返回
。
提权代码必须在调用前执行,且要确保
已启用(不是仅获取句柄)
用
命令在 WinDbg 中验证:若输出显示 “Scanning all processes...” 且无拒绝提示,说明权限到位
Release 模式下关闭所有调试器连接,否则某些 Windows 版本会静默降级信息类
句柄总数本身是个瞬时快照,没有原子性保证;如果你在循环中反复调用并观察到剧烈波动(比如 ±5000),大概率是其他进程正在批量创建/关闭句柄,而不是你的代码有问题。
NtQuerySystemInformationSTATUS_INVALID_INFO_CLASSNtQuerySystemInformationSystemHandleInformation24SYSTEM_HANDLE_INFORMATIONSTATUS_INVALID_INFO_CLASSSystemExtendedHandleInformation64SystemKernelDebuggerInformation64ntdll.dllNtQuerySystemInformationSE_DEBUG_PRIVILEGESystemExtendedHandleInformationNumberOfHandlesSYSTEM_HANDLE_INFORMATION_EXSYSTEM_HANDLE_INFORMATION_EXSYSTEM_HANDLE_INFORMATIONnullptrSTATUS_INFO_LENGTH_MISMATCH*ReturnLengthHandleCountULONGSYSTEM_HANDLE_TABLE_ENTRY_INFO_EXObjectTypeIndexFileEvent// 示例片段:获取总数(省略权限提升和错误处理)
ULONG size = 0;
NTSTATUS status = pNtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)64, nullptr, 0, &size);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
auto buf = std::make_unique(size);
status = pNtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)64, buf.get(), size, &size);
if (NT_SUCCESS(status)) {
auto info = reinterpret_cast(buf.get());
printf("Total handles: %lu\n", info->HandleCount); // 这就是你要的总数
}
} GetProcessHandleCountGetProcessHandleCountDWORDOpenProcessNtQuerySystemInformationsvchostlsassSystemExtendedHandleInformationSTATUS_ACCESS_DENIEDSeDebugPrivilege!handle