写在前面
此问题是在不同线程之间通信时出现的,在开始下一次任务之前,要确保某个子线程已退出(后来才想到在适当地方join前述子线程就可以了),不过当时已经使用PostMessage实现了不同线程通信,在此记录一下,或许他日有用。
实现代码
import ctypes
WM_USER = 0x400
WM_PLAYER_STOP = WM_USER + 0x1
# 用于接收消息,在接收到消息之前将阻塞进程
GetMessageW = ctypes.windll.user32.GetMessageW
GetMessageW.argtypes = [ctypes.POINTER(ctypes.wintypes.MSG), ctypes.wintypes.HWND, ctypes.c_uint, ctypes.c_uint]
# 此方法只能将消息发送到同一线程
PostMessageW = ctypes.windll.user32.PostMessageW
PostMessageW.argtypes = [ctypes.wintypes.HWND,ctypes.c_uint,ctypes.wintypes.HINSTANCE, ctypes.c_uint]
# 此方法大致等同于GetMessage,具体见MSDN
PeekMessageW = ctypes.windll.user32.PeekMessageW
PeekMessageW.argtypes = [ctypes.POINTER(ctypes.wintypes.MSG), ctypes.wintypes.HWND, ctypes.c_uint, ctypes.c_uint,ctypes.c_int]
# 此方法可以将消息发送到指定的线程
PostThreadMessageW = ctypes.windll.user32.PostThreadMessageW
PostThreadMessageW.argtypes = [ctypes.wintypes.DWORD,ctypes.c_uint,ctypes.wintypes.HINSTANCE, ctypes.c_uint]
# 用于接收到消息之后的后续处理
DispatchMessageW = ctypes.windll.user32.DispatchMessageW
TranslateMessage = ctypes.windll.user32.TranslateMessage
TranslateMessage.argtypes = [ctypes.POINTER(ctypes.wintypes.MSG)]
DispatchMessageW.argtypes = [ctypes.POINTER(ctypes.wintypes.MSG)]
def postmessage():
# threading.main_thread().ident为主线程的ID
PostThreadMessageW(ctypes.wintypes.DWORD(threading.main_thread().ident),ctypes.c_uint(WM_PLAYER_STOP),ctypes.wintypes.HINSTANCE(WM_PLAYER_STOP),ctypes.c_uint(0))
def testgetmsg():
# 创建子线程,子线程向主线程发送一条消息
t = threading.Thread(target = postmessage)
t.start()
t.join()
# 主线程发送消息
PostMessageW(ctypes.wintypes.HWND(0),ctypes.c_uint(WM_PLAYER_STOP),ctypes.wintypes.HINSTANCE(WM_PLAYER_STOP),ctypes.c_uint(0))
ctypes.windll.user32.PostQuitMessage(0)
# Windows消息结构体
message = ctypes.wintypes.MSG()
while True:
# 第一个参数是message对象的指针,第二个参数是目标窗口句柄,后面两个参数为消息类型的搜索范围
msg = GetMessageW(ctypes.byref(message), 0, WM_USER, WM_USER + 100)
if message.message == WM_PLAYER_STOP:
print(message.message)
if msg in [0,-1]:
break
else:
TranslateMessage(ctypes.byref(message))
DispatchMessageW(ctypes.byref(message))