MFC訊息詳解

來源:互聯網
上載者:User

MFC訊息詳解

1. 怎樣使用MFC發送一個訊息用MFC發送一個訊息的方法是,
    首先,應擷取接收訊息的CWnd類對象的指標;
    然後,調用CWnd的成員函數SendMessage( )。
        LRESULT Res=pWnd->SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
        pWnd指標指向目標CWnd類對象。變數Msg是訊息,wParam和lParam變數包含訊息的參數,如按一下滑鼠哪裡或選擇了什麼功能表項目。目標視窗返回的訊息結果放在變數Res中。
        發送訊息到一個沒有CWnd類對象的視窗,可以用下列目標視窗的控制代碼直接調用Windows API:
        LRESULT Res=::SendMessage(HWND hWnd, UINT Msg,  WPARAM wParam, LPARAM lParam);
        這裡的hWnd是目標視窗的控制代碼。
2. 怎樣用MFC寄送一個訊息
    用MFC寄送一個訊息與發送一個訊息幾乎相同,但寄送時用PostMessage( ) ,而不是用SendMessage( );傳回值Res也不一樣,Res不是一個由目標視窗返回的值,而是一個布爾值,用來表示訊息是否成功地放到訊息佇列中。
3. 檢索一個寄送訊息
    正常情況下,一旦訊息被寄送後,應用程式在後台發送它。但是在特殊情況下,需要你自己去刪除一個訊息,例如想在應用程式接收到某種訊息之前停止應用程式。有兩種方法可以從應用程式訊息佇列中刪除一個訊息,但這兩種方法都沒有涉及MFC。
■ 第一種方法:在不干擾任何事情之下窺視訊息佇列,看看一個訊息是否在那裡。
    BOOL res=::PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ) ;
■ 第二種方法:實際上是等待,一直等到一個新的訊息到達隊列為止,然後刪除並返回該訊息。
    BOOL res=::GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
    在這兩種方法中,變數hWnd指定要截獲訊息的視窗,如果該變數設為NULL,所有視窗訊息將被截獲。wMsgFilterMin和wMsgFilterMax變數與SendMessage( )中的變數Msg相對應,指定查看訊息的範圍。如果用"0,0",則所有的訊息都將被截獲。如果用WM_KEYFIRST,WM_KEYLAST或WM_MOUSEFIRST,WM_MOUSELAST,則所有鍵盤或滑鼠的訊息將被截獲。wRemoveMsg變數指定PeekMessage( )是否應該真正地從隊列中刪除該訊息。(GetMessage( )總是刪除訊息)。該變數可以取兩個值:
    ■ PM_REMOVE,PeekMessage( )將刪除訊息。
    ■ PM_NOREMOVE,PeekMessage( )將把訊息留在隊列裡,並返回它的一個拷貝。
    當然,如果把訊息留在訊息佇列中,然後再次調用PeekMessage( )查看相同類型的訊息,則將返回完全相同的訊息。
    lpMsg變數是一個指向MSG結構的指標,MSG包含檢索到的訊息。
    typedef struct tagMSG {
                        HWND hwnd; // window handle message is intended for
                        UINT message;
                        WPARAM wParam;
                        LPARAM lParam;
                        DWORD time; // the time the message was put in the queue
                        POINT pt; // the location of the mouse cursor when the
                                       // message was put in the queue
                        } MSG;
4. MFC怎樣接收一個寄送的訊息
    MFC處理一個寄送和發送訊息的唯一明顯不同是寄送的訊息要在應用程式的訊息佇列中花費一些時間。在訊息泵(message pump)彈出它之前,它要一直在隊列中。
    訊息泵
    MFC應用程式中的訊息泵在CWinApp的成員函數Run()中。應用程式開始運行時,Run()就被調用,Run()把時間分割成兩部分。一部分用來執行幕後處理,如取消臨時CWnd對象;另一部分用來檢查訊息佇列。當一個新的訊息進來時,Run()抽取它—即用GetMessage( )從隊列中取出該訊息,運行兩個訊息翻譯函數,然後用DispatchMessage( )函數調用該訊息預期的目標視窗進程。
    訊息泵調用的兩個翻譯函數是PreTranslateMessage( )和::TranslateMessage( )。目標視窗的MFC類可調用reTranslateMessage在發送訊息給它之前進行訊息翻譯,例如,CFrameWnd用PreTranslateMessage( )將加速鍵(如,Ctrl+S隱藏檔)轉換為命令訊息。翻譯前的訊息通常被處理掉,而翻譯後的訊息(如果有的話)將被重新寄送到隊列裡。::TranslateMessage是一個視窗函數,將原始鍵碼轉換為鍵字元。訊息一旦被DispatchMessage()發送,MFC處理它就像處理SendMessage()發送的訊息一樣。
5. MFC怎樣處理一個接收到的訊息
    處理接收到的訊息的目的非常簡單:將訊息指向一個函數,該函數通過訊息中的訊息標識符處理它。非MFC視窗用簡單的case語句來實現該目標,每個case語句執行一些函數,或調用其他一些函數。
    MainWndProc(HWND hWnd, UINT message, W PARAM wParam,LPARAM lParam)
    {
        switch(message)
        {
        case WM_CREATE:
            : : :
        break;
        case WM_PAINT:
            : : :
        break;
        default:
        return(DefWindowProc(hWnd,message,wParam,lParam));
        }
        return(NULL);
    }
    任何遺漏的訊息將被傳輸到一個預設的訊息處理函數,但是,case語句不能很好地適應C++和封裝技術。在C++環境中,要求訊息被一個專門處理該類型訊息的類的成員函數處理。因此,MFC不採用case語句,而採用更加複雜和迴旋的方法。但它允許用私人類處理訊息,而只需做下面三件事情:
    ■ 從將要接收訊息的CWnd類對象衍生類別(對於命令訊息是CCmdTarget)。
    ■ 在衍生類別中寫一個處理訊息的成員函數。
    ■ 在類中定義一個尋找表(叫做訊息映像),該表具有成員函數的條目和它要處理的訊息的標識符。
    然後,MFC依次調用下面的函數,指引輸入訊息到處理函數。
    1) AfxWndProc( )接收訊息,尋找訊息所屬的CWnd對象,然後調用AfxCallWndProc( )。
    2) AfxCallWndProc( )儲存訊息(訊息標識符和參數)供未來參考,然後調用WindowProc( )。
    3) WindowProc( ) 發送訊息給OnWndMsg( ) ,然後,如果訊息未被處理,則發送給DefWindowproc( )。
    4) OnWndMsg( )要麼為WM_COMMAND訊息調用OnCommand( ),要麼為WM_NOTIFY訊息調用OnNotify( )。任何被遺漏的訊息都將是一個視窗訊息。OnWndMsg( )搜尋類的訊息映像,以找到一個能處理任何視窗訊息的處理函數。如果OnWndMsg( )不能找到這樣的處理函數,則把訊息返回到WindowProc( ),由它將訊息發送給DefWindowProc( )。
    5) OnCommand()查看這是不是一個控制項通知(lParam不是NULL);如果它是,OnCommand( )就試圖將訊息映射到製造通知的控制項;如果它不是一個控制項通知,或者控制項拒絕映射的訊息,OnCommand( )就調用OnCmdMsg( )。
    6) OnNotify( )也試圖將訊息映射到製造通知的控制項;如果映射不成功, OnNotify( )就調用相同的OnCmdMsg( )函數。
    7) 根據接收訊息的類,OnCmdMsg( )將在一個稱為命令傳遞(Command Routing)的過程中潛在地傳遞命令訊息和控制項通知。例如,如果擁有該視窗的類是一個架構類,則命令和通知訊息也被傳遞到視圖和文檔類,並為該類尋找一個訊息處理函數。
為什麼要訊息映像?
    這畢竟是C++語言;為什麼OnWndMsg( )不為每個視窗訊息調用一個預定義的虛擬函數?因為它太占CPU。若是那樣,當掃描一個訊息映像以加速該過程時,OnWndMsg( )可能會做出意想不到的事情,並陷入彙編器。注意通過重載WindowProc( )、OnWndMsg( )、OnCommand( )、OnNotify( ) 或OnCmdMsg( )可以修改這一過程。重載OnWndMsg( )可以在視窗訊息被排序之前插入該過程。重載OnCommand( )或OnNotify( )可以在訊息被反射之前插入該過程。
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.