如何进一步调试SendKeysCtypes(win7 64bit,py2.7)?

时间:2012-05-08 17:08:46

标签: python windows 64-bit pywin32 sendkeys

我试图让SendKeysCtypes处理 py2.7和win7 64bit Here is src

问题:

运行SendKeysCtypes.py但没有任何反应。测试应该打开记事本并写一些文字。

问题代码是:

def GetInput(self):
    "Build the INPUT structure for the action"
    actions = 1
    # if both up and down
    if self.up and self.down:
        actions = 2

    inputs = (INPUT * actions)()

    vk, scan, flags = self._get_key_info()

    for inp in inputs:
        inp.type = INPUT_KEYBOARD

        inp._.ki.wVk = vk
        inp._.ki.wScan = scan
        inp._.ki.dwFlags |= flags

    # if we are releasing - then let it up
    if self.up:
        inputs[-1]._.ki.dwFlags |= KEYEVENTF_KEYUP

    return inputs

def Run(self):
    "Execute the action"
    inputs = self.GetInput()
    return SendInput(
        len(inputs),
        ctypes.byref(inputs),
        ctypes.sizeof(INPUT))
上面代码中的

SendInput()什么都不做。

其他测试

在这里,我们陷入困境,因为我的Windows编程非常有限,任何人都可以对此有所了解吗?

编辑1:

  • 在“64位问题”跟踪之后,引导我到SO question,看看我是否可以转换它。

1 个答案:

答案 0 :(得分:0)

您正在使用的StructureUnion类有两个问题。我将使用其中一个类重现the code you linked to的代码段:

class KEYBDINPUT(ctypes.Structure):
    "A particular keyboard event"
    _pack_ = 2  # FIXME: don't do this
    _fields_ = [
        # C:/PROGRA~1/MICROS~4/VC98/Include/winuser.h 4292
        ('wVk', WORD),
        ('wScan', WORD),
        ('dwFlags', DWORD),
        ('time', DWORD),
        ('dwExtraInfo', DWORD),  # FIXME: use correct data type
    ]

(我添加了 FIXME 来指出有问题的部分。)

首先,您使用 _pack_ = 2 不正确。您根本不应使用任何_pack_对齐说明符。默认设置在32位和64位Windows上均可正常工作。

纯粹偶然的是,它在32位Windows上与_pack_ = 2一起使用:代码中使用的所有2字节大小的数据类型成对出现并从已经对齐的边界开始,因此碰巧产生与4字节对齐相同的结构。

但是,在64位Windows下,基本对齐是8字节,因此如果您在那里使用_pack_ = 2_pack_ = 4,结构将会错位并且大小错误。

第二个问题是ULONG_PTR 中有没有ctypes.wintypes,这将是dwExtraInfo <的正确的数据类型/ strong>即可。在32位Windows下ULONG_PTR是无符号的32位整数,而在64位Windows下,它是无符号的64位整数。

MSDN article about Windows Data Types显示了它的定义方式:

#if defined(_WIN64)
 typedef unsigned __int64 ULONG_PTR;
#else
 typedef unsigned long ULONG_PTR;
#endif

使用DWORDULONG用于dwExtraInfo因此只能在32位Windows下工作,否则会产生错误的大小。

虽然使用一些基于POINTER的数据类型会恰好产生正确对齐和大小的结构,但在意义和使用方面都是错误的,因为ULONG_PTR是&#34;无符号整数,也可以存储(铸造)指针&#34;而不是一个实际的指针。

通过wintypes查看,您会注意到WPARAM的定义与ULONG_PTR的定义完全相同。因此,获得ULONG_PTR的快速而肮脏(但仍然相当稳健)的方式是:

from ctypes.wintypes import WPARAM as ULONG_PTR

或者,您可以使用受他们启发的一段代码并自行定义:

import ctypes

for ULONG_PTR in [ctypes.c_ulong, ctypes.c_ulonglong]:
    if ctypes.sizeof(ULONG_PTR) == ctypes.sizeof(ctypes.c_void_p):
        break
else:
    raise TypeError("cannot find a suitable type for ULONG_PTR")

有了这些改编,你可以定义这样的结构:

class MOUSEINPUT(ctypes.Structure):
    _fields_ = [
        ('dw',          LONG),
        ('dy',          LONG),
        ('mouseData',   DWORD),
        ('dwFlags',     DWORD),
        ('time',        DWORD),
        ('dwExtraInfo', ULONG_PTR),
    ]


class KEYBDINPUT(ctypes.Structure):
    _fields_ = [
        ('wVk',         WORD),
        ('wScan',       WORD),
        ('dwFlags',     DWORD),
        ('time',        DWORD),
        ('dwExtraInfo', ULONG_PTR),
    ]


class HARDWAREINPUT(ctypes.Structure):
    _fields_ = [
        ('uMsg',    DWORD),
        ('wParamL', WORD),
        ('wParamH', WORD),
    ]


class _INPUT(ctypes.Union):
    _fields_ = [
        ('mi', MOUSEINPUT),
        ('ki', KEYBDINPUT),
        ('hi', HARDWAREINPUT),
    ]


class INPUT(ctypes.Structure):
    _anonymous_ = ['']
    _fields_ = [
        ('type', DWORD),
        ('', _INPUT),
    ]