【问题标题】:Ending a Program Mid-Run中途结束程序
【发布时间】:2011-08-26 18:16:25
【问题描述】:

pythoncom.PumpMessages()

据我了解,这一行基本上告诉程序永远等待。就我的目的而言,它似乎正在工作。但是,我希望能够在适当的刺激下结束该计划。如何结束上述行,或停止程序继续运行。

【问题讨论】:

  • 在您明确说明您在等待什么刺激之前,没有答案是完整的。

标签: python exit message-pump pythoncom


【解决方案1】:

根据这些docspythoncom.PumpMessages()

泵送当前线程的所有消息,直到出现 WM_QUIT 消息。

所以停止收集消息的一种方法是通过使用ctypes 库调用PostQuitMessage 将WM_QUIT 消息发布到消息队列:

ctypes.windll.user32.PostQuitMessage(0)

【讨论】:

  • 8 年后,这似乎不再起作用了 :)
【解决方案2】:

这是一个使用计时器线程退出应用程序的示例:

import win32api
import win32con
import pythoncom
from threading import Timer

main_thread_id = win32api.GetCurrentThreadId()

def on_timer():
    win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);

t = Timer(5.0, on_timer) # Quit after 5 seconds
t.start()

pythoncom.PumpMessages()

PostQuitMessage() 只能在主线程中工作,但随后主线程被阻塞,所以它本身并不是很有用。只有将自己的自定义消息处理挂接到消息循环中才能使用它。

【讨论】:

    【解决方案3】:

    我想通过GreggBoaz Yaniv 扩展这两个答案。您通常会在单独的线程中运行阻塞代码,因此您需要将 WM_QUIT 发送到线程。您应该使用 Gregg 指出的PostQuitMessage,但这仅适用于当前线程。您不应该使用 PostThreadMessage 发送 WM_QUIT (不记得我在文档中看到它的位置)。您可以在讨论“Why is there a special PostQuitMessage function?”中了解更多信息。我认为最好先将 WM_CLOSE 发送到线程。

    # if more hotkeys needs to be supported at the same time this class needs to be rewritten
    class HotKey:
        def __init__(self, modifier_key, virtual_key, callback):
            self.hotkey_id = 1
            # shared variable to pass thread id
            self.pid = mpdummy.Value('l', 0)
    
            # start checking hotkey press in new thread
            self.process_pool = mpdummy.Pool()
            self.process_pool.apply_async(HotKey.register, (self.hotkey_id, self.pid, modifier_key, virtual_key, callback, ))
            self.process_pool.close()
    
        # bind windows global hotkey
        @staticmethod
        def register(hotkey_id, pid, modifier_key, virtual_key, callback):
            # set thread ID to shared variable
            # Win API could also be used:
            # ctypes.windll.Kernel32.GetCurrentThreadId()
            pid.value = mpdummy.current_process().ident
    
            # register hotkey with Win API
            logging.getLogger('default').info("Registering hotkey with id " + str(hotkey_id) + " for key " + str(modifier_key) + " " + str(virtual_key))
            if not ctypes.windll.user32.RegisterHotKey(None, hotkey_id, modifier_key, virtual_key):
                logging.getLogger('default').info("Unable to register hotkey with id " + str(hotkey_id))
    
            msg = ctypes.wintypes.MSG()
            try:
                # wait for a message - it doesn't return until some message arrives
                while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
                    # WM_HOTKEY     0x0312
                    # https://msdn.microsoft.com/en-us/library/windows/desktop/ms646279(v=vs.85).aspx
                    if msg.message == 0x0312:
                        logging.getLogger('default').info("Pressed hotkey with id " + str(hotkey_id))
                        callback()
                    # WM_CLOSE
                    # https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
                    elif msg.message == 0x0010:
                        # quit current thread
                        # WM_QUIT shouldn't be send with PostThreadMessageA therefore we send WM_CLOSE and quit inside thread.
                        # More info at:
                        # https://msdn.microsoft.com/en-us/library/windows/desktop/ms644945(v=vs.85).aspx
                        # https://blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453
                        ctypes.windll.user32.PostQuitMessage(0)
                    ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
                    ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
            finally:
                logging.getLogger('default').info("Unregistering hotkey for id " + str(hotkey_id))
                ctypes.windll.user32.UnregisterHotKey(None, hotkey_id)
    
        def unregister(self):
            # send WM_CLOSE signal to thread checking for messages
            # WM_CLOSE      0x0010
            # https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
            ctypes.windll.user32.PostThreadMessageA(self.pid.value, 0x0010, 0, 0)
            # wait for thread to finish
            self.process_pool.join()
    

    我将它用于RegisterHotKey,但原理相同。这个类可以被称为:

    # bind global hotkey for "pressing" start/split button
    # MOD_ALT       0x0001
    # VK_F12        0x7B
    # https://msdn.microsoft.com/en-us/library/windows/desktop/ms646309(v=vs.85).aspx
    # https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731.aspx
    self.hotkey = hotkey.HotKey(0x0001, 0x7B, self.special_key_pressed)
    

    当你想结束等待消息时调用:

    self.hotkey.unregister()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2022-01-18
      • 2013-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      相关资源
      最近更新 更多