孙鑫VC++讲座笔记-(3)MFC程序框架的剖析

1.小知识

MFC中,以_t开头的标识符是已定义的宏,例如:

#define _tWinMain WinMain

#define _tMain main

Afx(application framwork)开头命名的函数是系统定义的框架函数,作用是为了把MFC中的类有机的结合在一起。例如:

AfxWinMain()

MFC中所有类都是以C开头

2.系统自动生成的类

Test工程,一个单文档应用程序为例:

CAboutDlg  关于对话框类,没有太大的作用

CMainFrame 框架类

CTestApp 应用程序类  唯一的代表了一个应用程序。一个MFC程序中有且只能有一个这个类

CTestDoc   这个类和下面的类是使用了文档视类结构,把数据的本身和它的显示分开

CTestView

3.建议 要对MFC的类继承结构有一个清晰的认识。例如:

CObject->CCmdTarget->CWnd


4.WinMain
函数依然是应用程序的入口点,不过在MFC编程过程中,你并不能在你的程序中找到这个函数,因为它被封装了,它会在编译链接的时候链接进来。当然你可以在安装目录下找到MFC文件夹下的SRC文件夹,SRC下是MFC源代码。
路径:MFC|SRC|APPMODUL.CPP
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
{
 // call shared/exported WinMain
 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);//
即调用AfxWinMain函数
}
注意:(#define _tWinMain   WinMain
5.
程序最开始执行的是全局变量,即先构造了一个CTestApp类的对象theApp,然后应该是调用其构造函数,因为CTestApp是继承CWinApp,故应该先调用父类的构造函数。CWinApp构造函数:MFC|SRC|APPCORE.CPP
CWinApp::CWinApp(LPCTSTR lpszAppName){...}//
具体参见定义,lpszAppName有缺省值。
6.
程序继续执行,这时执行到WinMain函数了,即调用AfxWinMain函数,打开AfxWinMain()函数路径:MFC|SRC|WINMAIN.CPP
AfxWinMain()函数中:
CWinApp* pApp = AfxGetApp();
说明:pApp存储的是指向WinApp派生类对象(theApp)的指针。

附:AFX头声明表示:Application FrameWork,即应用程序框架。
7.
接下来是设计,注册,创建,

调用pThread->InitInstance()
说明:pThread也指向theApp,由于基类中virtual BOOL InitApplication()定义为虚函数,所以调用pThread->InitInstance()时候,调用的是派生类CTEAppInitInstance()函数。

nReturnCode = pThread->Run();
说明:pThread->Run()完成了消息循环。

8,注册窗口类:AfxEndDeferRegisterClass();
AfxEndDeferRegisterClass()
函数所在文件:MFC|SRC|APPCORE.CPP
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){...}
说明:设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。
调试:CWinApp::CWinApp();->CTEApp theApp;->CTEApp ::CTEApp()->CWinApp::CWinApp()->CTEApp ::CTEApp()->_tWinMain(){}//进入程序
->AfxWinMain();->pApp->InitApplication()
->pThread->InitInstance()//父类InitInstance虚函数;->CTEApp::InitInstance()//子类实现函数;->AfxEndDeferRegisterClass(LONG fToRegister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在PreCreateWindow中进行注册)//之后进入创建窗口阶段(以下再不做调试)

9PreCreateWindow()//主要是注册窗口类
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 if( !CFrameWnd::PreCreateWindow(cs) )
  return FALSE;
 return TRUE;
}
说明:
CFrameWnd::PreCreateWindow()
函数所在文件:MFC|SRC|WINFRM.CPP
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 if (cs.lpszClass == NULL)
 {
  VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
   //
判断AFX_WNDFRAMEORVIEW_REG型号窗口类是否注册,如果没有注册则注册
  cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOW background
   //
把注册后的窗口类名赋给cs.lpszClass
 }

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

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

 return TRUE;
}

其中:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);//PreCreateWindow()
是个虚函数,如果子类有则调用子类的。
#define VERIFY(f)          ASSERT(f)
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
define AFX_WNDFRAMEORVIEW_REG          0x00008
const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;//WINCORE.CPP
文件中,定义为全局数组。
//#define AFX_WNDFRAMEORVIEW  AFX_WNDCLASS("FrameOrView")

10,创建窗口:
Create()
函数路径:MFC|SRC|WINFRM.CPP:
CFrameWnd::Create(...){
 ...
 CreateEx(...);//
从父类继承来的,调用CWnd::CreateEx().
 ...
}

CWnd::CreateEx()函数路径:MFC|SRC|WINCORE.CPP
BOOL CWnd::CreateEx(...){
 ...
 if (!PreCreateWindow(cs))//
虚函数,如果子类有调用子类的。
 {
  PostNcDestroy();
  return FALSE;
 }
 ...
 HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
  cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
  cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

 ...
}
说明:CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreateWindow(cs)修改cs结构体成员来修改所要的窗口外观。PreCreateWindow(cs))//是虚函数,如果子类有调用子类的。
HWND CreateWindowEx(
  DWORD dwExStyle,     
  LPCTSTR lpClassName, 
  LPCTSTR lpWindowName,
  DWORD dwStyle,       
  int x,               
  int y,               
  int nWidth,          
  int nHeight,         
  HWND hWndParent,     
  HMENU hMenu,         
  HINSTANCE hInstance, 
  LPVOID lpParam       
);
typedef struct tagCREATESTRUCT { // cs
    LPVOID    lpCreateParams;
    HINSTANCE hInstance;
    HMENU     hMenu;
    HWND      hwndParent;
    int       cy;
    int       cx;
    int       y;
    int       x;
    LONG      style;
    LPCTSTR   lpszName;
    LPCTSTR   lpszClass;
    DWORD     dwExStyle;
} CREATESTRUCT;

11,显示和更新窗口:
CTEApp
类,TEApp.cpp
m_pMainWnd->ShowWindow(SW_SHOW);//
显示窗口,m_pMainWnd指向框架窗口的指针
m_pMainWnd->UpdateWindow();//
更新窗口
说明:
class CTEApp : public CWinApp{...}
class CWinApp : public CWinThread{...}
class CWinThread : public CCmdTarget
{
 ...
public:
 CWnd* m_pMainWnd;
 ...
...
}

12,消息循环:
int AFXAPI AfxWinMain()
{ ...
 // Perform specific initializations
 if (!pThread->InitInstance()){...}
 //
完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
 nReturnCode = pThread->Run();
 //
继承基类Run()方法,调用CWinThread::Run()来完成消息循环
 ...
}

CWinThread::Run()
方法路径:MFC|SRC|THRDCORE.CPP
int CWinThread::Run()
{ ...
  // phase2: pump messages while available
  do//
消息循环
  {
   // pump message, but quit on WM_QUIT
   if (!PumpMessage())//
取消息并处理
    return ExitInstance();
   ...
  } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
 ...
}
说明:
BOOL PeekMessage(,,,,)
函数说明
The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure.
If a message is available, the return value is nonzero.
If no messages are available, the return value is zero.

/
BOOL CWinThread::PumpMessage()
{
 ...
 if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))//
取消息
 {...}
 ...
 // process this message
 if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
 {
  ::TranslateMessage(&m_msgCur);//
进行消息(如键盘消息)转换
  ::DispatchMessage(&m_msgCur);//
分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。)
 }
 return TRUE;
}

13,文档与视结构:
可以认为View类窗口是CMainFram类窗口的子窗口。
DOCument
类是文档类。
DOC-VIEW
结构将数据本身与它的显示分离开。
文档类:数据的存储,加载
视类:数据的显示,修改

14,文档类,视类,框架类的有机结合:
CTEAppCTEApp::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
 IDR_MAINFRAME,
 RUNTIME_CLASS(CTEDoc),
 RUNTIME_CLASS(CMainFrame),       // main SDI frame window
 RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);//
增加到模板
...

15.视图类是框架窗口的子类,获得CWnd类的父窗口的函数CWnd* GetParent( ) const;
     
视图类以及框架类都是Cwnd类的子类,由于CWnd类中有一个成员变量m_hWnd,故所有CWnd类的子类在调用函数的时候都不需要传递句柄。例如BOOL ShowWindow ( int nCmdShow );
BOOL ShowWindow(//SDK
编程的时候要传入当前窗口的句柄。
HWND
hWnd,     // handle to window
  int nCmdShow   // show state
)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值