久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

剖析Windows消息處理機制

 fisher60 2012-12-02


前一段,幫人寫了個小控件,,又溫習(xí)了一遍Windows消息處理機制,,現(xiàn)在把一些知識點總結(jié)出來,供大家參考.


1.窗口
   Windows程序是由一系列的窗口構(gòu)成的,,每個窗口都有自己的窗口過程,,窗口過程就是一個擁有有固定 Signature 的 C函數(shù),具體格式如下:

   LRESULT CALLBACK WindowProc(HWND hwnd,
       UINT uMsg,
       WPARAM wParam,
       LPARAM lParam
   );
  
   窗口類型:
   可重疊窗口(Overlapped Window),,
   彈出窗口(Pop-up Window),,
   子窗口(Child Window)
  
   窗口之間的關(guān)系: 父子關(guān)系,擁有關(guān)系,,前后關(guān)系。
  
2.線程
    一個進程至少擁有一個線程,,稱為主線程,,如果一個線程創(chuàng)建了窗口,擁有GUI資源,,那么也稱該線程為GUI線程,否則就為工作線程,。窗口是由線程創(chuàng)建的,
 創(chuàng)建窗口的線程就擁有該窗口,。這種線程擁有關(guān)系的概念對窗口有重要的意義:建立窗口的線程必須是為窗口處理所有消息的線程,。為了使這個概念更加明
 確具體,可以想像一個線程建立了一個窗口,然后就結(jié)束了,。在這種情況下,,窗口不會收到一個WM_DESTROY或WM_NCDESTROY消息,因為線程已經(jīng)結(jié)束,,不可
 能被用來使窗口接收和處理這些消息,。每個線程,如果它至少建立了一個窗口,,都由系統(tǒng)對它分配一個消息隊列,。這個隊列用于窗口消息的派送(dispatch)。
 為了使窗口接收這些消息,,線程必須有它自己的消息循環(huán),,消息循環(huán)一般如下:
 
 MSG msg;
 while( GetMessage(&msg, NULL, 0, 0) )
 {
  TranslateMessage (&msg);
  DispatchMessage (&msg);
 }
 
 應(yīng)用程序不斷的從消息隊列中獲取消息,然后系統(tǒng)通過DispatchMessage函數(shù)分派消息到相應(yīng)窗口的窗口過程,使得消息得到處理,。當(dāng)獲取到WM_QUIT消息時,,
 GetMessage返回0,循環(huán)結(jié)束,。
 
3.消息
 消息,,就是指Windows發(fā)出的一個通知,告訴應(yīng)用程序某個事情發(fā)生了,。例如,,單擊鼠標(biāo)、改變窗口尺寸,、按下鍵盤上的一個鍵都會使Windows發(fā)送一個消息
 給應(yīng)用程序,,它被定義為:
  typedef struct {
  HWND hwnd;    //窗口句柄, 發(fā)生在哪個窗口上
  UINT message;   //消息標(biāo)識號 ( WM_MOUSEMOVE, WM_LBUTTONDOWN, ... )
  WPARAM wParam;   //消息參數(shù)1
  LPARAM lParam;   //消息參數(shù)2
  DWORD time;
  POINT pt;
 } MSG, *PMSG;
 一個消息結(jié)構(gòu)體包含了該事件 所有完備信息,當(dāng)應(yīng)用程序收到該消息時,,就可以做出相應(yīng)處理了,。
 
 消息分類

 <1>.隊列消息和非隊列消息

  從消息的發(fā)送途徑上看,消息分兩種:隊列消息和非隊列消息,。
  隊列消息送到系統(tǒng)消息隊列,,然后到線程消息隊列;非隊列消息直接送給目的窗口過程,。

  這里,,對消息隊列闡述如下:
  Windows維護一個系統(tǒng)消息隊列(System message queue),每個GUI線程有一個線程消息隊列(Thread message queue),。鼠標(biāo),、鍵盤事件由鼠標(biāo)或鍵盤驅(qū)動
  程序轉(zhuǎn)換成輸入消息并把消息放進系統(tǒng)消息隊列,例如WM_MOUSEMOVE,、WM_LBUTTONUP,、WM_KEYDOWN,、WM_CHAR等等。Windows每次從系統(tǒng)消息隊列移走一個
  消息,,確定它是送給哪個窗口的和這個窗口是由哪個線程創(chuàng)建的,,然后,把它放進窗口創(chuàng)建線程的線程消息隊列,。線程消息隊列接收送給該線程所創(chuàng)建窗口
  的消息,。線程從消息隊列取出消息,通過Windows把它送給適當(dāng)?shù)拇翱谶^程來處理,。
  
  除了鍵盤,、鼠標(biāo)消息以外,隊列消息還有WM_PAINT,、WM_TIMER和WM_QUIT,。這些隊列消息以外的絕大多數(shù)消息是非隊列消息。


 <2>.系統(tǒng)消息和應(yīng)用程序消息

  從消息的來源來看,,可以分為:系統(tǒng)定義的消息和應(yīng)用程序定義的消息,。

  系統(tǒng)消息ID的范圍是從0到WM_USER-1,或0X80000到0XBFFFF,;應(yīng)用程序消息從WM_USER(0X0400)到0X7FFF,,或0XC000到0XFFFF;WM_USER到0X7FFF范圍的消息
  由應(yīng)用程序自己使用,;0XC000到0XFFFF范圍的消息用來和其他應(yīng)用程序通信,,為了ID的唯一性,使用::RegisterWindowMessage來得到該范圍的消息ID,。
 
 <3>.窗口消息,,命令消息,控件通知消息
  根據(jù)處理過程的不同,可以分為三類:窗口消息,,命令消息,,控件通知消息。
  
  (1).窗口消息
   一般以WM_開頭,,如WM_CREATE, WM_SIZE, WM_MOUSEMOVE等標(biāo)準(zhǔn)的Windows消息, 用于窗口相關(guān)的事件通知,,窗口消息將由系統(tǒng)分配到該窗口的窗口過程處理。
  (2).命令消息 (WM_COMMAND)
   一種特殊的窗口消息,,它從一個窗口發(fā)送到另一個窗口以處理來自用戶的請求,,通常是從子窗口發(fā)送到父窗口,例如,,點擊按鈕時,按鈕的父窗口會收到
   WM_COMMAND消息,,用以通知父窗口按鈕被點擊,,經(jīng)測試:子窗口向父窗口發(fā)送WM_COMMAND消息,或者稱為父窗口會收到WM_COMMAND消息,操作系統(tǒng)并不是
   通過將WM_COMMAND消息放入到父窗口的消息隊列中去,,而是直接調(diào)用了父窗口的窗口過程,,以 WM_COMMAND 為消息標(biāo)識參數(shù)(UINT uMsg),實現(xiàn)這個功能的
   API函數(shù)正是: LRESULT DispatchMessage(const MSG *lpmsg);
  (3).控件通知消息
   WM_NOTIFY消息,,當(dāng)用戶與控件交互(Edit, Button...)時,,通知消息會從控件窗口發(fā)送到父窗口,這種消息的目的不是為了處理用戶命令,,而是為了讓父窗
   口能夠適時的改變控件,。
  

4.測試
 <1>.測試代碼:
 
  消息循環(huán)中,將從消息隊列中取出的消息逐一打印出來,,

while(GetMessage(&msg, NULL, 00))
  
{
   
char buf[1024];
   sprintf_s(buf, 
1024"hWnd:%d uMsg: %d WParam: %d  LParam: %d\n",
    msg.hwnd, msg.message, msg.wParam, msg.lParam);
   std::cout
<<buf;
   TranslateMessage(
&msg);
   DispatchMessage(
&msg);
  }


  在窗口過程中,,如果收到 WM_COMMAND 消息,就在窗口上輸入來,。

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  
{
   
switch (message)
   
{
   
case WM_COMMAND:
    HDhdc 
= GetDC (hwnd) ;
    SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
    TextOut(hdc, 
24 * cxChar, cyChar * (rect.bottom / cyChar - 1),
      szBuffer,
      wsprintf(szBuffer, szFormat,
      TEXT (
"WM_COMMAND"),
      HIWORD(wParam), LOWORD(wParam),
      HIWORD(lParam), LOWORD(lParam))
      );

    ReleaseDC (hwnd, hdc) ;
    ValidateRect (hwnd, 
&rect) ;
    
break ;
   
   
   
   }

   

   
return DefWindowProc (hwnd, message, wParam, lParam) ;
 }


 

      <2>.運行結(jié)果
    一個窗口,,窗口上有一個按鈕子窗口,然后還有一個控制臺,,輸出消息循環(huán)中的每條消息,,當(dāng)父窗口收到 WM_COMMAND 消息時,
    會在屏幕上輸出,。





      (1). 當(dāng)鼠標(biāo)在父窗口上移動時:
   



            可見父窗口 hWnd: 461982,,uMsg : 521 ( WM_MOUSEMOVE ),從線程消息隊列中取出的,。



      (2). 當(dāng)鼠標(biāo)在按鈕子窗口上移動時:



            可見按鈕 hWnd: 462118,,uMsg : 521 ( WM_MOUSEMOVE),從線程消息隊列中取出的,。



      (3). 當(dāng)鼠標(biāo)在父窗口上點擊時:




         父窗口收到了 513(WM_LBUTTONDOWN), 514(WM_LBUTTONUP) 消息,,從線程消息隊列中取出的。



      (4). 當(dāng)鼠標(biāo)在按鈕窗口上點擊時:




         按鈕窗口從線程的消息隊列中取出了 513(WM_LBUTTONDOWN), 514(WM_LBUTTONUP) 消息,,父窗口收到了WM_COMMAND
         消息,,TextOut 繪制出 WM_COMMAND 文本。
         

         我在 WM_COMMAND 的消息處理語句處打有斷點,,看下圖:



         
         可見,,窗口過程是被系統(tǒng)調(diào)用的,調(diào)用時系統(tǒng)傳入的參數(shù)值為:
                        hwnd:          0x00070c9e,,十進制就是461982,,父窗口句柄;
                        message:      273 (WM_COMMAND)
                        wParam:      ...
                         lParam:       ...
          具體是WinMain中的哪一個函數(shù)中最后調(diào)用了 窗口過程 WndProc 呢,,見下圖:







            原來是在 DispatchMessage 函數(shù)中,,再看看參數(shù)的值:
            msg.hwnd:             0x00070d26,,十進制是462118,是按鈕窗口的句柄;
            msg.message:         514 (  WM_LBUTTONUP  )
            哦~~~~,,原來是操作系統(tǒng)在從該線程的消息隊列中取出按鈕的 WM_LBUTTONUP (鼠標(biāo)左鍵釋放) 消息后,,調(diào)用
            DispatchMessage 分派消息,DispatchMessage 會先將 WM_LBUTTONUP 消息分派到按鈕的窗口過程(系統(tǒng)默認(rèn)有),,
            這里的分派到按鈕的窗口過程就是調(diào)用俺就的窗口過程,,然后又以 按鈕的父窗口的句柄為 窗口過程的第一個
            參數(shù), WM_COMMAND 為窗口過程的第二個參數(shù) 調(diào)用了 父窗口的窗口過程,,也就是將 WM_COMMAND
            消息分發(fā)到了父窗口,,從而使父窗口得到了通知。這些,,都是 Windows 來完成的,,應(yīng)用程序只需要在相應(yīng)的窗口
            過程中處理相應(yīng)的消息。

            從上面,,我們還可以看出,,WM_COMMAND 是非隊列消息,直接分派到目的窗口過程,,而不是放入到消息隊列中,,
            讓消息循環(huán)去取。



 總結(jié):

           簡而言之,, 標(biāo)準(zhǔn)Windows消息發(fā)送到產(chǎn)生窗口,,通知消息(WM_COMMAND, WM_NOTIFY)發(fā)送到父窗口,這是Windows
           的標(biāo)準(zhǔn)消息處理過程,,MFC對 Window API 進行了封裝,,有自己的一套消息處理流程, 消息順著一條路徑流動,,需要
           處理的對象可以添加消息響應(yīng)函數(shù)處理之,,對于命令消息,它有 CView , CDocument,  CMainFram ,  CWinApp 一系列處理
          節(jié)點,,對于通知消息,,MFC還加入一種很好的機制:消息反射,就是父窗口收到子窗口發(fā)出的通知消息后,,會將此消息
           發(fā)送給子窗口,,先讓子窗口處理,如果子窗口不處理,,父窗口再處理之,,這樣有利于將所有消息處理代碼都集成了子窗口
           中,有利于控件的開發(fā),。MFC的消息處理,,我不予詳細(xì)討論了,,有興趣的可以參考侯捷的<<深入淺出MFC>>。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多