Ошибка Python ctypes — TypeError: требуется целое число (получен тип LP_c_long)

#python #ctypes

#python #ctypes

Вопрос:

Я пытаюсь поиграть с Python и ctypes, экспериментируя с некоторыми API-интерфейсами Windows. У меня есть фрагмент кода, который терпит неудачу, и я не уверен, почему. Я установил все типы аргументов и возвращаемые типы в соответствии с документацией MSDN. Ошибка, которую я получаю, такова: TypeError: an integer is required (got type LP_c_long) . Вы можете увидеть все ошибки в разделе вывода. Дело в том, что, насколько я могу судить, типы аргументов и возвращаемые типы верны, и я не уверен, что нужно исправить.

 from ctypes import *
from ctypes import wintypes as w

user32 = windll.user32
kernel32 = windll.kernel32

HOOKPROC = WINFUNCTYPE(HRESULT, c_int, w.WPARAM, w.LPARAM)  # Callback function prototype

user32.SetWindowsHookExW.argtypes = [c_int, HOOKPROC, w.HINSTANCE, w.DWORD]
user32.SetWindowsHookExW.restype = w.HHOOK
   
kernel32.GetModuleHandleW.argtypes = [w.LPCWSTR]
kernel32.GetModuleHandleW.restype = w.HANDLE

user32.GetMessageW.argtypes = [w.LPMSG, w.HWND, w.UINT, w.UINT]
user32.GetMessageW.restype = w.BOOL

user32.CallNextHookEx.argtypes = [w.HHOOK, c_int, w.WPARAM, w.LPARAM]
user32.CallNextHookEx.restype = w.LPLONG

def hook_procedure(nCode, wParam, lParam):
   print("Hello...")
   #return user32.CallNextHookEx(hook, nCode, wParam, lParam)
   return user32.CallNextHookEx(hook, nCode, wParam, c_lParam)
   
ptr = HOOKPROC(hook_procedure)
        
hook = user32.SetWindowsHookExW(
    13,
    ptr,
    kernel32.GetModuleHandleW(None),
    0
)

msg = w.MSG()                             # MSG data structure
user32.GetMessageW(byref(msg), 0, 0, 0) # Wait for messages to be posted


 

Выходной сигнал:

 Hello...
Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 262, in 'converting callback result'
TypeError: an integer is required (got type LP_c_long)
Exception ignored in: <function hook_procedure at 0x0000025C469551F0>
 

Ответ №1:

Проблема здесь:

 user32.CallNextHookEx.restype = w.LPLONG
 

CallnextHookEx возвращает an LRESULT , который в C определяется как a LONG_PTR . Это не указатель, а целое число размером с указатель (4 байта в 32-разрядных системах, 8 байт в 64-разрядных системах). wintypes не имеет этого типа, но LPARAM имеет то же определение (LONG_PTR), поэтому вы можете использовать следующее для определения, которое будет работать на 32- и 64-разрядном Python:

 from ctypes import wintypes as w
LRESULT = w.LPARAM
...
user32.CallNextHookEx.restype = LRESULT
 

Комментарии:

1. Ну ладно. Я просто предположил, что все, что имеет PTR в названии, является указателем.

2. @user1720897 Неправильное присвоение имен со стороны Windows при переходе с 32-разрядной на 64-разрядную ОС. LPLONG является ДЛИННЫМ указателем. LONG_PTR является ДЛИНОЙ того же размера, что и указатель. Только что добавленные Win32 API, в которых целые числа должны были увеличиваться на 64-разрядной _PTR версии (например, INT_PTR, LONG_PTR, DWORD_PTR). они будут составлять 4 байта в 32-разрядной Windows и 8 байт в 64-разрядной Windows.