分享

清晖

 liyanweicc 2011-04-18
 

队列消息和非队列消息

window消息分为队列消息和非队列消息。

队列消息:

对于队列消息而言,windows系统将消息扔到队列中。流程是:当用户移动鼠标、按键盘等操作时,设备驱动程序生成队列消息,并放置在系统消息队列中。系统每次从系统消息队列中拿出一个消息,检查它们的目标窗口,然后把它们发送到目标窗口所属线程的消息队列中。windows程序有一个消息循环从消息队列中获取数据,消息循环首先GetMessage,然后TanslateMessageDispatchMessageDispatchMessage根据消息结构MSG中的窗口句柄获取其对应的窗口过程函数的地址,进而调用该窗口过程。

队列消息一般是用户的键盘输入(例如WM_KEYDOWNWM_KEYUP),键盘输入的字符(WM_CHAR),鼠标消息(例如WM_MOUSEMOVEWM_LBUTTONDOWN)。队列消息还包括WM_TIMERWM_PAINTWM_QUIT等。

程序可以通过PostMessage发送队列消息。消息填充到队列中后函数马上返回而不是等待消息处理完成。

GetMessage可以从消息队列中取数据,PeekMessage可以从消息队列中查看数据但不取出。

非消息队列

对于非队列消息而言,是windows系统直接调用窗口过程。而不经过消息循环的流程。

其余的都是非队列消息。非队列消息经常是一些windows函数产生的。例如ShowWindow会产生WM_SIZEWM_SHOWWINDOW消息。队列消息可能会产生非队列消息,例如单击一个菜单项会导致一个鼠标队列消息,最后又会导致一个WM_C0MMAND非队列消息。

实验和疑惑

      windows程序中调用SendMessage,则可以在调试堆栈中看到消息的处理函数对应的堆栈帧在SendMessage的堆栈帧的上面。说明消息的处理函数是由SendMessage间接调用的。

      而如果使用PostMessage,则处理函数的堆栈帧则在GetMessage的堆栈帧的上方,说明消息是从队列中取出的。

      上面是同一个进程的情况。但如果使用一个进程向另一个进程的窗口通过SendMessage发送消息,则消息处理函数的堆栈帧也在GetMessage堆栈帧的上方。估计是一个进程不能直接调用另一个进程的函数,只能是向消息队列中填入消息。但虽然进入了消息队列,但这个SendMessage仍然是阻塞的。进程间发送消息的机制还是没有搞清楚。

相关原始资料

来自《Programming Windows

I've talked about Windows sending messages to a window, which means that Windows calls the window procedure. But a Windows program also has a message loop that retrieves messages from a message queue by calling GetMessage and dispatches these messages to the window procedure by calling DispatchMessage.

So, does a Windows program poll for messages (much like a character-mode program polling for keyboard input) and then route these messages to some location? Or does it receive messages directly from outside the program? Well, both.

Messages can be either "queued" or "nonqueued." The queued messages are those that are placed in a program's message queue by Windows. In the program's message loop, the messages are retrieved and dispatched to the window procedure. The nonqueued messages are the results of calls by Windows directly to the window procedure. It is said that queued messages are "posted" to a message queue and that nonqueued messages are "sent" to the window procedure. In any case, the window procedure gets all the messages—both queued and nonqueued—for the window. The window procedure is "message central" for the window.

The queued messages are primarily those that result from user input in the form of keystrokes (such as the WM_KEYDOWN and WM_KEYUP messages), characters that result from keystrokes (WM_CHAR), mouse movement (WM_MOUSEMOVE), and mouse-button clicks (WM_LBUTTONDOWN). Queued messages also include the timer message (WM_TIMER), the repaint message (WM_PAINT), and the quit message (WM_QUIT).

The nonqueued messages are everything else. Nonqueued messages often result from calling certain Windows functions. For example, when WinMain calls CreateWindow, Windows creates the window and in the process sends the window procedure a WM_CREATE message. When WinMain calls ShowWindow, Windows sends the window procedure WM_SIZE and WM_SHOWWINDOW messages. When WinMain calls UpdateWindow, Windows sends the window procedure a WM_PAINT message. Queued messages signaling keyboard or mouse input can also result in nonqueued messages. For example, when you select a menu item with the keyboard or mouse, the keyboard or mouse message is queued but the eventual WM_COMMAND message indicating that a menu item has been selected is nonqueued.

This process is obviously complex, but fortunately most of the complexity is Windows' problem rather than our program's. From the perspective of the window procedure, these messages come through in an orderly and synchronized manner. The window procedure can do something with these messages or ignore them.

When I say that messages come through in an orderly and synchronized manner, I mean first that messages are not like hardware interrupts. While processing one message in a window procedure, the program will not be suddenly interrupted by another message.

Although Windows programs can have multiple threads of execution, each thread's message queue handles messages for only the windows whose window procedures are executed in that thread. In other words, the message loop and the window procedure do not run concurrently. When a message loop retrieves a message from its message queue and calls DispatchMessage to send the message off to the window procedure, DispatchMessage does not return until the window procedure has returned control back to Windows.

However, the window procedure could call a function that sends the window procedure another message, in which case the window procedure must finish processing the second message before the function call returns, at which time the window procedure proceeds with the original message. For example, when a window procedure calls UpdateWindow, Windows calls the window procedure with a WM_PAINT message. When the window procedure finishes processing the WM_PAINT message, the UpdateWindow call will return controls back to the window procedure.

This means that window procedures must be reentrant. In most cases, this doesn't cause problems, but you should be aware of it. For example, suppose you set a static variable in the window procedure while processing a message and then you call a Windows function. Upon return from that function, can you be assured that the variable is still the same? Not necessarily—not if the particular Windows function you call generated another message and the window procedure changes the variable while processing that second message. This is one of the reasons why certain forms of compiler optimization must be turned off when compiling Windows programs.

In many cases, the window procedure must retain information it obtains in one message and use it while processing another message. This information must be saved in variables defined as static in the window procedure, or saved in global variables.

来自MSDN

Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the mouse or keyboard converts the input into messages and places them in the system message queue. The system removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. A thread's message queue receives all mouse and keyboard messages for the windows created by the thread. The thread removes messages from its queue and directs the system to send them to the appropriate window procedure for processing.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多