GetRawInputData模块的pData参数如何填写

How do I fill in the pData parameter of the GetRawInputData module

我是 ctypes 的新手,我在使用 GetRawInputData 函数时遇到了问题。我不确定如何填写第三个参数。这是代码现在的样子

def get_raw_input(handle):
    dw_size = c_uint()
    GetRawInputData(handle, RID_INPUT, None, byref(dw_size), sizeof(RawInputHeader))
    lpb = LPBYTE(dw_size)
    print(lpb.contents)
    GetRawInputData(handle, RID_INPUT, lpb, byref(dw_size), sizeof(RawInputHeader))
    print(lpb.contents)
    return cast(lpb, POINTER(RawInput))

我是这样定义模块的:

GetRawInputData = user32.GetRawInputData
GetRawInputData.argtypes = INT, UINT, LPVOID, PUINT, UINT
GetRawInputData.restype = UINT
GetRawInputData.errcheck = errcheck

get_raw_input 为 运行 时,输出为以下之一:

c_byte(48)
c_byte(0)
c_byte(40)
c_byte(1)

有一些示例 C++ 代码 here,但我不确定在 Python.

中应该是什么样子

这是完整的 运行ning 代码(如果有点乱,请见谅):

window.py(运行s 的文件)

from ctypes import *
from ctypes.wintypes import *
from structures import *
from constants import *
from devices import get_raw_input, register_devices
import random
import sys


def errcheck(result,func,args):
    if result is None or result == 0:
        raise WinError(get_last_error())
    return result


user32 = WinDLL('user32', use_last_error=True)
k32 = WinDLL('kernel32', use_last_error=True)
gdi32 = WinDLL('gdi32',use_last_error=True)
RegisterClass = user32.RegisterClassW
RegisterClass.argtypes = POINTER(WndClass),
RegisterClass.restype = ATOM
RegisterClass.errcheck = errcheck
CreateWindowEx = user32.CreateWindowExW
CreateWindowEx.argtypes = DWORD, LPCWSTR, LPCWSTR, DWORD, INT, INT, INT, INT, HWND, HMENU, HINSTANCE, LPVOID
CreateWindowEx.restype = HWND
CreateWindowEx.errcheck = errcheck
GetModuleHandle = k32.GetModuleHandleW
GetModuleHandle.argtypes = LPCWSTR,
GetModuleHandle.restype = HMODULE
GetModuleHandle.errcheck = errcheck
DefWindowProc = user32.DefWindowProcW
DefWindowProc.argtypes = HWND, UINT, WPARAM, LPARAM
DefWindowProc.restype = LRESULT
ShowWindow = user32.ShowWindow
ShowWindow.argtypes = HWND, INT
ShowWindow.restype = BOOL
UpdateWindow = user32.UpdateWindow
UpdateWindow.argtypes = HWND,
UpdateWindow.restype = BOOL
UpdateWindow.errcheck = errcheck
BeginPaint = user32.BeginPaint
BeginPaint.argtypes = HWND, POINTER(PaintStruct)
BeginPaint.restype = HDC
BeginPaint.errcheck = errcheck
FillRect = user32.FillRect
FillRect.argtypes = HDC, POINTER(RECT), HBRUSH
FillRect.restype = INT
FillRect.errcheck = errcheck
EndPaint = user32.EndPaint
EndPaint.argtypes = HWND, POINTER(PaintStruct)
EndPaint.restype = BOOL
EndPaint.errcheck = errcheck
PostQuitMessage = user32.PostQuitMessage
PostQuitMessage.argtypes = INT,
PostQuitMessage.restype = None
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = POINTER(MSG),
TranslateMessage.restype = BOOL
DispatchMessage = user32.DispatchMessageW
DispatchMessage.argtypes = POINTER(MSG),
DispatchMessage.restype = LRESULT
GetClientRect = user32.GetClientRect
GetClientRect.argtypes = HWND, POINTER(RECT)
GetClientRect.restype = BOOL
GetClientRect.errcheck = errcheck
GetMessage = user32.GetMessageW
GetMessage.argtypes = POINTER(MSG), HWND, UINT, UINT
GetMessage.restype = BOOL
DrawText = user32.DrawTextW
DrawText.argtypes = HDC, LPCWSTR, INT, POINTER(RECT), UINT
DrawText.restype = LRESULT
LoadIcon = user32.LoadIconW
LoadIcon.argtypes = HINSTANCE, LPCWSTR
LoadIcon.restype = HICON
LoadIcon.errcheck = errcheck
LoadCursor = user32.LoadCursorW
LoadCursor.argtypes = HINSTANCE, LPCWSTR
LoadCursor.restype = HCURSOR
LoadCursor.errcheck = errcheck
GetStockObject = gdi32.GetStockObject
GetStockObject.argtypes = INT,
GetStockObject.restype = HGDIOBJ
CreateSolidBrush = gdi32.CreateSolidBrush
CreateSolidBrush.argtypes = COLORREF,
CreateSolidBrush.restype = HBRUSH
TextOut = gdi32.TextOutW
TextOut.argtypes = HDC, INT, INT, LPCWSTR, INT
TextOut.restype = INT
SetBkMode = gdi32.SetBkMode
SetBkMode.argtypes = HDC, INT
SetBkMode.restype = INT
SetTextColor = gdi32.SetTextColor
SetTextColor.argtypes = HDC, COLORREF
SetTextColor.restype = COLORREF


def window_callback(handle, message, w_param, l_param):
    ps = PaintStruct()
    rect = RECT()

    if message == WM_PAINT:
        hdc = BeginPaint(handle, byref(ps))
        GetClientRect(handle, byref(rect))

        SetBkMode(hdc, -1)
        SetTextColor(hdc, 0xFFFFFF)

        FillRect(hdc, byref(ps.rcPaint), CreateSolidBrush(0x0))
        DrawText(hdc, 'Testing oawguna', -1, byref(rect), DT_SINGLELINE|DT_CENTER|DT_VCENTER)

        EndPaint(handle, byref(ps))
        return 0
    elif message == WM_INPUT:
        raw_input = get_raw_input(l_param)
    elif message == WM_DESTROY:
        PostQuitMessage(0)
        return 0
    return DefWindowProc(handle, message, w_param, l_param)


def run():
    instance = GetModuleHandle(None)
    class_name = 'TestWindow'

    wnd = WndClass()
    wnd.style = CS_HREDRAW | CS_VREDRAW
    wnd.lpfnWndProc = WNDPROC(window_callback)
    wnd.hInstace = instance
    wnd.hCursor = LoadCursor(None, IDC_ARROW)
    wnd.lpszClassName = class_name

    RegisterClass(byref(wnd))

    handle = CreateWindowEx(
        0, class_name, 'Python Window', WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        None, None, instance, None
    )

    ShowWindow(handle, SW_NORMAL)
    UpdateWindow(handle)

    register_devices(handle)
    msg = MSG()
    while GetMessage(byref(msg), None, 0, 0) != 0:
        TranslateMessage(byref(msg))
        DispatchMessage(byref(msg))

    return msg.wParam


if __name__ == "__main__":
    sys.exit(run())

devices.py:

from ctypes import *
from ctypes.wintypes import *
from structures import *
from constants import *


def errcheck(result,func,args):
    if result is None or result == -1:
        raise WinError(get_last_error())
    return result


user32 = WinDLL('user32', use_last_error=True)
RegisterRawInputDevices = user32.RegisterRawInputDevices
RegisterRawInputDevices.argtypes = (RawInputDevice * 7), UINT, UINT
RegisterRawInputDevices.restype = BOOL
RegisterRawInputDevices.errcheck = errcheck
GetRawInputData = user32.GetRawInputData
GetRawInputData.argtypes = INT, UINT, LPVOID, PUINT, UINT
GetRawInputData.restype = UINT
GetRawInputData.errcheck = errcheck


def register_devices(hwnd_target=None):
    page = 0x01
    devices = (RawInputDevice * 7)(
        RawInputDevice(page, 0x01, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x02, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x04, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x05, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x06, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x07, DW_FLAGS, hwnd_target),
        RawInputDevice(page, 0x08, DW_FLAGS, hwnd_target),
    )
    RegisterRawInputDevices(devices, len(devices), sizeof(devices[0]))


def get_raw_input(handle):
    dw_size = c_uint()
    GetRawInputData(handle, RID_INPUT, None, byref(dw_size), sizeof(RawInputHeader))
    lpb = LPBYTE(dw_size)
    print(lpb.contents)
    GetRawInputData(handle, RID_INPUT, lpb, byref(dw_size), sizeof(RawInputHeader))
    print(lpb.contents)
    return cast(lpb, POINTER(RawInput))

constants.py:

from ctypes.wintypes import *
from ctypes import c_int64, WINFUNCTYPE, c_void_p


LRESULT = c_int64
HCURSOR = c_void_p

USAGE_PAGE = 0x01
USAGE = 0x06
DW_FLAGS = 0
DW_TYPE = 2
WM_INPUT = 0x00FF
WM_PAINT = 0x000F
WM_DESTROY = 0x0002
WM_QUI = 0x0012
RIDI_DEVICENAME = 0x20000007
RIDI_DEVICEINFO = 0x2000000b
ERROR_INSUFFICIENT_BUFFER = 0x7A
WS_EX_CLIENTEDGE = 0x00000200
WS_BORDER = 0x00800000
CS_BYTEALIGNCLIENT = 0x1000
CS_HREDRAW = 2
CS_VREDRAW = 1
SW_NORMAL = 1
CW_USEDEFAULT = -2147483648
WS_OVERLAPPED = 0x00000000
WS_CAPTION = 0x00C00000
WS_SYSMENU = 0x00080000
WS_THICKFRAME = 0x00040000
WS_MINIMIZEBOX = 0x00020000
WS_MAXIMIZEBOX = 0x00010000
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
RID_INPUT = 0x10000003
PM_REMOVE = 0x0001
DT_SINGLELINE = 32
DT_CENTER = 1
DT_VCENTER = 4
IDI_APPLICATION = LPCWSTR(32512)
IDC_ARROW = LPCWSTR(32512)
WHITE_BRUSH = 0
WNDPROC = WINFUNCTYPE(LRESULT, HWND, UINT, WPARAM, LPARAM)

structures.py:

from ctypes import Structure, windll, WINFUNCTYPE, c_int64, Union, c_byte, c_void_p
from ctypes.wintypes import *
from constants import *


HCURSOR = c_void_p


class RawInputDevice(Structure):
    _fields_ = [
        ("usUsagePage", USHORT),
        ("usUsage", USHORT),
        ("dwFlags", DWORD),
        ("hwndTarget", HWND),
    ]


class RawInputDeviceList(Structure):
    _fields_ = [
        ("hDevice", HANDLE),
        ("dwType", DWORD),
    ]


class RIDDeviceInfoHID(Structure):
    _fields_ = [
        ("dwVendorId", DWORD),
        ("dwProductId", DWORD),
        ("dwVersionNumber", DWORD),
        ("usUsagePage", USHORT),
        ("usUsage", USHORT),
    ]


class RIDDeviceInfo(Structure):
    _fields_ = [
        ("cbSize", DWORD),
        ("dwType", DWORD),
        ("hid", RIDDeviceInfoHID),
    ]


class WndClass(Structure):
    _fields_ = [
        ("style", UINT),
        ("lpfnWndProc", WNDPROC),
        ("cbClsExtra", INT),
        ("cbWndExtra", INT),
        ("hInstance", HINSTANCE),
        ("hIcon", HICON),
        ("hCursor", HCURSOR),
        ("hbrBackground", HBRUSH),
        ("lpszMenuName", LPCWSTR),
        ("lpszClassName", LPCWSTR),
    ]


class PaintStruct(Structure):
    _fields_ = [
        ("hdc", HDC),
        ("fErase", BOOL),
        ("rcPaint", RECT),
        ("fRestore", BOOL),
        ("fIncUpdate", BOOL),
        ("rgbReserved", BYTE * 32),
    ]


class RawInputHeader(Structure):
    _fields_ = [
        ("dwType", DWORD),
        ("dwSize", DWORD),
        ("hDevice", HANDLE),
        ("wParam", WPARAM),
    ]


class RawHID(Structure):
    _fields_ = [
        ("dwSizeHid", DWORD),
        ("dwCount", DWORD),
        ("bRawData", BYTE),
    ]


class MouseStruct(Structure):
    _fields_ = [
        ("usButtonFlags", USHORT),
        ("usButtonData", USHORT)
    ]


class MouseUnion(Union):
    _fields_ = [
        ("ulButtons", ULONG),
        ("data", MouseStruct)
    ]


class RawMouse(Structure):
    _fields_ = [
        ("usFlags", USHORT),
        ("data", MouseUnion),
        ("ulRawButtons", ULONG),
        ("lLastX", LONG),
        ("lLastY", LONG),
        ("ulExtraInformation", ULONG),
    ]


class RawKeyboard(Structure):
    _fields_ = [
        ("MakeCode", USHORT),
        ("Flags", USHORT),
        ("Reserved", USHORT),
        ("VKey", USHORT),
        ("Message", UINT),
        ("ExtraInformation", ULONG),
    ]


class RawUnion(Union):
    _fields_ = [
        ("mouse", RawMouse),
        ("keyboard", RawKeyboard),
        ("hid", RawHID)
    ]


class RawInput(Structure):
    _fields_ = [
        ("header", RawInputHeader),
        ("data", RawUnion),
    ]

清单[Python.Docs]: ctypes - A foreign function library for Python.

此(修复)已作为 的一部分涵盖。

问题是LPBYTE (POINTER(c_byte))初始化:

  • 没有参数,包装一个NULL指针

  • 使用参数(整数值),它将将该值存储在指向的区域(并且使用它作为大小)。
    更多,该区域将是 064bit(通过实验发现)意味着尝试在其外部索引会触发 Undefined Behavior,即使程序没有崩溃(那是因为旁边的区域没有被认领由其他变量)

要分配一定大小的内存区域,使用create_string_buffer(或者一个数组——但是你会将其传递给需要指针的函数时必须 cast)。

>>> import ctypes as ct
>>> import ctypes.wintypes as wt
>>>
>>>
>>> pb0 = wt.LPBYTE()
>>> bool(pb0)
False
>>> pb0.contents
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: NULL pointer access
>>>
>>> ll = ct.c_longlong(0x010203040506070809)  # Will be truncated (head part - due to little endianness)
>>> pb1 = wt.LPBYTE(ll)
>>> bool(pb1)
True
>>> pb1.contents
c_byte(9)
>>> [pb1[e] for e in range(0, 10)]  # @TODO - cfati: will genarate UB !!!
[9, 8, 7, 6, 5, 4, 3, 2, 0, 0]
>>>
>>> buf = ct.create_string_buffer(12)
>>> len(buf)
12
>>> buf[0]
b'\x00'
>>> buf[12]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index