Files
skate-3-rust-engine/tools/update_processes.py
T

32 lines
1.6 KiB
Python

"""Release file locks only for executables owned by this installation."""
import os
def close_programs(root, names):
if os.name != 'nt': return
import ctypes as c
from ctypes import wintypes as w
root=root.resolve()
targets={os.path.normcase(str(root/name)) for name in names if name.lower().endswith('.exe')}
k=c.WinDLL('kernel32',use_last_error=True)
ps=c.WinDLL('psapi',use_last_error=True)
k.OpenProcess.argtypes=[w.DWORD,w.BOOL,w.DWORD];k.OpenProcess.restype=w.HANDLE
k.QueryFullProcessImageNameW.argtypes=[w.HANDLE,w.DWORD,w.LPWSTR,c.POINTER(w.DWORD)]
k.TerminateProcess.argtypes=[w.HANDLE,w.UINT]
k.WaitForSingleObject.argtypes=[w.HANDLE,w.DWORD]
k.CloseHandle.argtypes=[w.HANDLE]
ps.EnumProcesses.argtypes=[c.POINTER(w.DWORD),w.DWORD,c.POINTER(w.DWORD)]
pids=(w.DWORD*65536)();used=w.DWORD()
if not ps.EnumProcesses(pids,c.sizeof(pids),c.byref(used)):
raise OSError('Could not check running game processes')
for pid in pids[:used.value//c.sizeof(w.DWORD)]:
if pid==os.getpid():continue
# Query and terminate through the same handle, avoiding PID-reuse races.
h=k.OpenProcess(0x1000|0x0001|0x100000,False,pid)
if not h:continue
try:
text=c.create_unicode_buffer(32768);size=w.DWORD(len(text))
if k.QueryFullProcessImageNameW(h,0,text,c.byref(size)) and os.path.normcase(text.value) in targets:
if not k.TerminateProcess(h,0):raise OSError('Could not close '+text.value)
if k.WaitForSingleObject(h,10000)!=0:raise OSError('Timed out closing '+text.value)
finally:k.CloseHandle(h)