[MFC学习笔记]--孙鑫第三课

    我新建了一个MFC app工程,名字叫mfcTest,然后VC6++给我自动生成了一些类。CAboutDlg类,CMainFrame类,CMfcTestApp类,CMfcTestDoc类,CMfcTestView类.

    接下来,我要一个个学习这种类。这些类都有基类,这些基类都是MFC的类库里面的。

    CMfcTestApp 是继承了CWinApp类。

    The CWinApp class is the base class from which you derive a Windows application object. An application object provides member functions for initializing your application (and each instance of it) and for running the application.

 

    CMfcTestApp theAPP;在自动生成的代码中,CMfcTestApp声明了一个全局对象theAPP。也就是,我们打开的窗口什么的,都是theAPP这个对象。

    Afx:Application Framework应用程序框架,集成了很多类用来设置。

 

    CMainFrame类生成的是框架窗口,就如下图的蓝色线,也就是app最大的那个窗口框。CMfcTestView产生的就是那个子窗口。就是用粗线描绘的地方。

 

CMfcDoc类是用来加载一些数据,然后CMfcView类是用来显示这些数据的。

 

CAboutDlg:关于对话框的类,是继承Cwnd类,也是一种窗口类。

 

 

在第三课中,自动生成的代码,在内部是怎么进行的呢?

step 1.CMfcTestApp类声明一个全局对象theAPP  this 指针指向这个对象

step 2.进入winmain()函数,在MFC\SRC\APPMODUL.CPP 中。他是这么定义的。

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
{
 
 return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

最后跳转到AfxWinMain();函数当中去了。

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 LPTSTR lpCmdLine, int nCmdShow)
{
 ASSERT(hPrevInstance == NULL);

 int nReturnCode = -1;
 CWinThread* pThread = AfxGetThread();
 CWinApp* pApp = AfxGetApp();

 // AFX internal initialization
 if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
  goto InitFailure;

 // App global initializations (rare)
 if (pApp != NULL && !pApp->InitApplication())
  goto InitFailure;

 // Perform specific initializations
 if (!pThread->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();

在这个函数中,我们进行了一些初始化的工作。

 

然后进入一个pThread->InitInstance()函数,在这个函数中,完成应用程序的初始化工作,注册,创建,显示,更新窗口类。

 

step 3.注册一个窗口类 我们用了AfxEndDeferRegisterClass这个函数。这个函数在...\MFC\SRC\WINCORE.CPP 中。AfxRegisterClass这个也是注册这个窗口

 

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
{
 // 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;

 // common initialization
 WNDCLASS wndcls;
 memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL defaults
 wndcls.lpfnWndProc = DefWindowProc;
 wndcls.hInstance = AfxGetInstanceHandle();
 wndcls.hCursor = afxData.hcurArrow;

 INITCOMMONCONTROLSEX init;
 init.dwSize = sizeof(init);

 // work to register classes as specified by fToRegister, populate fRegisteredClasses as we go
 if (fToRegister & AFX_WND_REG)
 {
  // Child windows - no brush, no icon, safest default class styles
  wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  wndcls.lpszClassName = _afxWnd;
  if (AfxRegisterClass(&wndcls))
   fRegisteredClasses |= AFX_WND_REG;
 }
 if (fToRegister & AFX_WNDOLECONTROL_REG)
 {
  // OLE Control windows - use parent DC for speed
  wndcls.style |= CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  wndcls.lpszClassName = _afxWndOleControl;
  if (AfxRegisterClass(&wndcls))
   fRegisteredClasses |= AFX_WNDOLECONTROL_REG;
 }
 if (fToRegister & AFX_WNDCONTROLBAR_REG)
 {
  // Control bar windows
  wndcls.style = 0;   // control bars don't handle double click
  wndcls.lpszClassName = _afxWndControlBar;
  wndcls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  if (AfxRegisterClass(&wndcls))
   fRegisteredClasses |= AFX_WNDCONTROLBAR_REG;
 }
 if (fToRegister & AFX_WNDMDIFRAME_REG)
 {
  // MDI Frame window (also used for splitter window)
  wndcls.style = CS_DBLCLKS;
  wndcls.hbrBackground = NULL;
  if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))
   fRegisteredClasses |= AFX_WNDMDIFRAME_REG;
 }
 if (fToRegister & AFX_WNDFRAMEORVIEW_REG)
 {
  // SDI Frame or MDI Child windows or views - normal colors
  wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))
   fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;
 }
 if (fToRegister & AFX_WNDCOMMCTLS_REG)
 {
  // this flag is compatible with the old InitCommonControls() API
  init.dwICC = ICC_WIN95_CLASSES;
  fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WIN95CTLS_MASK);
  fToRegister &= ~AFX_WIN95CTLS_MASK;
 }
 if (fToRegister & AFX_WNDCOMMCTL_UPDOWN_REG)
 {
  init.dwICC = ICC_UPDOWN_CLASS;
  fRegisteredClasses |= _AfxInitCommonControls(&init, AFX_WNDCOMMCTL_UPDOWN_REG);
 }

.....

 // must have registered at least as mamy classes as requested
 return (fToRegister & fRegisteredClasses) == fToRegister;
}

step 4:创建窗口  这里用的是CreateEX.代码如下,在WINCORE.CPP中可以看见。

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
  LPCTSTR lpszWindowName, DWORD dwStyle,
  const RECT& rect, CWnd* pParentWnd, UINT nID,
  LPVOID lpParam /* = NULL */)
{
 return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
  pParentWnd->GetSafeHwnd(), (HMENU)nID, lpParam);
}

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)
{
 // allow modification of several common create parameters
 CREATESTRUCT cs;//这个CREATESTRUCT 就是为了能够让程序员在创建窗口之前,修改一些基本的窗口参数
 cs.dwExStyle = dwExStyle;
 cs.lpszClass = lpszClassName;
 cs.lpszName = lpszWindowName;
 cs.style = dwStyle;
 cs.x = x;
 cs.y = y;
 cs.cx = nWidth;
 cs.cy = nHeight;
 cs.hwndParent = hWndParent;
 cs.hMenu = nIDorHMenu;
 cs.hInstance = AfxGetInstanceHandle();
 cs.lpCreateParams = lpParam;

 if (!PreCreateWindow(cs))
 {
  PostNcDestroy();
  return FALSE;
 }

 AfxHookWindowCreate(this);
 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);

 

step 5: 显示 和 更新 窗口

 

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

 

step 6:消息循环   在   ...\MFC\SRC\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
}

知识点补充:我们自己在写一些类的成员函数的时候,比如我们定义了一个CWnd::ShowWindow();但是我们在实现的时候用了SDK的API函数。

就可以这样  BOOL CWnd::ShowWindow(int nCndShow){ ::ShowWindow()}  // ::ShowWindow()这样就是表示调用了SDK的API函数。

 

BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

const RECT& rect 这是一个结构体的引用。结构体本质上也是一种class,于是我们用CRect类的构造函数,声明了一个对象来代替这个结构体。比如,这个参数

就可以设置成为 CRect(0,0,100,100)

 

int CMainFrame::OnCreate();函数专门用来处理窗口创建时的消息int CMfcTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CView::OnCreate(lpCreateStruct) == -1)
  return -1;
 
  m_btn.Create("weixin",WS_CHILD|WS_VISIBLE|BS_AUTO3STATE ,CRect(0,0,100,100),/*GetParent()*/this,123);
  m_btn.ShowWindow(SW_SHOWNORMAL); // TODO: Add your specialized creation code here

 
 return 0;
}
上面的GetParent()是为了得到父窗口的指针,this是theAPP的指针,

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值