来自不同线程的Pythoncom PumpMessages

编程入门 行业动态 更新时间:2024-10-21 03:39:28
本文介绍了来自不同线程的Pythoncom PumpMessages的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我想做的事情类似于,但使用 threading ,例如此处.还使用了此处的答案,我的代码可以正常工作,只是没有ItemItem事件可以识别(实际上,我认为是的,但是在另一个线程中,这就是为什么没有输出的原因.)

I want to do something similar to what is asked here, but using threading like here. Using also the answer from here, I got my code working, only that an ItemAdd event is not recognised (actually, I think it is, but in the other thread, which is why there is no output).

"""Handler class that watches for incoming mails""" import ctypes # for the WM_QUIT to stop PumpMessage() import logging import win32com.client import sys import threading import time import pythoncom # outlook config CENTRAL_MAILBOX = "My Mailbox" # get the outlook instance and inbox folders outlook = win32com.client.Dispatch("Outlook.Application") marshalled_otlk = pythoncom.CoMarshalInterThreadInterfaceInStream( pythoncom.IID_IDispatch, outlook) class HandlerClass(object): def OnItemAdd(self, item): logger.info("New item added in central mailbox") if item.Class == 43: logger.info("The item is an email!") class OtlkThread(threading.Thread): def __init__(self, marshalled_otlk, *args, **kwargs): super().__init__(*args, **kwargs) self.marshalled_otlk = marshalled_otlk self.logger = logging.getLogger("OLThread") def run(self): self.logger.info("Starting up Outlook watcher\n" "To terminate the program, press 'Ctrl + C'") pythoncom.CoInitialize() outlook = win32com.client.Dispatch( pythoncom.CoGetInterfaceAndReleaseStream( self.marshalled_otlk, pythoncom.IID_IDispatch ) ) user = outlook.Session.CreateRecipient(CENTRAL_MAILBOX) central_inbox = outlook.Session.GetSharedDefaultFolder(user, 6).Items self.logger.info(f"{central_inbox.Count} messages in central inbox") win32com.client.DispatchWithEvents(central_inbox, HandlerClass) pythoncom.PumpMessages() pythoncom.CoUninitialize() # this is prbly unnecessary as it will never be reached def main(): # pythoncom.CoInitialize() OtlkThread(marshalled_otlk, daemon=True).start() if __name__ == "__main__": status = main() while True: try: # pythoncom.PumpWaitingMessages() time.sleep(1) except KeyboardInterrupt: logger.info("Terminating program..") ctypes.windll.user32.PostQuitMessage(0) sys.exit(status)

我尝试了各种方法,例如将 sys.coinit_flags = 0 放在顶部,如建议的此处),在主线程中调用 PumpWaitingMessages(),并且在侧线程本身中获取Outlook应用程序,而不是传递编组的对象.这些都不起作用.

I have tried various things, such as putting sys.coinit_flags=0 at the top, as suggested here), calling PumpWaitingMessages() in the main thread, and getting the Outlook application in the side thread itself, instead of passing the marshalled object. None of these have worked.

当我只是将PumpMessages放入主线程(相同的 HandlerClass ,但没有单独的线程)时,它可以工作,并且在到达时可以识别电子邮件,但是很明显,该线程被阻塞了,甚至无法收到KeyboardInterrupt异常抓到了.

When I just put PumpMessages in the main thread (same HandlerClass but no separate thread) it works and emails are recognised upon arrival, but obviously the thread is blocked and not even the KeyboardInterrupt exception can be caught.

那么,如何使Outlook Watcher在单独的线程中运行,以将消息发送到主线程以在那里输出?

So, how do I get the outlook watcher running in the separate thread to send the messages to the main thread for output there?

推荐答案

再次非常感谢Michael的回答,这导致我这个答案,其中还包含指向优秀示例的链接.从答案和示例中得出的主要结论是,与其将Outlook作为一个编组对象传递,不如将它作为客户端传递给处理程序.另外,要使用 WithEvents 代替 DispatchWithEvents ,并在导入 pythoncom之前将 sys.coinit_flags = 0 设置为.

Again thanks a lot for your answer Michael, it led me to this answer which also contains a link to an excellent example. The main takeaway from the answer and the example is that, instead of passing Outlook as a marshalled object, just pass it as client to the handler. Also, to use WithEvents instead of DispatchWithEvents and to set sys.coinit_flags = 0 before importing pythoncom.

最终结果如下:

"""Handler class that watches for incoming mails""" import ctypes # for the WM_QUIT to stop PumpMessage() import logging import sys import time from threading import Thread sys.coinit_flags = 0 # pythoncom.COINIT_MULTITHREADED == 0 from pythoncom import (CoInitializeEx, CoUninitialize, COINIT_MULTITHREADED, PumpWaitingMessages) from win32com.client import Dispatch, WithEvents # outlook config CENTRAL_MAILBOX = "My Mailbox" # COM event handler class IncomingMailHandler: def OnItemAdd(self, item): logger.info("New item added in central mailbox") if item.Class == 43: logger.info(f"The item is an email with subject {item.Subject}") # main thread def main(): # get the outlook instance and inbox folders outlook = Dispatch("Outlook.Application") user = outlook.Session.CreateRecipient(CENTRAL_MAILBOX) central_inbox = outlook.Session.GetSharedDefaultFolder(user, 6).Items logger.info(f"{central_inbox.Count} messages in central inbox") # launch the second thread thread = Thread(target=watcher, args=(central_inbox,), daemon=True) thread.start() # other thread worker function def watcher(client): logger = logging.getLogger("watcher") CoInitializeEx(COINIT_MULTITHREADED) WithEvents(client, IncomingMailHandler) # event loop 2 _loop = 0 while True: PumpWaitingMessages() _loop += 1 if _loop % 20 == 0: logger.info("Watcher is running..") time.sleep(0.5) CoUninitialize() if __name__ == "__main__": logger.info("Starting up Outlook watcher\n" "To terminate the program, press 'Ctrl + C'") status = main() while True: try: time.sleep(0.5) except KeyboardInterrupt: logger.info("Terminating program..") ctypes.windll.user32.PostQuitMessage(0) sys.exit(status)

更多推荐

来自不同线程的Pythoncom PumpMessages

本文发布于:2023-11-12 12:23:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1581487.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   Pythoncom   PumpMessages

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!