pywin32 / pywinauto在最小化时无法在远程桌面中正常工作

时间:2018-05-11 20:02:26

标签: sap remote-desktop pywin32 pywinauto

我有一个Jenkins管道,它在远程服务器上执行一个程序,该程序使用pywin来操作应用程序进行功能测试。

当我使用远程桌面时,我的应用程序运行良好,但当我关闭远程桌面并从Jenkins运行时,应用程序会丢失。

我所做的是打开应用并发送回车键。

这是我的应用:

os.startfile("C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.exe")

time.sleep(5)
handle = win32gui.FindWindow(0, "SAP Logon 740")  

keyboard = Controller()
keyboard.press(Key.enter)

所以我尝试将焦点添加到应用程序以强制关注但没有成功:

os.startfile("C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.exe")

time.sleep(5)
handle = win32gui.FindWindow(0, "SAP Logon 740")  

win32gui.ShowWindow(handle, 5)           
win32gui.SetForegroundWindow(handle)

keyboard = Controller()
keyboard.press(Key.enter)

我将按键更改为相同的结果:

shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('{ENTER}')

我尝试更改为pywinauto尝试单击按钮而不是发送回车,但我发现更多问题,因为pywinauto无法识别我的应用程序标题:

app = Application().start("C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.exe")

app["SAP Logon 740"] # this doesn't work
app.top_window_()    # this doesn't work either

handle = win32gui.FindWindow(0, "SAP Logon 740")  
sapApp = app.window_(handle = handle)            #Finally this works but...

sapApp["Log &On"].click()                        # This doesn't work
sapApp.log_on.Click()                            # This doesn't work

我得到了这个例外:

ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_ulong instance instead of pointer to c_long

我知道这个名字是因为我试过了:

print(sapApp.descendants(control_type="MenuBar"))

得到了这个结果:

[<win32_controls.ButtonWrapper - 'Log &On', Button, 14221798>, ...]

所以我知道这个按钮的名称,但是没有能够点击它。

我也尝试将焦点设置到应用程序,结果相同:

sapApp.SetFocus()

随着远程桌面oppened一切正常但它已关闭我的应用程序没有输入

以前有人有这个问题吗?我没想到还能尝试什么呢?

由于

修改

这是ctypes错误的完整描述:

File "e:\Jenkins\workspace\my-project\scripts\test_pywin.py", line 23, in <module> sapApp.log_on.Click()
File "E:\Python_V365\lib\site-packages\pywinauto\controls\hwndwrapper.py", line 725, in click self.verify_actionable()
File "E:\Python_V365\lib\site-packages\pywinauto\base_wrapper.py", line 591, in verify_actionable self.wait_for_idle()
File "E:\Python_V365\lib\site-packages\pywinauto\controls\hwndwrapper.py", line 710, in wait_for_idle win32functions.WaitGuiThreadIdle(self)
File "E:\Python_V365\lib\site-packages\pywinauto\win32functions.py", line 283, in WaitGuiThreadIdle GetWindowThreadProcessId(handle, ctypes.byref(process_id))
ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_ulong instance instead of pointer to c_long

还尝试(后端=&#34; uia&#34;)以相同的结果启动应用程序:

app = Application(backend="uia").start("C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.exe")

启动程序后尝试连接会给我这个错误:

app = Application().connect(title="SAP Logon 740", timeout=10)

File "e:\Jenkins\workspace\tacion_BehaveImplementation-637TPHZXXSFG4MVWWWJCBSJOWSAVPZMPOYFKFKNYKRT5XRBIZFBQ\scripts\test_pywin.py", line 12, in <module> app = Application().connect(title="SAP Logon 740", timeout=10)
File "E:\Python_V365\lib\site-packages\pywinauto\application.py", line 944, in connect self.process = findwindows.find_element(**kwargs).process_id
File "E:\Python_V365\lib\site-packages\pywinauto\findwindows.py", line 84, in find_element elements = find_elements(**kwargs)
TypeError: find_elements() got an unexpected keyword argument 'timeout'

这最终有效:

app = Application().connect(title="SAP Logon 740", backend="uia")
sapApp = app["SAP Logon 740"]

但是发现问题实际上是我需要等待应用程序完全加载所以这也有效:

app = Application().start("C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplogon.exe")
time.sleep(5)
app["SAP Logon 740"]

但是按钮仍然存在同样的问题

2 个答案:

答案 0 :(得分:1)

远程桌面的问题不依赖于该工具。 RDP本身在最小化或断开连接时不保留GUI上下文(当操作系统被锁定时会发生相同的效果)。但是这些症状通常涉及.click_input().type_keys() / keyboard.SendKeys()方法,这些方法在没有GUI上下文的情况下无效。

最小化RDP问题的解决方法:

  1. 将RDP切换到窗口模式(非全屏),在那里运行脚本并快速切换到本地计算机。现在你可以正常工作了。这是手动运行的最简单方法。

  2. 在本地的远程计算机(我使用TightVNC)和VNC客户端(也称为TightVNC)上安装VNC服务器软件。如果您看到黑屏,则可能需要更新远程计算机上的视频卡驱动程序。如果至少使用一次RDP,则还必须重新启动远程主机。主要好处:您甚至可以从远程主机断开连接,但TightVNC将始终保持GUI上下文。这更适合自动运行(Jenkins代理必须在此活动桌面中运行,它根本不能作为服务运行)。像Citrix这样的另一个虚拟桌面环境也可以用于此目的,但我没有个人经验。

  3. RDP(mstsc命令)有一些参数可以从当前连接解除虚拟远程桌面的绑定(现在不记得了)。用于自动远程运行的其他工具可能包括psexec或Ansible with psexec插件。

  4. 如果找不到此应用程序的主窗口(进程PID),则saplogon.exe可能会生成具有目标窗口的另一个进程。然后,您必须app = Application().connect(title="SAP Logon 740", timeout=10)与正确的进程ID绑定。这对于这样的发射器来说是非常普遍的问题。

    ctypes.ArgumentError更有趣。请提供错误的完整回溯。我怀疑这可以在pywinauto方面修复。可能会发生这种错误,因为其他Python库使用ctypes方式不正确,但可能会有问题。

    如果使用默认的“win32”后端无法找到LogOn按钮,您可以尝试Application(backend="uia").connect(...)。差异在Getting Started Guide

    中解释

答案 1 :(得分:0)

如果我了解您的问题(也是我的问题),可以在此处找到正确的答案:

https://support.smartbear.com/testcomplete/docs/testing-with/running/via-rdp/keeping-computer-unlocked.html

(此链接来自此页面:Remote Execution Guide in pywinauto

确切的操作过程,如页面中所述:

  

要断开与远程桌面的连接,请在   远程计算机(在“远程桌面”窗口中)作为管理员:

     

%windir%\ System32 \ tscon.exe RDP-Tcp#NNN / dest:console

     

其中RDP-Tcp#NNN是当前远程桌面会话的ID,   例如,RDP-Tcp#0。您可以在Windows任务管理器上看到它   “会话”列中的“用户”标签。

     

您将看到“您的远程桌面会话已结束”消息,并且   远程桌面客户端将关闭。但是所有的程序和测试   远程计算机将继续正常运行。

我只是对其进行测试,所以可以正常工作。