什么是消息泵?

发布于 2024-08-20 11:31:15 字数 649 浏览 11 评论 0原文

此线程中(发布大约一年前)有一个关于在非交互式会话中运行 Word 可能出现的问题的讨论。那里给出的(非常强烈的)建议是不要这样做。在一篇文章中,它指出“Office API 都假设您在桌面上的交互式会话中运行 Office,配有显示器、键盘和鼠标,最重要的是,还有消息泵。”我不确定那是什么。 (我使用 C# 编程的时间大约只有一年;我的其他编程经验主要是使用 ColdFusion。)

更新:

我的程序运行大量 RTF 文件,以提取用于构建医疗报告编号的两条信息。我没有尝试弄清楚 RTF 中的格式化指令是如何工作的,而是决定在 Word 中打开它们并从那里提取文本(而不实际启动 GUI)。有时,程序会在处理一个文件的过程中出现问题,并导致附加到该文档的 Word 线程处于打开状态(我仍然需要弄清楚如何关闭该线程)。当我重新运行程序时,我当然收到了一个通知,有一个线程正在使用该文件,我是否想打开一个只读副本?当我说“是”时,Word GUI 突然不知从哪里弹出并开始处理文件。我想知道为什么会发生这种事;但看起来也许一旦弹出对话框,消息泵也开始将主 GUI 推送到 Windows?

In this thread (posted about a year ago) there is a discussion of problems that can come with running Word in a non-interactive session. The (quite strong) advice given there is not to do so. In one post it is stated "The Office APIs all assume you are running Office in an interactive session on a desktop, with a monitor, keyboard and mouse and, most importantly, a message pump." I'm not sure what that is. (I've been programming in C# for only about a year; my other programming experience has primarily been with ColdFusion.)

Update:

My program runs through a large number of RTF files to extract two pieces of information used to construct a medical report number. Rather than try and figure out how the formatting instructions in RTF work, I decided to just open them in Word and pull the text out from there (without actually starting the GUI). Occasionally, the program hiccuped in the middle of processing one file, and left a Word thread open attached to that document (I still have to figure out how to shut that one down). When I re-ran the program, of course I got a notification that there was a thread using that file, and did I want to open a read-only copy? When I said Yes, the Word GUI suddenly popped up from nowhere and started processing the files. I was wondering why that happened; but it looks like maybe once the dialog box popped up the message pump started pushing the main GUI to Windows as well?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

半岛未凉 2024-08-27 11:31:15

消息循环是任何本机 Windows 程序中都存在的一小段代码。它大致如下所示:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ 
   TranslateMessage(&msg); 
   DispatchMessage(&msg); 
} 

GetMessage() Win32 API 从 Windows 检索消息。您的程序通常会花费 99.9% 的时间等待 Windows 告诉它发生了一些有趣的事情。 TranslateMessage() 是一个翻译键盘消息的辅助函数。 DispatchMessage() 确保使用消息调用窗口过程。

每个启用 GUI 的 .NET 程序都有一个消息循环,它由 Application.Run() 启动。

消息循环与 Office 的相关性与 COM 相关。 Office 程序是启用 COM 的程序,这就是 Microsoft.Office.Interop 类的工作方式。 COM 代表 COM 组件类处理线程,它确保对 COM 接口进行的调用始终从正确的线程进行。大多数 COM 类在注册表中都有一个注册表项来声明其 ThreadingModel,到目前为止,最常见的类(包括 Office)使用“Apartment”。这意味着调用接口方法的唯一安全方法是从创建类对象的同一线程进行调用。或者换句话说:到目前为止,大多数 COM 类都不是线程安全的。

每个启用 COM 的线程都属于一个 COM 单元。有两种类型:单线程单元 (STA) 和多线程单元 (MTA)。单元线程 COM 类必须在 STA 线程上创建。您可以在 .NET 程序中看到这一点,Windows 窗体或 WPF 程序的 UI 线程的入口点具有 [STAThread] 属性。其他线程的公寓模型由 Thread.SetApartmentState() 方法设置。

如果 UI 线程不是 STA,Windows 管道的大部分将无法正常工作。特别是拖放、剪贴板、Windows 对话框(如 OpenFileDialog)、控件(如 WebBrowser)、UI 自动化应用程序(如屏幕阅读器)。还有许多 COM 服务器,例如 Office。

STA 线程的硬性要求是它永远不应该阻塞并且必须泵送消息循环。消息循环很重要,因为 COM 使用它来将接口方法调用从一个线程编组到另一个线程。尽管 .NET 使封送调用变得容易(例如 Control.BeginInvoke 或 Dispatcher.BeginInvoke),但这实际上是一件非常棘手的事情。执行调用的线程必须处于众所周知的状态。您不能随意中断线程并强制它进行方法调用,这会导致可怕的重入问题。线程应该处于“空闲”状态,而不是忙于执行任何改变程序状态的代码。

也许您可以看到这会导致什么结果:是的,当程序执行消息循环时,它是空闲的。实际的封送处理是通过 COM 创建的隐藏窗口进行的,它使用 PostMessage 使该窗口的窗口过程执行代码。在 STA 线程上。消息循环确保此代码运行。

A message loop is a small piece of code that exists in any native Windows program. It roughly looks like this:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ 
   TranslateMessage(&msg); 
   DispatchMessage(&msg); 
} 

The GetMessage() Win32 API retrieves a message from Windows. Your program typically spends 99.9% of its time there, waiting for Windows to tell it something interesting happened. TranslateMessage() is a helper function that translates keyboard messages. DispatchMessage() ensures that the window procedure is called with the message.

Every GUI enabled .NET program has a message loop, it is started by Application.Run().

The relevance of a message loop to Office is related to COM. Office programs are COM-enabled programs, that's how the Microsoft.Office.Interop classes work. COM takes care of threading on behalf of a COM coclass, it ensures that calls made on a COM interface are always made from the correct thread. Most COM classes have a registry key in the registry that declares their ThreadingModel, by far the most common ones (including Office) use "Apartment". Which means that the only safe way to call an interface method is by making the call from the same thread that created the class object. Or to put it another way: by far most COM classes are not thread-safe.

Every COM enabled thread belongs to a COM apartment. There are two kinds, Single Threaded Apartments (STA) and a Multi Thread Apartment (MTA). An apartment threaded COM class must be created on an STA thread. You can see this back in .NET programs, the entry point of the UI thread of a Windows Forms or WPF program has the [STAThread] attribute. The apartment model for other threads is set by the Thread.SetApartmentState() method.

Large parts of Windows plumbing won't work correctly if the UI thread is not STA. Notably Drag+Drop, the clipboard, Windows dialogs like OpenFileDialog, controls like WebBrowser, UI Automation apps like screen readers. And many COM servers, like Office.

A hard requirement for an STA thread is that it should never block and must pump a message loop. The message loop is important because that's what COM uses to marshal an interface method call from one thread to another. Although .NET makes marshaling calls easy (Control.BeginInvoke or Dispatcher.BeginInvoke for example), it is actually a very tricky thing to do. The thread that executes the call must be in a well-known state. You can't just arbitrarily interrupt a thread and force it to make a method call, that would cause horrible re-entrancy problems. A thread should be "idle", not busy executing any code that is mutating the state of the program.

Perhaps you can see where that leads: yes, when a program is executing the message loop, it is idle. The actual marshaling takes place through a hidden window that COM creates, it uses PostMessage to have the window procedure of that window execute code. On the STA thread. The message loop ensures that this code runs.

墨落成白 2024-08-27 11:31:15

“消息泵”是任何 Windows 程序的核心部分,负责将窗口消息分派到应用程序的各个部分。这是Win32 UI编程的核心。由于它的普遍性,许多应用程序使用消息泵在不同模块之间传递消息,这就是为什么 Office 应用程序如果在没有任何 UI 的情况下运行就会崩溃。

维基百科有一个基本描述

The "message pump" is a core part of any Windows program that is responsible for dispatching windowing messages to the various parts of the application. This is the core of Win32 UI programming. Because of its ubiquity, many applications use the message pump to pass messages between different modules, which is why Office applications will break if they are run without any UI.

Wikipedia has a basic description.

草莓酥 2024-08-27 11:31:15

John 正在谈论 Windows 系统(以及其他基于窗口的系统 - X Window、原始 Mac OS....)通过消息系统使用事件实现异步用户界面。

每个应用程序的幕后都有一个消息系统,每个窗口都可以将事件发送到其他窗口或事件侦听器 - 这是通过向消息队列添加消息来实现的。有一个主循环始终运行,查看此消息队列,然后将消息(或事件)分派给侦听器。

维基百科文章Microsoft Windows 中的消息循环展示了基本的 Windows 程序——正如您所见,在最基本的层面上,Windows 程序只是“消息泵”。

因此,将所有内容整合在一起。设计用于支持 UI 的 Windows 程序无法充当服务的原因是它需要始终运行消息循环来启用 UI 支持。如果您将其实现为所描述的服务,它将无法处理内部异步事件处理。

John is talking about how the Windows system (and other window based systems - X Window, original Mac OS....) implement asynchronous user interfaces using events via a message system.

Behind the scenes for each application there is a messaging system where each window can send events to other windows or event listeners -- this is implemented by adding a message to the message queue. There is a main loop which always runs looking at this message queue and then dispatching the messages (or events) to the listeners.

The Wikipedia article Message loop in Microsoft Windows shows example code of a basic Windows program -- and as you can see at the most basic level a Windows program is just the "message pump".

So, to pull it all together. The reason a windows program designed to support a UI can't act as a service is because it needs the message loop running all the time to enable UI support. If you implement it as a service as described, it won't be able to process the internal asynchronous event handling.

独闯女儿国 2024-08-27 11:31:15

COM 中,消息泵对公寓之间发送的消息进行序列化和反序列化。公寓是一个可以在其中运行 COM 组件的微型进程。公寓有单线程和自由线程模式。单线程公寓主要是不支持多线程的 COM 组件应用程序的遗留系统。它们通常与 Visual BASIC(因为它不支持多线程代码)和遗留应用程序一起使用。

我猜想 Word 的消息泵要求源于 COM API 或应用程序的某些部分,而不是线程安全。请记住,.NET 线程和垃圾收集模型不能很好地与 COM 配合使用盒子的。 COM 具有非常简单的垃圾收集机制和线程模型,要求您以 COM 方式执行操作。使用标准 Office PIA 仍然需要您显式关闭 COM 对象引用,因此您需要跟踪创建的每个 COM 句柄。如果您不小心,PIA 还会在幕后创建一些东西。

.NET-COM 集成本身就是一个完整的主题,甚至还有关于该主题的书籍。即使从交互式桌面应用程序中使用 Office 的 COM API 也需要您跳过重重困难并确保显式释放引用。

Office 可以被认为是线程不安全的,因此您将需要一个单独的 Word 实例、Excel或每个线程的其他 Office 应用程序。您将不得不承担启动开销或维护线程池。必须仔细测试线程池,以确保正确释放所有 COM 引用。即使启动和关闭实例也需要您确保正确释放所有引用。未能在此处点 i 和跨 t 将导致大量死 COM 对象,甚至整个正在运行的 Word 实例被泄露。

In COM, a message pump serialises and de-serialises messages sent between apartments. An apartment is a mini process in which COM components can be run. Apartments come in single threaded and free threaded modes. Single threaded apartments are mainly a legacy system for applications of COM components that don't support multi-threading. They were typically used with Visual BASIC (as this did not support multi-threaded code) and legacy applications.

I guess that the message pump requirement for Word stems from either the COM API or parts of the application not being thread safe. Bear in mind that the .NET threading and garbage collection models don't play nicely with COM out of the box. COM has a very simplistic garbage collection mechanism and threading model that requires you to do things the COM way. Using the standard Office PIAs still requires you to explicitly shut down COM object references, so you need to keep track of every COM handle created. The PIAs will also create stuff behind the scenes if you're not careful.

.NET-COM integration is a whole topic all by itself, and there are even books written on the subject. Even using COM APIs for Office from an interactive desktop application requires you to jump through hoops and make sure that references are explicitly released.

Office can be assumed to be thread-unsafe, so you will need a separate instance of Word, Excel or other Office applications for each thread. You would have to incur the starting overhead or maintain a thread pool. A thread pool would have to be meticulously tested to make sure all COM references were correctly released. Even starting and shutting down instances requires you to make sure all references are released correctly. Failure to dot your i's and cross your t's here will result in large numbers of dead COM objects and even whole running instances of Word being leaked.

谜兔 2024-08-27 11:31:15

维基百科建议它指的是程序的主事件循环

Wikipedia suggests it means the program's main Event Loop.

如果没有 2024-08-27 11:31:15

我认为这个 Channel 9 讨论有一个很好的简洁解释:

这个窗口通信过程是通过所谓的Windows消息泵实现的。将消息泵视为一个支持应用程序窗口和桌面之间协作的实体。

I think that this Channel 9 discussion has a nice succinct explanation:

This process of window communication is made possible by the so-called Windows Message Pump. Think of the Message Pump as an entity that enables cooperation between application windows and the desktop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文