pywin32 / pywinauto не работает должным образом в удаленном рабочем столе, когда он свернут - PullRequest
0 голосов
/ 11 мая 2018

У меня есть конвейер 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()

С удаленным рабочим столом все работает нормально, но оно закрыто, мое приложение не получает ввод

Так что кто-нибудьбыла эта проблема раньше?У меня заканчиваются идеи, что еще можно попробовать?

Спасибо

РЕДАКТИРОВАТЬ:

Это полный след ошибки 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

Также попытался (backend = "uia") запустить приложение с теми же результатами:

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"]

Но все равно та же проблема с кнопкой

1 Ответ

0 голосов
/ 12 мая 2018

UPD: все практики, перечисленные ниже, собраны в Руководство по удаленному выполнению , которое может быть более современным.

Проблема с удаленным рабочим столом не зависит от инструмента.Сам RDP не сохраняет контекст GUI, когда он свернут или отключен (тот же эффект имеет место, когда ОС заблокирована).Но симптомы обычно включают .click_input() и .type_keys() / keyboard.SendKeys() методы, которые не работают без контекста GUI.

Обходные пути для минимизированной проблемы RDP:

  1. Переключение RDP в оконноережим (не полный экран), запустите скрипт и быстро переключитесь на локальный компьютер.Теперь вы можете работать в обычном режиме.Это самый простой способ для ручного запуска.

  2. Установите программное обеспечение сервера VNC на удаленном компьютере (я использовал TightVNC) и клиент VNC (также TightVNC) на локальном компьютере.Вам может потребоваться обновить драйверы видеокарты на удаленном компьютере, если вы видите черный экран.Вы также должны перезагрузить удаленный хост, если RDP использовался хотя бы один раз.Основное преимущество: вы даже можете отключиться от удаленного хоста, но TightVNC всегда будет поддерживать контекст GUI.Это больше подходит для автоматического запуска (агент Jenkins должен запускаться на этом активном рабочем столе, он вообще не может быть запущен как служба).Для этой цели может подойти и другая среда виртуального рабочего стола, например Citrix, но у меня нет личного опыта.

  3. RDP (команда mstsc) имеет некоторый параметр для отсоединения виртуального удаленного рабочего стола оттекущее соединение (не помню сейчас).Дополнительные инструменты для автоматического удаленного запуска могут включать psexec или Ansible с плагином psexec.


Если главное окно для этого приложения не найдено (PID процесса), возможно, saplogon.exeпорождает другой процесс с целевым окном.Затем вам нужно сделать app = Application().connect(title="SAP Logon 740", timeout=10), чтобы связать с правильным идентификатором процесса.Это довольно распространенная проблема для таких пусковых установок.


ctypes.ArgumentError более интересна.Пожалуйста, предоставьте полный трассировку ошибки.Я подозреваю, что это можно исправить на стороне Pywinauto.Такая ошибка может возникать из-за того, что другие библиотеки Python используют ctypes неверным способом, но, возможно, ее можно обойти, возможно.


Если кнопка входа в систему не может быть найдена с помощью бэкенда по умолчанию «win32», вы можетепопробуйте Application(backend="uia").connect(...).Различие объясняется в Руководстве по началу работы .

...