我试图了解 python 通过 pywin32 库使用 Windows 消息的能力。为此,我创建了两个应该并行运行的脚本。一个是应该发送消息的客户端,另一个是应该打印所有传入消息的服务器。为了使用窗口消息,我给了他们带有 tkinter 库的 gui 窗口。
但是当我运行它们时,并行服务器没有收到任何消息,即使看起来没有错误并且 Windows 处理签出。我确保在 Visual Studio 中使用 Microsoft Spy++ 到达正确的句柄。
我使用此功能找到他们的句柄:
def get_window_handle_by_tittle(tittle):
window_handle = [0]
def window_callback(hwnd, lParam):
window_tittle, window_handle = lParam
current_tittle = win32gui.GetWindowText(hwnd)
if current_tittle == window_tittle:
# check if this is the target window
window_handle[0] = hwnd
return False
else:
return True
try:
# Start the enumeration of top-level windows
lParam = (tittle, window_handle)
win32gui.EnumWindows(window_callback, lParam)
return window_handle[0]
except pywintypes.error as e:
if window_handle[0] and window_handle[0] != 0:
# Check window title if provided
return window_handle[0]
else:
return None
except Exception as e:
print(f"Error getting window handle: {e}")
这是客户端代码以及我作为不同 python 脚本的主要功能运行的客户端和服务器代码。
import time
import win32api
import win32gui
import tkinter as tk
import pywintypes
WM_USER = 0x0400
WM_STATEREQUEST = WM_USER + 1005
WM_STATEANSWER = WM_USER + 1006
def client:
root = tk.Tk()
root.title("WM_client")
root.geometry("400x300")
root.update()
root.deiconify()
python_hwnd = get_window_handle_by_tittle("WM_client")
print(f"Server handle is {hex(python_hwnd)}, starting listening")
target = get_window_handle_by_tittle("WM_server")
while True:
print(f"message to be sent {hex(int(target))}, {WM_STATEREQUEST} , {hex(python_hwnd)}, 0")
response = win32api.SendMessage(target, WM_STATEREQUEST, python_hwnd, 0)
print("server sent message response code", response)
print("last error given", win32api.GetLastError())
time.sleep(1)
def server:
root = tk.Tk()
root.title("WM_server")
root.geometry("400x300")
root.update()
root.deiconify()
python_hwnd = get_window_handle_by_tittle("WM_server")
print(f"Server handle is {hex(python_hwnd)}, starting listening")
while True:
msg = win32gui.PeekMessage(python_hwnd, 0, 100, win32con.PM_NOREMOVE)
if msg[0] != 0:
# Extract values from the tuple
window_handle, message_type, w_param, l_param, time_posted, (cursor_x, cursor_y) = msg[1]
if message_type != 96:
# exclude windows paint messages
# Print each value
print("\nWindow Handle:", window_handle)
print("Message Type:", hex(message_type), message_type)
print("wParam:", w_param)
print("lParam:", l_param, "\n")
这不是服务器的 PeekMessage 函数的问题,而是客户端的问题。因为如果是这种情况,我也可以使用 Spy++ 看到它们。所以现在我不认为我需要创建一个钩子函数来代替 pywin32 的 peek 消息函数。这里的问题是消息没有被发送或至少没有以某种方式发送到正确的窗口。
我希望服务器打印出通过 SendMessage() 函数发送的消息。特别是在确认脚本窗口的窗口句柄之后。
显然 peekMessages 对我不起作用,必须创建一个具有适当钩子功能的侦听器类来侦听消息。我仍然不知道 win32py 库如何处理 Windows 消息的意图,但我从另一个地方获取的这个孤子对我有用。
class Listener:
def __init__(self):
message_map = {
WM_MESSAGEONE : self.OnMessageOne ,
WM_MESSAGETWO : self.OnMessageTwo
}
wc = win32gui.WNDCLASS()
wc.lpfnWndProc = self.WndProc # Set window procedure
wc.lpszClassName = 'message-listener'
hinst = wc.hInstance = win32api.GetModuleHandle(None)
classAtom = win32gui.RegisterClass(wc)
self.hwnd = win32gui.CreateWindow (
classAtom,
"WM_server",
0,
0,
0,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
0,
0,
hinst,
None
)
def WndProc(self, hwnd, msg, wparam, lparam):
if msg == win32con.WM_COPYDATA:
return 0
elif msg == WM_MESSAGEONE : # Handle custom message
return self.OnMessageOne (hwnd, msg, wparam, lparam)
elif msg == WM_MESSAGETWO : # Handle custom message
return self.OnMessageTwo(hwnd, msg, wparam, lparam)
else:
return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)