孙鑫MFC笔记教程(3)--MFC应用程序框架

单文档应用程序启动流程 1.Tess.cpp --> CTestApp theApp 2.Tess.cpp --> CTestApp::CTestApp() 3.APPMODUL.cpp --> _tWinMain() !!! 4.WINMAIN.cpp --> AfxWinMain(); 5.WINMAIN.cpp AfxWinMain() --> InitInstance(); 6.Tess.cpp --> InitInstance(); 7.WINCORE.cpp --> AfxEndDeferRegisterClass();!!! 8.CMainFrm.cpp --> CMainFrame::PreCreateWindow(); 9.WINFRM.cpp CMainFrame::PreCreateWindow() --> CFrameWnd::PreCreateWindow(); 10.WINCORE.cpp --> AfxEndDeferRegisterClass(); 11.WINFRM.cpp --> CFrameWnd::Create();!!!LoadFram 12.WINFRM.cpp CFrameWnd::Create() --> CWnd::CreateEx(); 13.显示 14.更新 15.消息循环 CTestApp theApp -> CWinApp() -> CTestApp() -> _tWinMain() ->CTestApp::InitInstance() -> AfxEndDeferRegisterClass() -> CMainFrame::PreCreateWindow() -> CMainFrame::CreateEx() -> CMainFrame::PreCreateWindow() -> CTestApp::PreCreateWindow()改外观,完成创建窗口 其中 AfxEndDeferRegisterClass() 设计窗口类,注册窗口,窗口过程选择的是一个缺省的窗口过程Wndcls.lpfuWndProc = DefWindowProc; CMainFrame::PreCreateWindow() 调用 CFrameWnd::PreCreateWindow() 再注册一次 1.CWND类封装了和窗口相关的类, 设计窗口类:在MFC中预先设计好了几种窗口类,只需要去注册一下就行了 2.任何程序都是以WinMain函数为入口,在MFC中是通过链接器把它链接进来的 3.在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 #include using namespace std; //a的值在main函数调用之前就有值了,全局变量或者全局对象 //在main加载的时候就已经为全局分配内存空间,赋上初值 // CPoint pt-->CPoint(){}-->int main() int a = 10; class CPoint { public: CPoint(){} }; CPoint pt; int main() { cout<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的构造函数有缺省的参数    .............................. } 5. 回到_tWinMain(...)函数    查找AfxWinMain()函数,Afx表示应用程序框架类函数,相当于全局函数 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(); //获得指针,这里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;    } 6. 在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) 7. 注册窗口类   AfxEndDeferRegisterClass函数   WINCORE.CPP中                       (注册窗口类应该在PreCreateWindow中调用)   由于是单文档应用程序的原因,事先调用AfxEndDeferRegisterClass函数注册窗口     MFC中创建窗口的时候是注册,而单文档的应用程序是在之前就注册了                 ------------------------------------------------------------------------------------- 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) 8. 产生窗口  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是一个虚函数,调用子类的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;  }  .................................................... } ----------------------------------------------------------------------------------- 9. 显示更新窗口   Test.CPP -----------------------------------------------------------------------------------  m_pMainWnd->ShowWindow(SW_SHOW);  m_pMainWnd->UpdateWindow();      //m_pMainWnd指向框架窗口对象的指针 ----------------------------------------------------------------------------------- 10. 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; } 11. 窗口过程 (在AfxEndDeferRegisterClass函数中设置)  wndcls.lpfnWndProc = DefWindowProc;   //缺省的窗口过程 12. 封装一个CWND类 class CWnd { public: BOOL CreateEx(DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // registered class name LPCTSTR lpWindowName, // window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // menu handle or child identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam); // window-creation data BOOL ShowWindow(int nCmdShow); BOOL UpdateWindow(); public: HWND m_hWnd; }; BOOL CWnd::CreateEx(DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // registered class name LPCTSTR lpWindowName, // window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // menu handle or child identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam) // window-creation data { m_hWnd=::CreateWindowEx(dwExStyle,lpClassName,dwStyle,x,y, nWidth,nHeight,hWndParent,hMenu,hInstance, lpParam); if(m_hWnd!=NULL) return TRUE; else return FALSE; } BOOL CWnd::ShowWindow(int nCmdShow) { return ::ShowWindow(m_hWnd,nCmdShow); } BOOL CWnd::UpdateWindow() { return ::UpdateWindow(m_hWnd); } int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { WNDCLASS wndcls; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; ...... RegisterClass(&wndcls); CWnd wnd; wnd.CreateEx(...); wnd.ShowWindow(SW_SHOWNORMAL); wnd.UpdateWindow(); //第一堂课讲的内容 HWND hwnd; hwnd=CreateWindowEx(); ::ShowWindow(hwnd,SW_SHOWNORMAL); ::UpdateWindow(hwnd); ...... } 13.CTestView其实也是一个窗口,可以看作是CMainFrame框架窗口的一个子窗口,覆盖在CMainFrame之上 14.CTestDoc : CDocument : CCmdTarget : CObject 不是一个窗口     数据存储、加载由CDocument类完成     数据显示、修改由CView类完成 15.CMainFrame、CDocument、CView 是如何组织在一起的呢     在CTestApp::InitInstance()中定义了一个单文挡指针CSingleDocTempLate* pDocTemplate将这三个类有机组织在一起了,然后用AddDocTemplate(pDocTemplate);载入文档模板 16.CAbout : CDialog : CWnd : CCmdTarget : CObject 是一个窗口 17.::ShowWindow(), ::表示你调用的是一个全局函数     想调用全局函数,sdk函数,都可以用::来引用     类内成员函数名与sdk函数名一致,可以用::区分 18.窗口类对象和窗口的关系     窗口对象和程序对象不是一回事,窗口销毁了程序不一定就销毁了,程序销毁了,窗口就一定销毁了,和程序析构函数有关     窗口与程序相联系的纽带是窗口句柄 HWND hwnd;     也就是说,窗口销毁了,CMainFrame、CView 仍然存活,其内成员函数依然可以调用     CWnd 中就定义有一个HWND结构 m_hwnd,用来保存窗口句柄 19.mfc中结构体也是一个类 20.CMainFrame::OnCreate()中定义一个按钮     {        CButton btn;        btn.Create("test",WS_CHTID,CRect(0,0,100,100),this,12345);                   "显示文本",显示类型,显示对角,归属窗口,按钮标志     }     不显示的原因有两个:     1 这里btn是一个局部变量,走出OnCreate()右大括号的时候,对象被销毁了,于是窗口也销毁了       也就是前面说的,窗口与对象的存活关系     2 少了窗口显示过程btn.ShowWindow(),也可以在Create()中增加显示类型标志WS_VISIBLE省略该步     类内用this指的就是类对象的句柄了 Button 控件其实就是一个窗口,因此在Create()类型时,可以指定窗口类型同时指定按钮类型 单选按钮控件、复选按钮控件,其实就是button的不同按钮类型 继承于CWnd的button类,与CWnd同样定义有一个HWND结构 m_hwnd,用来保存button窗口句柄,因此一般不用显式地定义另一个HWND结构来保存button窗口句柄,需要就调用就行了 18、CMainFrame的客户区包括了工具栏部分 可以看到代码执行结果是按钮把工具栏给遮住了     CView的客户区就是空白部分 如果要在CView的客户区中显示,可以把变量定义、代码放入CView类中 21.窗口显示在哪里并不是因为代码放在哪个窗口类代码中,而是看Create()中指定的归属窗口是哪个 如果把原显示在CView客户区的代码Create()指定的归属窗口句柄this改为GetParent(), 按钮就显示在CMainFrame客户区中了 GetParent() api函数,获取父窗口句柄 22.每个窗口类内都定义并维护着一个指向该窗口的句柄

你可能感兴趣的:(孙鑫MFC笔记教程,mfc,框架,null,button,application,winapi)