孙鑫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 <iostream> using namespace std; //a的值在main函数调用之前就有值了,全局变量或者全局对象 //在main加载的时候就已经为全局分配内存空间,赋上初值 // CPoint pt-->CPoint(){}-->int main() int a = 10; class CPoint { public: CPoint(){} }; CPoint pt; int main() { cout<<a<<endl; return 0; } 4. 在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的构造函数有缺省的参数 .............................. } 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.每个窗口类内都定义并维护着一个指向该窗口的句柄

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值