Vous transmettez un ID de processus à des fonctions qui prennent un handle de fenêtre. Ce que vous voulez faire est énumérer des poignées pour les fenêtres de niveau supérieur, puis mapper chaque fenêtre à un ID de processus.
Première permet de définir les prototypes de fonction ctypes pour obtenir une vérification de type correcte sur les arguments de fonction. En outre, utilisez use_last_error=True
pour obtenir la gestion d'erreur la plus sûre via ctypes.get_last_error
. Un grand nombre de fonctions Windows renvoient 0 pour une erreur, il est donc pratique d'avoir une seule fonction errcheck
pour ce cas, par exemple check_zero
.
from __future__ import print_function
import ctypes
from ctypes import wintypes
from collections import namedtuple
user32 = ctypes.WinDLL('user32', use_last_error=True)
def check_zero(result, func, args):
if not result:
err = ctypes.get_last_error()
if err:
raise ctypes.WinError(err)
return args
if not hasattr(wintypes, 'LPDWORD'): # PY2
wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
WindowInfo = namedtuple('WindowInfo', 'pid title')
WNDENUMPROC = ctypes.WINFUNCTYPE(
wintypes.BOOL,
wintypes.HWND, # _In_ hWnd
wintypes.LPARAM,) # _In_ lParam
user32.EnumWindows.errcheck = check_zero
user32.EnumWindows.argtypes = (
WNDENUMPROC, # _In_ lpEnumFunc
wintypes.LPARAM,) # _In_ lParam
user32.IsWindowVisible.argtypes = (
wintypes.HWND,) # _In_ hWnd
user32.GetWindowThreadProcessId.restype = wintypes.DWORD
user32.GetWindowThreadProcessId.argtypes = (
wintypes.HWND, # _In_ hWnd
wintypes.LPDWORD,) # _Out_opt_ lpdwProcessId
user32.GetWindowTextLengthW.errcheck = check_zero
user32.GetWindowTextLengthW.argtypes = (
wintypes.HWND,) # _In_ hWnd
user32.GetWindowTextW.errcheck = check_zero
user32.GetWindowTextW.argtypes = (
wintypes.HWND, # _In_ hWnd
wintypes.LPWSTR, # _Out_ lpString
ctypes.c_int,) # _In_ nMaxCount
Voici une fonction pour lister les fenêtres visibles. Il utilise un rappel qui est une fermeture sur result
au lieu d'utiliser l'argument lParam
facultatif. Ce dernier nécessiterait de jeter l'argument. L'utilisation d'une fermeture est plus simple.
def list_windows():
'''Return a sorted list of visible windows.'''
result = []
@WNDENUMPROC
def enum_proc(hWnd, lParam):
if user32.IsWindowVisible(hWnd):
pid = wintypes.DWORD()
tid = user32.GetWindowThreadProcessId(
hWnd, ctypes.byref(pid))
length = user32.GetWindowTextLengthW(hWnd) + 1
title = ctypes.create_unicode_buffer(length)
user32.GetWindowTextW(hWnd, title, length)
result.append(WindowInfo(pid.value, title.value))
return True
user32.EnumWindows(enum_proc, 0)
return sorted(result)
Pour être complet, voici une liste de tous les ID de processus. Cela inclut les processus appartenant à d'autres sessions Windows (par exemple, les services de la session 0).
psapi = ctypes.WinDLL('psapi', use_last_error=True)
psapi.EnumProcesses.errcheck = check_zero
psapi.EnumProcesses.argtypes = (
wintypes.LPDWORD, # _Out_ pProcessIds
wintypes.DWORD, # _In_ cb
wintypes.LPDWORD,) # _Out_ pBytesReturned
def list_pids():
'''Return sorted list of process IDs.'''
length = 4096
PID_SIZE = ctypes.sizeof(wintypes.DWORD)
while True:
pids = (wintypes.DWORD * length)()
cb = ctypes.sizeof(pids)
cbret = wintypes.DWORD()
psapi.EnumProcesses(pids, cb, ctypes.byref(cbret))
if cbret.value < cb:
length = cbret.value // PID_SIZE
return sorted(pids[:length])
length *= 2
Par exemple:
if __name__ == '__main__':
print('Process IDs:')
print(*list_pids(), sep='\n')
print('\nWindows:')
print(*list_windows(), sep='\n')
liens MSDN:
Il fonctionne très bien. Merci pour l'aide, l'explication et les liens. – Gunnm