Which alternative property can be used for attaching to app's window
Hi,
I'm using Appium, WinAppDriver 1.1, Python, Windows 10. Need to test a Qt application. For the first launch the app is shown as a dialog with 'Continue' and 'Cancel' buttons. The problem is inspect.exe doesn't provide NativeWindowHandle attribute for the tested app (to be more exact NativeWindowHandle = 0 due to console log). How is it possible to catch of the app?
Maybe the answer is to use Window property in MSAA mode (this property exists and has value according to inspect.exe output). But I did not find how to turn WinAppDriver to such mode.
There are two screens from inspect.exe (one screen for 'UI Automation' mode, another for 'MSAA' mode).
UI Automation:
How found: Mouse move (652,343)
hwnd=0x03820700 32bit class="Qt5QWindowIcon" style=0x96080000 ex=0x80000
BoundingRectangle: {l:359 t:272 r:663 b:495}
ProcessId: 908
Name: ""
AccessKey: ""
HasKeyboardFocus: false
IsKeyboardFocusable: false
IsEnabled: true
HelpText: ""
IsPassword: false
IsOffscreen: false
ProviderDescription: "[pid:908,providerId:0x0 Main(parent link):Microsoft: MSAA Proxy (unmanaged:uiautomationcore.dll)]"
IsDockPatternAvailable: false
IsExpandCollapsePatternAvailable: false
IsGridItemPatternAvailable: false
IsGridPatternAvailable: false
IsInvokePatternAvailable: false
IsMultipleViewPatternAvailable: false
IsRangeValuePatternAvailable: false
IsScrollPatternAvailable: false
IsScrollItemPatternAvailable: false
IsSelectionItemPatternAvailable: false
IsSelectionPatternAvailable: false
IsTablePatternAvailable: false
IsTableItemPatternAvailable: false
IsTextPatternAvailable: false
IsTogglePatternAvailable: false
IsTransformPatternAvailable: false
IsValuePatternAvailable: false
IsWindowPatternAvailable: false
IsItemContainerPatternAvailable: false
IsVirtualizedItemPatternAvailable: false
FirstChild: ""
LastChild: ""
Next: [null]
Previous: [null]
Other Props: Object has no additional properties
Children: ""
""
""
Ancestors: "<font color="red"><b>WARNING!</b></font>" pane
"Desktop 1" pane
[ No Parent ]
MSAA:
How found: Mouse move (652,417)
hwnd=0x03820700 32bit class="Qt5QWindowIcon" style=0x96080000 ex=0x80000
ChildId: 0
Interfaces: IOleWindow
Impl: Remote native IAccessible
Name: [null]
Value: [null]
Role: client (0xA)
State: normal (0x0)
Location: {l:359, t:272, w:304, h:223}
Selection:
Description: [null]
Kbshortcut: [null]
DefAction: [null]
Help: [null]
HelpTopic: ""
ChildCount: 3
Window: 0x3820700
FirstChild: none : client : normal
LastChild: none : client : normal
Next: [null]
Previous: [null]
Left: [null]
Up: [null]
Right: [null]
Down: [null]
Other Props: Object has no additional properties
Children: none : client : normal
none : client : normal
none : client : normal
Ancestors: "<font color="red"><b>WARNING!</b></font>" : dialog : sizeable,moveable
"My app" : application : normal
[ No Parent ]
Also, there is the test:
import unittest
from appium import webdriver
class SimpleTests(unittest.TestCase):
def setUp(self):
path_to_app = "C:\\Program Files (x86)\\My app\\myapp.exe"
app_name = "My app"
desired_caps = {}
desired_caps["app"] = path_to_app
desired_caps["platformName"] = "Windows"
desired_caps["deviceName"] = "WindowsPC"
try:
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
except:
print("An exception is caught. Possible cannot locate the app. Continue execution.")
# Create desktop session
desired_caps["app"] = "Root"
desktop_session = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
app_window = desktop_session.find_element_by_name(app_name)
# Trying to find a handle of the app
app_top_level_handle = app_window.get_attribute("NativeWindowHandle")
app_top_level_handle = hex(int(app_top_level_handle))
desired_caps2 = {}
desired_caps2["appTopLevelWindow"] = app_top_level_handle
desired_caps2["platformName"] = "Windows"
desired_caps2["deviceName"] = "WindowsPC"
# Initialize app session
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps2)
def tearDown(self):
self.driver.quit()
def test_simple_actions(self):
#just exit from the app by clicking cancel button
self.driver.find_element_by_name("Cancel").click()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(SimpleTests)
unittest.TextTestRunner(verbosity=2).run(suite)
Originally posted by @vnabokit in https://github.com/Microsoft/WinAppDriver/issues/283#issuecomment-456845359
It seems, no way to attach to existed app's window if impossible to get capability appTopLevelWindow.
WinAppDriver accepts either app or appTopLevelWindow capability (due to my console log):
[selenium.common.exceptions.InvalidArgumentException: Message: Bad capabilities. Specify either app or appTopLevelWindow to create a session]. appTopLevelWindow can be taken only from NativeWindowHandle app's property.
Also, WinAppDriver cannot interact with properties from MSAA mode: https://github.com/Microsoft/WinAppDriver/issues/363
Still hope some workaround exists but I've finished to explore abilities WinAppDriver for testing Qt apps.
Thanks! :)
I too am looking for an alternative capability. Since Microsoft choose to terminate CodedUI without providing an equal alternative I am stuck trying to make the WinAppDriver work, unfortunately it is proving difficult to attach to existing windows by titles or by anything else that is consistent. And the NativeWindowHandle changes on every run.
For a bit more clarification, Inspect does show the NativeWindowHandle for the IE browser I want to hook into. And using System.Diagnostics.Process.GetProcessesByName("iexplorer") and looping through the results I can actually get one.
Unfortunately, when I pass this value, which is actually called MainWindowHandle on the process, it still blows up saying "cannot find active window specified by capabilities: appTopLevelWindow"
EDIT: After looking through all the test examples I modified the code to process.MainWindowHandle.ToString("x"), I had not been using the ToString("x") prior. This worked. Not a great solution, but it is functioning.
Followed a detour to solve my problem (almost same as yours) and it helped
``import pygetwindow as gw import keyboard import time
time.sleep(5)
dialog_title = "Your MSAA Dialog Title"
dialog_window = gw.getWindowsWithTitle(dialog_title)
if dialog_window: dialog_window[0].activate() keyboard.press_and_release('enter') else: print(f"Window with title '{dialog_title}' not found.")``