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

我试图让SendKeysCtypes工作在py2.7和win7 64bit 。 这是src

问题:

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

问题代码是这样的:

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()什么也不做。

其他testing

  • 我试了这个答案的代码,它工作正常。 但是这个代码有一些其他的问题。

  • 根据作者,它应该使用py3.1

  • SendInput()返回0 ,这意味着“被另一个线程阻塞”

  • 调用ctypes.GetLastError()会给我们提供错误代码87 ,这意味着“ERROR_INVALID_PARAMETER”

而在这里,我们卡住了,因为我的Windows编程是非常有限的,任何人都可以在这方面做点什么?

编辑1:

  • 跟着“64位是问题”的踪影,把我带到这个SO问题 ,看看我能不能把它转换。

Solutions Collecting From Web of "如何进一步debugging(win7 64bit,py2.7)的SendKeysCtypes?"

您正在使用的StructureUnion类有两个问题。 我将从你链接到的代码中重新编写一段代码 ,例如:

 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_ = 2_pack_ = 4 ,结构将会错位并且大小错误。

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

有关Windows数据类型的MSDN文章显示了它的定义:

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

因此,对于dwExtraInfo使用DWORDULONG只能在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), ]