Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 异步调用ReadDirectoryChangesW的完成例程_Python_Python 2.7_Winapi_Ctypes - Fatal编程技术网

Python 异步调用ReadDirectoryChangesW的完成例程

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

我试图使用python中的
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()