getfileinformationbyhandle 查不到锁文件的进程,因为它仅返回文件元数据,不包含持有句柄的pid;需通过系统句柄表反查,如用handle.exe枚举或调用ntquerysysteminformation手动扫描。

为什么 GetFileInformationByHandle 查不到锁文件的进程?
因为 Windows 内核不直接暴露“谁锁了这个文件”——锁是进程在句柄级别持有的,而句柄信息不跨进程可见。你调用 GetFileInformationByHandle 只能得到文件元数据(如 dwVolumeSerialNumber、nFileIndexLow),它压根不返回持有者 PID。
真正能定位到进程的,是内核对象视图:每个打开/锁定文件的句柄,本质是某个进程对 File 对象的引用。必须从系统全局句柄表反向查起。
用 handle.exe 快速定位(Sysinternals 方案)
这是最实用、无需编码的进阶手段。微软官方认可的 handle.exe(来自 Sysinternals 套件)能枚举所有进程的句柄,并支持模糊匹配路径或文件名。
- 下载
handle.exe(注意选 x64 或 x86 匹配你的目标进程架构) - 以管理员权限运行:
handle.exe -a "C:\path\to\locked.txt" - 输出类似:
notepad.exe pid: 1234 420: C:\path\to\locked.txt—— 其中420是句柄值,1234就是 PID - 若文件被多个进程打开,会列出全部;加
-u可显示用户名,-p可按 PID 过滤
注意:handle.exe 依赖 NtQuerySystemInformation 的 SystemHandleInformation 类,Win10 1809+ 默认禁用该接口(出于安全考虑),需临时启用策略或改用 handle64.exe + 管理员权限。
C++ 调用 NtQuerySystemInformation 手动扫描(高风险但可控)
自己写代码绕过 handle.exe 限制是可行的,但属于未公开 API 使用,稳定性取决于 Windows 版本和补丁级别。核心步骤是:
- 用
OpenProcess枚举所有活跃进程(需PROCESS_QUERY_INFORMATION权限) - 对每个进程调用
NtQuerySystemInformation(SystemHandleInformation, ...)获取其句柄表快照 - 遍历每个句柄,用
NtDuplicateObject复制为当前进程可读的句柄,再用GetFinalPathNameByHandle解析路径 - 比对路径字符串是否匹配目标文件(注意 NT 对象路径如
\Device\HarddiskVolume1\path\file.txt需标准化)
关键坑:NtQuerySystemInformation 返回的 SYSTEM_HANDLE_TABLE_ENTRY_INFO 中的 ObjectTypeNumber 必须是 28(FILE 类型),否则跳过;且复制句柄后必须立即 CloseHandle,否则句柄泄漏。
为什么不用 CreateFile + ERROR_SHARING_VIOLATION 反推进程?
很多人想靠“尝试打开失败 → 推断谁占着”,这不可靠。原因有三:
-
CreateFile失败只说明共享模式冲突,不等于文件被独占打开(比如对方用FILE_SHARE_READ打开,你却请求GENERIC_WRITE,也会报错) - 错误码
ERROR_SHARING_VIOLATION和ERROR_ACCESS_DENIED容易混淆,后者可能是权限问题而非占用 - 即使确认被占用,也无法知道是哪个 PID —— Windows 不提供“上一个打开者”的元数据
所以,靠错误码做进程定位是徒劳的;真要自动化,必须走句柄表或 WMI(Win32_Process + CIM_DataFile 关联)路线,但 WMI 性能差、延迟高、且不保证实时反映句柄状态。
真正的难点不在怎么查,而在查到之后要不要杀进程——很多系统服务(如 Windows Search、OneDrive、防病毒软件)会静默持有句柄,强行终止可能引发蓝屏或数据损坏。别急着 TerminateProcess。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











