Python 异步调用ReadDirectoryChangesW的完成例程
我试图使用python中的Python 异步调用ReadDirectoryChangesW的完成例程,python,python-2.7,winapi,ctypes,Python,Python 2.7,Winapi,Ctypes,我试图使用python中的ReadDirectoryChangesW(带完成例程的异步模式) 在我的发言之后,我了解到必须提供重叠结构和回拨 该文档中对回调的描述如下: VOID CALLBACK FileIOCompletionRoutine( _In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped ); 因此,我将ctypes
ReadDirectoryChangesW
(带完成例程的异步模式)
在我的发言之后,我了解到必须提供重叠结构和回拨
该文档中对回调的描述如下:
VOID CALLBACK FileIOCompletionRoutine(
_In_ DWORD dwErrorCode,
_In_ DWORD dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped
);
因此,我将ctypes
WINFUNCTYPE工厂实例化为:
RDCW_CALLBACK_F = ctypes.WINFUNCTYPE(None, ctypes.wintypes.DWORD, ctypes.wintypes.DWORD, ctypes.POINTER(OVERLAPPED))
并尝试访问FileIOCompletionRoutine
call:
ReadDirectoryChangesW = ctypes.windll.kernel32.ReadDirectoryChangesW
ReadDirectoryChangesW.restype = ctypes.wintypes.BOOL
ReadDirectoryChangesW.errcheck = _errcheck_bool
ReadDirectoryChangesW.argtypes = (
ctypes.wintypes.HANDLE, # hDirectory
LPVOID, # lpBuffer
ctypes.wintypes.DWORD, # nBufferLength
ctypes.wintypes.BOOL, # bWatchSubtree
ctypes.wintypes.DWORD, # dwNotifyFilter
ctypes.POINTER(ctypes.wintypes.DWORD), # lpBytesReturned
ctypes.POINTER(OVERLAPPED), # lpOverlapped
RDCW_CALLBACK_F # FileIOCompletionRoutine # lpCompletionRoutine
)
请注意,如果我尝试使用FileIOCompletionRoutine
作为同步调用(将None
传递给它的最后两个参数),它会工作
当我试图通过完成例行程序时,问题出现了:
#Routine implementation
def dir_change_callback(dwErrorCode,dwNumberOfBytesTransfered,p):
print("dir_change_callback!")
#Get WINFUNC from factory
call2pass = RDCW_CALLBACK_F(dir_change_callback)
try:
event_buffer = ctypes.create_string_buffer(BUFFER_SIZE)
nbytes = ctypes.wintypes.DWORD()
overlapped_read_dir = OVERLAPPED()
ReadDirectoryChangesW(handle, ctypes.byref(event_buffer),
len(event_buffer), recursive,
WATCHDOG_FILE_NOTIFY_FLAGS,
ctypes.byref(nbytes),
ctypes.byref(overlapped_read_dir), call2pass)
该调用可以工作,如果我在程序执行期间不在受监视的目录中执行更改,它将运行而不会崩溃。
但是,如果发生更改,程序将崩溃:
hand = get_directory_handle(os.path.abspath("/test/"))
read_directory_changes(hand, False)
time.sleep(10)
事故报告
Nombre del evento de problema (Problem event name): APPCRASH
Nombre de la aplicación (Application Name): python.exe
Nombre del módulo con errores (Module name): ntdll.dll
Versión del módulo con errores (Module version): 6.1.7601.18247
Código de excepción (Exception code): c0000005
Desplazamiento de excepción (Exception offset): 000337a2
Versión del sistema operativo (OS Version): 6.1.7601.2.1.0.256.48
我认为当WinApi试图调用回调代码时会出现问题,因此我怀疑我没有正确构建传递给调用的WINFUNC
另一方面,我在python上发现了以下警告:
注意:请确保尽可能长地保留对CFUNCTYPE()对象的引用
它们是从C代码中使用的。ctypes没有,如果你没有,它们可能会
被垃圾收集,当进行回调时程序崩溃
但我保留了对可调用的全局引用,因此,除非我错了,否则我认为这不是问题所在
您是否曾经调用过kernel32
windows调用来传递用python实现的回调?我试着这样做对吗
编辑
我刚刚弄清楚是什么导致了崩溃:event\u buffer
不是全局的,它是在回调开始之前收集的。
虽然使其成为全局修复了崩溃,但进程终端中没有打印消息“dir\u change\u callback!”。我试图从回调创建一个新文件并向其写入一些消息,但结果仍然是一样的:这就像回调没有被执行一样。这很奇怪,因为上面描述的崩溃应该与回调执行相关联
c类型
文档说明:
另外,请注意,如果在创建的线程中调用回调函数
在Python的控制之外(例如,由调用
回调),ctypes在每个
调用。这种行为在大多数情况下都是正确的,但它意味着
使用threading.local存储的值将无法跨
不同的回调,即使这些调用来自同一个C
线
作为ctypes
的新手,我知道这个虚拟线程是执行系统调用的进程的线程,可能在执行调用之前该进程就被终止了。
这个问题似乎支持这个观点。我试图在我的代码中重现该问题锁定方案,但锁定仍保持解锁状态,就像试图打印的版本一样:回调似乎没有执行:
lck = threading.Lock()
lck.acquire()
def dir_change_callback(dwErrorCode,dwNumberOfBytesTransfered,p):
lck.release()