关于 Windows 消息队列






3.67/5 (5投票s)
2002年4月18日
3分钟阅读

174000

1654
本文是为 Win32 API 程序员撰写的,主题是 Windows 消息队列。
引言
众所周知,MFC 是在 Windows 系统上开发应用程序的最强大工具。它的类专门用于处理你能想象到的各种复杂任务,并且所选解决方案的灵活性非常出色。 它是开发大型软件的最佳方法,可以使程序员远离各种细节问题。在处理基于窗口的系统时,这应该是一个最大的优势,但是...
线程
我们在这里谈论的不是基于窗口的系统。“程序的基本工作单元是线程”,MSDN 库中这样写道。除了堆栈和执行路径等许多背景细节之外,它还必须涵盖消息队列的实现。这并非强制规定,但您会在每个支持窗口的线程中找到它。 这也是一个非常普遍的误解的原因:窗口有一个消息队列。 错!消息队列属于线程,发送到窗口的消息由线程中的消息循环分发到该线程。我将通过这篇文章附带的程序来说明这一点。
程序
这是一个基于控制台的应用程序;无模式对话框通过控制台的消息队列管理其消息,因此一次不会有两个队列。该代码为您提供了一个类和主函数。
CConsoleQueue
此类实现消息循环和处理消息的原始系统。它具有以下方法
RunQueue
- 运行经典的消息循环
while (GetMessage(&msg, NULL, 0, 0)) // extract the message // from the queue { if (fctMan=(*this)[msg.message]) fctMan((void *)msg.wParam); else { TranslateMessage(&msg); // necessary to listen the keyboard DispatchMessage(&msg); // message goes to the default // procedure } }
EndQueue
- 通过发送 WM_QUIT
终止消息循环
PostMessage(NULL, WM_QUIT, 0, 0); // message to interrupt // the loop by returning // FALSE on GetMessage
RegisterMessageHandler
- 将处理程序函数注册到特定消息。当消息在消息循环中被接收时,将调用该处理程序。要传递句柄的值,您应该在调用 PostMessage
时通过 WPARAM
传递它。
注意:这可以被认为是 The Adaptive Communication Environment (ACE) 提出的 reactor 概念的框架。
RemoveAll
- 移除所有关联(来自 reactor)
主
此函数的目的是 - 逐步执行 - 如下
1. 创建一个用于向队列发送消息的无模式对话框
hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), NULL, DialogProcedure); ShowWindow(hWndDialog, SW_SHOW);
2. 在线程上设置一个计时器
nTimer=SetTimer(NULL, 0, nDelay*1000, TimerProcedure);
3. 注册用户定义消息的处理程序
queue.RegisterMessageHandler(WM_USER_DEFINED, UserDefined);
4. 运行队列
queue.RunQueue();
行为
目的是在消息队列中放入WM_TIMER
消息;每个 WM_TIMER
都将打印到控制台的全局缓冲区。如果缓冲区在最后的 nKeepQueueSteps WM_TIMER
中没有修改,最后一个将停止计时器并结束消息队列。 修改缓冲区是在无模式对话框中通过在编辑框中写入内容并按“发送缓冲区”完成的。按“发送用户定义”会将 WM_USER_DEFINED
消息发送到队列。最终
请注意,使用 NULL
作为第一个参数调用 PostMessage
会将消息放入当前线程的消息队列中。
另一个观察是关于设置计时器的。这只存在于队列的事件中,而不是窗口的资源。 它属于线程,并且只有通过调用 DispatchMessage
才能到达窗口。
最后要说的是消息循环。 这个表达式是程序员的一个限制。 实际上,您可以在单个线程的执行中拥有多个消息循环。 要测试这一点,只需将 main
的实际内容在函数的正文中像这样进行复制
hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), NULL, DialogProcedure); // ... cout<<endl<<"program ends here..."<<endl; hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), NULL, DialogProcedure); // ... cout<<endl<<"program ends here..."<<endl; // ... hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), NULL, DialogProcedure); // ... cout<<endl<<"program ends here..."<<endl;