Microsoft Windows的訊息迴圈

微軟視窗作業系統是以事件驅動做為程式設計的基礎。程式的執行緒會從作業系統取得訊息。應用程式會不斷迴圈呼叫GetMessage函式（或是PeekMessage函式）來接收這些訊息，這個迴圈稱之為「事件迴圈」。基本上事件迴圈的程式碼如下所示（C語言 / C++程式語言）：
MSG msg; //用于存储一条消息BOOL bRet;//从UI线程消息队列中取出一条消息while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0){
   if (bRet == -1)
   {
       //错误处理代码，通常是直接退出程序
    }
    else
    {
       TranslateMessage(&msg); //按键消息转换为字符消息
       DispatchMessage(&msg); //分发消息给相应的窗体
     }}
雖然在程式上並沒有很嚴格的規定與要求，但是一般來說，它的事件迴圈通常會呼叫TranslateMessage函式與DispatchMessage函式，這兩個函式會傳遞訊息給回呼函式，以及呼叫相應視窗的訊息處理常式。
現在的繪圖介面架構程式設計，例如Visual Basic與Qt基本上是不會要求應用程式直接擁有視窗程式的訊息迴圈，但是會以鍵盤與滑鼠的按鍵動作來作為事件的處理機制。在這些架構底下，訊息迴圈的痕跡還是可以被找到的。
注意：在上述的原始碼裡，尤其在while迴圈大於零的條件。即使GetMessage函式的傳回值型態是英文字大寫的BOOL，但是在Win32視窗程式裡，它是被定義成int整數型態，它有兩個值，TRUE是整數的1，FALSE是整數的0。整數 -1代表error（例如第二個參數為輸出的窗口控制代碼但取不到值的時候），整數0值當GetMessage取得到WM_QUIT訊息。假如有其他訊息，那麼非零值會當成傳回值（有訊息的傳回值通常是正值，但是有些程式設計的說明文件不一定會說明的很詳細）。

歷史

16位元Windows系統為非搶先單執行緒模式，應用程式沒有傳送訊息佇列，向窗口傳送一個訊息總是按同步方式執行，也即傳送程式要在接受訊息的窗口完全處理完訊息之後才能繼續執行。這通常是一個所期望的特性。但是，如果接收訊息的窗口花很長的時間來處理訊息或者出現掛起，則傳送程式就不能再執行。這意味著系統是不強壯的。如果應用程式訊息佇列（只用於存放投寄的訊息）為空，由於沒有虛擬輸入訊息佇列，SendMessage或PeekMessage函式存取系統事件佇列查取可用的滑鼠或鍵盤輸入訊息。如果系統佇列中沒有需要處理的事件，SendMessage或PeekMessage函式掃描所有窗口以處理需要修改重繪的區域。如果沒有需要重繪的區域，則交出CPU控制權。恢復CPU控制權時，檢視是否有定時器過期。至此如果沒有訊息可返回，SendMessage進入睡眠，直至被輸入事件喚醒；PeekMessage如果沒有設定PM_NOYIELD標記，則會讓出CPU控制權，但不會讓執行緒休眠，重新獲得CPU後PeekMessage將控制權返回到執行緒，並返回一個空值指出這個執行緒沒有要處理的訊息了。
本文主要關注Win32系統的訊息處理機制。

UI執行緒

Windows系統規定，窗口和勾點（hook）這兩種User物件分別由建立窗口和安裝勾點的執行緒所擁有，一旦該執行緒結束，作業系統會自動刪除窗口或解除安裝勾點。而其他的User物件（圖示icon、游標cursor、窗口類WndClass、選單、加速鍵表等）則歸行程所有，行程結束時作業系統會自動刪除這些物件。
建立窗口的執行緒必須就是處理窗口所有訊息的執行緒，即UI執行緒（User Interface Thread）建立了表單及表單上的各種控制項，系統為UI執行緒分配一個訊息佇列用於窗口訊息的派送（dispatch）。為了使窗口處置這些訊息，執行緒必須有它自己的「訊息迴圈」。只有當一個執行緒呼叫Windows API中的GDI（Graphics Device Interface）和User函式時，作業系統才會將其看成是一個UI執行緒，並為它分配一些另外的資源，建立一套執行緒訊息佇列；否則，作業系統把非UI執行緒視作普通工作執行緒（Workhorse），不會為它建立訊息佇列。因此，呼叫PostThreadMessage前，這個執行緒必須是UI執行緒從而有投寄訊息的佇列，通常可在該執行緒中呼叫一次PeekMessage函式以達到這個目的。
如果一個UI執行緒結束執行，作業系統會自動回收它所建立的所有表單。

表單過程

表單過程（Window Procedure）是一個函式，每個表單有一個表單過程，負責處理該表單的所有訊息。
UI控制項也是獨立的「Window」，擁有自己的「表單過程」。

GetMessage偽演算法

BOOL GetMessage(MSG *lpMsg, HWND hWnd , UINT wMsgFilterMin, UINT wMsgFilterMax){
         //查看QS_SENDMESSAGE标志，如果有的话循环处理，直到没有消息位置
         DWORD dwRetVal = 0;
         ThreadInfo threadInfo;
 
FLAG_SENDPROCLOOP:
         GetThreadInfo(GetCurrentThreadId(), &threadInfo);
         while (threadInfo.QS_SENDMESSAGE == QS_SIGNALSET) {
                   //从发送消息队列中获取消息
                   dwReturnVal = GetMsgFromQueue(QUEUE_SEND, lpMsg, hWnd,wMsgFilterMin, wMsgFilterMax);
                   //判断是否取到消息,有则调用窗口函数，无则复为QS_SENDMESSAGE标志
                   If (dwReturnVal == GETMESSAGE_HASMESSAGE) {
                            //调用指定窗口的窗口函数
                            CallWindowProc(hWnd, &threadInfo, lpMsg);
                   }
                   else {
                            QS_SENDMESSAGE = QS_SIGNALRESET;
                            break;
                   }
         }
         //在继续处理之前再次检查发送消息队列
         if (threadInfo.QS_SENDMESSAGE == QS_SIGNALSET) goto FLAG_SENDPROCLOOP;
         //检查发送消息队列, 如果有消息则取发送消息
         //判断是否还有发送消息，没有了则复位QS_POSTMESSAGE标志
         if (threadInfo.QS_POSTMESSAGE == QS_SIGNALSET) {
                   dwReturnVal = GetMsgFromQueue(QUEUE_POST, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
                   if (dwReturnVal == GETMESSAGE_LASTMESSAGE)
                            threadInfo.QS_POSTMESSAGE = QS_SIGNALRESET;
                  
                   return TRUE;
         }       
 
         //如果退出标志被置位
         if (threadInfo.QS_QUIT == QS_SIGNALSET) {
                   threadInfo.QS_QUIT = QS_SIGNALRESET;
                   FillMessage(lpMsg, MESSAGE_QUIT);
                   return FALSE;
         }
 
         //检查输入消息队列
         if (threadInfo.QS_INPUT == QS_SIGNALSET) {
                   DWORD dwRetVal = GetMessageFromQueue(QUEUE_INPUT, lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
                   //检查是否有键盘，鼠标消息
                   if (Test(dwRetVal, QS_KEY) == QS_LASTMOUSEKEYMESSAGE)
                            threadInfo.QS_KEY = QS_SIGNALRESET;
                   if (Test(dwRetVal, QS_MOUSEBUTTON) == QS_LASTMOUSEMESSAGE)
                            threadInfo.QS_MOUSEBUTTON = QS_SIGNALRESET;
 
                   return TRUE;
         }
 
         //测试QS_PAINT
         if (threadInfo.QS_PAINT == QS_SIGNALSET) {
                   //填充MSG，如果没有窗口过程确认窗口，则复位QS_PAINT标志
                   //...
                   //返回TRUE
                   threadInfo.QS_PAINT = QS_SIGNALRESET;
                   return TRUE;
         }
 
         if (threadInfo.QS_TIMER == QS_SIGNALSET) {
                   //填充MSG，如果没有定时器报时，则复位QS_TIMER标志
                   //...
                   //返回TRUE
                   return TRUE;
         }
 
         //等待有消息到达
         dwRetVal = MsgWaitForMultipleObjectsEx(...);
         if (...)
                   goto FLAG_SENDPROCLOOP;
 
         //等待失败
         return FALSE;}