Вызов API ctypes на Python приводит к нарушению доступа

#python #windows #api #ctypes

#python #Windows #API #ctypes

Вопрос:

Я пытаюсь перечислить каталог с помощью FindFirstFileW и FindNextFileW в python с использованием ctypes. FindFirstFileW выполняется успешно, но FindNextFileW или FindClose приводят к ошибке: исключение: запись с нарушением доступа 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)
 

Ответ №1:

Вы не установили .argtypes и .restype соответствующим образом для используемых функций. ctypes предполагается, что возвращаемые значения являются c_int , например, но дескрипторы являются 64-разрядными в 64-разрядном Python и усекаются до 32 бит. Кроме того, вы получаете дополнительное преимущество проверки типов ваших вызовов, поскольку ctypes знаете, какими должны быть типы параметров.

Также рекомендуется .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)