Pywinauto: Pywinauto doesn't see most of controls while connecting to Skype

Created on 19 May 2019  路  16Comments  路  Source: pywinauto/pywinauto

On pywinauto 0.6.6 this simple code snippet fails in one of 2 scenarious:

    app = Application(backend="uia").start("skype.exe")
    sleep(8)

    skp = app.window(title_re='Skype.*')
    sleep(8)

    search = skp["Search for people, groups & messages"]
    search.click()

It either fails on line skp = app.window(title_re='Skype.*'):

Traceback (most recent call last):
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 256, in __resolve_control
    criteria)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\timings.py", line 458, in wait_until_passes
    raise err
pywinauto.timings.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "skype.py", line 300, in <module>
    status = add_friends(prefix, min_mutuals, invitation_msg)
  File "skype.py", line 130, in add_friends
    search.click()
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 362, in __getattribute__
    ctrls = self.__resolve_control(self.criteria)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 259, in __resolve_control
    raise e.original_exception
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
    func_val = func(*args, **kwargs)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 201, in __get_ctrl
    dialog = self.backend.generic_wrapper_class(findwindows.find_element(**criteria[0]))
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\findwindows.py", line 87, in find_element
    raise ElementNotFoundError(kwargs)
pywinauto.findwindows.ElementNotFoundError: {'title_re': 'Skype.*', 'backend': 'uia', 'process': 9112}

or fails in the moment when code trying to reach search control using line search = skp["Search for people, groups & messages"]

C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py",` line 256, in __resolve_control criteria)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\timings.py", line 458, in wait_until_passes
    raise err
pywinauto.timings.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "skype.py", line 300, in <module>
    status = add_friends(prefix, min_mutuals, invitation_msg)
  File "skype.py", line 130, in add_friends
    search.click()
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 362, in __getattribute__
    ctrls = self.__resolve_control(self.criteria)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 259, in __resolve_control
    raise e.original_exception
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\timings.py", line 436, in wait_until_passes
    func_val = func(*args, **kwargs)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\application.py", line 220, in __get_ctrl
    ctrl = self.backend.generic_wrapper_class(findwindows.find_element(**ctrl_criteria))
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\findwindows.py", line 84, in find_element
    elements = find_elements(**kwargs)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\findwindows.py", line 303, in find_elements
    elements = findbestmatch.find_best_control_matches(best_match, wrapped_elems)
  File "C:\Users\Bravissimo\AppData\Local\conda\conda\envs\py36\lib\site-packages\pywinauto\findbestmatch.py", line 533, in find_best_control_matches
    raise MatchError(items = name_control_map.keys(), tofind = search_text)
pywinauto.findbestmatch.MatchError: Could not find 'Search for people, groups & messages' in 'dict_keys(['', 'Pane', 'TitleBar', '0', '1', '2', 'System', 'SystemMenu', 'Menu', 'System0', 'System1', 'System2', 'MenuItem', 'SystemMenuItem', 'Button', 'MinimalizujButton', 'Minimalizuj', 'Button0', 'Button1', 'Button2', 'Maksymalizuj', 'MaksymalizujButton', 'Button3', 'Zamknij', 'ZamknijButton', 'Custom', '3', 'Custom0', 'Custom1', 'Custom2', '4', 'Custom3', '5', 'Custom4', '6', 'Custom5', '7'])

Also in this message you can see that there're only few controls visible, while most of them aren't here. 2 weeks ago this code worked, but now it works very rarely and in most cases fails.

Do you have any idea why it's happening?

3rd-party issue question

Most helpful comment

A-ha-ha! The fifth Skype.exe process with pid = 32 eats 100% of one CPU core for this period of time! Come on, Skype team! What are you doing?

All 16 comments

Hi @dstepanenko if pywinauto wasn't updated, the only assumption is Skype update or Windows update changed something.

The code can be customized with more flexible timings this way:

app = Application(backend="uia").start("skype.exe")

skp = app.window(title_re='Skype.*') # actual search is NOT happening here
skp.wait('ready', timeout=20) # wait up to 20 sec. (actual search is done, return early if found)

search = skp["Search for people, groups & messages"]
search.click() # actual search of the sub-element is done here (inside of call to .click())

Hi @dstepanenko if pywinauto wasn't updated, the only assumption is Skype update or Windows update changed something.

The code can be customized with more flexible timings this way:

app = Application(backend="uia").start("skype.exe")

skp = app.window(title_re='Skype.*') # actual search is NOT happening here
skp.wait('ready', timeout=20) # wait up to 20 sec. (actual search is done, return early if found)

search = skp["Search for people, groups & messages"]
search.click() # actual search of the sub-element is done here (inside of call to .click())

Vasily, thank you for the reply. The question isn't what changed, but how to fix it. The thing is that in Inspect I see many controls, edits and other elements, they're visible and enabled, but due to some reasons I can't reach them via pywinauto. Do you have any idea on how to do it? Or maybe you know the reason why it's not possible?

thanks,
Dmitry

Maybe it's worth to re-install comtypes so that comtypes cache is cleared. If UIAutomationCore.dll was updated, the cache might be outdated.

Maybe it's worth to re-install comtypes so that comtypes cache is cleared. If UIAutomationCore.dll was updated, the cache might be outdated.

Today I installed python 3.6.1 from scratch with all the libraries and rerun the code - still same issue. Any other thoughts?

Vasily, I missed your comment about using waits everywhere. I tried it and it worked (didn't expect my timeouts wasn't enough but it seems they were). Thank you for your help!

P.S.: may I ask you not to close this issue for the next 24 hours so that in case this fix won't work in a stable manner we can go back to this issue?

P.P.S: thank you once again!

Upd: After first successful attempt with waits all the next attempts failed. I increased timeout from 20 seconds for 5 minutes it didn't help

Let me comment with, probably, the most frequent recommendation on this project. Can you see the control and its parent hierarchy in Inspect.exe running in uia mode?

Let me comment with, probably, the most frequent recommendation on this project. Can you see the control and its parent hierarchy in Inspect.exe running in uia mode?

yes, I do. Please go ahead

Well, the interesting thing is that Skype version 8.45.0.41 runs 4 (four!) processes Skype.exe as you can check in "Details" tab of Task Manager. So connect(path='Skype.exe') won't help.

This code is working (pretty slowly) for me:

from pywinauto.application import Application

app = Application(backend="uia").start(r'"C:\Program Files (x86)\Microsoft\Skype for Desktop\Skype.exe"')
app = Application(backend='uia').connect(title_re='Skype.*') # takes 40.5 seconds!

skp = app.window(title_re='Skype.*')
skp.wait('ready', timeout=20) # takes 1.2 sec.

search = skp["Search for people, groups & messages"]
search.click() # takes 7.1 sec.

The third timing seems OK because Skype main window contains 422 elements and this step can be faster this way: skp.child_window(title="Search for people, groups & messages", control_type='Button', found_index=0) which takes 0.5 sec.

The first timing (~40.5 sec.) looks magic because Desktop(backend="uia").windows() takes 0.4 sec. only. Looks like the problem should be in method .connect().

If you add .start("skype.exe"), then method Desktop(backend="uia").windows() takes ~40 seconds! So probably the magic happens when Skype launcher checks for existing Skype instance. And this definitely looks like a bug in UIAutomationCore.dll or in other Windows DLLs.

P.S. Inspect.exe hangs for the same time approximately.

A-ha-ha! The fifth Skype.exe process with pid = 32 eats 100% of one CPU core for this period of time! Come on, Skype team! What are you doing?

Reported the issue to Skype through standard feedback form with the link to this issue. Let's wait for a month at least for any reaction.

Well, the interesting thing is that Skype version 8.45.0.41 runs 4 (four!) processes Skype.exe as you can check in "Details" tab of Task Manager. So connect(path='Skype.exe') won't help.

This code is working (pretty slowly) for me:

from pywinauto.application import Application

app = Application(backend="uia").start(r'"C:\Program Files (x86)\Microsoft\Skype for Desktop\Skype.exe"')
app = Application(backend='uia').connect(title_re='Skype.*') # takes 40.5 seconds!

skp = app.window(title_re='Skype.*')
skp.wait('ready', timeout=20) # takes 1.2 sec.

search = skp["Search for people, groups & messages"]
search.click() # takes 7.1 sec.

The third timing seems OK because Skype main window contains 422 elements and this step can be faster this way: skp.child_window(title="Search for people, groups & messages", control_type='Button', found_index=0) which takes 0.5 sec.

The first timing (~40.5 sec.) looks magic because Desktop(backend="uia").windows() takes 0.4 sec. only. Looks like the problem should be in method .connect().

I should've mentioned that Skype has several processes - I also noticed it.

I created the script that iterates over all Skype processes trying to connect to each of them and it haven't suceeded also:

    for i in range(4):
      os.system("taskkill /f /im Skype.exe")
    sleep(8)
    app0 = Application(backend="uia").start(r'"C:\Program Files (x86)\Microsoft\Skype for Desktop\Skype.exe"')
    sleep(8)
    skype_processes = []
    c = wmi.WMI ()
    for process in c.Win32_Process ():
      if process.Name == "Skype.exe":
        skype_processes.append(process.ProcessId)

    for i, process in enumerate(skype_processes):
      try:
        app = Application(backend='uia').connect(process=process) # takes 40.5 seconds!
      except:
            print("Failed to find process {0} while connecting. {1}-th process out of {2}".format(process, i, len(skype_processes)))
            continue

      winsound.Beep(frequency, duration)

      skp = app.window(title_re='Skype.*')
      try:
        skp.wait('ready', timeout=40) # takes 1.2 sec.
      except:
            print("Failed to find skype in {0} skype process. {1}-th process out of {2}".format(process, i, len(skype_processes)))
            continue
      winsound.Beep(frequency // 3, duration)

      try:
        search = skp["Search for people, groups & messages"]
        search.wait('ready', timeout=20)
        search.click() # takes 7.1 sec.
        winsound.Beep(frequency // 9, duration)
        print("Sucess with {0} skype process. {1}-th process out of {2}".format(process, i, len(skype_processes)))
        break
      except:
        print("Failed to find search in {0} skype process. {1}-th process out of {2}".format(process, i, len(skype_processes)))

Here are the output of it:

Failed to find search in 9464 skype process. 0-th process out of 5
Failed to find skype in 11720 skype process. 1-th process out of 5
Failed to find skype in 9664 skype process. 2-th process out of 5
Failed to find skype in 14728 skype process. 3-th process out of 5
Failed to find process 13704 while connecting. 4-th process out of 5

so, after connecting to the first skype process (9464) the script is able to find window, but not able to find search button. For the next 3 it's not able to find window with title "Skype.*". The last process is seems to be dead process of previously killed skype.

Reported the issue to Skype through standard feedback form with the link to this issue. Let's wait for a month at least for any reaction.

If you'll receive from microsoft something like link to the opened issue, please share it with me

Nothing yet. Just a workaround to check already running Skype instance on Python side can be applied so far.

Application's method .connect(title_re='...', visible_only=False) is what you need. It can raise an exception by timeout if Skype window is not found.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

van9konst picture van9konst  路  17Comments

lanzorg picture lanzorg  路  16Comments

MagazinnikIvan picture MagazinnikIvan  路  14Comments

Enteleform picture Enteleform  路  19Comments

jjbright picture jjbright  路  15Comments