第3课 mfc框架程序剖析

1.      在main或WinMain之前,全局变量已经被分配内存并初始化了。

2.      构造子类时会调用父类的构造函数,而如果父类的构造函数中有this指针,那么此指针指向的是子类对象而不是父类对象

3.在MFC中在WinMain之前有个theApp全局变量先被构造并被初始化,而由于子类构造函数执行前,其父类的构造函数先被执行,所以CTestApp的父类CWinAPP的构造函数先执行。产生了theApp对象后,在WinMain()中的指针*pThread和*pApp就有了内容。

4.MFC大致流程:

CTestApp theApp;//构造全局对象

WinMain()

{

AfxWinMain();//调用下面的函数

}

AfxWinMain()

{

pThread->Initinstance();//初始化工作和注册窗口类,窗口显示和更新

pThread->Run();//消息循环

}

而在BOOLCTestApp::InitInstance()中的代码

 CSingleDocTemplate* pDocTemplate;

 pDocTemplate = new CSingleDocTemplate(

 IDR_MAINFRAME,

 RUNTIME_CLASS(CTestDoc),

 RUNTIME_CLASS(CMainFrame),      // main SDI frame window

 RUNTIME_CLASS(CTestView));

 AddDocTemplate(pDocTemplate);

完成了将这三个类关联起来的工作。

5,MFC中不需要设计窗口类,应为MFC已经帮我们设计好了,我们只要注册就好了

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

7,CMainFrame的PreCreateWindow()://主要是注册窗口类,以及在创建窗口之前让用户有机会对style进行修改
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
 if( !CFrameWnd::PreCreateWindow(cs) )
  return FALSE;
 return TRUE;
}
说明:
CFrameWnd::PreCreateWindow()函数所在文件:WINFRM.CPP
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 if (cs.lpszClass == NULL)
 {
  VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
   //判断AFX_WNDFRAMEORVIEW_REG型号窗口类是否注册,如果没有注册则注册
  cs.lpszClass = _afxWndFrameOrView;  // COLOR_WINDOWbackground
   //把注册后的窗口类名赋给cs.lpszClass
 }

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

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

 returnTRUE;
}

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

实际上正常的流程应该是在PreCreateWindow注册窗口类的,但是在SDI程序中,为了便于文档管理,注册提前了

 

8,创建窗口:
这里只讲解了框架窗口的创建,它的Create()函数在WINFRM.CPP中:
CFrameWnd::Create(...){
 ...
 CreateEx(...);//从父类继承来的,调用CWnd::CreateEx().
 ...
}

CWnd::CreateEx()函数在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;

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

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

 

11.如何在单文档文件中显示一个CButton的对象?

在CMainFrame::OnCreate()中定义一个CButton的对象btn;然后调用btn.Create("维新",WS_DISABLED   |WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,

 CRect(0,0,300,100),/*GetParent(),*/this,123);

注意点:

    (1).此处btn不能是局部变量,否则它的生命周期太短,将不能显示。

    (2).在create函数的第二个参数中加入WS_VISIBLE 参数才行。否则必须调用ShowWindow

也可以在view的OnCreate消息响应函数中加入

    (3).CButton类的定义头文件在afxwin.h中,而stdafx.h包含了afxwin.h,所以可以直接使用。因为MFC中的每一个类中都有#include"stdafx.h"的声明。


你可能感兴趣的:(第3课 mfc框架程序剖析)