Search code examples
pythonwindowswin32guisetforegroundwindow

Python win32gui SetAsForegroundWindow function not working properly


I am trying to write a program that finds a window by searching for its title. Once it has found the window, it will attempt to bring it to front. I am using win32gui API to achieve this. I am able to get it to work for the most part, but for some reason it does not work if the taskmanager is in front. I have the follow sample code.

import win32gui, win32con
import re, traceback
from time import sleep

class cWindow:
    def __init__(self):
        self._hwnd = None

    def BringToTop(self):
        win32gui.BringWindowToTop(self._hwnd)

    def SetAsForegroundWindow(self):
        win32gui.SetForegroundWindow(self._hwnd)

    def Maximize(self):
        win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE)

    def setActWin(self):
        win32gui.SetActiveWindow(self._hwnd)

    def _window_enum_callback(self, hwnd, wildcard):
        '''Pass to win32gui.EnumWindows() to check all the opened windows'''
        if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None:
            self._hwnd = hwnd

    def find_window_wildcard(self, wildcard):
        self._hwnd = None
        win32gui.EnumWindows(self._window_enum_callback, wildcard)


def main():
    sleep(5)
    try:      
        wildcard = ".*Building Operation WorkStation.*"
        cW = cWindow()
        cW.find_window_wildcard(wildcard)
        cW.Maximize()
        cW.BringToTop()
        cW.SetAsForegroundWindow()

    except:
        f = open("log.txt", "w")
        f.write(traceback.format_exc())
        print traceback.format_exc()
main()

I pieced this together from multiple online sources. It seems to work for the most part but for some windows like the task manager, it'll work sometimes but fails the rest. When it doesnt work properly, all I notice is the application icon blinks yellow. Is there a proper way of doing this to make sure the window that I am interested in is set to foreground 100% of the times? I am not sure if this is relevant but I am using Windows 7 Professional (32-bit) with Service Pack 1.


Solution

  • I found a solution: if taskmanager, then kill it. I added a method to cWindow:

    def kill_task_manager(self):
        # Here I use your method to find a window because of an accent in my french OS,
        # but you should use win32gui.FindWindow(None, 'Task Manager complete name').
        wildcard = 'Gestionnaire des t.+ches de Windows'
        self.find_window_wildcard(wildcard)
        if self._hwnd:
            win32gui.PostMessage(self._hwnd, win32con.WM_CLOSE, 0, 0)  # kill it
            sleep(0.5)  # important to let time for the window to be closed
    

    Call this method just after cW = cWindow().

    Another bug trap is to prevent this exception in SetAsForegroundWindow:

    error: (0, 'SetForegroundWindow', 'No error message is available')
    

    just send an alt key before the win32gui call:

    # Add this import
    import win32com.client
    
    # Add this to __ini__
    self.shell = win32com.client.Dispatch("WScript.Shell")
    
    # And SetAsForegroundWindow becomes
    def SetAsForegroundWindow(self):
        self.shell.SendKeys('%')
        win32gui.SetForegroundWindow(self._hwnd)
    

    Last, if I may, do not compare != None but is not None. More pythonic ;)

    This is the full code:

    # coding: utf-8
    
    import re, traceback
    import win32gui, win32con, win32com.client
    from time import sleep
    
    
    class cWindow:
        def __init__(self):
            self._hwnd = None
            self.shell = win32com.client.Dispatch("WScript.Shell")
    
        def BringToTop(self):
            win32gui.BringWindowToTop(self._hwnd)
    
        def SetAsForegroundWindow(self):
            self.shell.SendKeys('%')
            win32gui.SetForegroundWindow(self._hwnd)
    
        def Maximize(self):
            win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE)
    
        def setActWin(self):
            win32gui.SetActiveWindow(self._hwnd)
    
        def _window_enum_callback(self, hwnd, wildcard):
            '''Pass to win32gui.EnumWindows() to check all the opened windows'''
            if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) is not None:
                self._hwnd = hwnd
    
        def find_window_wildcard(self, wildcard):
            self._hwnd = None
            win32gui.EnumWindows(self._window_enum_callback, wildcard)
    
        def kill_task_manager(self):
            wildcard = 'Gestionnaire des t.+ches de Windows'
            self.find_window_wildcard(wildcard)
            if self._hwnd:
                win32gui.PostMessage(self._hwnd, win32con.WM_CLOSE, 0, 0)
                sleep(0.5)
    
    def main():
        sleep(5)
        try:
            wildcard = ".*Building Operation WorkStation.*"
            cW = cWindow()
            cW.kill_task_manager()
            cW.find_window_wildcard(wildcard)
            cW.BringToTop()
            cW.Maximize()
            cW.SetAsForegroundWindow()
    
        except:
            f = open("log.txt", "w")
            f.write(traceback.format_exc())
            print(traceback.format_exc())
    
    
    if __name__ == '__main__':
        main()
    

    Sources: how do I close window with handle using win32gui in Python and win32gui.SetActiveWindow() ERROR : The specified procedure could not be found.