在WinMain中不使用消息循环是否明智?

6

这可能是有史以来最简单的win32程序...

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdLine, int show)
{
    MessageBox(0, "Hello world..", "Salutations!", MB_OK);
    return 0;
}

..这个程序完全没有调用通常的GetMessage()函数。我的问题是:如果我的程序不处理任何窗口消息,操作系统能够应对吗?也就是说,它会导致内存泄漏吗?或者其他一些资源问题,除非我运行了16K次才会出现?

从更广泛的意义上讲,Win32在多大程度上依赖于应用程序处理其消息?我希望编译器在将可执行文件链接为Windows程序时,运行时能够清理任何类型的消息队列,无论是否被清空。


为了澄清,MessageBox()仅被用来以我认为微不足道的方式说明程序正在执行某些操作。对于在此上下文中“窗口消息”的含义所造成的混淆,我感到抱歉。 - JustJeff
更换示例。目前情况下,此程序中确实存在消息循环,这不是您要求的内容。 - jmucchiello
@jmucchiello:我认为他的问题意图仍然很明确,这个“错误”是一个很好的学习例子。 - P Daddy
6个回答

11

技术上来说,你确实有一个窗口和一个消息循环,只是它们不在你的代码中。

调用 MessageBox() 会创建一个窗口(类 #32770),并运行一个本地的消息循环。直到消息循环退出,也就是发送 WM_NCDESTROY 消息,该函数才返回到你的代码中。我认为这与响应 DialogBox() 的相同消息循环一样。

但是,你可以用任何其他真正不创建消息循环的东西替换你对 MessageBox() 的调用,你仍然会没问题。Windows 不关心你是否有消息循环,虽然一些功能(主要是 UI 相关的)没有消息循环可能很难或不可能使用。事实上,你根本不需要链接到 user32,而一些没有用户界面的应用程序也不需要。

现在,如果你创建了一个窗口,并且没有以 某种 方式处理它的消息,那么 Windows XP 及更高版本将使用一个“ghost”窗口来代替你的窗口,该窗口具有白色客户区域,任务管理器将告诉用户该应用程序未响应。

尽管一开始看起来是这样,但消息循环并不是 Windows 标准模板中的魔法或严格要求的部分。不过,由于它是处理窗口消息的最佳方法,因此在大多数 Windows 应用程序中,它被高度融入为标准。大多数 Windows 应用程序的“事件驱动”性质使我们有时忘记了,Windows 应用程序最初是设计为单线程的,在这个模型中,运行在单个线程内的代码,而不是操作系统内部的某种看不见的力量,必须在我们的代码中进行每个函数调用。虽然多线程的添加在某种程度上改变了这一点,但基本模型仍然保持不变。

编辑

关于消息队列的注意事项:

正如其他地方所提到的,消息队列仅在创建窗口时(并且以每个线程为基础)才会被创建。您的示例程序,在创建消息框时确实创建了一个消息队列。但当您的应用程序退出时,这个队列不一定为空。这个队列只是一个内存结构。它是一个内存块,可以容纳一定数量的消息对象(指定目标 hWnd、消息ID、wParam、lParam、消息发布时的系统时间、鼠标位置以及允许从中推导出键盘和鼠标按钮状态的一些数据),以及队列头和队列尾的指针(我假设它是一个循环队列)。当应用程序退出时,像属于进程的所有内存一样,这个内存会被立即释放。
当然,还有其他一些必须在您的进程外清理的东西。例如,操作系统必须保留所有现有窗口的表,以及创建它们的线程和进程。当然,这些也都会自动清理。

在使用COM对象时,是否需要一个消息循环,因为COM使用消息循环在所谓的“多线程COM公寓”模型中调度这些之间的调用? - Armen Michaeli

4

由于您没有窗口,所以不需要消息循环。在Win32中,消息被发送给窗口而不是应用程序。


很抱歉说这是100%错误的。上面的程序确实有一个窗口,并且它确实有一个消息循环。 - 1800 INFORMATION
我想我过于考虑这个问题了,想象Windows会为每个进程创建一个消息队列,并且某些东西(特别是初始化/清理)可能需要'Windows程序'以此方式运行。 - JustJeff
消息框确实会创建一个窗口,从而产生一个循环,但这是否是他所询问的内容呢? - Robert
为每个泵送消息或创建窗口的线程创建消息队列,根据需要进行创建。通常这意味着每个进程有一个消息队列(但并非总是如此)。 - 1800 INFORMATION
@1800 信息:它确实显示了一个对话框,但是这个对话框驻留在其中一个 Win32 API DLL 中(如果我没记错的话是 user32.dll)。因此消息循环也驻留在那里... - Milan
如果你要问关于一个没有消息循环或任何窗口的程序的问题,那么最好不要发布有消息循环和窗口的示例代码。使用隐式消息循环的程序和自己编写的程序之间几乎没有太大区别。 - 1800 INFORMATION

3

你确实有一个消息循环 - MessageBox是一个模态对话框,因此其中包含一个消息循环。


好的,没问题,但是消息框只是一个微不足道的操作,旨在说明该程序确实有所作为。 - JustJeff

2

您不需要创建窗口。但是,仍然有一些消息类型,例如:

  • WM_TIMER
  • WM_TIMECHANGE
  • WM_CLIPBOARDUPDATE
  • WM_COPYDATA
  • WM_POWER

您可能需要使用这些消息类型。因此,保留一个"幽灵"窗口也不会有问题。


幽灵窗口?你能详细说明一下吗?听起来像是有用的东西! - JustJeff
幽灵窗口实际上与您所说的不同(请参阅我的帖子)。您所指的是隐藏或不可见窗口,称为消息窗口,有时也称为消息泵或消息接收器。 - P Daddy
是的,你说得对。我的意思是一个充当消息泵的窗口,一个用户看不到也无法交互的窗口。 - Nick Dandoulakis

2

如果您没有窗口,那么没关系,但是如果您有窗口,则需要确保为其提供消息。否则,系统会在等待您响应的广播消息上挂起。这对于像COM这样创建用于消息处理的隐藏窗口的事情非常重要。如果您的主线程不泵送消息(例如通过调用WaitForSingleObject),则对您的COM对象的调用将无法处理,并且任何发送广播的程序都将出现挂起的情况。


0
我曾经在某个地方读到过(但找不到参考资料)的是,Windows会根据需要创建消息队列。如果您从未调用查找消息队列的函数,则永远不会创建消息队列。这是以每个线程为基础发生的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接