注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

MFC框架程序简要分析——转载  

2012-02-02 17:03:26|  分类: C/C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
转自:http://www.cctry.com/thread-27235-1-2.html
个人收获不错分享给大家
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 Files\Microsoft Visual Studio\VC98\MFC\SRC下的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_pMainWnd\n");
   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这一默认过程来处理的,而是采取了一种称为消息映射机制来处理各种消息的
  评论这张
 
阅读(270)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017