getfileinformationbyhandle无法获取其他进程锁定的文件句柄,因为句柄是进程私有资源;需以管理员权限调用ntquerysysteminformation枚举系统句柄,筛选目标进程的file对象并复制句柄获取路径。

为什么 GetFileInformationByHandle 拿不到被其他进程锁定的文件句柄
因为 Windows 的句柄是进程私有的,你自己的进程没打开那个文件,就根本不存在对应句柄——GetFileInformationByHandle 只能查自己持有的句柄。想查别人锁了什么,得绕过句柄本身,从系统级资源视图切入。
核心路径是:枚举系统所有打开的文件对象 → 筛出目标进程 → 提取其打开的文件路径和锁状态。这需要内核调试符号支持和 SeDebugPrivilege 权限,普通用户模式代码做不到。
- 必须以管理员权限运行程序,否则
NtQuerySystemInformation会返回STATUS_ACCESS_DENIED - 不能依赖
FindFirstFile或CreateFile,它们只作用于路径,不反映句柄级独占锁(比如CREATE_ALWAYS+FILE_SHARE_NONE) -
Process Hacker、Handle(Sysinternals)底层用的正是SystemHandleInformation类接口,不是 Win32 API
用 NtQuerySystemInformation 枚举进程句柄的真实步骤
这是目前最可行的方案,但要注意:它不是公开 Win32 API,需手动加载 ntdll.dll 并解析函数指针;结构体定义在 WDK 头文件里,需自行声明或抄录。
- 调用
NtQuerySystemInformation两次:第一次获取缓冲区大小,第二次读取全部句柄信息(SystemHandleInformation类型) - 遍历返回的
SYSTEM_HANDLE_INFORMATION数组,过滤ProcessId == 目标PID且ObjectTypeNumber == 28(对应File对象) - 对每个匹配句柄,调用
NtDuplicateObject在当前进程复制该句柄(需DUPLICATE_DUP_HANDLE+DUPLICATE_SAME_ACCESS),再用GetFinalPathNameByHandle获取路径 - 若复制失败(如权限不足或句柄已关闭),说明该句柄可能处于独占锁状态,但无法进一步判断锁类型(共享/排他/字节范围)
示例关键片段(省略错误检查):
NTSTATUS status = NtQuerySystemInformation(SystemHandleInformation, buffer, size, &retSize);
// …… 解析 buffer 中每个 SYSTEM_HANDLE_TABLE_ENTRY_INFO
if (entry.ProcessId == targetPid && entry.ObjectTypeNumber == 28) {
HANDLE dupHandle;
NtDuplicateObject(hTargetProc, (HANDLE)(ULONG_PTR)entry.HandleValue,
GetCurrentProcess(), &dupHandle, 0, 0, DUPLICATE_SAME_ACCESS);
WCHAR path[MAX_PATH];
GetFinalPathNameByHandle(dupHandle, path, MAX_PATH, FILE_NAME_NORMALIZED);
}
为什么 GetLockInformation 和 LockFileEx 都不适用
这两个函数操作的是当前进程已打开的句柄上的锁,不是“发现谁锁了某个路径”。即使你知道路径 C:.txt,调用 CreateFile 打开它时失败并返回 ERROR_SHARING_VIOLATION,你也只能确认“被锁”,无法知道是哪个进程、哪个句柄、锁了哪段范围。
-
LockFileEx必须传入本进程有效的文件句柄,对别人进程的锁完全不可见 -
GetLockInformation是 NT 内部函数,未导出,WinSDK 不提供声明,也不接受任意句柄输入 - 试图用
\.C:.txt这类设备路径绕过,会触发不同驱动层行为,且多数情况下仍因权限拒绝而失败
实际调试中最容易卡住的三个点
不是代码写不对,而是环境和认知偏差导致白忙活。
- 没启用
SeDebugPrivilege:即使管理员运行,也要显式调用OpenProcessToken+AdjustTokenPrivileges开启该权限,否则NtQuerySystemInformation返回空或截断数据 - 忽略句柄继承与跨会话限制:Windows 服务或 Session 0 中的进程(如 svchost)的句柄默认不可见,
NtQuerySystemInformation只返回当前会话可见的句柄 - 误把“可打开”当“无锁”:某些程序用
FILE_FLAG_NO_BUFFERING或直接发 IRP 锁定磁盘扇区,此时文件路径甚至不会出现在句柄列表中,Process Explorer也查不到
真要定位到字节级锁,得进内核调试器看 EPROCESS 的 ObjectTable 和具体 FILE_OBJECT 的 FsContext,那已经超出用户态程序能力边界了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











