2016-05-28 2 views
0

J'essaie d'obtenir des noms de titres de fenêtres Windows et des pids à travers des poignées avec des objets longs. Mon code fonctionne mais il y a quelque chose qui ne va pas. Je reçois seulement 4 titres de fenêtre quand je devrais obtenir 10 ou plus. Quelqu'un peut-il m'aider et me dire comment réparer ce code? Je pense que le problème est avec la façon dont je convertis les objets longs (je ne les comprends pas très bien, ainsi que les ctypes en général).Comment obtenir des noms de fenêtres Windows avec des types ctypes en python

from __future__ import print_function 
from ctypes import * 

psapi = windll.psapi 
titles = [] 


# get window title from pid 
def gwtfp(): 
    max_array = c_ulong * 4096 
    pProcessIds = max_array() 
    pBytesReturned = c_ulong() 

    psapi.EnumProcesses(byref(pProcessIds), 
         sizeof(pProcessIds), 
         byref(pBytesReturned)) 

    # get the number of returned processes 
    nReturned = pBytesReturned.value/sizeof(c_ulong()) 
    pidProcessArray = [i for i in pProcessIds][:nReturned] 
    print(pidProcessArray) 
    # 
    EnumWindows = windll.user32.EnumWindows 
    EnumWindowsProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int)) 
    GetWindowText = windll.user32.GetWindowTextW 
    GetWindowTextLength = windll.user32.GetWindowTextLengthW 
    IsWindowVisible = windll.user32.IsWindowVisible 


    for process in pidProcessArray: 
     #print("Process PID %d" % process) 
     if IsWindowVisible(process): 
      length = GetWindowTextLength(process) 
      buff = create_unicode_buffer(length + 1) 
      GetWindowText(process, buff, length + 1) 
      titles.append(buff.value) 


gwtfp() 
print(titles) 

Répondre

2

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:

+0

Il fonctionne très bien. Merci pour l'aide, l'explication et les liens. – Gunnm