对于我的一些python应用程序,我正在使用ctypes和windowsapi安装系统钩子,为了使它们工作,必须运行一个消息循环。因为我有其他事情发生在前台,所以这个消息循环被设置为作为后台线程运行。这个部分工作得很好,但是当我想停止这个后台线程时,我无法让它退出,当收到WM_QUIT消息时GetMessage函数应该返回0,而我的消息循环体应该返回0,但是由于某些原因它从来没有这样做过。 我尝试过SendMessage、PostMessage、PostThreadMessage和PostQuitMessage的各种组合,但都没有成功。在
#!python3
import tkinter as tk
import ctypes
import ctypes.wintypes
from threading import Thread
user32 = ctypes.windll.user32
def loop():
msg = ctypes.wintypes.MSG()
while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0:
print('msg')
user32.TranslateMessageW(msg)
user32.DispatchMessageW(msg)
print('end of loop')
def SendMessage1():
user32.SendMessageA(0xFFFF, 0x001C, 0, 0) # broadcast handle, app_activate message
def SendMessage2():
user32.SendMessageA(0, 0x001C, 0, 0) # null handle
def PostMessage1():
user32.PostMessageA(0xFFFF, 0x001C, 0, 0)
def PostMessage2():
user32.PostMessageA(0, 0x001C, 0, 0)
def PostThreadMessage1():
user32.PostThreadMessageA(0xFFFF, 0x001C, 0, 0)
def PostThreadMessage2():
user32.PostThreadMessageA(0, 0x001C, 0, 0)
def PostQuitMessage1():
user32.PostQuitMessage(0)
def PostQuitMessage2():
user32.PostQuitMessage(0)
root = tk.Tk()
t = Thread(target=loop)
t.daemon=True
t.start()
tk.Button(root, text='SendMessage 1', command=SendMessage1).pack()
tk.Button(root, text='SendMessage 2', command=SendMessage2).pack()
tk.Button(root, text='PostMessage 1', command=PostMessage1).pack()
tk.Button(root, text='PostMessage 2', command=PostMessage2).pack()
tk.Button(root, text='PostThreadMessage 1', command=PostThreadMessage1).pack()
tk.Button(root, text='PostThreadMessage 2', command=PostThreadMessage2).pack()
tk.Button(root, text='PostQuitMessage 1', command=PostQuitMessage1).pack()
tk.Button(root, text='PostQuitMessage 2', command=PostQuitMessage2).pack()
root.mainloop()
我也尝试了这些函数的A和W变量。我认为问题可能是因为我无法获取实际监听消息的线程的句柄,也找不到任何与此相关的文档。在
我还研究了在线程上下文中引发一个异常,但是由于挂起是在dll中而不是在python代码中,GIL已经被释放了,这并不能导致它退出。在
我怎样才能让这个线程优雅地退出呢?在
确定我确实需要线程的句柄,并且可以使用
kernel32.GetCurrentThreadId()
函数访问它:相关问题 更多 >
编程相关推荐