我尝试在windows11,python 3.11中使用以下程序来挂接焦点更改事件。
import win32con
import pythoncom
from ctypes import wintypes, windll, WINFUNCTYPE
# WinEventProc and GUITHREADINFO
WinEventProc = WINFUNCTYPE(
None,
wintypes.HANDLE,
wintypes.DWORD,
wintypes.HWND,
wintypes.LONG,
wintypes.LONG,
wintypes.DWORD,
wintypes.DWORD
)
# focus_changed function
def focus_changed(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
print("Focus changed event detected")
# Main code
hook = windll.user32.SetWinEventHook(
win32con.EVENT_SYSTEM_FOREGROUND,
win32con.EVENT_SYSTEM_FOREGROUND,
0,
WinEventProc(focus_changed),
0,
0,
win32con.WINEVENT_OUTOFCONTEXT
)
if not hook:
print(f"SetWinEventHook failed")
print("Script is running...")
while True:
try:
pythoncom.PumpWaitingMessages()
except KeyboardInterrupt:
print("Exiting...")
break
# Cleanup: Unhook events and release resources
windll.user32.UnhookWinEvent(hook)
字符串
当我启动记事本时,我希望看到控制台上打印的“检测到焦点更改事件”。
当我启动上面的程序时,它会打印“脚本正在运行..."。
当我启动记事本时,上面的程序无声地终止,没有打印焦点改变事件消息或任何其他消息。
1条答案
按热度按时间snvhrwxg1#
主要问题是使用
WinEventProc(focus_changed)
作为SetWinEventHook
的参数。这是一个引用计数为零的对象,并且在调用后立即被释放。来自ctypes
文档:注意事项:确保只要在C代码中使用
CFUNCTYPE()
(* 和WINFUNCTYPE()
*)对象,就保持对它们的引用。ctypes不这样做,如果不这样做,它们可能会被垃圾收集,在回调时使程序崩溃。创建永久引用的一种方法是简单地用原型装饰回调函数。
下面的工作代码。还请注意,在
ctypes
函数上显式声明参数类型是一个很好的做法,可以更好地进行类型和错误检查。例如,ctypes
假定非指针参数和所有返回值都是32位整数。句柄是整数,但都是64位的。如果句柄足够大,则值将被截断,除非参数或返回值被声明为句柄。字符串