走進windows編程的世界-----訊息處理函數(1)

來源:互聯網
上載者:User

標籤:windows   win32   

Win32訊息機制    過程驅動:程式是按照我們預先定義好的順序執行,每執行一步,下一步都已經按照預定的順序 繼續執行,直至程式結束。    事件驅動:程式的執行順序是無序的。某個時間點所執行的代碼,是由外界 通知。由於我們無法決定程式執行順序。所以代碼的執行也是無序的。  Win32基本訊息   WM_DESTROY:
      視窗銷毀時的訊息,可以做退出或善後處理  WM_CREATE:
      視窗建立訊息,是在視窗建立後,視窗處理函數收到的第一條訊息
  可以在這個訊息內,做初始化或者穿件子視窗
  WPARAM wParam - 不使用
  LPARAM lParam - CREATESTRUCT指標
   WM_SIZE:
      當視窗大小發生改變時,會收到這個訊息。
  可以在這個訊息中調整視窗的布局
 WM_SYSCOMMAND:
      系統命令訊息,當點擊系統功能表和按鈕時會收到
  可以在這個訊息中,提示使用者儲存資料等
 WM_PAINT:
      繪圖訊息
      鍵盤訊息:
 滑鼠訊息
 WM_TIME:定時器訊息  訊息的擷取和發送
     擷取GetMessage/PeekMessage
         GetMessage 擷取訊息,阻塞函數
         PeekMessage 擷取訊息,非阻塞函數
     發送SendMessage/PostMessage
         SendMessage 發送訊息並等候訊息處理結束才返回。 
         PostMessage 發送訊息後立即返回,不關心訊息處理的結果。 
LRESULT SendMessage/PostMessage(          HWND hWnd,      //處理訊息視窗          UINT Msg,       //訊息的ID          WPARAM wParam,  //訊息的參數          LPARAM lParam );//訊息的參數

 3 訊息組成和分類
   3.1 訊息組成
      視窗控制代碼/訊息ID/訊息參數(WPARAM.LPARAM)
   3.2 訊息分類
      3.2.1 系統訊息 - 由系統定義和使用的訊息
         例如:WM_CREATE/WM_SIZE
         訊息ID範圍為: 0 - 0x03FF(WM_USER-1)
      3.2.2 使用者定義訊息 - 應用程式可以自己定義和使用的訊息, WM_USER(0x0400)
         從WM_USER的ID開始,到0x7FFF,是使用者可以定義使用的訊息.
      3.2.3 其他訊息範圍
         WM_APP(0x8000)-0xBFFF:應用程式訪問視窗的訊息ID
         0xC000-0xFFFF: 應用程式訪問訊息,使用字串註冊系統產生相應訊息ID
      3.2.4 使用者定義訊息的使用
         1)定義自訂訊息ID:

 #define   WM_FIRSTMSG  (WM_USER+1)

         2)在視窗處理函數中,響應訊息

 switch( nMsg ) { case WM_FIRSTMSG:   //處理函數    break; }

         3)SendMessage/PostMessage發送訊息

    SendMessage( hWnd, WM_FIRSTMSG, 0, 0 );

  4 訊息佇列
    4.1 訊息佇列 - 用於儲存訊息的記憶體空間,訊息在隊列中是先入先出.
    4.2 訊息佇列的分類
      4.2.1 系統訊息佇列 - 由系統維護的訊息佇列. 
      4.2.2 應用程式訊息佇列(線程訊息對列) -屬於每個線程的各自擁有的訊息佇列.
  
  5 訊息和訊息佇列
    5.1 根據訊息和訊息佇列關係,將訊息分成兩種:
      隊列訊息 - 可以存放在訊息佇列中的訊息.
      非隊列訊息 - 發送時不進入訊息佇列.
    5.2 隊列訊息
      首先存放到訊息佇列當中,然後由GetMessage/PeekMessage取出,然後進行處理.
      例如: 滑鼠訊息/鍵盤訊息/WM_PAINT/WM_QUIT/M_TIMER訊息
    5.3 非隊列訊息
      訊息發送直接發送給指定的視窗,尋找視窗的處理函數,返回處理結果.
 
 6 訊息的擷取   
    6.1 訊息迴圈
      6.1.1 GetMesssage從隊列中擷取訊息,判斷是否是WM_QUIT訊息,如果發現是WM_QUIT訊息,訊息迴圈結束,否則繼續下一步.
      6.1.2 TranslateMessage 翻譯按鍵訊息,如果發現有按鍵訊息,產生字元訊息放入訊息對列, 繼續下一步
      6.1.3 DispatchMessage 找到訊息所發視窗的處理函數,處理訊息.處理完成後,返回6.1.1.
    6.2 GetMesssage和PeekMessage
      6.2.1 從線程訊息佇列中擷取訊息,如果找到訊息,就返回訊息,進行訊息處理. 如果未找到訊息,執行6.2.2
      6.2.2 尋找系統訊息佇列.通過向系統訊息佇列查詢,如果找到訊息,擷取訊息並返回,進行訊息處理.如果未找到訊息,執行6.2.3
      6.2.3 檢查視窗需要重新繪製的範圍,如果發現存在重新繪製的範圍,會產生WM_PAINT訊息.然後進行訊息處理, 如果未找,執行6.2.4
      6.2.4 檢查WM_TIMER定時器訊息,如果發現存在已經到時的定時器,會產生WM_TIMER訊息.進行訊息處理. 如果未找,執行6.2.5
      6.2.5 執行記憶體管理工作.
      6.2.6 根據函數不同,處理結果不同:
        GetMesssage - 阻塞,等候下一條訊息
        PeekMessage - 讓出控制權,交給後面的代碼執行.
        
  7 訊息發送  
    7.1 訊息發送分兩種
       發送(Send)訊息 - 直接發送給指定的視窗,並等候結果.
       投遞(Post)訊息 - 發送到訊息佇列當中,立刻返回,由訊息迴圈處理.
    7.2 PostMessage和SendMessage
      PostMessage產生隊列訊息,由於發送後不等候訊息處理結果,所以不能確定訊息是否被處理成功.
      SendMessage產生非隊列訊息,可以確定訊息是否成功. 

看下面的程式碼範例: 
/*File : message.cpp *Auth : sjin *Date : 20140519 *Mail : [email protected] */#include <iostream>#include <Windows.h>#include <stdio.h>HINSTANCE g_hInst = NULL;HWND g_button = NULL;LRESULT CALLBACK WndProc(HWND hWnd,                         UINT nMsg,                         WPARAM wParam,                         LPARAM lParam);/*註冊視窗*/BOOL RegisterWnd(LPSTR pszClassName){    WNDCLASSEX wce = {0};    wce.cbClsExtra = 0;    wce.cbSize = sizeof(wce);    wce.cbWndExtra = 0;    wce.hbrBackground = HBRUSH(COLOR_BTNFACE+1);    wce.hCursor = NULL;    wce.hIcon = NULL;    wce.hIconSm = NULL;    wce.hInstance = g_hInst;    wce.lpfnWndProc = WndProc;    wce.lpszClassName = pszClassName;    wce.lpszMenuName = NULL;    wce.style = CS_HREDRAW|CS_VREDRAW;    ATOM nAtom = RegisterClassEx(&wce);    if(0 == nAtom)        return FALSE;    return TRUE;}/*建立視窗*/HWND CreateWnd(LPSTR pszClassName){    HWND hWnd = CreateWindowEx(0, pszClassName,        "MyWnd", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,        CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,        NULL,NULL,g_hInst,NULL);    return hWnd;} /*顯示視窗*/void DisplayWnd(HWND hWnd){    ShowWindow(hWnd, SW_SHOW);    UpdateWindow(hWnd);}void wm_create(HWND hWnd,UINT nMsg,           WPARAM wParam,LPARAM lParam){LPCREATESTRUCT pCreateStruct = LPCREATESTRUCT(lParam);/*列印視窗的名字  先彈出這個對話方塊,點擊OK後快顯視窗  *///MessageBox(NULL, pCreateStruct->lpszName,"WM_CREATE",MB_OK);/*建立一個子視窗*/ g_button = CreateWindowEx(0, "BUTTON","BUTTON", WS_CHILD|WS_VISIBLE, 30,        20,100,50,        hWnd,NULL,g_hInst,NULL);}void wm_size(HWND hWnd,UINT nMsg,           WPARAM wParam,LPARAM lParam){INT nWidth = LOWORD(lParam);INT nHeight = HIWORD(lParam);CHAR szText[256] = {‘\0‘};sprintf(szText,"W:%d;H:%d",nWidth,nHeight);//MessageBox(NULL, szText,"WM_SIZE",MB_OK); if(NULL != g_button)    {        int nX = (nWidth - 100)/2;        int nY = (nHeight - 100)/2;        MoveWindow(g_button, nX, nY, 100, 100, TRUE);    }}/*執行系統命令函數處理*/BOOL wm_syscommand(HWND hWnd,UINT nMsg,           WPARAM wParam,LPARAM lParam){switch(wParam){case SC_CLOSE:if(IDOK == MessageBox(NULL,"是否將檔案存檔","提示",MB_OKCANCEL|MB_ICONWARNING)){return TRUE;} else {return FALSE;}break;default:break;}return FALSE;}/*訊息處理函數*/LRESULT CALLBACK WndProc(HWND hWnd,                         UINT nMsg,                         WPARAM wParam,                         LPARAM lParam){    switch(nMsg){/*Win 32 基本訊息  WM_DESTROY:       視窗銷毀時的訊息,可以做退出或善後處理  WM_CREATE:       視窗建立訊息,是在視窗建立後,視窗處理函數收到的第一條訊息   可以在這個訊息內,做初始化或者穿件子視窗   WPARAM wParam - 不使用   LPARAM lParam - CREATESTRUCT指標  WM_SIZE:       當視窗大小發生改變時,會收到這個訊息。   可以在這個訊息中調整視窗的布局  WM_SYSCOMMAND:       系統命令訊息,當點擊系統功能表和按鈕時會收到   可以在這個訊息中,提示使用者儲存資料等  WM_PAINT:       繪圖訊息      鍵盤訊息:  滑鼠訊息  WM_TIME:定時器訊息*/    case WM_DESTROY://視窗銷毀時的訊息/*向視窗發送WM_QUIT 訊息*/        //SendMessage(hWnd, WM_QUIT, 0, 0);/*發送訊息並等候訊息處理結束才返回*/        PostMessage(hWnd, WM_QUIT, 0, 0);/*發送訊息後立即返回,不關心訊息處理的結果*/        //PostQuitMessage(0);return 0;case WM_CREATE:/*建立視窗*/wm_create(hWnd,nMsg,wParam,lParam);break;case WM_SIZE:/*視窗拖動*/wm_size(hWnd,nMsg,wParam,lParam);break;case WM_SYSCOMMAND:/*執行系統命令*/if(!wm_syscommand(hWnd,nMsg,wParam,lParam)){return 0;}break;            }    return DefWindowProc(hWnd, nMsg, wParam, lParam);}/*訊息迴圈*/void Message(){/* MSG 結構體參數描述typedef struct tagMSG {     // msg         HWND hwnd; //訊息視窗控制代碼       UINT message;//訊息標示       WPARAM wParam;//訊息的參數       LPARAM lParam;//訊息的參數       DWORD time;//訊息的時間       POINT pt;//訊息產生時,滑鼠的位置     } MSG;    */    MSG msg = {0};/*  BOOL GetMessage(      LPMSG lpMsg,//存放擷取到的訊息資料 由系統填寫關於訊息的參數      HWND hWnd,//擷取訊息的視窗控制代碼,可接受指定視窗訊息      UINT wMsgFilterMin,//訊息過濾的起始訊息      UINT wMsgFilterMax //訊息過濾的終止訊息  );   return :         TRUE :成功擷取訊息;FALSE:擷取到WM_QUIT訊息時。   可以使用PostQuitMessage向視窗發送WM_QUIT訊息   GetMessage:擷取訊息,阻塞函數   PeekMessage:擷取訊息,非阻塞函數 */    while(GetMessage(&msg, NULL, 0, 0))    {/*TranslateMessage:  就是將鍵盤的訊息轉換成字元訊息  1、首先檢查是否是鍵盤訊息  2、如果發現是按鍵訊息,將根據按鍵,產生字元訊息     在下一個GetMessage執行時,收到這個訊息  3、如果未發現按鍵訊息,未做任何處理*/        TranslateMessage(&msg);/*DispatchMessage  根據訊息資料內視窗控制代碼,找到這個視窗的視窗處理函數, 調用處理函數,進行訊息處理。          如果MSG中,HWND視窗控制代碼為空白,DispatchMessage不做任何處理。*/        DispatchMessage(&msg);    }}int APIENTRY WinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPSTR     lpCmdLine,                     int       nCmdShow){    g_hInst = hInstance;    RegisterWnd("MyWnd");    HWND hWnd = CreateWnd("MyWnd");    DisplayWnd(hWnd);    Message();    return 0;}





相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.