我不知道你想找到这两个的:
但无论哪种方式,答案都是类似的。
显然这是可行的,或者那些工具不能这样做,对吧?不幸的是,Python stdlib中没有任何东西可以提供帮助。你是怎么做到的?
您将需要访问Windows API功能 - 通过pywin32
,或其他。
有两种方法可以解决这个问题。第一种方法是使用NT内核对象API,这非常困难,而且只有在需要使用非常旧版本的Windows时才真正需要。第二个,NtQuerySystemInformation
,是你可能想要的。
细节非常复杂(并没有很好的记录),但他们解释in a CodeProject sample program和on the Sysinternals forums。
如果你不理解这些页面上的代码,或者如何从Python调用它,那么你真的不应该这样做。如果你了解要点,但有疑问或陷入困境,当然你可以在这里寻求帮助(或者在sysinternals论坛或其他地方)。
但是,即使你已经使用for Windows之前,还有你可能不知道几点需要注意一下:
许多功能要么不记录,或文档没有告诉你哪些DLL找到他们。他们都将在ntdll
或kernel32
;但在某些情况下,NtFooBar
文档名称只是真实ZwFooBar
函数的别名,因此如果在任一DLL中找不到NtFooBar
,请查找ZwFooBar
。
至少在旧版本的Windows,ZwQuerySystemInformation
不作为你所期望的:你不能用一个0 SystemInformationLength
调用它,检查ReturnLength
,分配该大小的缓冲区,然后再试一次。你可以做的唯一的事情是从一个有足够空间的缓冲区开始,例如8个句柄,尝试一下,看看你是否得到一个错误STATUS_INFO_LENGTH_MISMATCH,增加这个数字8,然后再试一次,直到它成功(或者失败并产生一个不同的错误)。该代码看起来是这样的(假设你已经定义了SYSTEM_HANDLE
结构):
STATUS_INFO_LENGTH_MISMATCH = 0xc0000004
i = 8
while True:
class SYSTEM_HANDLE_INFORMATION(Structure):
_fields_ = [('HandleCount', c_ulong),
('Handles', SYSTEM_HANDLE * i)]
buf = SYSTEM_HANDLE_INFORMATION()
return_length = sizeof(buf)
rc = ntdll.ZwQuerySystemInformation(SystemHandleInformation,
buf, sizeof(buf),
byref(return_length))
if rc == STATUS_INFO_LENGTH_MISMATCH:
i += 8
continue
elif rc == 0:
return buf.Handles[:buf.HandleCount]
else:
raise SomeKindOfError(rc)
最后,该文件并没有真正解释任何地方,但你知道一个HANDLE获得的方式是一个文件到一个路径名是有点复杂。只需使用NtQueryObject(ObjectNameInformation)
就会返回内核对象空间路径名,然后您必须将其映射到DOS路径名,可能为UNC的普通NT路径名或\?\路径名。当然,第一个不能在没有映射盘符的网络驱动器上工作;前两种都不适用于路径很长的文件。
当然还有一个更简单的选择:只要开handle
,Unlocker
,或通过subprocess
其他一些命令行工具。
或者介于两者之间,建立上面链接CodeProject上的项目,只是通过打开它的DLL并调用其GetOpenedFiles
方法,它会做的辛勤工作为您服务。
由于该项目构建了一个正常的WinDLL样式的DLL,因此可以使用正常的方式调用它。如果您从未使用,文档中的示例显示您几乎需要知道的所有内容,但我会给出一些伪代码来帮助您开始。
首先,我们需要为您要编写的回调函数创建一个OF_CALLBACK
类型,如Callback functions中所述。由于OF_CALLBACK
的原型是在.h文件中定义的,我无法到达这里,我只是在猜测它。你必须看看真实的版本并自己翻译。但是,你的代码将是这个样子:
from ctypes import windll, c_int, WINFUNCTYPE
from ctypes.wintypes import LPCWSTR, UINT_PTR, HANDLE
# assuming int (* OF_CALLBACK)(int, HANDLE, int, LPCWSTR, UINT_PTR)
OF_CALLBACK = WINFUNCTYPE(c_int, HANDLE, c_int, LPWCSTR, UINT_PTR)
def my_callback(handle, namelen, name, context):
# do whatever you want with each handle, and whatever other args you get
my_of_callback = OF_CALLBACK(my_callback)
OpenFileFinder = windll.OpenFileFinder
# Might be GetOpenedFilesW, as with most Microsoft DLLs, as explained in docs
OpenFileFinder.GetOpenedFiles.argtypes = (LPCWSTR, c_int, OF_CALLBACK, UINT_PTR)
OpenFileFinder.GetOpenedFiles.restype = None
OpenFileFinder.GetOpenedFiles(ru'C:\Path\To\File\To\Check.txt', 0, my_of_callback, None)
这很可能是你在回调得到什么实际是指向某种结构,或者你将不得不define-结构列表可能与您直接拨打Nt/Zw功能所需的SYSTEM_HANDLE
相同。因此,让我举个例子 - 如果您在回拨中取回SYSTEM_HANDLE *
而不是HANDLE
,那么它就像这样简单:
class SYSTEM_HANDLE(Structure):
_fields_ = [('dwProcessId', DWORD),
('bObjectType', BYTE),
('bFlags', BYTE),
('wValue', WORD),
('pAddress', PVOID),
('GrantedAccess', DWORD)]
# assuming int (* OF_CALLBACK)(int, SYSTEM_HANDLE *, int, LPCWSTR, UINT_PTR)
OF_CALLBACK = WINFUNCTYPE(c_int, POINTER(SYSTEM_HANDLE), c_int, LPWCSTR, UINT_PTR)
是否有打开文件的.filename.swp文件? – Matt
@Matt:不,没有。 – abarnert
@Matt:只有VIM才能打开文件。 – nneonneo