mfc程序执行流程,mfc应用程序的执行过程

  mfc程序执行流程,mfc应用程序的执行过程

  1.创建应用程序对象。

  在程序开始时,产生一个(且只有一个)应用程序对象theApp,即CWinApp对象。一旦产生了这个全局对象,就会执行它的构造函数。因为没有定义CMyWinApp构造函数,所以执行CWinApp类的构造函数。APPCORE的第75行定义了这个函数。CPP,而且你可以搜出来自己嚼。所以CWinApp中的成员变量会因为全局对象theApp的诞生而获得配置和初始值。

  2、WinMain出道

  用SDK编程时,程序的入口点是WinMain函数,但是在MFC程序中我们没有看到WinMain函数。哦!~原来她藏在MFC代码里。当App配置完成,WinMain登场,慢一点!仔细看程序,却没有连接WinMain函数的代码!这个我也不知道。MFC已经准备好了,并由链接器直接添加到应用程序代码中。原来她在appmodule.cpp里,好了,我们认为app配置完成后,程序会到appmodule.cpp,那怎么办?看一下从APPMODUL中提取的以下代码。CPP:

  外部 C int WINAPI

  _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)

  {

  //调用共享/导出的WinMain

  返回AfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);

  }

  _tWinMain函数的“_t”是一个为支持Unicode而准备的宏。

  _tWinMain函数的返回值是AfxWinMain函数的返回值,在WinMain的第21行定义。CPP稍微整理一下,就能看出这个“程序入口点”主要做什么:

  int afx API afx winmain(h instance h instance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)

  {

  int nReturnCode=-1;

  cwin app * pApp=AfxGetApp();

  AfxWinInit(hInstance,hPrevInstance,lpCmdLine,nCmdShow);

  pApp-init application();

  pApp- InitInstance()

  nReturnCode=pApp-Run();

  afx winterm();

  返回nReturnCode

  }

  AfxGetApp()函数是获取CMyWinApp对象指针的,所以上面第6行到第8行函数相当于调用:

  CMyWinApp:init application();

  CMyWinApp:InitInstance()

  CMyWinApp:Run();

  从而引起呼叫:

  cwin app:init application();//因为CMyWinApp不重写InitApplication

  CMyWinApp:InitInstance() //因为CMyWinApp重写了InitInstance。

  cwin app:Run();//因为CMyWinApp不会覆盖Run

  用过SDK写程序的朋友,现在可能会心一笑。

  3.AfxWinInit——AFX内部初始化操作

  AfxWinInit是CWinApp构造函数之后的第一个操作,主要做AFX的内部初始化,处理很多意外问题。它对应于AfxWinTerm()。该函数在APPINIT的第24行中定义。CPP,所以这里就不拿出来了。搜出来自己嚼!

  4.执行CWinApp:InitApplication

  AfxWinInit之后,操作是pApp- InitApplication。我们已经知道pApp指向CMyWinApp对象。拨打电话时:

  pApp-init application();

  相当于调用:

  CMyWinApp:init application();

  但是你要知道CMyWinApp继承了CWINAP,InitApplication是CWINAP的虚函数。我们没有重写(大多数情况下,我们不需要重写),所以上面的操作相当于调用:

  cwin app:init application();

  APPCORE的第125行定义了这个函数。CPP自己搜出来!我不会搬出去。里面所有的操作都是MFC为了内部管理而做的(其实我也看不懂。知道有这种事就好了)。

  5.执行CWinApp:InitInstance

  AfxWinMain在InitApplication函数后调用pApp- InitInstance。当程序调用:

  pApp-InitInstance();

  相当于调用:

  CMyWinApp:init instance();

  但是你要知道CMyWinApp继承了CWINAP,InitInstance是CWINAP的虚函数。我们已经重写过了,上面的操作就是调用我们自己的这个InitInstance函数(CMyWinApp)。

  6.CFrameWnd:Create生成主窗口(并首先注册窗口类)

  现在我们来到CWinApp:InitInstance,它首先创建一个CMyFrameWnd对象来生成主窗口。在创建CMyFrameWnd对之前,应该首先执行构造函数CMyFrameWnd:CMyFrameWnd(),该函数使用Create函数生成一个窗口:

  CMyFrameWnd:CMyFrameWnd()

  {

  Create(NULL, Hello MFC ,WS_OVERLAPPEDWINDOW,rectDefault,NULL, main menu );

  }

  Create是CFrameWnd的成员函数,会产生一个窗口。用过SDK编程的朋友都知道,创建主窗口时,必须注册一个窗口类,指定窗口的属性等。但是,这里用的是哪个窗口类呢?Create函数的第一个参数(其他参数请参考MSDN或《深出浅出MFC》)指定将窗口类设置为NULL。这是什么意思?意思是用MFC内置的air类生成一个标准的大纲窗口,但是我们的程序一般不注册任何窗口类!哦,Create函数会在窗口生成之前触发窗口类的注册。

  我们先来挖掘一下Create函数做了什么。在WINFRM的第538行定义了Create函数。CPP(这里不复制代码,大家自己打开看看)。该函数在第562行调用CreateEx函数。由于CreateEx是CWnd的成员函数,而CFrameWnd是从CWnd派生出来的,所以会调用CWnd:CreateEx。WINCORE的665行定义了这个函数。CPP是代码的一部分:

  BOOL CWnd:CreateEx(DWORD dwex style,LPCTSTR lpszClassName,

  LPCTSTR lpszWindowName,DWORD dwStyle,

  int x,int y,int nWidth,int nHeight,

  HWND hWndParent,HMENU nIDorHMenu,LPVOID lpParam)

  {

  //允许修改几个常见的创建参数

  创建结构化cs;

  cs . dwex style=dwex style;

  cs . lpsz class=lpsz class name;

  cs.lpszName=lpszWindowName

  cs.style=dwStyle

  cs.x=x

  cs.y=y

  cs.cx=nWidth

  cs.cy=nHeight

  cs . hwnd parent=hwnd parent;

  cs . hm enu=nIDorHMenu;

  cs . h instance=AfxGetInstanceHandle();

  cs.lpCreateParams=lpParam

  if(PreCreateWindow(cs))

  {

  post ncdestroy();

  返回FALSE

  }

  AfxHookWindowCreate(this);

  HWND HWND=:CreateWindowEx(cs . dwex style,cs.lpszClass,

  cs.lpszName,cs.style,cs.x,cs.y,cs.cx,cs.cy,

  cs.hwndParent,cs.hMenu,cs.hInstance,cs . lpcreateparams);

  .

  }

  用过SDK编程的朋友看到上面的代码应该有点感觉了。函数中调用的PreCreateWindows是一个虚函数,在CWnd和CFrameWnd中定义。因为这个指针指向的对象,这里应该调用CFrameWnd:PreCreateWindow。WINFRM的第521行定义了该函数。CPP是代码的一部分:

  BOOL CFrameWnd:pre create window(create struct cs)

  {

  if (cs.lpszClass==NULL)

  {

  VERIFY(AfxDeferRegisterClass(AFX _ WNDFRAMEORVIEW _ REG));

  cs . lpsz class=_ afxWndFrameOrView;//颜色_窗口背景

  }

  .

  }

  AfxDeferRegisterClass是AFXIMPL中定义的宏。H.宏如下所示:

  #定义AfxDeferRegisterClass(fClass)afxendferregisterclass(fClass)

  注意:这里的宏与《深入浅出MFC》不同。以上代码摘自Visual C 6.0。

  AfxEndDeferRegisterClass是在WINCORE的3619行中定义的。CPP这个函数很复杂,主要注册五个窗口类(哇!终于看到了窗口类。我如何能使用五?还不知道),就在窗口生成之前调用不同类的PreCreateWindow成员函数,准备注册窗口类。如果指定的窗口类为空,将使用系统默认的类。从CWnd及其派生类的PreCreateWindow成员函数中,我们可以看到对于不同功能的窗口,整个框架使用了哪些窗口类。

  7.窗口显示和更新

  CMyFrameWnd:CMyFrameWnd结束后,窗口已经诞生;进程返回CMyWinApp:InitInstance,于是调用ShowWindow函数显示窗口,调用UpdateWindow函数发送WM_PAINT消息。在SDK程序中,通过窗口函数处理消息。现在,窗口功能在哪里,如何交付给it?先说CWinApp:Run。

  8.执行CWINAP:运行——程序,活水之源。

  执行CMyWinApp:InitInstance函数后,程序进入AfxWinMain函数的pApp- Run。现在我们知道这会执行CWinApp:Run函数,这个函数是在APPCORE的第391行定义的。CPP这里是程序代码:

  int CWinApp:Run()

  {

  if(m _ pMainWnd==NULL AfxOleGetUserCtrl())

  {

  //没有启动/嵌入或/自动化,但是没有主窗口!

  TRACE0(警告:CWinApp:Run -退出应用程序中的m_pMainWnd为空。/n’);

  AfxPostQuitMessage(0);

  }

  返回CWinThread:Run();

  }

  该函数调用CWinThread:Run函数,该函数在THRDCORE的第456行中定义。CPP我这里就不抄了。PumpMessage函数在函数的第480行调用,该函数在THRDCORE的第810行定义。CPP排序后的部分代码如下:

  BOOL CWinThread:PumpMessage()

  {

  如果(!* GetMessage(m _ msg cur,NULL,NULL,NULL))

  {

  返回FALSE

  }

  //处理此消息

  if (m_msgCur.message!=WM_KICKIDLE!PreTranslateMessage( m_msgCur))

  {

  translate message(m _ msg cur);

  * dispatch message(m _ msg cur);

  }

  返回TRUE

  }

  该函数的主要操作是将消息从:DispatchMessage发送到窗口函数(CWnd:DefWindowProc),但程序一般不提供任何窗口函数。但是,在AfxEndDeferRegisterClass中,窗口函数被指定为:

  wnd cls . lpfnwndproc=DefWindowProc;

  虽然窗口函数被指定为DefWindowProc(CWnd:DefWindowProc)的成员函数,但实际上消息并没有被泵到那里,而是一个名为AfxWndProc的全局函数。

  9.——用于连接消息和处理功能的消息映射机制

  此时,主窗口已经生成,等待各种消息,然后调用相应的处理函数。但是,消息和处理功能是如何连接在一起的呢?MFC采用消息映射机制(message mapping mechanism),为应用程序提供了两组具有“非常方便的接口”的宏。原理我也不太清楚,这里也没法解释。主要用法是:第一,在类声明中结合DECLARE_MESSAGE_MAP()给出处理函数,比如:

  类CMyFrameWnd:公共CFrameWnd

  {

  公共:

  CMyFrameWnd();

  afx _ msg void OnPaint();//对于WM_PAINT

  afx _ msg void on about();//for WM_COMMAND (IDM_ABOUT)

  声明消息映射()

  }

  然后在对应的任意位置使用BEBIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏。CPP文件(当然,不在函数内)添加相应的消息,例如:

  BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)

  ON_COMMAND(IDM_ABOUT,OnAbout)

  ON_WM_PAINT()

  END_MESSAGE_MAP()

  为什么这样的宏之后消息会自动流向指定的函数?答案在于消息图的结构设计。自己找《深入浅出MFC》第三章的消息图模拟程序!

mfc程序执行流程,mfc应用程序的执行过程