[MFC]MFC程序结构(二)

来源:互联网 发布:阿里软件平台 编辑:程序博客网 时间:2024/05/17 06:24

窗口创建过程

1.1 加载菜单
1.2 调用CWnd::CreateEx创建窗口
    1.2.1 调用 PreCreateWindow 设计并注册窗口类  
    1.2.2 调用AfxHookWindowCreate设置钩子————HOOK(钩子)-将自己的处理函数,挂接入系统的处理过程。
           调用SetWindowsHookEx,创建了一个WH_CBT类型的钩子,_AfxCbtFilterHook钩子的回调函数。
    1.2.3 调用CreateWindowEx创建窗口,立即调用_AfxCbtFilterHook
    1.2.4 调用AfxUnhookWindowCreate 卸载钩子
1.3 _AfxCbtFilterHook函数执行
    1.3.1 获取MFC提供的窗口处理函数的地址(AfxWndProcBase的地址)
    1.3.2 使用SetWindowLong将窗口的处理函数由原来的DefWindowProc替换为AfxWndProcBase

消息映射机制

Windows程序中的消息处理是在winproc函数中,通过switch结构实现的。但当处理的消息比较多时,switch-case结构将变得分支很多,影响程序的可读性。而在MFC中,则采用消息映射的结构进行结构化消息处理。进行MFC消息处理,程序员要做的就是为每个要处理的消息提供一个消息处理函数,然后系统通过MFC提供的一套消息映射系统来调用相应的消息处理函数。消息映射就是消息与消息处理函数一对一的联系。MFC的消息映射采用消息映射宏的方式,把消息和消息处理函数一一对应起来。在其头文件中可以找到DECLARE_MESSAGE_MAP()宏。

消息映射机制的使用    

     1.1 在窗口类的定义中添加消息映射的声明宏
         DECLARE_MESSAGE_MAP()  
     1.2 在窗口类的实现中添加消息映射的实现宏
         BEGIN_MESSAGE_MAP(CMsgFrame,CFrameWnd)
         END_MESSAGE_MAP() 
     1.3 添加消息处理函数的定义和实现 
     1.4 添加消息标识与消息处理函数的映射关系
         BEGIN_MESSAGE_MAP(CMsgFrame,CFrameWnd)
          ON_MESSAGE(WM_CREATE,OnCreate)
          ON_MESSAGE(WM_PAINT,OnPaint)
         END_MESSAGE_MAP()

MFC对消息的分类

MFC把消息分为5类:窗口消息,控件通知消息,命令消息,用户自定义消息,系统注册消息

  • 窗口消息(标准消息)

大部分的窗口,键盘,鼠标等消息,如当创建窗口,绘制窗口,移动窗口,销毁窗口,以及使用键盘,鼠标等与操作窗口有关的动作时,产生的消息均属于窗口消息。窗口消息有MFC的窗口(CWnd)对象来处理。系统提供了标准的消息处理函数。
消息映射宏:ON_WM_XXX()

  • 控件通知消息

控件是一个windows的一个子窗口(eg:对话框中的按钮,编辑框等),控件通知消息是指在事件发生时,由控件或其他类型的子窗口发送到父窗口的消息。它通知父窗口,该控件接受了某操作,为父窗口进一步控制子窗口提供了条件。
消息映射宏:ON_xx_CLICKED/DBCLK(控件ID,响应函数)

  • 命令消息

菜单,工具栏以及按钮等消息。一般与处理用户的请求有关,主要是来自菜单,工具栏和加速键的通知消息。从CCmdTarget派生的类(eg:文档,文档模板,应用程序对象,窗口和视图等)都能处理命令消息。
消息映射宏:ON_COMMAND(命令ID,响应函数)
ON_COMMAND_RANGE(起始ID,终止ID,响应函数)
响应函数基本是:afx_msg void memberFun()
所有由用户定义的命令消息也由ON_COMMAND定义消息映射关系。
命令消息的执行过程:
2.1在CWnd::OnWndMsg函数中,判断消息如果是WM_COMMAND调用OnCommand函数
2.2 在OnCommand函数,调用CCmdTarget::OnCmdMsg函数
2.3 在OnCmdMsg函数中,查找消息映射。

  • 用户自定义消息

通过#define定义消息标识,eg #define WM_USERDEFMSG (WM_USER+101)
消息映射宏:ON_MESSAGE(命令ID,响应函数)
响应函数的原型:afx_msg LRESULT memberFun(WPARAM,LPARAM)

  • 系统注册消息

UINT RegisterWindowMessage(LPCTSTR lpString   //消息名称);//返回值消息标识
消息映射宏:ON_REGISTERED_MESSAGE(注册ID,响应函数)
响应函数的原型:afx_msg LRESULT memberFun(WPARAM,LPARAM)
eg:const UINT WM_USERDEFMSG=::RegisterWindowMessage(_T("UserDefMsg"));
ON_REGISTERED_MESSAGE(WM_USERDEFMSG,OnUserDefMsg)

实例

1.新建工程MFCBase

新建MFC工程(view或者dialog),删除系统生产的文件,就剩下stdafx.h和stdafx.cpp,新建MFCBase.cpp文件,

或者,新建Win32工程来改成MFC工程,删除系统生产的文件,就剩下stdafx.h(在其内部添加afxwin.h头文件)和stdafx.cpp,新建MFCBase.cpp文件;并修改工程的属性,常规-->MFC的使用:把使用标准windows库 改成 在静态库中使用MFC

#include "stdafx.h"class CMainFrame:public CFrameWnd{public:virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam );};LRESULT CMainFrame::WindowProc( UINT message, WPARAM wParam, LPARAM lParam ){switch (message){case WM_CREATE:MessageBox(L"OnCreate");break;case WM_PAINT:PAINTSTRUCT ps={0};CDC* pDC=BeginPaint(&ps);pDC->TextOut(50,100,L"Hello MFC");EndPaint(&ps);break;}return CFrameWnd::WindowProc(message,wParam,lParam);}  class CMyWinApp:public CWinApp{public:virtual BOOL InitInstance();};BOOL CMyWinApp::InitInstance(){CMainFrame* pFrame=new CMainFrame;pFrame->Create(NULL,L"MFCWnd");m_pMainWnd=pFrame;pFrame->ShowWindow(SW_SHOW);pFrame->UpdateWindow();return TRUE;}CMyWinApp theApp; 

结果:先出现对话框:再出现框架窗口:

2.新建工程MFCCmd

创建工程同上,新建文件MFCCmd.cpp文件

// MyMFCCmd.cpp : 定义应用程序的入口点。 #include "stdafx.h"  #define ON_CMD_T1 1025//菜单消息标识#define ON_CMD_T2 1026//菜单消息标识#define ON_CMD_T3 1027//菜单消息标识#define ON_CMD_EDIT 1028//菜单消息标识#define WM_USERDEFMSG (WM_USER+101)//用户自定义消息标识const UINT WM_USERDEFMSG2=RegisterWindowMessage(L"UserDefMsg2");//系统注册消息标识class CMainFrame:public CFrameWnd{DECLARE_MESSAGE_MAP()protected:afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );afx_msg void OnTest1();afx_msg void OnTestRange(UINT nID);afx_msg void OnEditChange();afx_msg LRESULT OnUserDefMsg(WPARAM wParam,LPARAM lParam);//用户自定义消息函数afx_msg LRESULT OnUserDefMsg2(WPARAM wParam,LPARAM lParam);//系统注册消息函数}; BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)ON_WM_CREATE()//窗口消息ON_COMMAND(ON_CMD_T1,OnTest1)//命令消息ON_MESSAGE(WM_USERDEFMSG,OnUserDefMsg)//用户自定义消息ON_REGISTERED_MESSAGE(WM_USERDEFMSG2,OnUserDefMsg2)//系统注册消息ON_EN_CHANGE(ON_CMD_EDIT,OnEditChange)//控件消息ON_COMMAND_RANGE(ON_CMD_T2,ON_CMD_T3,OnTestRange)END_MESSAGE_MAP() int CMainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct ){//创建按钮CreateWindow(L"BUTTON",L"Test1",WS_CHILD|WS_VISIBLE,50,50,60,40,m_hWnd,(HMENU)ON_CMD_T1,AfxGetInstanceHandle(),NULL);CreateWindow(L"BUTTON",L"Test2",WS_CHILD|WS_VISIBLE,50,100,60,40,m_hWnd,(HMENU)ON_CMD_T2,AfxGetInstanceHandle(),NULL);CreateWindow(L"BUTTON",L"Test3",WS_CHILD|WS_VISIBLE,50,150,60,40,m_hWnd,(HMENU)ON_CMD_T3,AfxGetInstanceHandle(),NULL);CreateWindow(L"EDIT",L"",WS_CHILD|WS_VISIBLE|WS_BORDER,150,90,70,50,m_hWnd,(HMENU)ON_CMD_EDIT,AfxGetInstanceHandle(),NULL);return 0;}LRESULT CMainFrame::OnUserDefMsg(WPARAM wParam,LPARAM lParam){MessageBox(L"OnUserDefMsg");return 0;}LRESULT CMainFrame::OnUserDefMsg2(WPARAM wParam,LPARAM lParam){MessageBox(L"OnUserDefMsg2");return 0;}void CMainFrame::OnTest1(){//MessageBox(L"OnTest1");SendMessage(WM_USERDEFMSG,NULL,NULL);//发送系统注册消息 SendMessage(WM_USERDEFMSG2,NULL,NULL);//发送用户自定义消息}void CMainFrame::OnTestRange(UINT nID){CString strID;strID.Format(L"%d",nID);MessageBox(strID); }  void CMainFrame::OnEditChange(){CWnd* pWnd=GetDlgItem(ON_CMD_EDIT);CString strContent;pWnd->GetWindowTextW(strContent);MessageBox(strContent);}class CCmdApp:public CWinApp{public:virtual BOOL InitInstance();};BOOL CCmdApp::InitInstance(){CMainFrame* pFrame=new CMainFrame;pFrame->Create(NULL,L"MFCCmd");m_pMainWnd=pFrame;    pFrame->ShowWindow(SW_SHOW);pFrame->UpdateWindow();return TRUE;}CCmdApp theApp; 

结果:点击test2按钮输入e:

3.分析这两个工程的异同

相同点:各自都创建了CFrameWin框架窗口子类和CWinApp窗口应用子类,且重写窗口应用的初始化成员函数InitInstance()基本相同

不同点:主要表现在创建创建窗口的过程和消息的处理方面。工程MFCBase主要根据win32窗口应用程序的思想来创建窗口和处理消息的。而工程MFCCmd用到了MFC的消息映射来创建窗口和处理消息的。