API(Application Programming Interface):开放给应用程序调用的系统功能。

一个Windows Application(SDK):

WinMain

ReristerClass

CreateWindow

GetMessage/DispatchMessage

/Window Procedure

various Windows APIs

一个MFC Application:

WinMain由MFC提供

RegisterClass包装于AfxWinInit中

CreateWindow在CWinApp::InitInstance中调用

GetMessage/DispatchMessage包装在CWinApp::Run中

Window Procedure由MFC提供

Windows APIs包装在MFC各类中

Massage Mapping, Message Routing.

Dynamic Creation, Serialization.

CWinApp代表程序本体——代替WndProc

传统上SDK程序的WinMain所完毕的工作如今由CWinAoo的三个函数完毕:

virtual BOOL InitApplication();

virtual BOOL InitInstance();

virtual int Run();

WinMain仅仅是扮演驾驶它们的角色。

传统的SDK窗体函数写法是:

long FAR PASCAL WndProc(HWND hWnd, UINT msg, WORD wParam, LONG lParam)
{
switch(msg) {
case WM_COMMAND :
swtich(wParam) {
case IDM_ABOUT :
OnAbout(hWnd, wParam, lParam);
break;
}
break;
case WM_PAINT :
OnPaint(hWnd, wParam, lParam);
break;
default :
DefWindowProc(hWnd, msg, wParam, lParam);
}
}

MFC中使用两个函数OnPaint(),OnAbout()与其相应。MFC中的声明例如以下:

class CMyFrameWnd : public CFrameWnd
{
public :
CMyFrameWnd();
afx_msg void OnPaint();
afx_msg void OnAbout();
DECLARE_MESSAGE_MAP()
}

OnPaint处理WM_PAINT

OnAbout处理WM_COMMAND和IDM_ABOUT

MFC内建的一个Message机制。会把消息自己主动送到“与消息相应的特定函数”中去,消息与相应函数之间的相应关系由程序猿指定。DECLARE_MESSAGE_MAP另搭配其他宏,就能够非常便利的将消息与其处理函数关联在一起:

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)

ON_WM_PAINT()

ON_COMMAND(IDM_ABOUT, OnAbout)

END_MESSAGE_MAP()

/***********************************************************/
/* WINMAIN.CPP */
/***********************************************************/
/* int AFXAPI AfxWinMain (...) */
/* { */
/* CWinApp* pApp = AfxGetApp(); */
/* */
/* AfxWinInit(...); */
/* */
/* pApp->InitApplication(); */
/* pApp->InitInstance(); */
/* nReturnCode = pApp->Run(); */
/* */
/* AfxWinTerm(); */
/* } */
/***********************************************************/
/* HELLO.CPP */
/***********************************************************/
/* CMyWinApp theApp; //application object */
/* */
/* BOOL CMyWinApp::initInstance() */
/* { */
/* m_pMainWnd = new CMyFrameWnd(); */
/* m_pMainWnd->ShowWindow(m_nCmdShow); */
/* m_pMainWnd->UpdateWindow(); */
/* return TRUE; */
/* } */
/* */
/* CMyFrameWnd::CMyFrameWnd() */
/* { */
/* Create(NULL, "Hello MFC", ..., "MainMenu"); */
/* } */
/* */
/* void CMyFrameWnd::OnPaint() {...} */
/* void CMyFrameWnd::OnAbout() {...} */
/* */
/* BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) */
/* ON_COMMAND(IDM_ABOUT, OnAbout) */
/* ON_WM_PAINT() */
/* END_MESSAGE_MAP() */
/***********************************************************/

Application object:每个MFC应用程序都有一个,并且仅仅有一个。

WINMAIN.CPP中,AfxGetApp事实上就是取得CMyWinApp对象指针。所以,AfxWinMain中这种操作:

CWinApp* pApp = AfxGetApp();

pApp->InitApplication();

pApp->InitInstance();

nReturnCode = pApp->Run();

事实上就相当于调用:

CMyWinApp::InitApplication();

CMyWinApp::InitInstance();

CMyWinApp::Run();

因而导致调用:

CWinApp::InitApplication(); //由于CMyWinApp并没有改写InitApplication

CMyWinAPP::InitInstance(); //由于CMyWinApp改写了InitInstance

CWinApp::Run(); //由于CMyWinApp并没有改写Run

AfxWinInit——AFX内部初始化操作

WinMain一開始即调用AfxWinInit,注冊四个窗体类。

MFC中也会为我们注冊窗体类,但不再是在AfxWinInit中完毕。

pApp指向CMyWinApp对象(theApp)。所以,当程序调用:

pApp->InitApplication();

CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数;若我们并没有改写它(大部分情况下不需改写它),上述操作相当于调用:

CWinApp::InitApplication();

与此类似,当程序调用

pApp->InitInstance();

相当于调用:

CMyWinApp::InitInstance();。

CFrameWnd::Create 产生主窗体(并先注冊窗体类)

CMyWinApp::InitInstance 一開始new了一个CMyFrameWnd对象,准备用作主框窗体的C++对象。

new会引发构造函数:

CMyFrameWnd::CMyFrameWnd()

{

Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu");

}

当中,Create是CFrameWnd的成员函数,他将产生一个窗体。

CFrame::Create的规格:

BOOL Create(LPCTSTR lpszClassName, //指定WNDCLASS窗体类

LPCTSTR lpszWindowName,
//指定窗体标题

DWORD dwStyle = WS_OVERLAPPEDWINDOW,
//指定窗体风格

const RECT& rect = rectDefault,
//指定窗体的位置与大小

CWnd* pParentWnd = NULL,
//指定父窗体

LPCTSTR lpszMenuName = NULL,
//指定菜单

DWORD dwExStyle = 0,

CCreateContext* pContext = NULL );
//指向CCreateContext结构的指针,framework利用它,在具备Document/View结构的程序中初始化外框窗体.

pApp指向CMyWinApp对象(theApp)。所以,当程序调用:

pApp->Run();

相当于调用:

CMyWinApp::Run();

把消息与处理函数连接在一起:Message Map机制





MFC提供给应用程序使用的“非常方便的接口”是两组宏。以Hello的主窗体为例。第一个操作是在HELLO.H的CMyFrameWnd加上DECLARE_MESSAGE_MAP:

class CMyFrameWnd : public CFrameWnd

{

public :

CMyFrameWnd();

afx_msg void OnPaint();

afx_msg void OnAbout();

DECLARE_MESSAGE_MAP();

}

第二个操作是在HELLO.CPP的不论什么位置(当然不能在函数之内)使用宏例如以下:

BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)

ON_WM_PAINT()

ON_COMMAND(IDM_ABOUT, OnAbout)

END_MESSAGE_MAP()





MFC把消息主要分为三大类。Message Map机制中对于消息与函数间的相应关系也明白下面三种:

  标准Windows消息(WM_xxx)的相应规则:

    |-----------------------------------------------------------------------------|
| 宏名称 | 相应消息 | 消息处理函数(名称已由系统默认) |
|-------------------|-------------------|-------------------------------------|
| 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_LBUTTONDOWN | WM_LBUTTONDOWN | OnLButtonDown |
|-------------------|-------------------|-------------------------------------|
| ON_WM_LBUTTONUP | WM_LBUTTONUP | OnLButtonUp |
|-------------------|-------------------|-------------------------------------|
| ON_WM_MOUSEMOVE | WM_MOUSEMOVE | OnMouseMove |
|-------------------|-------------------|-------------------------------------|
| ON_WM_PAINT | WM_PAINT | OnPaint |
|-----------------------------------------------------------------------------|

命令消息(WM_COMMAND)的一般相应规则是:

    ON_COMMAND(<id>, <memberFxn>)

    比如:

ON_COMMAND(IDM_ABOUT,
OnAbout)

ON_COMMAND(IDM_FILENEW,
OnFileNew)

ON_COMMAND(IDM_FILEOPEN,OnFileOpen)

ON_COMMAND(IDM_FILESAVE,OnFileSave)

  "Notification消息"(由控件产生。比如 BN_xxx)的相应机制的宏分为好几种(由于控件分为好几种),例:

    |-----------------------------------------------------------|
| 控件 | 宏名称 |消息处理函数|
|----------|-----------------------------------|------------|
| 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 |
|-----------------------------------------------------------|

各个消息处理函数均以afx_msg void 为函数类型。

WinMain和MFC的差别的更多相关文章

  1. QT和MFC的差别

    QT和MFC的差别 在使用MFC之前就已经使用Qt这个事实可能影响了我的客观性. (MFC效率较高,但大量的Windows API和消息机制使得其较难理解,不易用:QT封装较好,易用且跨平台,但效率较 ...

  2. MFC框架中消失的WinMain()

    学过一段时间的MFC之后,很多人大概都有一个疑问:在MFC中,WinMain()哪去了?因为任何一个使用过Win32 SDK编程的人都知道,WinMain()函数是Win32程序开始的入口点,可是在M ...

  3. 总结《二》MFC中WinMain和CALLBACK

    MFC中WinMain和回调函数CALLBACK 一,路线        1.一般普通窗口或控件建立调用的CWnd :: CreateEx函数        2.经过资源对话框创建的即不调用的CWnd ...

  4. MFC学习-第2,3课 MFC框架的运行机制

    转自:http://blog.163.com/zhigang0633@126/blog/static/38790491200822711526168/ 讲述MFC AppWizard的原理与MFC程序 ...

  5. MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx

    MFC中存在的不属于任何类的全局函数,它们统统在函数名称开头加上Afx. 函数名称 说明 AfxWinInit 被WinMain(MFC提供)调用的一个函数,用做MFC GUI程序初始化的一部分,如果 ...

  6. (转)win32Application和win32ApplicationConsole

    这几天在创建MFC项目时,常常遇到一下两个连接错误,例如: 1. LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _ma ...

  7. 孙鑫VC学习系列教程

    教程简介 1.循序渐进 从Win32SDK编程开始讲解,帮助大家理解掌握Windows编程的核心 -- 消息循环机制. 2.通俗易懂 编程语言枯燥难懂,然而通过孙鑫老师形象化的讲解,Windows和M ...

  8. 孙鑫C++教学视频

    视频百度云:https://pan.baidu.com/s/1jKf6GoY 在线观看:http://list.youku.com/albumlist/show?id=3567028&asce ...

  9. <MFC_1>深入剖析MFC的WinMain和消息机制

    一.开篇引论 熟悉Win32开发的朋友,应该非常了解它的基本组成和流程 1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗 ...

随机推荐

  1. Android开发笔记(1)——View

    笔记链接:http://www.cnblogs.com/igoslly/p/6781592.html   一.View基础知识            IDE——Integrated Developme ...

  2. JAVA 学习笔记 - 基础语法 2

    ---恢复内容开始--- 1.数组的申明和应用 数据类型 数组名称[] = null;             //在堆栈中申明变量名称 数组名称 =  new  数据类型[10];       // ...

  3. struts2特殊符号替换

    今天用struts2做了一个小例子,结果发现个问题 action代码如下 private String table; public String execute(){ setName("pe ...

  4. token机制完成登录状态保持/身份认证

    一般APP都是刚安装后,第一次启动时需要登录(提示你需要登录或者直接启动在登录界面).而只要登录成功后,以后每次启动时都是登录状态,不需要每次启动时再次登录.不过,也有些APP若你长期未启动,再次启动 ...

  5. angular5中的自定义指令(属性指令)

    属性型指令用于改变一个 DOM 元素的外观或行为. 在 Angular 中有三种类型的指令: 组件 — 拥有模板的指令 结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令 属性型指令 ...

  6. C++ CEF 浏览器中显示 Tooltip(标签中的 title 属性)

    在 Windows 中将 CEF 集成到 C++ 客户端以后,默认是无法显示 tooltip 的,比如图片标签中的 title 属性. 实现的方式其实很简单,按下面的步骤操作就可以: 创建一个文本文件 ...

  7. 安装ubuntu系统空间分配问题

    以下是我安装linux系统(ubuntu)时的系统空间配置,以50G为例: 挂载点 大小 格式 分区类型 / 15G Ext4 主分区 /home 30G Ext4 逻辑分区 /boot 1G Ext ...

  8. JS中遍历EL表达式中后台传过来的Java集合

    前言:在我的项目里有这么一个情况,后台直接model.addAttribute()存储了一个对象,此对象内部有一个集合,前端JSP处理的方法正常情况下就是直接使用EL表达式即可.但是如果在JS中需要使 ...

  9. IDLE in Python (Ubuntu)

    To lauch IDLE in the Current Woking Directory >>> usr/bin/idle3 Alt + n  # next command Alt ...

  10. 洛谷 1569 [USACO11FEB]属牛的抗议

    [题解] 非常显然的DP,f[i]表示到第i个位置最多分成几组,f[i]=Max(f[i],f[j]+1) (j<i,sum[j]<=sum[i]) #include<cstdio& ...