Windows Message 消息队列,消息循环,Post消息,Send消息

本文旨在说明一些概念性的东西:

MessageQueue

The system does not automatically create a messagequeue for each thread. Instead, the system creates a message queueonly for threads that performoperations which require a message queue.If the thread creates one or morewindows, a message loopmust beprovided; this message loop retrieves messages from the thread's message queueand dispatches them to the appropriate window procedures.

         Thesystem maintains a single systemmessage queue and one thread-specific message queue for each graphical userinterface (GUI) thread.

To avoid the overhead(开销) ofcreating a message queue for non–GUI threads, all threads are created initiallywithout a message queue. The system creates a thread-specific message queueonly when the thread makes itsfirstcallto one of the User or Windows Graphics Device Interface (GDI)functions.

         Whenever the user moves the mouse,clicks the mouse buttons, or types on the keyboard, the device driver for themouse or keyboard converts the inputinto messages and places them in the systemmessage queue. The system removes the messages, one at a time, from thesystem message queue, examines them to determine the destination window, andthen posts them to the message queue of the thread that created the destinationwindow.


Creatinga Message Loop

You create amessage loop by using the GetMessage andDispatchMessage functions. If your application must obtain character inputfrom the user, include the TranslateMessage function in the loop.

A simple messageloop consists of one function callto each of thesethree functions:GetMessage, TranslateMessage, and DispatchMessage.

Because thesystem directs messages to individual windows in an application, a thread mustcreate at least one window beforestarting its message loop

Can owns onemore message loop in a thread.

         Themessage loop ends when the GetMessage function removes theWM_QUITmessage from the message queue.



PostMessage

Post a message to a message queue.PostMessage places a message at the end of a thread's message queueand returns immediately, withoutwaiting for the thread to process the message.

The system usesthe window handle passed with thePostMessage function to determine which thread message queue should receive themessage. If the handle isHWND_TOPMOST,the system posts the message to the thread message queues of all top-level windows.

         hWnd,ifNULL, The function behaves like a call to PostThreadMessage with the dwThreadIdparameter set to the identifier of the current thread.

         PostMessagecreates an MSG structure for the message and copies the message to the messagequeue

         Current Thread & Other Thread

         kwinsdk.exe!WndProc(HWND__* hWnd=0x003a23c2, unsigned int message=1034, unsigned int wParam=0, longlParam=0)  Line 184   C++

        user32.dll!_InternalCallWinProc@20()  + 0x23 bytes 

        user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes     

        user32.dll!_DispatchMessageWorker@8()  + 0xed bytes   

        user32.dll!_DispatchMessageW@4()  + 0xf bytes


SendMessage

The SendMessagefunction is used to send a message directlyto a window procedure. SendMessage calls a window procedure andwaits forthat procedure to process themessage and return a result.

         Ifthe specified window was created by the calling thread, the window procedure is called as asubroutine(当一个线程向该线程所建立的窗口SendMessage消息时,它只是调用指定窗口的消息处理过程,并不将消息入队列). If the specified window was created by a different thread, thesystem switches to that thread and calls the appropriate window procedure.put it to message queue(当一个线程向另一个线程所建立的窗口SendMessage时,该消息要追加到接收消息线程的发送消息队列,然后发送消息的线程进入等待状态,接收消息的线程处理完该消息后,由系统唤醒发送消息的线程,这时发送线程继续进行). Messages sent between threads are processed only when thereceiving thread executes message retrieval code. The sending thread is blockeduntil the receiving thread processes the message. However, the sending threadwill process incoming nonqueued messages while waiting for its message to beprocessed. To prevent this, use SendMessageTimeout with SMTO_BLOCK set.

         Current Thread

         kwinsdk.exe!WndProc(HWND__* hWnd=0x00201276, unsigned int message=1034, unsigned int wParam=0, longlParam=0)  Line 180   C++

         user32.dll!_InternalCallWinProc@20()  + 0x23 bytes 

        user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes     

        user32.dll!_SendMessageWorker@24()  + 0x112 bytes      

        user32.dll!_SendMessageW@16()  + 0x4c bytes

        

         Other Thread put queue

         kwinsdk.exe!WndProc(HWND__* hWnd=0x003d23c2, unsigned int message=1034, unsigned int wParam=0, longlParam=0)  Line 187   C++

        user32.dll!_InternalCallWinProc@20()  + 0x23 bytes 

        user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes     

        user32.dll!_DispatchClientMessage@24()  + 0x51 bytes   

        user32.dll!___fnDWORD@4()  + 0x2b bytes        

        ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x2e bytes    

        user32.dll!_NtUserGetMessage@16()  + 0x15 bytes 

        user32.dll!_GetMessageW@16()  + 0x2b bytes


Windows消息机制

Windows中有一个系统消息队列,对于每一个正在执行的Windows应用程序,系统为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。

系统消息队列(System Message Queue) ,这是一个系统唯一的Queue,设备驱动(mouse,keyboard)会把操作输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列(thread-specific message queue)中等待处理。

应用程序队列,线程消息队列(Thread-specificMessage Queue)

每一个GUI线程都会维护这样一个线程消息队列。(这个队列只有在线程调用GDI函数时才会创建,默认不创建)。然后线程消息队列中的消息会被送到相应的窗口过程(WndProc)处理。

窗口函数

应用程序的消息由窗口处理函数进行处理,这个函数是在窗口类中注册过的,对于每个窗口类Windows 为我们预备了一个默认的窗口过程处理函数DefWindowProc(),这样做的好处是,我们可以着眼于我们感兴趣的消息,把其他不感兴趣的消息传递给默认窗口过程函数进行处理。每一个窗口类都有一个窗口过程函数,此函数是一个回调函数,它是由Windows 操作系统负责调用的,而应用程序本身不能调用它。

Windows为当前执行的每个Windows程序维护一个「消息队列」。在发生输入事件之后,Windows将事件转换为一个「消息」并将消息放入程序的消息队列中。程序通过执行一块称之为「消息循环」的程序代码从消息队列中取出消息:

while(GetMessage (&msg, NULL, 0, 0))       

{       

             TranslateMessage(&msg) ;       

             DispatchMessage(&msg) ;       

}

TranslateMessage(&msg); 将msg结构传给Windows,进行一些转换,比如A键按下,转换成WM_CHAR消息等。

DispatchMessage(&msg),再将msg结构传给Windows,然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理。这也就是说,Windows将呼叫窗口消息处理程序。一般窗口消息处理程序就是WndProc函数。处理完消息之后,WndProc传回到Windows。此时,Windows还停留在DispatchMessage呼叫中。在结束DispatchMessage呼叫的处理之后,Windows回到程序中,并且接着从下一个GetMessage呼叫开始消息循环。

 

队列化消息与非队列化消息

消息能够被分为「队列化的」和「非队列化的」。队列化的消息是由Windows放入程序消息队列中的。在程序的消息循环中,重新传回并分配给窗口消息处理程序。非队列化的消息在Windows呼叫窗口时直接送给窗口消息处理程序。也就是说,队列化的消息被「发送」给消息队列,而非队列化的消息则「发送」给窗口消息处理程序。任何情况下,窗口消息处理程序都将获得窗口所有的消息--包括队列化的和非队列化的。窗口消息处理程序是窗口的「消息中心」。队列化消息基本上是使用者输入的结果,以击键(如WM_KEYDOWN和WM_KEYUP消息)、击键产生的字符(WM_CHAR)、鼠标移动(WM_MOUSEMOVE)和鼠标按钮(WM_LBUTTONDOWN)的形式给出。队列化消息还包含时钟消息(WM_TIMER)、更新消息(WM_PAINT)和退出消息(WM_QUIT)。

非队列化消息则是其它消息。在许多情况下,非队列化消息来自呼叫特定的Windows函数。例如,当WinMain呼叫CreateWindow时,Windows将建立窗口并在处理中给窗口消息处理程序发送一个WM_CREATE消息。当WinMain呼叫ShowWindow时,Windows将给窗口消息处理程序发送WM_SIZE和WM_SHOWWINDOW消息。当WinMain呼叫UpdateWindow时,Windows将给窗口消息处理程序发送WM_PAINT消息。键盘或鼠标输入时发出的队列化消息信号,也能在非队列化消息中出现。例如,用键盘或鼠标选择了一个菜单项时,键盘或鼠标消息就是队列化的,而说明菜单项已选中的WM_COMMAND消息则可能就是非队列化的。

 

SendMessage()与PostMessage()

它们两者是用于向应用程序发送消息的。PostMessagex()将消息直接加入到应用程序的消息队列中,不等程序返回就退出;而SendMessage()则刚好相反,应用程序处理完此消息后,它才返回。我想下图能够比较好的体现这两个函数的关系:


总结:

1、一条线程在需要的时候才会有消息队列

2、有消息队列的线程可以有多个消息循环

3、SendMessage在线程之间还是线程之内都是阻塞的

4、PostMessage不会阻塞


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值