Skip to content

Utils win32

utils_win32

Module provides various routines to deal with application windows. NOTE: Windows platform only

Example / doctest:

>>> import utils_mystuff_windows
>>> print(find_window_ctypes("Excel"))
>>> print(find_window_win32gui("Excel"))
>>> print(find_window_ctypes("Access"))
>>> print(find_window_win32gui("Access"))

AssocQueryStringA = shlwapi.AssocQueryStringA module-attribute

AssocQueryStringW = shlwapi.AssocQueryStringW module-attribute

WM_CLOSE = 16 module-attribute

shlwapi = ctypes.WinDLL('shlwapi', use_last_error=True) module-attribute

ASSOCF

IGNOREBASECLASS = 512 class-attribute instance-attribute

INIT_BYEXENAME = 2 class-attribute instance-attribute

INIT_DEFAULTTOFOLDER = 8 class-attribute instance-attribute

INIT_DEFAULTTOSTAR = 4 class-attribute instance-attribute

INIT_IGNOREUNKNOWN = 1024 class-attribute instance-attribute

INIT_NOREMAPCLSID = 1 class-attribute instance-attribute

NOFIXUPS = 256 class-attribute instance-attribute

NONE = 0 class-attribute instance-attribute

NOTRUNCATE = 32 class-attribute instance-attribute

NOUSERSETTINGS = 16 class-attribute instance-attribute

OPEN_BYEXENAME = 2 class-attribute instance-attribute

REMAPRUNDLL = 128 class-attribute instance-attribute

VERIFY = 64 class-attribute instance-attribute

ASSOCSTR

COMMAND = 1 class-attribute instance-attribute

CONTENTTYPE = 14 class-attribute instance-attribute

DDEAPPLICATION = 9 class-attribute instance-attribute

DDECOMMAND = 7 class-attribute instance-attribute

DDEIFEXEC = 8 class-attribute instance-attribute

DDETOPIC = 10 class-attribute instance-attribute

DEFAULTICON = 15 class-attribute instance-attribute

EXECUTABLE = 2 class-attribute instance-attribute

FRIENDLYAPPNAME = 4 class-attribute instance-attribute

FRIENDLYDOCNAME = 3 class-attribute instance-attribute

INFOTIP = 11 class-attribute instance-attribute

NOOPEN = 5 class-attribute instance-attribute

QUICKTIP = 12 class-attribute instance-attribute

SHELLEXTENSION = 16 class-attribute instance-attribute

SHELLNEWVALUE = 6 class-attribute instance-attribute

TILEINFO = 13 class-attribute instance-attribute

close_app_file(filename: str, msg: str, title: str, partial_allowed: bool = True, timeout: int = 5, kill_app: bool = True) -> None

close_app_file - close data file opened by an application

Parameters:

Name Type Description Default
filename str

filename

required
msg str

message for alert box

required
title str

title for alert box

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout for waiting after closing

5
kill_app bool

kill application locking file to be closed

True
Source code in src\utils_mystuff_windows\utils_win32.py
def close_app_file(filename: str, msg: str, title: str, partial_allowed: bool = True, timeout: int = 5, kill_app: bool = True) -> None:
    """
    close_app_file - close data file opened by an application

    Args:
        filename (str): filename
        msg (str): message for alert box
        title (str): title for alert box
        partial_allowed (bool): partial matching of title allowed
        timeout (int): timeout for waiting after closing
        kill_app (bool): kill application locking file to be closed
    """

    # first attempt: close by window title
    if Utils.file_locked(filename):
        close_app_windowtitle(filename, partial_allowed, timeout)
    if Utils.file_locked(filename):
        close_app_windowtitle(os.path.splitext(os.path.basename(filename))[0], partial_allowed, timeout)
    # second attempt: kill respective process
    if Utils.file_locked(filename):
        executable = get_assoc_query(os.path.splitext(filename)[1])
        for proc in psutil.process_iter(['exe']):
            try:
                if proc.info['exe'] and os.path.normcase(proc.info['exe']) == os.path.normcase(executable):
                    proc.kill()
                    proc.wait(timeout=5)
                    starttime = time.time()
                    while Utils.file_locked(filename) and time.time() < starttime + timeout:
                        time.sleep(0.1)
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
                pass
    # third attempt:request to close manually
    while Utils.file_locked(filename):
        Utils.alertbox(msg, title)

close_app_windowtitle(title: str, partial_allowed: bool = True, timeout: int = 5) -> None

close_app_windowtitle - close window / application depending on title

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout for waiting after closing

5
Source code in src\utils_mystuff_windows\utils_win32.py
def close_app_windowtitle(title: str, partial_allowed: bool = True, timeout: int = 5) -> None:
    """
    close_app_windowtitle - close window / application depending on title

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int): timeout for waiting after closing
    """
    close_app_windowtitle_win32gui(title, partial_allowed, timeout)

close_app_windowtitle_ctypes(title: str, partial_allowed: bool = True, timeout: int = 5) -> None

close_app_windowtitle_ctypes - close window / application depending on title, variant using ctypes

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout for waiting after closing

5
Source code in src\utils_mystuff_windows\utils_win32.py
def close_app_windowtitle_ctypes(title: str, partial_allowed: bool = True, timeout: int = 5) -> None:
    """
    close_app_windowtitle_ctypes - close window / application depending on title, variant using ctypes

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int): timeout for waiting after closing
    """
    hwnd = find_window_ctypes(title, partial_allowed)
    if hwnd:
        ctypes.windll.user32.SendMessageA(hwnd, WM_CLOSE, 0, 0)
        starttime = time.time()
        while ctypes.windll.user32.IsWindow(hwnd) and time.time() < starttime + timeout:
            time.sleep(0.1)

close_app_windowtitle_taskkill(title: str) -> None

close_app_windowtitle_taskkill - close window / application depending on title, variant using taskkill

Parameters:

Name Type Description Default
title str

window title

required
Source code in src\utils_mystuff_windows\utils_win32.py
def close_app_windowtitle_taskkill(title: str) -> None:
    """
    close_app_windowtitle_taskkill - close window / application depending on title, variant using taskkill

    Args:
        title (str): window title
    """
    # os.system("taskkill /F /FI 'WINDOWTITLE eq {title}*'")   # wildcard not allowed at beginning of title
    os.system(f"for /f \"tokens=2 delims=,\" %a in ('tasklist /v /fo:csv /nh ^| findstr /r \"{title}\"') do taskkill /pid %a")
    time.sleep(0.1)

close_app_windowtitle_win32gui(title: str, partial_allowed: bool = True, timeout: int = 5) -> None

close_app_windowtitle_win32gui - close window / application depending on title, variant using win32gui

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout for waiting after closing

5
Source code in src\utils_mystuff_windows\utils_win32.py
def close_app_windowtitle_win32gui(title: str, partial_allowed: bool = True, timeout: int = 5) -> None:
    """
    close_app_windowtitle_win32gui - close window / application depending on title, variant using win32gui

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int): timeout for waiting after closing
    """
    hwnd = find_window_win32gui(title, partial_allowed)
    if hwnd:
        win32gui.SendMessage(hwnd, WM_CLOSE, 0, 0)
        starttime = time.time()
        while win32gui.IsWindow(hwnd) and time.time() < starttime + timeout:
            time.sleep(0.1)

find_window_ctypes(title: str, partial_allowed: bool = True) -> Any

find_window_ctypes - find windows from title, variant using ctypes

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True

Returns:

Type Description
Any

Union[str, bool]: title if found, False otherwise

Source code in src\utils_mystuff_windows\utils_win32.py
def find_window_ctypes(title: str, partial_allowed: bool = True) -> Any:
    """
    find_window_ctypes - find windows from title, variant using ctypes

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed

    Returns:
        Union[str, bool]: title if found, False otherwise
    """
    titles = []

    def foreach_window_gettitle(hwnd, lParam):
        if ctypes.windll.user32.IsWindowVisible(hwnd):
            length = ctypes.windll.user32.GetWindowTextLengthW(hwnd)
            classname = ctypes.create_unicode_buffer(100 + 1)
            ctypes.windll.user32.GetClassNameW(hwnd, classname, 100 + 1)
            buff = ctypes.create_unicode_buffer(length + 1)
            ctypes.windll.user32.GetWindowTextW(hwnd, buff, length + 1)
            titles.append((hwnd, buff.value.encode(), classname.value, ctypes.windll.user32.IsIconic(hwnd)))
        return True

    def refresh_wins() -> Any:
        titles: list[str] = []
        ctypes.windll.user32.EnumWindows(ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_int, ctypes.POINTER(ctypes.c_int))(foreach_window_gettitle), 0)

    refresh_wins()
    # exact matching of title
    for item in titles:
        if title == str(item[1].decode()):
            return item[0]
    # partial matching of title
    if partial_allowed:
        for item in titles:
            if title in str(item[1].decode()):
                return item[0]
    return False

find_window_win32gui(title: str, partial_allowed: bool = True) -> Any

find_window_ctypes - find windows from title, variant using win32gui

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True

Returns:

Type Description
Any

Union[str, bool]: title if found, False otherwise

Source code in src\utils_mystuff_windows\utils_win32.py
def find_window_win32gui(title: str, partial_allowed: bool = True) -> Any:
    """
    find_window_ctypes - find windows from title, variant using win32gui

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed

    Returns:
        Union[str, bool]: title if found, False otherwise
    """
    titles = []

    def foreach_window_gettitle(hwnd, lParam):
        if win32gui.IsWindowVisible(hwnd):
            classname = win32gui.GetClassName(hwnd)
            title = win32gui.GetWindowText(hwnd)
            titles.append((hwnd, title, classname, win32gui.IsIconic(hwnd)))
        return True

    def refresh_wins():
        titles = []
        win32gui.EnumWindows(foreach_window_gettitle, 0)

    refresh_wins()
    # exact matching of title
    for item in titles:
        if title == str(item[1]):
            return item[0]
    # partial matching of title
    if partial_allowed:
        for item in titles:
            if title in str(item[1]):
                return item[0]
    return False

get_assoc_query(extension: str, assoc_str: int = ASSOCSTR.EXECUTABLE.value) -> str

get_assoc_query - read file extension association info via Win32API

file extension association info is read via Win32API call. Watch out for ANSI vs double byte version(s)! Since UTF-8 ist standard in Python, using the double byte version avoids some conversion stuff.

Parameters:

Name Type Description Default
extension str

extension association info is looked for

required
assoc_str ASSOCSTR

association info index

EXECUTABLE.value

Returns:

Type Description
str

value

Source code in src\utils_mystuff_windows\utils_win32.py
def get_assoc_query(extension: str, assoc_str: int = ASSOCSTR.EXECUTABLE.value) -> str:
    """
    get_assoc_query - read file extension association info via Win32API

    file extension association info is read via Win32API call.
    Watch out for ANSI vs double byte version(s)! Since UTF-8 ist standard in Python,
    using the double byte version avoids some conversion stuff.

    Args:
        extension (str): extension association info is looked for
        assoc_str (ASSOCSTR): association info index

    Returns:
        value
    """
    # Step 1: Determine buffer size
    buffer_len = ctypes.wintypes.DWORD(0)
    hr = AssocQueryStringA(ASSOCF.NONE.value, assoc_str, extension.encode('cp1252'), None, None, ctypes.byref(buffer_len))
    # hr = AssocQueryStringW(ASSOCF.NONE.value, assoc_str, extension, None, None, ctypes.byref(buffer_len))
    if buffer_len.value == 0:
        return ""

    # Step 2: Allocate buffer and retrieve the value
    buffer = ctypes.create_string_buffer(buffer_len.value)
    hr = AssocQueryStringA(ASSOCF.NONE.value, assoc_str, extension.encode('cp1252'), None, buffer, ctypes.byref(buffer_len))
    result = buffer.value.decode()
    # buffer = ctypes.create_unicode_buffer(buffer_len.value)
    # hr = AssocQueryStringW(ASSOCF.NONE.value, assoc_str, extension, None, buffer, ctypes.byref(buffer_len))
    # result = buffer.value
    if hr != 0:  # S_OK is 0
        return ""

    return result

wait_for_window(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None

wait_for_window - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout time. Defaults to 5.

5
wait float

wait time. Defaults to 0.25.

0.25
Source code in src\utils_mystuff_windows\utils_win32.py
def wait_for_window(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None:
    """
    wait_for_window - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int, optional): timeout time. Defaults to 5.
        wait (float, optional): wait time. Defaults to 0.25.
    """
    wait_for_window_win32gui(title, partial_allowed, timeout, wait)

wait_for_window_ctypes(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None

wait_for_window_ctypes - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout time. Defaults to 5.

5
wait float

wait time. Defaults to 0.25.

0.25
Source code in src\utils_mystuff_windows\utils_win32.py
def wait_for_window_ctypes(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None:
    """
    wait_for_window_ctypes - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int, optional): timeout time. Defaults to 5.
        wait (float, optional): wait time. Defaults to 0.25.
    """
    starttime = time.time()
    while time.time() < starttime + timeout:
        hwnd = find_window_ctypes(title, partial_allowed)
        if hwnd:
            return
        else:
            time.sleep(wait)
    return

wait_for_window_win32gui(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None

wait_for_window_win32gui - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

Parameters:

Name Type Description Default
title str

window title

required
partial_allowed bool

partial matching of title allowed

True
timeout int

timeout time. Defaults to 5.

5
wait float

wait time. Defaults to 0.25.

0.25
Source code in src\utils_mystuff_windows\utils_win32.py
def wait_for_window_win32gui(title: str, partial_allowed: bool = True, timeout: int = 5, wait: float = 0.25) -> None:
    """
    wait_for_window_win32gui - wait for close window (overcome delay in asynchronous processing subprocess.Popen)

    Args:
        title (str): window title
        partial_allowed (bool): partial matching of title allowed
        timeout (int, optional): timeout time. Defaults to 5.
        wait (float, optional): wait time. Defaults to 0.25.
    """
    starttime = time.time()
    while time.time() < starttime + timeout:
        hwnd = find_window_win32gui(title, partial_allowed)
        if hwnd:
            return
        else:
            time.sleep(wait)
    return