diff --git a/aw_watcher_window/lib.py b/aw_watcher_window/lib.py index 09e634c..b769963 100644 --- a/aw_watcher_window/lib.py +++ b/aw_watcher_window/lib.py @@ -39,7 +39,12 @@ def get_current_window_windows() -> Optional[dict]: from . import windows window_handle = windows.get_active_window_handle() - app = windows.get_app_name(window_handle) + try: + app = windows.get_app_name(window_handle) + except Exception: # TODO: narrow down the exception + # try with wmi method + app = windows.get_app_name_wmi(window_handle) + title = windows.get_window_title(window_handle) if app is None: diff --git a/aw_watcher_window/windows.py b/aw_watcher_window/windows.py index dc78782..44403a8 100644 --- a/aw_watcher_window/windows.py +++ b/aw_watcher_window/windows.py @@ -1,18 +1,21 @@ -from typing import Optional - import os import time +from typing import Optional -import win32gui import win32api +import win32gui import win32process +import wmi + def get_app_path(hwnd) -> Optional[str]: """Get application path given hwnd.""" path = None _, pid = win32process.GetWindowThreadProcessId(hwnd) - process = win32api.OpenProcess(0x0400, False, pid) # PROCESS_QUERY_INFORMATION = 0x0400 + process = win32api.OpenProcess( + 0x0400, False, pid + ) # PROCESS_QUERY_INFORMATION = 0x0400 try: path = win32process.GetModuleFileNameEx(process, 0) @@ -21,26 +24,66 @@ def get_app_path(hwnd) -> Optional[str]: return path + def get_app_name(hwnd) -> Optional[str]: """Get application filename given hwnd.""" path = get_app_path(hwnd) if path is None: return None - + return os.path.basename(path) + def get_window_title(hwnd): return win32gui.GetWindowText(hwnd) + def get_active_window_handle(): hwnd = win32gui.GetForegroundWindow() return hwnd +# WMI-version, used as fallback if win32gui/win32process/win32api fails (such as for "run as admin" processes) + +c = wmi.WMI() + +""" +Much of this derived from: http://stackoverflow.com/a/14973422/965332 +""" + + +def get_app_name_wmi(hwnd) -> Optional[str]: + """Get application filename given hwnd.""" + name = None + _, pid = win32process.GetWindowThreadProcessId(hwnd) + for p in c.query("SELECT Name FROM Win32_Process WHERE ProcessId = %s" % str(pid)): + name = p.Name + break + return name + + +def get_app_path_wmi(hwnd) -> Optional[str]: + """Get application path given hwnd.""" + path = None + + _, pid = win32process.GetWindowThreadProcessId(hwnd) + for p in c.query( + "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = %s" % str(pid) + ): + path = p.ExecutablePath + break + + return path + + if __name__ == "__main__": while True: hwnd = get_active_window_handle() print("Title:", get_window_title(hwnd)) - print("App:", get_app_name(hwnd)) - time.sleep(1.0) \ No newline at end of file + print("App: ", get_app_name(hwnd)) + print("App (wmi): ", get_app_name_wmi(hwnd)) + print("Path: ", get_app_path(hwnd)) + print("Path (wmi): ", get_app_path_wmi(hwnd)) + + time.sleep(1.0) diff --git a/poetry.lock b/poetry.lock index 2e4a7cb..81235c1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "altgraph" @@ -996,6 +996,27 @@ secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17. socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wmi" +version = "1.5.1" +description = "Windows Management Instrumentation" +optional = false +python-versions = "*" +files = [ + {file = "WMI-1.5.1-py2.py3-none-any.whl", hash = "sha256:1d6b085e5c445141c475476000b661f60fff1aaa19f76bf82b7abb92e0ff4942"}, + {file = "WMI-1.5.1.tar.gz", hash = "sha256:b6a6be5711b1b6c8d55bda7a8befd75c48c12b770b9d227d31c1737dbf0d40a6"}, +] + +[package.dependencies] +pywin32 = "*" + +[package.extras] +all = ["pytest", "sphinx", "twine", "wheel"] +dev = ["pytest", "sphinx", "twine", "wheel"] +docs = ["sphinx"] +package = ["twine", "wheel"] +tests = ["pytest"] + [[package]] name = "zipp" version = "3.17.0" @@ -1014,4 +1035,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8,<3.13" -content-hash = "4223d10fc422cba0ee66d07ac912df5e4f0070651b7415a8af0b6260d82a89bf" +content-hash = "dc7f0b0a0b4df061c7027fc9340e07a0d3860f09a9020ec7a73723b929395389" diff --git a/pyproject.toml b/pyproject.toml index 630096e..42d9df7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ aw-watcher-window = "aw_watcher_window:main" python = "^3.8,<3.13" aw-client = "^0.5" pywin32 = {version = "306", platform = "win32"} +wmi = {version = "*", platform = "win32"} pyobjc-framework-ApplicationServices = { version = "*", platform="darwin"} pyobjc-framework-CoreText = {version = "*", platform="darwin"} pyobjc-framework-OSAKit = {version = "*", platform="darwin"}