首页 > 解决方案 > Python ctypes API 调用导致访问冲突

问题描述

我正在尝试使用 ctypes 在 python 中使用 FindFirstFileW 和 FindNextFileW 列出一个目录。FindFirstFileW 成功但 FindNextFileW 或 FindClose 导致 OSError: 异常:访问冲突写入 0xFFFFFFFFB8093F80

这是代码:

def assert_success(success):
    if not success:
        raise AssertionError(FormatError())

def assert_handle(handle):
    if handle == INVALID_HANDLE_VALUE:
        raise AssertionError(FormatError())
    

def FindFirstFileW(lpFileName):
    wfd = WIN32_FIND_DATAW()
    handle = windll.kernel32.FindFirstFileW(lpFileName, byref(wfd))
    assert_handle(handle)
    return handle, wfd

def FindNextFileW(handle):
    wfd = WIN32_FIND_DATAW()
    success = windll.kernel32.FindNextFileW(handle, byref(wfd))
    assert_success(success)
    return wfd

def FindClose(handle):
    success = windll.kernel32.FindClose(handle)
    assert_success(success)
    return success

handle, wfd = FindFirstFileW('C:\\Windows\\*')
print(wfd.cFileName)
wfd = FindNextFileW(handle)
print(wfd.cFileName)
FindClose(handle)

标签: pythonwindowsapictypes

解决方案


您尚未对正在使用的功能进行适当的 .argtypes设置。假设返回值是例如,但句柄在 64 位 Python 上是 64 位的,并且被截断为 32 位。此外,您还可以获得类型检查调用的额外好处,因为您知道参数类型应该是什么。.restypectypesc_intctypes

还建议.errcheck自动检查返回值:

尝试这个:

from ctypes import *
from ctypes import wintypes as w

INVALID_HANDLE_VALUE = w.HANDLE(-1).value
ERROR_NO_MORE_FILES = 18

def boolcheck(result,func,args):
    if not result:
        raise WinError(get_last_error())
    return None

# return True if more files
# return False if no more files
# raise exception for other reasons
def nomorecheck(result,func,args):
    if not result and get_last_error() != ERROR_NO_MORE_FILES:
        raise WinError(get_last_error())
    return result

def handlecheck(result,func,args):
    if result == INVALID_HANDLE_VALUE:
        raise WinError(get_last_error())
    return result

dll = WinDLL('kernel32',use_last_error=True)
dll.FindFirstFileW.argtypes = w.LPCWSTR,w.LPWIN32_FIND_DATAW
dll.FindFirstFileW.restype = w.HANDLE
dll.FindFirstFileW.errcheck = handlecheck
dll.FindNextFileW.argtypes = w.HANDLE,w.LPWIN32_FIND_DATAW
dll.FindNextFileW.restype = w.BOOL
dll.FindClose.errcheck = nomorecheck
dll.FindClose.argtypes = w.HANDLE,
dll.FindClose.restype = w.BOOL
dll.FindClose.errcheck = boolcheck

def find_files(directory):
    wfd = w.WIN32_FIND_DATAW()
    handle = dll.FindFirstFileW(directory, byref(wfd))
    yield wfd.cFileName
    while dll.FindNextFileW(handle, byref(wfd)):
        yield wfd.cFileName
    dll.FindClose(handle)

for file in find_files(r'c:\windows\*'):
    print(file)

推荐阅读