#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.