2016-05-28 19 views
0

Ich versuche Windows-Fenster Titelnamen und PID durch Handles mit langen Objekten zu erhalten. Mein Code funktioniert, aber etwas stimmt nicht. Ich bekomme nur 4 Fenstertitel, wenn ich 10 oder mehr bekomme. Kann mir jemand helfen und mir sagen, wie ich diesen Code reparieren kann? Ich denke, das Problem ist, wie ich lange Objekte konvertiere (ich verstehe sie nicht so gut, wie auch Ctypes im Allgemeinen).Wie Windows-Windows-Namen mit Ctypes in Python erhalten

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) 

Antwort

2

Sie übergeben eine Prozess-ID an Funktionen, die einen Fenstergriff übernehmen. Sie möchten Handles für die Fenster der obersten Ebene aufzählen und dann jedes Fenster einer Prozess-ID zuordnen.

Zuerst definieren wir die Ctypes-Funktionsprototypen, um eine korrekte Typprüfung für Funktionsargumente zu erhalten. Verwenden Sie auch use_last_error=True, um die sicherste Fehlerbehandlung über ctypes.get_last_error zu erhalten. Viele Windows-Funktionen geben für einen Fehler 0 zurück. Daher ist es praktisch, eine einzige errcheck-Funktion für diesen Fall zu verwenden, z. B. 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 

Hier ist eine Funktion, um die sichtbaren Fenster aufzulisten. Es verwendet einen Rückruf, bei dem es sich um einen Abschluss über result handelt, anstatt das optionale Argument lParam zu verwenden. Letzteres würde erfordern, das Argument zu werfen. Die Verwendung eines Verschlusses ist einfacher.

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) 

Der Vollständigkeit halber ist hier eine Funktion zum Auflisten aller Prozess-IDs. Dies schließt Prozesse ein, die zu anderen Windows-Sitzungen gehören (z. B. Dienste in Sitzung 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 

Zum Beispiel:

if __name__ == '__main__': 
    print('Process IDs:') 
    print(*list_pids(), sep='\n') 
    print('\nWindows:') 
    print(*list_windows(), sep='\n') 

MSDN Links:

+0

Es funktioniert großartig. Danke für Hilfe, Erklärung und Links. – Gunnm