詳解Windows消息分類以及WM_COMMAND與WM_NOTIFY的區別,以及模擬發送控件通知消息

轉自:http://blog.sina.com.cn/s/blog_4b3c1f950100nten.html


Windows消息的分類

1. 標準消息(隊列消息)
  除WM_COMMAND之外,所有以WM_開頭的消息都是標準消息,如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR。

     從CWnd派生的類都可以接收到這類消息。

     Windows每次從系統消息隊列移走一個消息,確定它是送給哪個窗口的和這個窗口是由哪個線程創建的,然後,把它放進窗口創建線程的線程消息隊列。線程消息隊列接收送給該線程所創建窗口的消息。線程從消息隊列取出消息,通過Windows 把它送給適當的窗口過程來處理。除了鍵盤、鼠標消息以外,隊列消息還有WM_PAINT、WM_TIMER 和WM_QUIT。

 
注意:標準消息並不需要我們指定處理函數名稱,是默認的對應關係。

例如:

       宏名稱                          對應消息                        消息處理函數

      ON_WM_CHAR               WM_CHAR                             OnChar
      ON_WM_CLOSE             WM_CLOSE                          OnClose
       ON_WM_CREATE           WM_CREATE                        OnCreate
      ON_WM_DESTROY           WM_DESTROY                     OnDestroy
      ON_WM_LBUTTONDO         WM_LBUTTONDOWN            OnLButtonDown
      ON_WM_LBUTTONUP         WM_LBUTTONUP                     OnLButtonUp
      ON_WM_MOUSEMOVE         WM_MOUSEMOVE                 OnMouseMove
      ON_WM_PAINT              WM_PAINT                                  OnPaint        

      .........                              ............                                    .......


2.命令消息
     
來自菜單、加速鍵或工具欄按鈕的消息均是命令消息。

     這類消息都以WM_COMMAND形式呈現。在MFC中,通過菜單項的標識(ID)來區分不同的命令消息;在SDK中,通過消息的wParam參數識別。從CCmdTarget派生的類都可以接收到這類消息,其wParam 記錄着該消息來自哪一個菜單項目。

例如:ON_COMMAND(IDM_ABOUT,    OnAbout)
          ON_COMMAND(IDM_FILENEW, OnFileNew)
          ON_COMMAND(IDM_FILEOPEN, OnFileOpen)
          ON_COMMAND(IDM_FILESAVE, OnFileSave)

          ...........

3.通告消息
    由控件產生的消息,例如按鈕,列表框的選擇等都會產生通告消息,目的是爲了向其父窗口(通常是對話框)通知事件的發生。

     這類消息是以WM_COMMANDWM_NOTIFY形式呈現的從CCmdTarget派生的類(如CDocument可以接受命令消息和通告消息,但不能接收標準消息(隊列消息)),都可以接收到這類消息。
   注意:由於CWnd類派生於CCmdTarget類,所以凡是從CWnd派生的類,他們既可以接收標準消息,也可以接收命令消息和通告消息。而對於從CCmdTarget類派生的類只能接收命令消息和通告消息,不能接受標準消息。

例如:    控件              宏                                         消息處理函數

          Button           ON_BN_CLICKED(<id>,<memberFxn>)           memberFxn
           ComboBox        ON_CBN_DBLCLK(<id>,<memberFxn>)          memberFxn
           Edit               ON_EN_SETFOCUS(<id>,<memberFxn>)       memberFxn
          ListBox          ON_LBN_DBLCLK(<id>,<memberFxn>)          memberFxn

         .........              ......................             ...........

 

標準消息和非標準消息的區分:

    標準消息: 帶有有控制後後續操作;

    非標準消息:只是簡單提示。

 

MFC命令消息的路由:

AfxWndProc(替換了窗口過程函數)->AfxCallWndProc->WindowProc->OnWnddMsg->(如果是命令消息則調用Oncommand;如果是通告消息則調用OnNotify)->OnCmdMsg


那麼通告消息到底是WM_COMMAND還是WM_NOTIFY呢?

解釋一:WM_NOTIFYWM_COMMAND 功能更強大,可以存儲一些額外的信息,WM_COMMAND 並不被所有的控件所支持。

解釋二:Edit,Button,ListBox等發送WM_COMMAND消息,ListView,Toolbar,Tree等編譯時如果不聯接comctl32.lib就通不過的。Common,Controls發送WM_NOTIFY消息,因爲需要提供的信息更多。

 

 

給對話框中的控件發送消息:

想要給CTreeCtrl控件模擬發送一個TCN_SELCHANGE消息。

想要給CButton控件模擬發送一個BN_CLICKED消息。

 

★  由上面對windows消息的分類,我們得知,這兩個消息都是通告消息。那是用 WM_COMMAND還是WM_NOTIFY呢?

根據上面的解釋,我們使用 TCN_SELCHANGE--WM_NOTIFY ,BN_CLICKED--WM_COMMAND

是不是這樣呢?咱們參看MSDN:

TCN_SELCHANGE

TCN_SELCHANGE
    lpnmhdr = (LPNMHDR) lParam;

Notifies a tab control's parent window that the currently selected tab has changed. This message is sent in the form of a  message.

  • No return value.

lpnmhdrAddress of an  structure. The hwndFrom member is the handle to the tab control. The idFrommember is the child window identifier of the tab control. The code member is TCN_SELCHANGE.

由上看出TCN_SELCHANGE確實是以呈現的,它包含以一個結構體指針的形式包含在lParam中。

typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR;

Contains information about a notification message.

hwndFromWindow handle to the control sending a message.idFromIdentifier of the control sending a message.codeNotification code. This member can be a control-specific notification code or it can be one of the common notification codes.

 

BN_CLICKED

The BN_CLICKED notification message is sent when the user clicks a button. The parent window of the button receives this notification message through the WM_COMMAND message.

BN_CLICKED idButton = (int) LOWORD(wParam); // identifier of button hwndButton = (HWND) lParam; // handle to button

由上看出BN_CLICKED確實是包含在WM_COMMAND 中的。

 

 

★  怎樣把通告消息溶到WM_COMMAND 和 中呢?

WM_NOTIFY
    idCtrl = (int) wParam;
    pnmh = (LPNMHDR) lParam;idCtrlIdentifier of the common control sending the message.pnmhAddress of an  structure that contains the notification code and additional information. 

WM_COMMAND
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam);         // item, control, or accelerator identifier
hwndCtl = (HWND) lParam;      // handle of control

組裝參數:

LPARAM MAKELPARAM(
  WORD
 wLow // low-order word
  WORD wHigh  // high-order word
);

或者

DWORD MAKELONG(
  WORD
 wLow // low-order word of long value
  WORD wHigh  // high-order word of long value );

 

★  向控件發消息我們可以使用以下兩個方法: 

LONG SendDlgItemMessage(
  HWND
 hDlg,      // handle of dialog box
  int nIDDlgItem, // identifier of control
  UINT Msg,       // message to send
  WPARAM wParam // first message parameter
  LPARAM lParam   // second message parameter
);
或者

LRESULT SendMessage(
  HWND
 hWnd,      // handle of destination window
  UINT Msg,       // message to send
  WPARAM wParam // first message parameter
  LPARAM lParam   // second message parameter
);

 


★  實例,驗證成功:

 //模擬發送TCN_SELCHANGE消息
 NMHDR  nmhdr;
 nmhdr.code = TCN_SELCHANGE;      
 nmhdr.hwndFrom = g_pMainDlg->m_TabCtrl.GetSafeHwnd();      
 nmhdr.idFrom= g_pMainDlg->m_TabCtrl.GetDlgCtrlID();
 ::SendDlgItemMessage(g_pMainDlg->m_hWnd,IDC_TAB1,WM_NOTIFY,MAKELONG(TCN_SELCHANGE,0),(LPARAM)(&nmhdr)); 


//發送BN_CLICKED消息

::SendMessage(g_pMainDlg->m_VNOnLine.m_hWnd,WM_COMMAND,MAKELPARAM(IDC_RANG_OFF,BN_CLICKED),(LPARAM)(::GetDlgItem(g_pMainDlg->m_VNOnLine.m_hWnd,IDC_RANG_OFF)));

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章