Replace WMI process enumeration with Win32 EnumProcesses (350x faster)
Use PROCESS_QUERY_LIMITED_INFORMATION + QueryFullProcessImageNameW instead of WMI Win32_Process. Reduces process enumeration from ~3s to ~8ms. All user-facing applications are detected; only protected system services are not visible (irrelevant for profile conditions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,19 +22,53 @@ class PlatformDetector:
|
|||||||
"""Detect running processes and the foreground window's process."""
|
"""Detect running processes and the foreground window's process."""
|
||||||
|
|
||||||
def _get_running_processes_sync(self) -> Set[str]:
|
def _get_running_processes_sync(self) -> Set[str]:
|
||||||
"""Get set of lowercase process names (blocking, call via executor)."""
|
"""Get set of lowercase process names via Win32 EnumProcesses.
|
||||||
|
|
||||||
|
Uses PROCESS_QUERY_LIMITED_INFORMATION + QueryFullProcessImageNameW
|
||||||
|
which is ~300x faster than WMI (~8ms vs ~3s). System services
|
||||||
|
running under protected accounts are not visible, but all
|
||||||
|
user-facing applications are covered.
|
||||||
|
"""
|
||||||
if not _IS_WINDOWS:
|
if not _IS_WINDOWS:
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pythoncom
|
psapi = ctypes.windll.psapi
|
||||||
pythoncom.CoInitialize()
|
kernel32 = ctypes.windll.kernel32
|
||||||
try:
|
|
||||||
import wmi
|
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
||||||
w = wmi.WMI()
|
|
||||||
return {p.Name.lower() for p in w.Win32_Process() if p.Name}
|
# Enumerate all PIDs
|
||||||
finally:
|
pid_array = (ctypes.wintypes.DWORD * 2048)()
|
||||||
pythoncom.CoUninitialize()
|
cb_needed = ctypes.wintypes.DWORD()
|
||||||
|
psapi.EnumProcesses(
|
||||||
|
ctypes.byref(pid_array), ctypes.sizeof(pid_array),
|
||||||
|
ctypes.byref(cb_needed),
|
||||||
|
)
|
||||||
|
n_pids = cb_needed.value // ctypes.sizeof(ctypes.wintypes.DWORD)
|
||||||
|
|
||||||
|
procs: Set[str] = set()
|
||||||
|
name_buf = ctypes.create_unicode_buffer(512)
|
||||||
|
|
||||||
|
for i in range(n_pids):
|
||||||
|
pid = pid_array[i]
|
||||||
|
if pid == 0:
|
||||||
|
continue
|
||||||
|
handle = kernel32.OpenProcess(
|
||||||
|
PROCESS_QUERY_LIMITED_INFORMATION, False, pid,
|
||||||
|
)
|
||||||
|
if not handle:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
buf_size = ctypes.wintypes.DWORD(512)
|
||||||
|
if kernel32.QueryFullProcessImageNameW(
|
||||||
|
handle, 0, name_buf, ctypes.byref(buf_size),
|
||||||
|
):
|
||||||
|
procs.add(os.path.basename(name_buf.value).lower())
|
||||||
|
finally:
|
||||||
|
kernel32.CloseHandle(handle)
|
||||||
|
|
||||||
|
return procs
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to enumerate processes: {e}")
|
logger.error(f"Failed to enumerate processes: {e}")
|
||||||
return set()
|
return set()
|
||||||
|
|||||||
Reference in New Issue
Block a user