一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - windows消息和消息隊列實例詳解

windows消息和消息隊列實例詳解

2021-02-20 14:24C語言教程網 C/C++

這篇文章主要介紹了windows消息和消息隊列實例詳解,詳細講述了Windows的消息機制與原理,對于深入理解和學習Windows應用程序設計有不錯的借鑒價值,需要的朋友可以參考下

本文詳細講述了windows消息和消息隊列的原理與應用方法。分享給大家供大家參考。具體分析如下:

與基于MS - DOS的應用程序不同,Windows的應用程序是事件(消息)驅動的。它們不會顯式地調用函數(如C運行時庫調用)來獲取輸入,而是等待windows向它們傳遞輸入。 windows系統把應用程序的輸入事件傳遞給各個窗口,每個窗口有一個函數,稱為窗口消息處理函數。窗口消息處理函數處理各種用戶輸入,處理完成后再將控制權交還給系統。窗口消息處理函數一般是在注冊一個窗口的時候指定的。你可以從典型的SDK程序中窗口消息處理函數是怎么聲明和實現的。

對于Windows XP系統:如果頂層窗口停止響應消息超過幾秒鐘,系統會認為窗口無回應。在這種情況下,系統將隱藏這個窗口,然后生成一個影子(ghost)窗口覆蓋在它上面。這個影子窗口具有著相同的Z軸順序,位置,大小,顯示屬性。影子窗口允許用戶將其移動,調整大小,甚至關閉(關閉的是停止響應的window)。此時只有這幾個動作是被允許的,在調試模式下,系統不會生成影子窗口。

本節討論以下主題:

Windows消息

 1.  消息類型

 2.  消息傳遞

 3.  消息處理

 4.  消息過濾

 5.  post message和send message

 6.  消息死鎖

 7.  廣播消息

 8.  查詢消息

現分述如下:

1. Windows消息

windows通過消息的形式向窗口傳遞用戶輸入。消息可以由系統和應用程序生成。該系統會為每個輸入事件產生相應的消息,

例如,用戶點擊鼠標,移動鼠標或滾動條,或是應用程序改變了系統的某些屬性,比如說系統更改了字體資源,改變了某個窗口的

大小。 不僅如此,應用程序可以生成消息,通告發送消息指定它的窗體去執行某些任務或者是與其他的應用程序交互。

windows系統將消息發送到一個窗口消息處理函數時傳遞四個參數:窗口句柄,消息標識符,兩個DWORD值(消息參數)。

窗口句柄標識了該消息的目的窗口。windows使用它來確定是哪個窗口的的窗口消息處理函數收到該消息。

一個消息標識符是一個有名字的常量,用來表明消息的意義。當一個窗口處理函數收到一條消息,它根據判斷消息標識符來決定如何處理該消息,例如,消息標識符WM_PAINT消息告訴窗口程序窗口的客戶區已發生變化,必須重繪。 消息參數(DWORD值)指定傳遞的數據或是數據的地址。消息參數可以是一個整型值,一個指針值。也可以為NULL。

一個窗口過程必須根據消息標識符來確定如何解釋消息參數。

2. windows 消息類型

本節描述消息的兩種類型:

(1) 系統定義的消息

(2) 應用程序定義的消息

系統定義的消息

操作系統向應用程序發送消息來和應用程序通訊。操作系統通過消息控制應用程序的運行,向應用程序傳遞用戶輸入以及一些其他有用的信息。

應用程序也可以發送系統定義的消息,應用程序通過這些消息去控制使用注冊窗口類創建的控件的窗口的運行。

每個系統定義的消息都有一個唯一的消息標識符和相應的符號常量(在windows SDK的頭文件里定義)。符號常量通常會表明系統定義的消息所屬的類別。不同的前綴表明不同的類別。一下是常見的分類:

    Prefix Message category

    WM        General window(一般的窗口)

    ABM        Application desktop toolbar (應用程序桌面工具條)

    BM        Button control (按鈕控件)

    CB        Combo box control (組合框控件)

    CBEM Extended combo box control(擴展的組合框控件)

    CDM        Common dialog box (普通的對話框)

    DBT        Device (設備)

    DL        Drag list box (下拉列表)

    DM        Default push button control (默認按鈕控件)

    DTM        Date and time picker control(日期和時間選擇控件)

    EM        Edit control (編輯控件)

    HDM        Header control (表頭控件)

    HKM        Hot key control (熱鍵控件)

    IPM        IP address control (IP地址控件)

    LB        List box control  (列表框控件)

    LVM        List view control (列表視圖控件)

    MCM        Month calendar control (數學日歷控件)

    PBM        Progress bar (進度條控件)

    PGM        Pager control ()

    PSM        Property sheet (屬性頁)

    RB        Rebar control (分隔條控件)

    SB        Status bar window (狀態條控件)

    SBM        Scroll bar control (滾動條控件)

    STM        Static control (靜態控件)

    TB        Toolbar (工具條)

    TBM        Trackbar (跟蹤欄)

    TCM        Tab control (選項卡控件)

    TTM        Tooltip control ()

    TVM        Tree-view control ()

    UDM        Up-down control ()

應用程序可以通過創建自定義的消息,用來和自己的窗口和其他進程通訊。如果應用程序創建了自己的消息,窗口處理函數可以解析這些信息,并作出相應的處理。

消息標識符值的取值范圍:

該系統保留了一個消息范圍,從0x0000到0x03FF(0x03FF等于WM_USER -1)范圍. 這個范圍內的值為系統定義的消息。應用程序不能使用這些值作為自己的自定義消息。

從0x0400(數值WM_USER)到0x7FFF的值是為應用程序保留的。應用程序可以使用這個范圍內的值來定義自己的消息。

如果你的操作系用的版本(windows version)主版本為4.0版,你還可以使用0x8000(WM_APP)到0xBFF之間的值來定義自己的消息。

除此之外,應用程序還可以調用RegisterWindowMessage函數注冊一個消息時,操作系統會返回一個介于0xC000和0xFFFF之間的一個消息標識符。并且保證這個返回值是系統唯一的。因此,可以避免和其他應用程序使用的消息相沖突。

3. 消息派發

windows使用兩種方法將消派發到一個窗口消息處理函數:一是將消息放到消息隊列(先進先出隊列),二是不放到消息隊列,直接發送到窗口消息處理函數,讓窗口處理函數來處理消息。

派發到消息隊列的消息被稱為排隊消息(Queued messages)。它們主要是用戶輸入事件,比如說鼠標或鍵盤消息盤,有WM_MOUSEMOVE消息,WM_LBUTTONDOWN,WM_KEYDOWN,和WM_CHAR消息。還有一些其他的,包括WM_TIMER,WM_PAINT,以及WM_QUIT。大多數其他的消息息,這是直接發送到窗口過程,被稱為非隊列消息(non queued messages)。

(1) 隊列(Queued)消息

windows可同時顯示任意數量的窗口。此時,系統使用消息隊列來將鍵盤和鼠標事件正確的派發到正確的窗口。

windows維護著一個系統消息隊列,以及分別為每個GUI線程維護一個各自的線程消息隊列。為了避免非GUI線程的創建線程消息隊列的開銷,所有線程創建初始化時,均不創建消息隊列。只有當線程第一次調用GDI函數時,系統才會為線程創建消息隊列。所以那些非GUI線程是沒有消息隊列的。

每當用戶移動鼠標,點擊按鈕或鍵盤時,鼠標或鍵盤的設備驅動程序會將輸入轉換成消息,并將消息放在系統消息隊列里。刪windows會檢查自己的消息隊列,如果消息隊列不為空,則每次取出并刪除一個消息,然后確定消息的目標窗口,然后把消息放到創建這個窗口的線程的線程消息隊列里。線程的消息隊列接收由線程創建的窗口的所有的鼠標和鍵盤消息。然后線程會從隊列中刪除信息,并告訴系統把它們派發到對應的窗口消息處理函數。

除了WM_PAINT, WM_TIMER和WM_QUIT消息以外,系統總是派發放在在消息隊列的末尾的消息。這將保證讓一個窗口以first-in, first-out的順序接收消息。WM_PAINT,WM_TIMER,和WM_QUIT消息,會一直被保存在隊列中,只有在隊列中沒有其他消息時才會被派發到窗口消息處理函數。此外,同一個窗口的多個WM_PAINT消息被合并成一個WM_PAINT消息,客戶區的所有無效部分也會被合并。這樣是為了減少窗口重繪客戶區的次數。

windows向線程消息隊列傳遞消息時,首先會填充一個MSG結構,然后將這個MSG結構復制到消息隊列。MSG中的信息包括:目標窗口,消息標識符,兩個消息參數,消息派發時的時間,鼠標光標位置。一個線程可以使用PostMessage或PostThreadMessage功能向自己的消息隊列或者是其他線程的消息隊列發送消息。

應用程序可以使用GetMessage函數從自己的消息隊列中刪除消息。查看而不刪除消息,用的是PeekMessage函數。

PeekMessage函數會返回一個帶有消息信息的MSG結構。

從消息隊列中刪除消息后,應用程序可以使用DispatchMessage函數指示系統將消息發送到一個窗口消息處理函數。 DispatchMessage的參數是是前一次調用GetMessage或PeekMessage獲得的MSG結構的指針。 DispatchMessage會傳遞窗口句柄,消息標識符,這兩個消息參數這些信息給窗口消息處理函數,它不會傳遞消息派發時間以及鼠標光標位置。應用程序可以在處理消息時調用的GetMessageTime和GetMessagePos來獲得這些信息。

線程可以使用WaitMessage函數,交出自己的控制權,當它的消息隊列中沒有消息時,調用WaitMessage函數會掛起線程,直到自己的消息隊列里有消息時才返回。

您可以調用SetMessageExtraInfo函數來關聯一個值給當前線程的消息隊列。然后調用GetMessageExtraInfo函數來獲取由GetMessage或PeekMessage函數得到的最后一條消息相關聯的值。你可以去msdn上看更多的關于這幾個函數的信息。

(2) 非隊列(Nonqueued)消息

Nonqueued消息被立即送往目的地的窗口消息處理函數,繞過了系統的消息隊列和線程消息隊列。系統通常會發送nonqueued消息,來通知那些會影響窗口的事件。例如,當用戶激活一個新的應用程序窗口時,系統會發送一些列消息到窗口,包括WM_ACTIVATE,WM_SETFOCUS,WM_SETCURSOR。這些消息通知窗口被激活,鍵盤輸入被定向到窗口,并且鼠標光標也移到窗口的邊界內。

Nonqueued消息也有可能來源于應用程序調用系統函數。例如,系統調用SetWindowPos函數移動一個窗口后會發送WM_WINDOWPOSCHANGED消息。 一些函數也發送nonqueued消息, 有BroadcastSystemMessage,BroadcastSystemMessageEx,SendMessage,SendMessageTimeout,和SendNotifyMessage。 關于這些函數的詳細信息,你可以查閱MSDN。

消息處理

應用程序必須刪除并處理發送到它的線程消息隊列的消息。單線程應用程序通常在它的WinMain函數的消息循環,刪除和分發消息到適當的窗口進行處理。多線程應用程序可以在每一個線程創建一個窗口的消息循環。以下章節描述了一個消息

循環如何工作,并講述窗口消息處理函數的作用:

(1)消息循環

(2)窗口處理函數

消息循環

一個簡單的消息循環包含調用以下三個函數:GetMessage,TranslateMessage,和DispatchMessage。請注意,如果有一個錯誤,GetMessage返回-1 -因此,需要測試它的返回值,來判斷為-1的情況

代碼片段:

 

復制代碼 代碼如下:

...

 

MSG msg;

BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

 

GetMessage函數從隊列中獲取消息,并將消息內容復制到一個MSG結構。它返回一個非零值,除非遇到WM_QUIT消息,此種返回FALSE并結束消息循環。在一個單線程應用程序,結束消息循環往往是在關閉應用程序的第一步。應用程序可以調用PostQuitMessage函數來響應WM_DESTROY,結束消息循環。

如果您指定一個窗口句柄作為GetMessage的第二個參數,那么GetMessage只獲取在消息隊列里和這個窗口有關的消息。 GetMessage也可以在隊列中篩選消息,只獲取指定范圍內的消息。如需有關消息過濾的詳細信息,請參考消息過濾。

線程的消息循環必須包括TranslateMessage,如果線程需要接受鍵盤字符的輸入。每次用戶按下一個鍵,該系統產生相應的虛擬鍵消息(WM_KEYDOWN和WM_KEYUP)。虛擬鍵消息包含一個虛擬鍵碼,標識的是被按下的鍵,而不是它相關的字符值。要獲得此值,消息循環必須包含TranslateMessage,用來將虛擬鍵消息翻譯成字符消息(WM_CHAR)的并放到應用程序的消息隊列里。經過若干次循環后,WM_CHAR消息會被并派發到一個窗口。

DispatchMessage函數將消息發送到到與MSG結構中的窗口句柄關聯的窗口。如果窗口句柄是HWND_TOPMOST,DispatchMessage則將消息發送到操作系統所有的頂層窗口。如果窗口句柄是NULL,DispatchMessage不做任何事。

一個應用程序的主線程初始化后,系統就啟動應用程序的消息循環,并創造至少一個窗口。一旦啟動,消息循環持續從該線程的消息隊列中刪除消息,并派發他們到相應的窗口。GetMessage函數從消息列表中獲取到WM_QUIT消息時,消息循環結束。

一個消息隊列只需要一個消息循環,即使一個應用程序包含有多個窗口。 DispatchMessage總是調度消息到正確的窗口,這是因為每個隊列中的消息是MSG結構,它包含著消息所屬的窗口的句柄。

您可以以多種方式來修改消息循環。例如,您可以從隊列中刪除消息,但是不派發他們。當發送有些不帶有目的地窗口的消息時這非常有用。您也可以使用GetMessage只獲取指定的消息,這是有用的,如果你必須你暫時繞過正常的消息隊列FIFO順序。

應用程序使用快捷鍵時,必須能夠將鍵盤消息轉換為命令消息。因此,應用程序的消息循環必須包括TranslateAccelerator函數調用。關于快捷鍵的更多信息,請參見鍵盤加速器。

如果一個線程使用一個無模式對話框,那么消息循環必須包括IsDialogMessage函數,以便該對話框可以接收鍵盤輸入。

(3)窗口消息處理函數

窗口消息函數接收和處理的所有發送到窗口的消息。每個窗口類有一個窗口消息處理函數,用該類創建的每個窗口使用同一窗口消息處理函數。

該系統將消息發送到一個窗口的程序,并傳遞消息的相關信息到窗口消息處理函數,窗口消息處理函數檢查消息標識符,根據傳過來的參數識別并處理不同的消息,

一個窗口過程通常不會忽略一個消息。如果消息沒有被處理,必須被發送給系統默認的窗口消息處理函數,這是否通過調用DefWindowProc函數,來執行一個默認的處理,并返回一個處理的結果。窗口程序必須然后返回該值作為自己的消息處理的結果。大多數窗口消息處理函數只處理一少部分消息,并將其他的返回給系統默認的窗口消息處理函數。

因為窗口消息處理函數被所有屬于同一個窗口類的窗口共享,它可以處理幾個不同的窗口的消息。要確定具體的窗口消息,窗口消息處理函數可以檢查消息結構里的窗口句柄。

希望本文所述對大家的Windows應用程序設計有所幫助。

延伸 · 閱讀

精彩推薦
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
主站蜘蛛池模板: 免费一级欧美片在线观免看 | 女班长的放荡日记高h | 99ri国产在线观看 | 亚洲国产第一区二区三区 | 国产精品视频一区二区三区w | 亚洲 欧美 清纯 校园 另类 | 亚洲视频一区二区在线观看 | 国产精品反差婊在线观看 | 国产一级片视频 | 免费毛片| 黄色wwwwww| 免费操比视频 | 亚洲色图欧美偷拍 | 农夫69小说小雨与农村老太 | 日韩精品一区二区三区老鸭窝 | 日本私人影院 | 日本一道一区二区免费看 | 亚洲欧美日韩综合一区久久 | 14一18cad中国大学生 | 国产aaaaa一级毛片 | 青青国产成人久久激情91麻豆 | 黑帮大佬与我的365天2标清中文 | 日韩欧美国产免费看清风阁 | 帅老头恋帅老头同性tv | 亚洲不卡高清免v无码屋 | 无遮无挡免费视频 | 久久AV国产麻豆HD真实乱 | chinese男gay飞机同志 | 娇小性色 | 朝鲜女人free性xxe | 国产动作大片 | 色老板在线免费观看 | 国产精品第1页在线播放 | 九九精品成人免费国产片 | 日本国产一区二区三区 | 黄动漫车车好快的车车a | 热久久最新视频 | a亚洲天堂 | 亚洲 日韩 国产 中文视频 | 国产主播99 | 亚洲国产自拍在线 |