• 消息处理(三)


    一、自定义命令

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

    (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
  • 相关阅读:
    VS2010自定义新建文件模版 狼人:
    理解“.NET技术”.NET程序集的执行过程 狼人:
    JAVA与.NET的相互调用——利用JNBridge桥接模式实现远程通讯 狼人:
    《Effective C#中文版:改善C#程序的50种方法》读书笔记 狼人:
    C#中“.NET技术”字符串的内存分配与驻留池 狼人:
    ASP.NET MVC 3和Razor中的@helper 语法 狼人:
    用C#实现HTTP协“.NET技术”议下的多线程文件传输 狼人:
    JA“.NET技术”VA与.NET的相互调用——TCP/IP相互调用基本架构 狼人:
    《Effective C#中文版:改善C#程序的50种方法》“.NET技术”读书笔记 狼人:
    C#“.NET技术” 中奇妙的函数联接序列的五种简单方法 狼人:
  • 原文地址:https://www.cnblogs.com/chengtulang/p/3193638.html
Copyright © 2020-2023  润新知