孙鑫VC学习笔记:第三讲 MFC应用程序框架

1.在MFC的源代码中查找入口函数WinMain().
 X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC

 APPMODUL.CPP文件中
------------------------------------------------------------------------
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
{                                                            //Breakpoint1
 // call shared/exported WinMain
 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
-------------------------------------------------------------------------
TCHAR.H
------------------------------------------------------------------------
#define _tWinMain   WinMain
------------------------------------------------------------------------
Test.cpp
------------------------------------------------------------------------
CTestApp::CTestApp()
{                                                             //Breakpoint2
 // TODO: add construction code here,
 // Place all significant initialization in InitInstance
}
------------------------------------------------------------------------
RUNNING: Breakpoint2->Breakpoint1
首先进入CTestApp的构造函数,然后才到达_tWinMain()函数
Test.cpp
--------------------------------------------------------------------------
CTestApp theApp;  //全局对象                                 //Breakpoint3
--------------------------------------------------------------------------
RUNNING: Breakpoint3->Breakpoint2->Breakpoint1

2.在MFC程序中,通过产生一个应用程序类的对象来表示应用程序本身
   在X:/Program Files/Microsoft Visual Studio/VC98/MFC/SRC搜索WinApp
   得到:
   APPCORE.CPP
--------------------------------------------------------------------------
   CWinApp::CWinApp(LPCTSTR lpszAppName)                 //CWinApp的构造函数
   {
 if (lpszAppName != NULL)
  m_pszAppName = _tcsdup(lpszAppName);
 else
  m_pszAppName = NULL;

 // initialize CWinThread state
 AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
 AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
 ASSERT(AfxGetThread() == NULL);
 pThreadState->m_pCurrentWinThread = this;   //this指针指向CTestApp对象(theApp)
                                                    //根据继承性的原理(使用程序测试)
 ASSERT(AfxGetThread() == this);
 m_hThread = ::GetCurrentThread();
 m_nThreadID = ::GetCurrentThreadId();

 // initialize CWinApp state
 ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
 pModuleState->m_pCurrentWinApp = this;
 ASSERT(AfxGetApp() == this);

 // in non-running state until WinMain
 m_hInstance = NULL;
 m_pszHelpFilePath = NULL;
 m_pszProfileName = NULL;
 m_pszRegistryKey = NULL;
 m_pszExeName = NULL;
 m_pRecentFileList = NULL;
 m_pDocManager = NULL;
 m_atomApp = m_atomSystemTopic = NULL;
 m_lpCmdLine = NULL;
 m_pCmdInfo = NULL;

 // initialize wait cursor state
 m_nWaitCursorCount = 0;
 m_hcurWaitCursorRestore = NULL;

 // initialize current printer state
 m_hDevMode = NULL;
 m_hDevNames = NULL;
 m_nNumPreviewPages = 0;     // not specified (defaults to 1)

 // initialize DAO state
 m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called

 // other initialization
 m_bHelpMode = FALSE;
 m_nSafetyPoolSize = 512;        // default size
   }
--------------------------------------------------------------------------------
CWinApp的构造函数带有参数LPCTSTR lpszAppName,而CTestApp的构造函数不带有任何参数.
在AFXWIN.H文件中
-----------------------------------------------------------------------------
class CWinApp : public CWinThread
{
 DECLARE_DYNAMIC(CWinApp)
public:

// Constructor
 CWinApp(LPCTSTR lpszAppName = NULL); //CWinApp的构造函数有缺省的参数   
 ..............................
}
------------------------------------------------------------------------------
3. 回到_tWinMain(...)函数
   查找AfxWinMain()函数,Afx表示应用程序框架类函数,相当于全局函数
-------------------------------------------------------------------------------
   int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
   {
 ASSERT(hPrevInstance == NULL);

 int nReturnCode = -1;
 CWinThread* pThread = AfxGetThread(); //线程的指针,也是指向子类
 CWinApp* pApp = AfxGetApp(); //获得指针,这里pApp指向派生类的指针(theApp)

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

 // App global initializations (rare)
 if (pApp != NULL && !pApp->InitApplication())//pApp->InitApplication()MFC内部
                                              //管理的函数
  goto InitFailure;

 // Perform specific initializations
 if (!pThread->InitInstance())  //pThread->InitInstance()       //Breakpoint4
                                //在AFXWIN.H中
           //virtual BOOL InitInstance();
           //InitInstance是一个虚函数
           //此时调用的InitInstance函数是
           //CTestApp::InitInstance()

 {
  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();//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;
   }
------------------------------------------------------------------------------------
4.在CTestApp的InitInstance()函数设置断点
------------------------------------------------------------------------------------
   BOOL CTestApp::InitInstance()
   {                                                      //Breakpoint5
 AfxEnableControlContainer();
        .............
   }
-------------------------------------------------------------------------------------
RUNNING:<1> 定义全局对象  CTestApp theApp;    (Breakpoint3)
        <2> 构造全局对象  CTestApp::CTestApp()(Breakpoint2)
 <3> 构造基类对象 
 <4> 进入_tWinMain函数                 (Breakpoint1)
 <5> 到达AfxWinMain函数
     if (!pThread->InitInstance())     (Breakpoint4)
 <6> 到达CTestApp::InitInstance()      (Breakpoint5)
5.注册窗口类
  AfxEndDeferRegisterClass函数
  WINCORE.CPP中                       (注册窗口类应该在PreCreateWindow中调用)
  由于是单文档应用程序的原因,事先调用AfxEndDeferRegisterClass函数注册窗口                     
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{                                                                  // Breakpoint6
 // 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;
 ........................
 wndcls.lpfnWndProc = DefWindowProc;       
}
-------------------------------------------------------------------------------------
BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
 WNDCLASS wndcls;
 if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
  &wndcls))                  //判断窗口是否注册
 {
  // class already registered
  return TRUE;
 }

 if (!::RegisterClass(lpWndClass))              //调用RegisterClass,API函数
 {
  TRACE1("Can't register window class named %s/n",
   lpWndClass->lpszClassName);
  return FALSE;
 }
 .................................................
}
-------------------------------------------------------------------------------------
        <7> 注册窗口类
    BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)  (Breakpoint6)
6.产生窗口
 CMainFrm.CPP
-------------------------------------------------------------------------------------
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{                                                                   (Breakpoint7)
 if( !CFrameWnd::PreCreateWindow(cs) )  //函数调用
  return FALSE;
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs

 return TRUE;
}
-------------------------------------------------------------------------------------
 <8>BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)        (Breakpoint7)
WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{                                                                    (Breakpoint8)
 if (cs.lpszClass == NULL)
 {
  VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
  //AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG)判断当前的窗口类有没有
  //注册,没有就注册
  cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
 }

 if ((cs.style & FWS_ADDTOTITLE) && afxData.bWin4)
  cs.style |= FWS_PREFIXTITLE;

 if (afxData.bWin4)
  cs.dwExStyle |= WS_EX_CLIENTEDGE;

 return TRUE;
}
-------------------------------------------------------------------------------------
AFXIMPL.h
-------------------------------------------------------------------------------------
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
-------------------------------------------------------------------------------------
 <9> BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)         (Breakpoint8)

WINCORE.cpp
-------------------------------------------------------------------------------------
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
 LPCTSTR lpszWindowName, DWORD dwStyle,
 int x, int y, int nWidth, int nHeight,
 HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{                                                                      (Breakpoint9)
 // allow modification of several common create parameters
 CREATESTRUCT cs;
 cs.dwExStyle = dwExStyle;
 cs.lpszClass = lpszClassName;
 ..............................
 if (!PreCreateWindow(cs))      //PreCreateWindow是一个虚函数
 {
  PostNcDestroy();
  return FALSE;
 }
 ...............................
}
-------------------------------------------------------------------------------------
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
  LPCTSTR lpszWindowName, DWORD dwStyle,
  const RECT& rect, CWnd* pParentWnd, UINT nID,
  LPVOID lpParam /* = NULL */)     //调用上面的CreateEx函数
{                                                                      (Breakpoint10)
 return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}
-------------------------------------------------------------------------------------

WINFRM.CPP
-------------------------------------------------------------------------------------
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
 LPCTSTR lpszWindowName,
 DWORD dwStyle,
 const RECT& rect,
 CWnd* pParentWnd,
 LPCTSTR lpszMenuName,
 DWORD dwExStyle,
 CCreateContext* pContext)
{                                                                  (Breakpoint11)         
 ..........................
 if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext)) //调用上面的
 {                                                            //CreateEx函数
  TRACE0("Warning: failed to create CFrameWnd./n");
  if (hMenu != NULL)
   DestroyMenu(hMenu);
  return FALSE;
 }
 ....................................................
}
-----------------------------------------------------------------------------------
7.显示更新窗口
  Test.CPP
-----------------------------------------------------------------------------------
 m_pMainWnd->ShowWindow(SW_SHOW);
 m_pMainWnd->UpdateWindow();      //m_pMainWnd指向框架窗口对象的指针
-----------------------------------------------------------------------------------

8.消息循环
THRDCORE.CPP
-----------------------------------------------------------------------------------
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
}
------------------------------------------------------------------------------------
BOOL CWinThread::PumpMessage()
{
 ASSERT_VALID(this);

 if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
 {
#ifdef _DEBUG
  if (afxTraceFlags & traceAppMsg)
   TRACE0("CWinThread::PumpMessage - Received WM_QUIT./n");
  m_nDisablePumpCount++; // application must die
   // Note: prevents calling message loop things in 'ExitInstance'
   // will never be decremented
#endif
  return FALSE;
 }

#ifdef _DEBUG
 if (m_nDisablePumpCount != 0)
 {
  TRACE0("Error: CWinThread::PumpMessage called when not permitted./n");
  ASSERT(FALSE);
 }
#endif

#ifdef _DEBUG
 if (afxTraceFlags & traceAppMsg)
  _AfxTraceMsg(_T("PumpMessage"), &m_msgCur);
#endif

 // process this message

 if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
 {
  ::TranslateMessage(&m_msgCur);
  ::DispatchMessage(&m_msgCur);
 }
 return TRUE;
}
----------------------------------------------------------------------------------

9.窗口过程 (在AfxEndDeferRegisterClass函数中设置)
 wndcls.lpfnWndProc = DefWindowProc;   //缺省的窗口过程

10.在MFC如何整合CMainFrm类,CTestView类,CTestDoc类?
   在
 BOOL CTestApp::InitInstance()中:
------------------------------------------------------------------------------------
CSingleDocTemplate* pDocTemplate;     //定义一个单文档的类模板
 pDocTemplate = new CSingleDocTemplate(
  IDR_MAINFRAME,
  RUNTIME_CLASS(CTestDoc),       //通过单文档的模板组合在一起
  RUNTIME_CLASS(CMainFrame),       // main SDI frame window
  RUNTIME_CLASS(CTestView));
 AddDocTemplate(pDocTemplate);           //增加到文档模板中
-------------------------------------------------------------------------------------

11.窗口与C++类的关系

   窗口销毁,C++的对象不一定销毁,窗口与C++窗口类的关系只不过是窗口类保存了窗口的句柄.
12.CButton
   m_btn.Create("维新",WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,
  CRect(0,0,100,100),/*GetParent(),*/this,123);
   CButton的窗口风格 WS_CHILD | WS_VISIBLE | BS_AUTO3STATE
   CTestView的父窗口是CMainFrm,在CTestView里面使用GetParent()函数,得到CMainFrm对象的
   指针.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值