WinMain和MFC的差别

Posted slgkaifa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WinMain和MFC的差别相关的知识,希望对你有一定的参考价值。

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的差别的主要内容,如果未能解决你的问题,请参考以下文章

VC中MFC从哪里开始运行,MFC怎么调试,很急呀

在 MFC 中,WinMain 函数如何找到用户应用程序对象的地址值?

使用 Ninja 使用 CMake 构建的 Unicode MFC 应用程序中未解决的 WinMain 错误

MFC6.0建立一个文档视图框架时,怎么找不到入口WinMain()函数

MFC框架程序剖析笔记(下篇)

VC中MFC从哪里开始运行,MFC怎么调试