1. 程式人生 > >新增自定義訊息處理

新增自定義訊息處理

1.PreTranslateMessage

PreTranslateMessage是訊息在送給TranslateMessage函式之前被呼叫的。

標頭檔案中過載該函式

virtual BOOL PreTranslateMessage(MSG* pMsg);

原始檔中寫實現方法

BOOL CClientDlg::PreTranslateMessage(MSG* pMsg) 

{
if (pMsg->message==1000)
{
ReceiveData();
return TRUE;
}
else
return CDialog::PreTranslateMessage(pMsg);

}

定義為1000的訊息由WSAAsyncSelect(m_client, m_hWnd, 1000, FD_READ)發出,PreTranslateMessage接收到該訊息就會接收資料。

2.PostMessage

函式原型:BOOL WINAPI      PostMessage(
                                                                              _In_opt_  HWND hWnd,                      //接收訊息的視窗的控制代碼,NULL表示傳送到當前執行緒視窗
                                                                              _In_      UINT Msg,                                //指定被寄送的訊息
                                                                              _In_      WPARAM wParam,                //指定附加的訊息特定的資訊
                                                                              _In_      LPARAM lParam                    //指定附加的訊息特定的資訊
                                                                            );
該函式將一個訊息放入(寄送)到與指定視窗建立的執行緒相聯絡訊息佇列裡,不等待執行緒處理訊息就返回,是非同步訊息模式。訊息佇列裡的訊息通過呼叫GetMessage和PeekMessage取得。
如果函式呼叫成功,返回非零,函式呼叫返回值為零。
標頭檔案:winuser.h;
輸入庫:user32.lib;
1、由於是使用者自己定義的訊息,所以首先要定義一個訊息巨集如下:
#define WM_MYMESSAGE (WM_USER+1)

注意:為防止使用者定義的巨集和系統定義巨集衝突,所以系統提供了一個WM_USER,只要是大於WM_USER可供使用者使用

2、定義一個訊息響應巨集,即將此巨集對映的函式,如下:

ON_MESSAGE(WM_MYMESSAGE,OnMyMssage)
WM_MYMESSAGE為自定義的巨集,OnMyMssage為訊息處理函式名

3、在標頭檔案中宣告自己的訊息處理函式,如下:

afx_msg LRESULT OnMyMssage(WPARAM w,LPARAM l);

4、定義訊息處理函式,如下:

LRESULT CPostMessageDlg::OnMyMssage(WPARAM wParam, LPARAM lParam)
{
     MessageBox(_T("自定義訊息"));
     return 1;
}

5、通過PostMessage函式將OnMyMssage新增到訊息佇列中,如下:

void CPostMessageDlg::OnButton1() //按鈕響應事件
{
     PostMessage(WM_MYMESSAGE,IDC_BUTTON1);//傳送之後立即返回
     //SendMessage(WM_MYMESSAGE);//傳送之後等待返回
}

3.SendMessage

函式原型
LRESULT SendMessage(

                                                 HWND hWnd,            //將接收訊息的視窗的控制代碼

                                                 UINT Msg,                  //指定被髮送的訊息

                                                 WPARAM wParam,  //指定被髮送的訊息

                                                 LPARAM IParam)      //指定被髮送的訊息

該函式將指定的訊息傳送到一個或多個視窗。此函式為指定的視窗呼叫視窗程式,直到視窗程式處理完訊息再返回。

例子

以下這個例子中是一個MFC的對話方塊應用程式,名字為MessageTest。它包括一個傳送對話方塊和一個接收對話方塊,其中傳送對話方塊和接收對話方塊都是主對話方塊的子對話方塊,利用訊息傳遞來從傳送對話方塊向接收對話方塊傳送資料。

標頭檔案

#define RECEIVE_TITLE "receive title"

#define GET_STRUCT WM_USER+1000
struct SendStruct
{
      int a;
      int b;
      int c;
      int d;
};

RECEIVE_TITLE定義接收對話方塊的標題,GET_STRUCT是訊息ID,WM_USER是使用者自定義訊息的起始ID。在生成的接受對話方塊的位置加入SetWindowText(RECEIVE_TITLE)。

1.      在接受對話方塊1的類的定義中加入
afx_msg LRESULT GetStruct(WPARAM wparam,LPARAM lparam);
2.      在對應的cpp檔案中加入
ON_MESSAGE(GET_STRUCT,ReceiveDlg::GetStruct)
3.      在函式實現部分加入
LRESULT ReceiveDlg::GetStruct(WPARAM wparam,LPARAM lparam)
{
      SendStruct* ss=(SendStruct*)wparam;
      CString str;
      str.Format("%d,%d,%d,%d",ss->a,ss->b,ss->c,ss->d);
      CEdit* edit1=(CEdit*)GetDlgItem(IDC_EDIT1);
      edit1->SetWindowText(str);
      free(ss);
      return 0;
}
4.      在傳送訊息的函式中加入
SendStruct *ss = (SendStruct *)malloc(sizeof(SendStruct));
ss->a=1;
ss->b=2;
ss->c=3;
ss->d=4;
HWND hWnd = ::FindWindowEx(this->GetParent()->m_hWnd, NULL, NULL, RECEIVE_TITLE);
FromHandle(hWnd)->SendMessage(GET_STRUCT,(WPARAM)(ss),0);

其中,m_hWnd為接收訊息的父視窗的控制代碼,RECEIVE_TITLE為接收訊息視窗的標題,得到的hWnd為接收訊息視窗的控制代碼。

總結:

PostMessage函式將一個訊息放入與建立這個視窗的訊息佇列相關的執行緒中,並立刻返回不等待執行緒處理訊息,SendMessage函式將指定的訊息發到視窗。它呼叫特定視窗的視窗處理函式,並且不會立即返回,直到視窗處理函式處理了這個訊息。SendMessage的確是傳送訊息,然後等待處理完成返回,但傳送訊息的方法為直接呼叫訊息處理函式(即WndProc函式),按照函式呼叫規則,肯定會等訊息處理函式返回之後,SendMessage才返回。而PostMessage卻沒有傳送訊息,PostMessage是將訊息放入訊息佇列中,然後立刻返回,至於訊息何時被處理,PostMessage完全不知道,此時只有訊息迴圈知道被PostMessage的訊息何時被處理了。
所以SendMessage只是呼叫我們的訊息處理函式,PostMessage只是將訊息放到訊息佇列中。更直接的說SendMessage的訊息是不進佇列的,而PostMessage的需要排隊。

我們可以PreTranslateMessage來對訊息預處理,該用的用,不該用的不用。用SendMessage傳送的訊息是不能用PreTranslateMessage來預處理的,因為SendMessage的訊息是不進佇列的。而Post的就可以。