2

我试图让 SendKeysCtypes 在py2.7 和 win7 64bit上工作。 这是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 问题,看看我是否可以转换它。
4

1 回答 1

0

您使用的Structure和类有两个问题。Union我将从您链接到的代码中复制一个片段,其中一个类作为示例:

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 上都可以正常工作。

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

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

第二个问题是没有ULONG_PTRinctypes.wintypes,这将dwExtraInfo. 在 32 位 WindowsULONG_PTR下是无符号 32 位整数,而在 64 位 Windows 下是无符号 64 位整数。

关于 Windows 数据类型的MSDN 文章显示了它是如何定义的:

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

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

虽然使用某些POINTER基于数据类型会碰巧产生一个正确对齐和大小的结构,但它在含义和用法上都是错误的,就像ULONG_PTR“一个也可以存储(强制转换的)指针的无符号整数”而不是一个实际指针。

仔细查看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),
    ]
于 2017-09-02T16:32:55.040 回答