Lesson3 MFC应用程序框架 ---孙鑫VC++教程

2024-01-23 10:58

本文主要是介绍Lesson3 MFC应用程序框架 ---孙鑫VC++教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Lesson3 MFC应用程序框架

state:

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对象的
   指针.

 

这篇关于Lesson3 MFC应用程序框架 ---孙鑫VC++教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/636183

相关文章

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

手把手教你idea中创建一个javaweb(webapp)项目详细图文教程

《手把手教你idea中创建一个javaweb(webapp)项目详细图文教程》:本文主要介绍如何使用IntelliJIDEA创建一个Maven项目,并配置Tomcat服务器进行运行,过程包括创建... 1.启动idea2.创建项目模板点击项目-新建项目-选择maven,显示如下页面输入项目名称,选择

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

Linux下MySQL8.0.26安装教程

《Linux下MySQL8.0.26安装教程》文章详细介绍了如何在Linux系统上安装和配置MySQL,包括下载、解压、安装依赖、启动服务、获取默认密码、设置密码、支持远程登录以及创建表,感兴趣的朋友... 目录1.找到官网下载位置1.访问mysql存档2.下载社区版3.百度网盘中2.linux安装配置1.

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

Python使用pysmb库访问Windows共享文件夹的详细教程

《Python使用pysmb库访问Windows共享文件夹的详细教程》本教程旨在帮助您使用pysmb库,通过SMB(ServerMessageBlock)协议,轻松连接到Windows共享文件夹,并列... 目录前置条件步骤一:导入必要的模块步骤二:配置连接参数步骤三:实例化SMB连接对象并尝试连接步骤四:

Linux使用粘滞位 (t-bit)共享文件的方法教程

《Linux使用粘滞位(t-bit)共享文件的方法教程》在Linux系统中,共享文件是日常管理和协作中的常见任务,而粘滞位(StickyBit或t-bit)是实现共享目录安全性的重要工具之一,本文将... 目录文件共享的常见场景基础概念linux 文件权限粘滞位 (Sticky Bit)设置共享目录并配置粘