Skip to content

Commit

Permalink
feat: added back wmi method on Windows as fallback for admin processes (
Browse files Browse the repository at this point in the history
#96)

* build(deps): added back wmi as a dependency

* feat(wip): added back wmi method on Windows as fallback for admin processes
  • Loading branch information
ErikBjare authored Jan 5, 2024
1 parent af38b35 commit 2d878c5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 10 deletions.
7 changes: 6 additions & 1 deletion aw_watcher_window/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
57 changes: 50 additions & 7 deletions aw_watcher_window/windows.py
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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)
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)
25 changes: 23 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down

0 comments on commit 2d878c5

Please sign in to comment.