使用kivy和pywinauto时的python-ctypes.ArgumentError
作者:互联网
我有一个kivy应用程序,可以使用pywinauto模块与其他窗口进行交互.该应用程序在Linux中运行良好(不使用pywinauto)但在Windows中我收到以下错误,应用程序甚至不会启动:
C:\Program Files (x86)\Python36_64\lib\site-packages\pywinauto\__init__.py:80: UserWarning: Revert to STA COM threading mode
warnings.warn("Revert to STA COM threading mode", UserWarning)
[INFO ] [GL ] NPOT texture support is available
[INFO ] [Base ] Start application main loop
Traceback (most recent call last):
File ".\application.py", line 368, in <module>
Application().run()
File "C:\Program Files (x86)\Python36_64\lib\site-packages\kivy\app.py", line 826, in run
runTouchApp()
File "C:\Program Files (x86)\Python36_64\lib\site-packages\kivy\base.py", line 477, in runTouchApp
EventLoop.start()
File "C:\Program Files (x86)\Python36_64\lib\site-packages\kivy\base.py", line 164, in start
provider.start()
File "C:\Program Files (x86)\Python36_64\lib\site-packages\kivy\input\providers\wm_touch.py", line 68, in start
self.hwnd, GWL_WNDPROC, self.new_windProc)
ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type
我认为这是pywinauto的一个问题的原因是我有以下几行,它在Linux中工作正常:
if SYSTEM == "Windows":
import win32gui
import win32process
import wmi
from pywinauto import application
import pywinauto
我也注释掉pywinauto导入行,然后开始.它可以链接到this issue.我真的不知道要包含什么代码,因为它在其他操作系统中工作….我假设pywinauto正在改变阻止kivy工作的东西.
我的问题是:如何在同一个应用程序中同时拥有kivy和pywinauto的功能?
解决方法:
我能够使用以下方法重现行为:
> Python 3.7.3 x64
> Kivy 1.10.1
> Pywinauto 0.6.6
作为旁注,之前我没有使用过任何2个软件包,我专门为这个任务安装了它们.
由于我不知道如何重现行为,我只是从[GitHub]: pywinauto/pywinauto – ctypes.ArgumentError @ click_input复制了MCVE(你也在问题中分享了),并略微修改了它(只是为了达到错误,没有风格,改进,等等等等) ).
code.py:
import random
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
import pywinauto # @TODO - cfati: moved after Kivy import(s), as it works otherwise (https://github.com/pywinauto/pywinauto/issues/419#issuecomment-488258224)
class DemoLayout(BoxLayout): pass
Builder.load_string("""
#: import datetime datetime.datetime
<DemoLayout>:
padding: 75
Button:
on_press: print(f"PRESSED @ {datetime.now()}")
""")
class Demo(App):
def build(self):
self.root = DemoLayout()
def on_start(self):
title = f"__KIVY_APP__{random.getrandbits(128)}"
Window.set_title(title)
hwnd = pywinauto.findwindows.find_window(title=title)
app = pywinauto.Application()
app.connect(handle=hwnd)
window = app.window(handle=hwnd).wrapper_object()
window.click_input(button="left", pressed="", coords=(100, 100), double=False, absolute=False)
Demo().run()
输出:
06001
在进一步说明之前,我想指出:
> [Python 3.Docs]: ctypes – A foreign function library for Python
> [MS.Docs]: SetWindowLongPtrW function
从后者可以看出,SetWindowLongPtrW的第三个参数可以是一个DWORD,一个HANDLE,一个函数指针,取决于第二个参数值:基本上它是一个可以映射到任何东西的void *.两个模块都通过ctypes调用此函数:
> Pywinauto([GitHub]: pywinauto/pywinauto – (0.6.6) pywinauto/pywinauto/win32functions.py):
try:
SetWindowLongPtr = ctypes.windll.user32.SetWindowLongPtrW
SetWindowLongPtr.argtypes = [win32structures.HWND, ctypes.c_int, win32structures.LONG_PTR]
SetWindowLongPtr.restype = win32structures.LONG_PTR
except AttributeError:
SetWindowLongPtr = SetWindowLong
> Kivy([GitHub]: kivy/kivy – (1.10.1) kivy/kivy/input/providers/wm_common.py):
try:
windll.user32.SetWindowLongPtrW.restype = WNDPROC
windll.user32.SetWindowLongPtrW.argtypes = [HANDLE, c_int, WNDPROC]
SetWindowLong_wrapper = windll.user32.SetWindowLongPtrW
except AttributeError:
windll.user32.SetWindowLongW.restype = WNDPROC
windll.user32.SetWindowLongW.argtypes = [HANDLE, c_int, WNDPROC]
SetWindowLong_wrapper = windll.user32.SetWindowLongW
说明:
> user32.dll仅在当前Python进程中加载一次
>上面的代码初始化函数,通常只在模块导入时执行一次(可以根据需要执行多次,但会降低性能)
>两个模块都指定了函数(windll.user32.SetWindowLongPtrW,因为我们在64位上)原型,但它们以不同的方式执行
>从上面的3中,最后导入模块的结果决定了函数原型的样子
>当导入的模块1st尝试使用原型时,它与传递的参数不匹配,因此错误
这就是为什么我必须在Kivy之后移动Pywinauto导入,以便Kivy尝试使用Pywinauto的原型调用该函数,否则它会起作用.它的
可能会反过来,但我没有找到Pywinauto会调用该函数的场景,因为它不相关.
看看2个ctypes原型和C one原型(来自MS URL),结果是:
> Pywinauto正在做正确的事情(我很好奇它如何在32位上运行)
> Kivy只使用SetWindowLongPtrW用例(带有函数指针的用例),为了简化操作,他们根据场景调整了原型.但是,它与C原型并不完全匹配,而且这个来自我的PoV,看起来像一个蹩脚的解决方法(获得)
我修改了我的Kivy装置和tadaa! (这是复活节兔子!:)):
注意:这里遇到一个(更简单的)变体:[SO]: How to keep pynput and ctypes from clashing?
@ EDIT0:
我已经提交了合并的[GitHub]: kivy/kivy – SetWindowLongPtrW ctypes prototype bug.不知道什么时候它将在市场上出售(PyPI,所以你可以简单地将其安装).
作为替代方案,您可以下载修补程序,并在本地应用更改.检查[SO]: Run/Debug a Django application’s UnitTests from the mouse right click context menu in PyCharm Community Edition? (@CristiFati’s answer)(修补utrunner部分)以了解如何在Win上应用补丁(基本上,每个以一个“”符号开头的行进入,并且以一个“ – ”符号开头的每一行都会消失).我正在使用Cygwin,顺便说一句.或者您可以下载3个已修改的文件并覆盖现有文件.无论如何,请先备份它们!此外,我不知道这些变化如何适应旧的Kivy版本.
标签:kivy,python,pywinauto,ctypes 来源: https://codeday.me/bug/20191008/1870904.html