三、MFC消息映射机制实现原理

一、消息映射

1、创建工程

 

 

2、编写代码

#include <afxwin.h>

class CMyFrameWnd : public CFrameWnd
{
	//DECLARE_MESSAGE_MAP();
protected: 
	static const AFX_MSGMAP* PASCAL GetThisMessageMap();
	virtual const AFX_MSGMAP* GetMessageMap() const;

public:
	LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
};
//BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
//	ON_MESSAGE(WM_CREATE, OnCreate)
//END_MESSAGE_MAP()
PTM_WARNING_DISABLE	
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{ 
	return GetThisMessageMap(); 
}
const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
{					
	static const AFX_MSGMAP_ENTRY _messageEntries[] = 
	{
		{ WM_CREATE, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >(OnCreate)) },
		{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}
	}; 
	static const AFX_MSGMAP messageMap = 
	{ 
		&CFrameWnd::GetThisMessageMap, &_messageEntries[0] 
	};
	return &messageMap;
}								
PTM_WARNING_RESTORE

	LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam)
{
	AfxMessageBox("WM_CREATE 消息处理");
	return 0;
}

class CMyWinApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	pFrame->Create(NULL, "MFCCreate");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

3、代码解析(宏展开内容)

 (1)虚函数调用静态函数

virtual const AFX_MSGMAP* GetMessageMap() const;
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{ 
    //获取本类的messagemap静态遍历地址
	return GetThisMessageMap(); 
}

(2)静态函数创建静态结构体(AFX_MSGMAP_ENTRY)数组,结构体最后一个元素为消息处理函数

struct AFX_MSGMAP_ENTRY
{
	UINT nMessage;   // 消息ID
	UINT nCode;      // 通知码
	UINT nID;        // 命令ID
	UINT nLastID;    // 最后一个命令ID
	UINT_PTR nSig;   // 处理消息的函数类型
	AFX_PMSG pfn;    // 处理函数地址(名称)
};

static const AFX_MSGMAP_ENTRY _messageEntries[] = 
	{
		{ WM_CREATE, 0, 0, 0, AfxSig_lwl,(AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) >(OnCreate)) },
		{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0}
	}; 

(3)静态函数创建静态结构体(AFX_MSGMAP),第一个元素为类父类的静态结构体(AFX_MSGMAP)地址,第二个元素为上一步创建的静态结构体(AFX_MSGMAP_ENTRY)数组地址

static const AFX_MSGMAP messageMap = 
	{ 
		&CFrameWnd::GetThisMessageMap,
		&_messageEntries[0]
	};

(4)由静态结构体(AFX_MSGMAP)组成的列表(链表头:当前类的结构体(AFX_MSGMAP_ENTRY);下一个元素:父类的结构体(AFX_MSGMAP_ENTRY))

4、消息处理原理

(1)由当前类(申明消息处理的类)获取列表头,遍历获取消息处理函数,然后调用消息处理函数

(2)消息追踪

//以WM_CREATE消息为例,捎带想着点WM_PAINT,WM_COMMAND(到了CWnd::OnWndMsg函数路线不一样)
AfxWndProc(...)
{
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
             //获取和hWnd绑定在一起的框架类对象地址(pFrame===pWnd)
  AfxCallWndProc(pWnd...)//参数pWnd===pFrame
  { 
    pWnd->WindowProc(...)//函数内部this为pFrame===pWnd *************
    {
      OnWndMsg(...)//函数内部this为pFrame===pWnd
      {
        const AFX_MSGMAP* pMessageMap = GetMessageMap();
                       //获取本类宏站开的静态变量的地址(链表头结点)
        const AFX_MSGMAP_ENTRY* lpEntry;

        for (; pMessageMap->pfnGetBaseMap != NULL;//此for就是在遍历链表
			pMessageMap = (*pMessageMap->pfnGetBaseMap)())
        {
           lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,message, 0, 0));
                           //如果找到返回找到的数组元素的地址,如果没找到返回NULL
           if(lpEntry != NULL )
           {
             goto LDispatch;
           }
           
        }
        LDispatch:
            lpEntry->pfn; //CMyFrameWnd::OnCreate
            调用CMyFrameWnd::OnCreate函数完成消息的处理
        
      }
    }
  }
}

二、消息的分类

1、分类

(1)标准Windows消息

        ON_WM_XXX

        ON_WM_CREATE        //创建消息

        ON_WM_APINT        //绘图消息

(2)自定义消息

        ON_MESSAGE

(3)命令消息

        ON_COMMAND

2、创建项目(MFCCmd)

3、编写程序

#include <afxwin.h>

//自定义消息
#define WM_MYMESSAGE WM_USER+1001

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();

public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnPaint();
	afx_msg void OnMouseMove(UINT nKey,CPoint pt);
	afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
private:
	CPoint m_pt;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()	//替换ON_WM_CREATE
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()


int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	AfxMessageBox("WM_CREATE 消息处理");
	::PostMessage(m_hWnd, WM_MYMESSAGE, 1, 2);	//发送消息
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
	PAINTSTRUCT ps={0};
	HDC hdc = ::BeginPaint(m_hWnd, &ps);
	::TextOut(hdc, m_pt.x, m_pt.y, "WM_PAINT 绘图消息", strlen("WM_PAINT 绘图消息"));
	::EndPaint(m_hWnd, &ps);
}
//鼠标移动消息
void CMyFrameWnd::OnMouseMove(UINT nKey,CPoint pt)
{
	m_pt.x = pt.x;
	m_pt.y = pt.y;
	//调用画图(画矩形),触发绘图消息
	::InvalidateRect(m_hWnd, NULL, TRUE);
}
//自定义消息处理函数
LRESULT CMyFrameWnd::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
	CString str;
	str.Format("wParam=%d, lParam=%d", wParam, lParam);
	AfxMessageBox(str);
	return 0;
}

class CMyWinApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	pFrame->Create(NULL, "MFCCreate");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

三、MFC菜单(命令消息)

1、菜单相关

        Win32 -》菜单句柄HMENU

        MFC -》CMENU类对象,该类的m_hMenu保存了菜单句柄(HMENU)

2、菜单使用步骤

(1)添加菜单资源

(2)将菜单设置到窗口

        方式1:利用pFrame调用Create函数时,传参绑定

        方式2:在处理框架窗口的WM_CREATE消息时

                CMenu menu;

                menu.LoadMenu(...);

3、创建项目(MFCMenu)

(1)创建项目

(2)添加资源文件(.rc),添加菜单资源

 

 

 (3)编写代码

#include <afxwin.h>
#include "resource.h"

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();
public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);

private:
	CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()
END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	m_menu.LoadMenu(IDR_MENU1);    //绑定菜单句柄
	SetMenu(&m_menu);
	return CFrameWnd::OnCreate(pcs);
}

class CMyWinApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
    //pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
	pFrame->Create(NULL, "MFCMenu");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

(4)命令消息(菜单消息)

#include <afxwin.h>
#include "resource.h"

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();
public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnNew();
private:
	CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	m_menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_menu);
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
	AfxMessageBox("框架类处理了-新建菜单项");
}

class CMyWinApp : public CWinApp
{
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL InitInstance();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
	AfxMessageBox("应用类处理了-新建菜单项");
}

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
    //pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
	pFrame->Create(NULL, "MFCMenu");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

(5)命令消息处理顺序

框架类 -> 应用类程序类

#include <afxwin.h>
#include "resource.h"

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();
public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnNew();
private:
	CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	m_menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_menu);
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
	AfxMessageBox("框架类处理了-新建菜单项");
}

class CMyWinApp : public CWinApp
{
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL InitInstance();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
	AfxMessageBox("应用类处理了-新建菜单项");
}

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
    //pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
	pFrame->Create(NULL, "MFCMenu");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

4、菜单项状态(勾选)

(1)消息与函数

Win32:

        WM_INITMENUPOPUP

        ::CheckMenuItem / ::EnableMenuItem

MFC:

        ON_WM_INITMENUPOPUP

        CMenu::CheckMenuItem / CMenu::EnableMenuItem

(2)程序

#include <afxwin.h>
#include "resource.h"

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();
public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnNew();
	afx_msg void OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i);
private:
	CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND(ID_NEW, OnNew)
	ON_WM_INITMENUPOPUP()
END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	m_menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_menu);
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
	AfxMessageBox("框架类处理了-新建菜单项");
}
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{
	//::CheckMenuItem(pPopup->m_hMenu, ID_NEW, MF_CHECKED);
	pPopup->CheckMenuItem(ID_NEW, MF_CHECKED);	
}

class CMyWinApp : public CWinApp
{
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL InitInstance();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
	AfxMessageBox("应用类处理了-新建菜单项");
}

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
    //pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
	pFrame->Create(NULL, "MFCMenu");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

5、右键菜单项(在界面右键,将显示菜单)

(1)消息与函数

Win32:

        WM_CONTEXTMENU

        ::TrackPopupMenu

MFC:

        ON_WM_CONTEXTMENU

        CMenu::TrackPopupMenu

(2)程序

#include <afxwin.h>
#include "resource.h"

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_MESSAGE_MAP();
public:
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnNew();
	afx_msg void OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint pt);
private:
	CMenu m_menu;
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND(ID_NEW, OnNew)
	ON_WM_INITMENUPOPUP()
	ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
	m_menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_menu);
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnNew()
{
	AfxMessageBox("框架类处理了-新建菜单项");
}
void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i)
{
	//::CheckMenuItem(pPopup->m_hMenu, ID_NEW, MF_CHECKED);
	pPopup->CheckMenuItem(ID_NEW, MF_CHECKED);	
}
void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint pt)
{
	/*
	HMENU pPopup = ::GetSubMenu(m_menu.m_hMenu, 0);	//获取菜单项句柄
	::TrackPopupMenu(pPopup, TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, 0, m_hWnd, NULL);
	*/
	CMenu* pPopup = m_menu.GetSubMenu(0);
	pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y, this);
}

class CMyWinApp : public CWinApp
{
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL InitInstance();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
	AfxMessageBox("应用类处理了-新建菜单项");
}

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd;
    //pFrame->Create(NULL, "MFCMenu", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL,(CHAR*)IDR_MENU1);
	pFrame->Create(NULL, "MFCMenu");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}

//应程序入口
CMyWinApp theApp;

代码链接:https://download.csdn.net/download/liutit/86249178

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值