现在的位置: 首页 > 综合 > 正文

MFC内部结构

2013年09月08日 ⁄ 综合 ⁄ 共 10567字 ⁄ 字号 评论关闭

我们在编写程序或是在看MFC类的书籍的时候,总会看到书上让我们在某个地方添加某某函数,响应什么消息。那么,到底为什么要在这地方加呢?为什么不能在其他地方添加消息响应函数呢?
接下来,我们就共同来讨论一下吧。
1.   MFC的运行步骤:(这是对于文档视图结构的应用程序的)
theApp(theApp())->  //应用程序全局对象的构造和内存分配
WinMain()->             //进入主函数
AfxWinMain()->        //调用API
InitAplacation()(应用程序的内部管理)-> //用于应用程序的内部管理的初始化
Initinstance()(theApp)->  //初始化应用程序对象
应用程序的Initinstance()->    //应用程序的初始化(创建和注册窗口类、显示和更新应用程序框架)
注册窗口类->
AfxEndDeferRegisterClass ()    (该函数根据不同的应用程序注册不同的窗口类)->
AfxRegisterClass()->
CMainFrame::PreCreateWindow()->
CFrameWnd::PreCreateWindow()->
AfxDeferRegisterClass()   (如果没有注册,就注册窗口类;它实际上是AfxEndRegisterClass()的宏)(一般都是在这里注册窗口类,由于文档窗口涉及到文档视图类的管理)->
LoadFrame()->   //载入框架
CFrameWnd::Create()->/
CWnd::CreateEx()->//创建应用程序窗口
CMainFrame::PreCreateWindow()      (实际上该函数是一个虚函数,也就是说如果子类为应用程序定义了该函数,那么它将调用子类的函数,因此,我们可以重载该函数来修改应用程序框架的外观)->//在框架窗口显示之前调用
ShowWindow()->UpdateWindow()->     //显示和更新

   消息循环:
   CwinThread::Run()->
do-while()循环(->PumpMessage()->GetMessage()->TranslateMessage()->DispatchMessage())

简单的说就是初始化全局对象进入主函数再进行窗口类的创建和注册并显示,然后进入消息循环。
theApp:全局变量或是类对象在程序运行前初始化。即分配内存空间,初始成员。(每一个MFC应用程序都只有一个全局对象theApp对象,我们用该全局对象唯一的表示该应用程序。)
下面我们给出这些函数如何跟踪(我的是装在C:盘下的他们都在。。/MFC/SRC/下)
WinMain()函数(C:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC/APPMODUL.CPP)
WinApp(C:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC/THRDCORE.CPP)
AfxWinMain()(C:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC/WINMAIN.CPP)
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
   LPTSTR lpCmdLine, int nCmdShow)
{
   ASSERT(hPrevInstance == NULL);

   int nReturnCode = -1;
   CWinThread* pThread = AfxGetThread();
   CWinApp* pApp = AfxGetApp();

   // AFX internal initialization
   if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
      goto InitFailure;

   // App global initializations (rare)
   if (pApp != NULL && !pApp->InitApplication())  // C:/Program Files/Microsoft Visual Studio/VC98/MFC/include/AFXWIN.H)
      goto InitFailure;

   // Perform specific initializations
   if (!pThread->InitInstance())     // C:/Program Files/Microsoft Visual Studio/VC98/MFC/include/AFXWIN.H)

   {
      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();

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;
}
AfxEndDeferRegisterClass
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
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;
}
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
   CWnd* pParentWnd, CCreateContext* pContext)
{
   // only do this once
   ASSERT_VALID_IDR(nIDResource);
   ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

   m_nIDHelp = nIDResource;    // ID for help context (+HID_BASE_RESOURCE)

   CString strFullString;
   if (strFullString.LoadString(nIDResource))
      AfxExtractSubString(m_strTitle, strFullString, 0);    // first sub-string

   VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

   // attempt to create the window
   LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
   LPCTSTR lpszTitle = m_strTitle;
   if (!Create(lpszClass, lpszTitle, dwDefaultStyle, rectDefault,
     pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))
   {
      return FALSE;   // will self destruct on failure normally
   }

   // save the default menu handle
   ASSERT(m_hWnd != NULL);
   m_hMenuDefault = ::GetMenu(m_hWnd);

   // load accelerator resource
   LoadAccelTable(MAKEINTRESOURCE(nIDResource));

   if (pContext == NULL)   // send initial update
      SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

   return TRUE;
}
CWnd::CreateEx()
virtual BOOL CreateEx(
   DWORD dwExStyle,
   LPCTSTR lpszClassName,
   LPCTSTR lpszWindowName,
   DWORD dwStyle,
   int x,
   int y,
   int nWidth,
   int nHeight,
   HWND hWndParent,
   HMENU nIDorHMenu,
   LPVOID lpParam = NULL
);
virtual BOOL CreateEx(
   DWORD dwExStyle,
   LPCTSTR lpszClassName,
   LPCTSTR lpszWindowName,
   DWORD dwStyle,
   const RECT& rect,
   CWnd* pParentWnd,
   UINT nID,
   LPVOID lpParam = NULL
);
CMainFrame::PreCreateWindow()
virtual BOOL PreCreateWindow(
   CREATESTRUCT& cs
);
typedef struct tagCREATESTRUCT {
   LPVOID lpCreateParams;
   HANDLE hInstance;
   HMENU hMenu;
   HWND hwndParent;
   int cy;
   int cx;
   int y;
   int x;
   LONG style;
   LPCSTR lpszName;
   LPCSTR lpszClass;
   DWORD dwExStyle;
} CREATESTRUCT;

CwinThread::Run()
int CWinApp::Run()
{
   if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
   {
      // Not launched /Embedding or /Automation, but has no main window!
      TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application./n");
      AfxPostQuitMessage(0);
   }
   return CWinThread::Run();
}

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
}
MFC中的窗口销毁时,对象不一定销毁,窗口只是与对象的m-hWnd关联;但是如果一个对象销毁了,则拥有该对象的窗口也要销毁。

好了,现在相信大家应该至少知道对于什么时候添加消息和在什么地方捕获消息有一个大致的了解了吧,写的仓促,难免有错,还请多多见量,谢谢。希望大家可以一起进步。
对了,希望大家不要说又浪费了你们的时间哦。

抱歉!评论已关闭.