mfc简介

MFC库是开发Windows应用程序的C++接口。MFC提供了面向对象的框架,将大部分的Windows API封装到C++类中,以类的成员函数的形式提供给程序开发人员调用。

先简要说明下MFC程序的运行过程:
★利用全局应用程序对象theApp启动应用程序; ★调用全局应用程序对象的基类CWinApp类的构造函数,然后调用theApp类的构造函数,完成应用程序的一些初始化工作,并将应用程序对象的指针保存起来;
★进入WinMain函数,在AfxWinMain函数中可以获取子类的指针,利用此指针调用虚函数InitInstance,根据多态性原来,实际上是调用子类的InitInstance函数,来完成应用程序的一些初始化工作,包括窗口类的注册,创建,显示和更新。在此期间还将多次调用CreateEx函数;
★进入消息循环,虽然MFC也设置了默认的窗口过程函数,但是MFC应用程序实际上是采用消息映射机制来处理各种消息的,当收到WM_QUIT消息时,突出消息循环,程序结束。
以下为VC++MFC框架程序的执行顺序流程做简要分析:
为便于说明,该程序为Text,对应的框架应用程序类为CTestApp

一、窗口创建之前
1.Windows应用程序在进入WinMain主函数之前,先执行全局变量与全局对象;
2.Windows应用程序首先定义了CTestApp类的全局对象theApp,因为CTestApp是从CWinApp继承而来,所以在调用CTestApp类的构造函数之前,先调用了CWinApp类的构造函数,然后调用其派生类对象theApp类的构造函数;
3.在应用程序调用完CWinApp类的构造函数,并执行了theApp类的构造函数,产生了theApp对象之后,则接下来进入WinMain函数 extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
} (WinMain函数实现:E:Program FilesMicrosoft Visual StudioVC98MFCSRC下的APPMODUL.CPP文件中)

4.在WinMain函数中,实际上是通过调用AfxWinMain函数来完成其功能的 int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL); int nReturnCode = -1;
CWinThread* pThread = AfxGetThread(); //1
CWinApp* pApp = AfxGetApp(); //2 // AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)) //3
goto InitFailure; // App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure; // Perform specific initializations
if (!pThread->InitInstance()) //4
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWndn");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run(); //5 InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();

AfxUnlockTempMaps(-1);
#endif AfxWinTerm();
return nReturnCode;
} (AfxWinMain函数实现:WINMAIN.APP)
注:Afx前缀的含糊代表应用程序框架函数。在MFC中,Afx为前缀的函数都是全局函数,可以在程序的任何位置调用它们。

5.在AfxWinMain函数中,实际上通过红色代码(InitInstance函数)完成了对窗口的创建步骤:设计窗口类,注册窗口类,创建窗口,显示窗口,更新窗口,消息循环,以及窗口过程函数
virtual BOOL InitInstance();

6.InitInstance函数为虚函数,根据多态性原理,AfxWinMain函数实际上是通过调用CTestApp的InitInstance函数 
BOOL CTestApp::InitInstance()
{
AfxEnableControlContainer(); // Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need. #ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif // Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications")); LoadStdProfileSettings(); // Load standard INI file options (including MRU) // Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views. CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTestView));
AddDocTemplate(pDocTemplate); // Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo); // Dispatch commands specified on the command line

if (!ProcessShellCommand(cmdInfo))
return FALSE; // The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow(); return TRUE;
}

二、MFC框架窗口的建立流程
1、设计和注册窗口类
1)窗口类的注册是通过AfxEndDeferRegisterClass函数完成的,在AfxEndDeferRegisterClass函数中,首先判断窗口类的类型,然后赋予相应的类名(wndcls.lpszClassName变量),这些类名都是MFC预定义的,之后调用 AfxRegisterClass函数注册窗口类 (AfxEndDeferRegisterClass函数实现:WINCORE.CPP AfxRegisterClass函数实现:WINCORE.CPP文件中)

2)在调用AfxRegisterClass函数时,AfxRegisterClass函数首先获得窗口类的信息,判断:如果窗口类已经注册,则直接返回一个真值;否则,没有注册,则调用RegisterClass函数注册该窗口类;
3)另外,CMainFrame类的对象中的PreCreateWindow函数,也是在窗口创建之前,是注册窗口类的一部分,在PreCreateWindow函数中,调用了AfxDeferRegisterClass函数,实际上这是一个宏,指向AfxEndDeferRegisterClass函数

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{
// mask off all classes that are already registered
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
fToRegister &= ~pModuleState->m_fRegisteredClasses;
if (fToRegister == 0)
return TRUE; LONG fRegisteredClasses = 0; // common initialization
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults
wndcls.lpfnWndProc = DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hCursor = afxData.hcurArrow; INITCOMMONCONTROLSEX init;
init.dwSize = sizeof(init); // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go
if (fToRegister & AFX_WND_REG)
{
// Child windows - no brush, no icon, safest default class styles
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpszClassName = _afxWnd;
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WND_REG;
}
if (fToRegister & AFX_WNDOLECONTROL_REG)
{
// OLE Control windows - use parent DC for speed
wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpszClassName = _afxWndOleControl;
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WNDOLECONTROL_REG;
}
if (fToRegister & AFX_WNDCONTROLBAR_REG)
{
// Control bar windows
wndcls.style = 0; // control bars don't handle double click
wndcls.lpszClassName = _afxWndControlBar;
wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
if (AfxRegisterClass(&wndcls))
fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;

}
if (fToRegister & AFX_WNDMDIFRAME_REG)
{
// MDI Frame window (also used for splitter window)
wndcls.style = CS_DBLCLKS;
wndcls.hbrBackground = NULL;
if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))
fRegisteredClasses |= AFX_WNDMDIFRAME_REG;
}
if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
{
// SDI Frame or MDI Child windows or views - normal colors
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))
fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;
}
if (fToRegister & AFX_WNDCOMMCTLS_REG)
{
// this flag is compatible with the old InitCommonControls() API
init.dwICC = ICC_WIN95_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);
fToRegister &= ~AFX_WIN95CTLS_MASK;
}
if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)
{
init.dwICC = ICC_UPDOWN_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_TREEVIEW_REG)
{
init.dwICC = ICC_TREEVIEW_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TREEVIEW_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_TAB_REG)
{
init.dwICC = ICC_TAB_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_TAB_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_PROGRESS_REG)
{
init.dwICC = ICC_PROGRESS_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_PROGRESS_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_LISTVIEW_REG)
{
init.dwICC = ICC_LISTVIEW_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_LISTVIEW_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_HOTKEY_REG)
{
init.dwICC = ICC_HOTKEY_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_HOTKEY_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_BAR_REG)
{
init.dwICC = ICC_BAR_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_BAR_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_ANIMATE_REG)
{
init.dwICC = ICC_ANIMATE_CLASS;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_ANIMATE_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_INTERNET_REG)
{
init.dwICC = ICC_INTERNET_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_INTERNET_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_COOL_REG)
{
init.dwICC = ICC_COOL_CLASSES;

fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_COOL_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_USEREX_REG)
{
init.dwICC = ICC_USEREX_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_USEREX_REG);
}
if (fToRegister & AFX_WNDCOMMCTL_DATE_REG)
{
init.dwICC = ICC_DATE_CLASSES;
fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_DATE_REG);
} // save new state of registered controls
pModuleState->m_fRegisteredClasses |= fRegisteredClasses; // special case for all common controls registered, turn on AFX_WNDCOMMCTLS_REG
if ((pModuleState->m_fRegisteredClasses & AFX_WIN95CTLS_MASK) == AFX_WIN95CTLS_MASK)
{
pModuleState->m_fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
fRegisteredClasses |= AFX_WNDCOMMCTLS_REG;
} // must have registered at least as mamy classes as requested
return (fToRegister & fRegisteredClasses) == fToRegister;
}
(AfxDeferRegisterClass宏定义:AFXIMPL.H)

2、创建窗口
1)在MFC程序中,窗口的创建是由CWnd类的CreateEx函数实现的
2)在MFC底层中,具体实现是由CFrameWnd类的LoadFrame函数调用CFrameWnd类的Create函数,而Create函数调用CWnd类的CreateEx函数来实现窗口创建的过程
原因:CFrameWnd类派生于CWnd类,而CWnd类的CreateEx函数不是虚函数,在CFrameWnd类中也没有对CreateEx函数进行重写,因此,根据类的继承性原理,CFrameWnd类的Create函数内调用的实际上就是CWnd类的CreateEX函数 (CFrameWnd类的Create函数声明:AFXWin.h 实现:WINFRM.CPP
CWnd类的CreateEx函数声明:AFXWin.h 实现:WINCORE.CPP)
3)显示窗口之前,在CWnd类的CreateEx函数内部再次调用了CMainFrame类的PreCreateWindow函数,再次调用的原因是可以让程序员在产生窗口之前有机会对窗口的外观进行修改

3、显示窗口和更新窗口
在Test程序的应用程序类(CTestApp)中有一个名为m_pMainWnd的成员变量,该变量是一个CWnd类型的指针,保存了应用程序框架窗口对象的指针,在CTestApp类的InitInstance函数中,通过此指向CMainFrame对象的指针实现对窗口的显示及更新
// The one and only window has been initialized, so show and update it.

m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();

4、消息循环
在AfxWinMain函数(见注释5)通过调用CWinThread类的Run函数完成消息循环
pThread->Run(); // main running routine until thread exits
int CWinThread::Run()
{
ASSERT_VALID(this); // for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0; // acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state
} // phase2: pump messages while available
do
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance(); // reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
} } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
} ASSERT(FALSE); // not reachable
} (CWinThread类的Run函数定义:THRDCORE.CPP)

5、窗口过程函数
在窗口注册AfxEndDeferRegisterClassA函数中,通过 wndcls.lpfnWndProc = DefWindowProc;
指定了一个默认的窗口过程DefWindowProc,实际上MFC程序并不是把所有消息都交给DefWindowProc这一默认过程来处理的,而是采取了一种称为消息映射机制来处理各种消息的


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值