如何在 python 中使用 ctypes 获取 Windows window 名称
How to get Windows window names with ctypes in python
我尝试通过长 objects 的句柄获取 Windows window 标题名称和 pids。我的代码有效,但有问题。当我应该获得 10 个或更多时,我只获得 4 window 个头衔。任何人都可以帮助并告诉我如何修复此代码吗?我认为问题在于我如何转换 long objects(我不太了解它们,以及一般的 ctypes)。
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)
您正在将进程 ID 传递给采用 window 句柄的函数。您要做的是枚举顶级 windows 的句柄,然后将每个 window 映射到进程 ID。
首先让我们定义 ctypes 函数原型,以便对函数参数进行正确的类型检查。此外,使用 use_last_error=True
通过 ctypes.get_last_error
获得最安全的错误处理。许多 Windows 函数 return 0 表示错误,因此在这种情况下使用单个 errcheck
函数很方便,例如 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
这是一个列出可见内容的函数 windows。它使用一个回调,该回调是对 result
的闭包,而不是使用可选的 lParam
参数。后者需要提出论点。使用闭包更简单。
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)
为了完整起见,这里有一个列出所有进程 ID 的函数。这包括属于其他 Windows 会话的进程(例如会话 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
例如:
if __name__ == '__main__':
print('Process IDs:')
print(*list_pids(), sep='\n')
print('\nWindows:')
print(*list_windows(), sep='\n')
MSDN 链接:
我尝试通过长 objects 的句柄获取 Windows window 标题名称和 pids。我的代码有效,但有问题。当我应该获得 10 个或更多时,我只获得 4 window 个头衔。任何人都可以帮助并告诉我如何修复此代码吗?我认为问题在于我如何转换 long objects(我不太了解它们,以及一般的 ctypes)。
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)
您正在将进程 ID 传递给采用 window 句柄的函数。您要做的是枚举顶级 windows 的句柄,然后将每个 window 映射到进程 ID。
首先让我们定义 ctypes 函数原型,以便对函数参数进行正确的类型检查。此外,使用 use_last_error=True
通过 ctypes.get_last_error
获得最安全的错误处理。许多 Windows 函数 return 0 表示错误,因此在这种情况下使用单个 errcheck
函数很方便,例如 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
这是一个列出可见内容的函数 windows。它使用一个回调,该回调是对 result
的闭包,而不是使用可选的 lParam
参数。后者需要提出论点。使用闭包更简单。
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)
为了完整起见,这里有一个列出所有进程 ID 的函数。这包括属于其他 Windows 会话的进程(例如会话 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
例如:
if __name__ == '__main__':
print('Process IDs:')
print(*list_pids(), sep='\n')
print('\nWindows:')
print(*list_windows(), sep='\n')
MSDN 链接: