消息处理(三)

一、自定义命令

为了使用自定义命令,一般要经过如下几个步骤:

(1)自定义命令ID

      命令ID是WORD型的。虽然可以自由设定其值,但是不能和应用程序中其他命令ID冲突。

      在资源文件中新建一个命令,例如#define ID_LOADTOIE 8888

(2)添加自定义消息映射项

BEGIN_MESSAGE_MAP(CMsgDialog,CDialog)
     ON_COMMAND(ID_LOADTOIE,LoadToIE)
END_MESSAGE_MAP()

(3)发送自定义命令
处理命令消息WM_COMMAND的窗口过程形式如下:

LRESULT CALLBACK WindowProc(
    HWND hWnd,        //窗口句柄
    WM_COMMAND,       //命令的消息标志固定为WM_COMMAND
    WPARAM wParam,   //通知代码(菜单、组合键命令)或标志(控件通知)       LPRARAM lParam,  //控件句柄
);

      wParam分成高低位两部分。如果为控件命令,则其高位部分为控件的通知代码;如果为加速键命令,则其高位部分为1;如果为菜单命令,其高位部分为0。wParam的低位部分表示控件、菜单或加速键的ID。
      对于控件命令,lParam表示控件句柄;否则lParam置为NULL。

MAKEWPARAM宏可以将两个WORD拼成一个WPARAM参数:

WPARAM MAKEWPARAM(
    WORD wLow,       //低位
     WORD wHigh,      //高位
);

发送自定义命令如下:

(4)处理自定义命令

命令处理成员的名字是任意的,但其签名是固定的。

Example:

.h

void LoadToIE();

.cpp

BEGIN_MESSAGE_MAP(CMsgStudyDlg, CDialog)
    //{{AFX_MSG_MAP(CMsgStudyDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_COMMAND_RANGE(IDC_BUTTON1,IDC_BUTTON4,OnButton)
    ON_COMMAND_EX(ID_HELP,OnHelp)
    ON_COMMAND(ID_LOADTOIE,LoadToIE)
END_MESSAGE_MAP()


UINT DownLoadURLThreadFunc(LPVOID obj)
{
    ASSERT(obj);
    CMsgStudyDlg * dlg = (CMsgStudyDlg *)obj;

    dlg->PostMessage(WM_COMMAND,MAKEWPARAM(ID_LOADTOIE,0),NULL);

    return 1;
}
void CMsgStudyDlg::OnButton(UINT nID)
{
    CWinThread * pThread;
    switch(nID)
    {
    case IDC_BUTTON1:
        AfxMessageBox("This is BUTTON1");
        pThread = AfxBeginThread(DownLoadURLThreadFunc,this);
        break;
    case IDC_BUTTON2:
        AfxMessageBox("This is BUTTON2");
        break;
    case IDC_BUTTON3:
        AfxMessageBox("This is BUTTON3");
        break;
    case IDC_BUTTON4:
        AfxMessageBox("This is BUTTON4");
        break;
    default:
        break;
    }
}

BOOL CMsgStudyDlg::OnHelp(UINT nID)
{
    AfxMessageBox("This is CMsgStudyDlg");
    //返回FALSE,允许沿着处理链继续处理
    return FALSE;
}

void CMsgStudyDlg::LoadToIE()
{
    AfxMessageBox("OK");
}
View Code

二、自定义窗口消息
操作系统保留一定范围的窗口消息标记作为自定义消息,自定义窗口消息的消息标志都大于WM_USER。

一旦有了消息标志,就可以用目标窗口对象的SendMessage或PostMessage发送(或投递)消息,以请求目标窗口的窗口过程对该消息进行处理。

目标窗口为了将自定义窗口消息和消息处理成员关联起来,要用到ON_MESSAGE消息映射宏:

#define ON_MESSAGE(message,memberFxn)
{message,0,0,0,AfxSig_lwl,
  (AFX_PMSG)(AFX_PMSGW)static_cast<LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM,LPARAM)>(memberFxn))},

该宏规定了处理自定义窗口消息的成员必须满足AfxSig_lwl规定的签名:LRESULT(WPARAM,LPARAM),参数WPARAM和LPARAM包含了跟自定义消息相关的特定数据。

(1)定义消息标记

#define WM_MYMSG (WM_USER + 100)

      如果仅在对话框内部使用自定义窗口消息,只需要在对话框的实现文件(.cpp)中添加自定义窗口消息的定义;如果在应用程序范围内使用自定义窗口消息,需要把自定义消息的定义放到Resource.h中。

(2)修改消息映射表

在对话框的消息映射表中加入一个ON_MESSAGE映射项:

BEGIN_MESSAGE_MAP(CMsgStudyDlg,CDialog)
   //...
   //使用自定义消息
  ON_MESSAGE(WM_MYMSG,OnMyMessage)
END_MESSAGE_MAP()

(3)添加自定义消息的成员函数

.h     //头文件中的声明
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

.cpp   //实现文件中的实现
LRESULT CMsgStudyDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
    return 0L;
}

自定义消息的处理函数首先从消息参数中获取了消息参数(存放在LPARAM中)。消息处理函数知道消息参数为何种类型,并将消息参数造型设定为约定的类型。
(4)引发自定义消息

this->SendMessage(WM_MYMSG,0,(LPARAM)(&dt));
或
this->PostMessage(WM_MYMSG,0,(LPARAM)(&dt));

      注意:SendMessage的消息参数指针&dt既可以引用在堆栈上分配的对象,又可以引用在C++运行堆上分配的对象;PostMessage的消息参数指针&dt只能引用在C++运行堆上分配的对象。因为SendMessage函数等待消息响应完成后才返回,而PostMessage函数不需要等待消息响应,所以在堆栈上分配的对象,在函数返回后,会立即被自动销毁,C++运行堆上的对象必须手动销毁。
Example:

.h

// Implementation
protected:
    HICON m_hIcon;

    // Generated message map functions
    //{{AFX_MSG(CMsgStudyDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnButton(UINT nID);
    afx_msg BOOL OnHelp(UINT nID);
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    void LoadToIE();

.cpp

#define WM_MYMSG (WM_USER + 100)

BEGIN_MESSAGE_MAP(CMsgStudyDlg, CDialog)
    //{{AFX_MSG_MAP(CMsgStudyDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_COMMAND_RANGE(IDC_BUTTON1,IDC_BUTTON4,OnButton)
    ON_COMMAND_EX(ID_HELP,OnHelp)
    ON_COMMAND(ID_LOADTOIE,LoadToIE)
    ON_MESSAGE(WM_MYMSG,OnMyMessage)
END_MESSAGE_MAP()



void CMsgStudyDlg::OnButton(UINT nID)
{
    CWinThread * pThread;
    CTime dt;
    CTime * pTime = NULL;
    switch(nID)
    {
    case IDC_BUTTON1:
        AfxMessageBox("This is BUTTON1");
        pThread = AfxBeginThread(DownLoadURLThreadFunc,this);
        break;
    case IDC_BUTTON2:
        AfxMessageBox("This is BUTTON2");
        dt = dt.GetCurrentTime();
        //设置消息参数
        this->SendMessage(WM_MYMSG,0,(LPARAM)&dt);
        break;
    case IDC_BUTTON3:
        AfxMessageBox("This is BUTTON3");
        dt = dt.GetCurrentTime();
        pTime = new CTime(dt);
        this->PostMessage(WM_MYMSG,1,(LPARAM)pTime);
        break;
    case IDC_BUTTON4:
        AfxMessageBox("This is BUTTON4");
        break;
    default:
        break;
    }
}



LRESULT CMsgStudyDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
    CTime * pTime = (CTime *)lParam;
    CString m_strTime;
    m_strTime.Format("发出消息的时间是:%d时: %d分",pTime->GetHour(),pTime->GetMinute());
    AfxMessageBox(m_strTime);
    if(wParam == 1)
    {
        delete pTime;
    }
    return 0L;
}
View Code

自定义窗口消息的总结:

(1)使用自定义消息请求窗口进行某种特殊的操作。

(2)自定义消息的消息标志必须大于WM_USER。

(3)可以利用消息参数携带数据,注意消息参数的内存管理,保证既不发生内存泄露,又能使消息参数有效。

三、登记消息

      自定义消息是局部范围的,同一应用程序中的消息窗口很容易利用自定义消息进行通信,但是如果要在两个进程之间通信,自定义消息就无能为力了,需要使用登记(或注册)消息。

(1)为了使用登记消息,首先要获得一个登记消息标记,该消息标记在整个系统内是唯一的。通过调用系统API RegisterWindowMessage,可以获得一个登记消息标记:

UINT RegisterWindowMessage(
  LPCTSTR lpString    //消息字符串
);

(2)在消息映射表中手工添加ON_REGISTERED_MESSAGE消息映射宏,添加登记消息的处理函数

#define ON_REGISTERED_MESSAGE(nMessageVariable,memberFxn)
{0xC000,0,0,0,(UINT_PTR)(UINT *)(&nMessageVariable),
(AFX_PMSG)(AFX_PWMSG)(static_cast<LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM,LPARAM)>(memberFxn))},

(3)处理登记消息的成员函数

其定义表明处理登记消息的成员函数具有如下签名:LRESULT(WPARAM wParam,LPARAM lParam)

Example:

.h

    // Generated message map functions
    //{{AFX_MSG(CMsgStudyDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnButton(UINT nID);
    afx_msg BOOL OnHelp(UINT nID);
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
    afx_msg LRESULT OnMyRegisteredMsg(WPARAM wParam,LPARAM lParam);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()


.cpp


//1.
static UINT NEAR WM_MYREGISTEREDMSG = RegisterWindowMessage("WM_MYREGISTEREDMSG");


//2.
BEGIN_MESSAGE_MAP(CMsgStudyDlg, CDialog)
    //{{AFX_MSG_MAP(CMsgStudyDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_COMMAND_RANGE(IDC_BUTTON1,IDC_BUTTON4,OnButton)
    ON_COMMAND_EX(ID_HELP,OnHelp)
    ON_COMMAND(ID_LOADTOIE,LoadToIE)
    ON_MESSAGE(WM_MYMSG,OnMyMessage)
    ON_REGISTERED_MESSAGE(WM_MYREGISTEREDMSG,OnMyRegisteredMsg)
END_MESSAGE_MAP()

//3.
void CMsgStudyDlg::OnButton(UINT nID)
{
    CWinThread * pThread;
    CTime dt;
    CTime * pTime = NULL;
    CWnd * pWnd = NULL;
    TCHAR className[256];
    CString title;
    switch(nID)
    {
    case IDC_BUTTON1:
        AfxMessageBox("This is BUTTON1");
        pThread = AfxBeginThread(DownLoadURLThreadFunc,this);
        break;
    case IDC_BUTTON2:
        AfxMessageBox("This is BUTTON2");
        dt = dt.GetCurrentTime();
        //设置消息参数
        this->SendMessage(WM_MYMSG,0,(LPARAM)&dt);
        break;
    case IDC_BUTTON3:
        AfxMessageBox("This is BUTTON3");
        dt = dt.GetCurrentTime();
        pTime = new CTime(dt);
        this->PostMessage(WM_MYMSG,1,(LPARAM)pTime);
        break;
    case IDC_BUTTON4:
        AfxMessageBox("This is BUTTON4");
        this->GetWindowText(title);
        ::GetClassName(this->m_hWnd,className,255);
        pWnd = this->FindWindow(className,title);
        ASSERT(pWnd);
        pWnd->SendMessage(WM_MYREGISTEREDMSG);
        break;
    default:
        break;
    }
}


//4.
LRESULT CMsgStudyDlg::OnMyRegisteredMsg(WPARAM wParam,LPARAM lParam)
{
    AfxMessageBox("收到自定义的登记消息");
    return 0L;
}
View Code
原文地址:https://www.cnblogs.com/chengtulang/p/3193638.html