【问题标题】:Never getting past PumpMessages永远不会过去 PumpMessages
【发布时间】:2013-12-20 20:11:55
【问题描述】:

我正在编写一个通过程序的 WM_COPYDATA api 进行交互的脚本,但我卡在 PumpMessage 功能上。

import win32con, win32api, win32gui
import ctypes, ctypes.wintypes

FindWindow = ctypes.windll.user32.FindWindowW
SendMessage = ctypes.windll.user32.SendMessageW

class COPYDATASTRUCT(ctypes.Structure):
    _fields_ = [
        ('dwData', ctypes.wintypes.LPARAM),
        ('cbData', ctypes.wintypes.DWORD),
        ('lpData', ctypes.c_char_p)
        #formally lpData is c_void_p, but we do it this way for convenience
]

PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)

class Stickies:

    def __init__(self):
        message_map = {
            win32con.WM_COPYDATA: self.OnCopyData
        }
        wc = win32gui.WNDCLASS()
        wc.lpfnWndProc = message_map
        wc.lpszClassName = 'MyWindowClass'
        hinst = wc.hInstance = win32api.GetModuleHandle(None)
        classAtom = win32gui.RegisterClass(wc)
        self.hwnd = win32gui.CreateWindow (
            classAtom,
            "win32gui test",
            0,
            0, 
            0,
            win32con.CW_USEDEFAULT, 
            win32con.CW_USEDEFAULT,
            0, 
            0,
            hinst, 
            None
        )
        self.send_message("api do register")

    def __enter__(self):
        return self

    def __exit__(self):
        self.send_message("api do deregister")

    def send_message(self, msg):
        hwnd = FindWindow(None, "ZhornSoftwareStickiesMain")
        cds = COPYDATASTRUCT()
        cds.dwData = 0
        str = msg.encode("ascii")
        cds.cbData = ctypes.sizeof(ctypes.create_string_buffer(str))
        cds.lpData = ctypes.c_char_p(str)
        SendMessage(hwnd, win32con.WM_COPYDATA, self.hwnd, ctypes.byref(cds))

    def OnCopyData(self, hwnd, msg, wparam, lparam):
        pCDS = ctypes.cast(lparam, PCOPYDATASTRUCT)
        msg = pCDS.contents.lpData.decode("ascii", "ignore")

        if msg != None:
            print(msg)

        return 1

s = Stickies()
win32gui.PumpMessages()

# Never gets past previous line
print("Hello, world!")

在我的代码中,我可以成功发送和接收消息,但我不确定如何让我的脚本执行其他操作。我的目标是将此作为基类,然后将其合并到其他脚本中。

我不知道该怎么做:

  1. 通过 pumpmessage() 函数
  2. 在课堂外处理消息。

任何帮助将不胜感激。

【问题讨论】:

  • PumpMessages 实现了一个标准的 Windows 消息循环。它循环和处理消息。在线程收到 WM_QUIT 消息之前(通常在 gui 应用程序中关闭主窗口时),您不会期望它返回。
  • @arx:那么有没有更好的等待消息的方法?不幸的是,我真的没有在网上找到很多关于 Python 这类东西的信息/示例。

标签: winapi python-3.x win32com win32gui


【解决方案1】:

SendMessage 是同步的。将WM_COPYDATA 发送到其他应用程序,您的代码将在 Windows 内部消息循环中等待,直到您收到回复。

这意味着您的代码可以在等待时响应来自其他应用程序的消息。如果协议涉及消息交换,则可能需要这样做。

只有在回复未经请求的消息时才需要消息循环。

我不知道你在做什么,但很可能你可以完全删除对win32gui.PumpMessages 的调用。

【讨论】:

  • 这是不对的,或者至少术语是关闭的。 SendMessage(..., WM_COPYDATA, ...) 确实是同步的。但是当消息被处理时,对SendMessage 的调用会返回。我认为说“您的代码将在 Windows 内部消息循环中等待,直到您收到回复”是不明智的。发生的情况是调用进程阻塞,直到接收进程完成处理。这不是消息循环。
  • 现在,可能确实需要一个消息循环。有些东西必须调度传入的同步消息。通常这是作为消息循环的一部分完成的。这是在对GetMessage 的调用中完成的。
  • @DavidHeffernan 如果您收到一条响应 SendMessage 的消息(非常频繁发生的事情),那么它是如何传递的?我忘了。我认为你是对的,它不是消息循环。也许消息是直接传递给窗口过程的。无论哪种方式,它都不会通过 your 消息循环。如果他正在驱动另一个应用程序,他不会收到任何未经请求的消息,那么他为什么需要消息循环?
  • 这取决于消息何时返回。它是否会在对SendMessage 的调用中返回。还是它回来后又回来了。
  • 问题不清楚。他正在编写一个脚本来驱动另一个应用程序,所以我假设消息协议是简单且同步的。但是,是的,我们不知道。
【解决方案2】:

PumpMessages 冻结当前线程。如果你想在 PumpMessages 之后做一些事情,考虑创建一个新线程并使用 threading 模块运行它:

import threading
import win32gui

def otherCodeToRun(x, y, z):
    print("Hello World!")

t = threading.Thread(target=otherCodeToRun, args=(x, y, z, )) // You can leave out args if you don't have any parameters.
t.start()

win32gui.PumpMessages()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    相关资源
    最近更新 更多