程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> VC++深入詳解:MFC框架窗口(1)

VC++深入詳解:MFC框架窗口(1)

編輯:vc教程

  1.設計和注冊窗口

  有了WinMain函數,根據創建Win32應用程序的步驟,接下來應該是設計窗口類和注冊窗口類了。MFC已經為我們預定義了一些默認的標准窗口類,只需要選擇所需的窗口類,然後注冊就可以了。窗口類的注冊是由AfxEndDeferRegisterClass函數完成的,該函數的定義位於WINCORE.CPP文件中。其定義代碼較長,由於篇幅所限,在這裡僅列出部分代碼,如例3-10所示。

  例3-10

  BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
  {
  ……
    // common initialization
    WNDCLASS wndcls;
    memset(&wndcls, 0, sizeof(WNDCLASS));  // start with NULL defaults
  ① wndcls.lpfnWndProc = DefWindowProc;
    wndcls.hInstance = AfxGetInstanceHandle();
    wndcls.hCursor = afxData.hcurArrow;
  ……
    // 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_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;
    }
  ……
  }

  從例3-10所示代碼可知,AfxEndDeferRegisterClass函數首先判斷窗口類的類型,然後賦予其相應的類名(wndcls.lpszClassName變量),這些類名都是MFC預定義的。之後就調用AfxRegisterClass函數注冊窗口類,後者的定義也位於WINCORE.CPP文件中,代碼如例3-11所示。

  例3-11

  BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
  {
    WNDCLASS wndcls;
    if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
      &wndcls))
    {
      // class already registered
      return TRUE;
    }
    if (!::RegisterClass(lpWndClass))
    {
      TRACE1("Can't register window class named %sn",
        lpWndClass->lpszClassName);
      return FALSE;
    }
    if (afxContextIsDLL)
    {
      AfxLockGlobals(CRIT_REGCLASSLIST);
      TRY
      {
        // class registered successfully, add to registered list
        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
        LPTSTR lpszUnregisterList = pModuleState->m_szUnregisterList;
        // the buffer is of fixed size -- ensure that it does not overflow
        ASSERT(lstrlen(lpszUnregisterList) + 1 +
          lstrlen(lpWndClass->lpszClassName) + 1 <
          _countof(pModuleState->m_szUnregisterList));
        // append classname + newline to m_szUnregisterList
        lstrcat(lpszUnregisterList, lpWndClass->lpszClassName);
        TCHAR szTemp[2];
        szTemp[0] = 'n';
        szTemp[1] = '';
        lstrcat(lpszUnregisterList, szTemp);
      }
      CATCH_ALL(e)
      {
        AfxUnlockGlobals(CRIT_REGCLASSLIST);
        THROW_LAST();
        // Note: DELETE_EXCEPTION not required.
      }
END_CATCH_ALL
      AfxUnlockGlobals(CRIT_REGCLASSLIST);
    }
    return TRUE;
  }

  從例3-11所示代碼可知,AfxRegisterClass函數首先獲得窗口類信息。如果該窗口類已經注冊,則直接返回一個真值;如果尚未注冊,就調用RegisterClass函數注冊該窗口類。讀者可以看出這個注冊窗口類函數與第2章介紹的Win32 SDK編程中所使用的函數是一樣的。

  小技巧:如果在當前工程文件中查找某個函數或字符串,可以利用工具欄上的“Find in Files”工具按鈕或Edit菜單下的Find in Files命令;如果在當前文件中查找某個函數或字符串,可以使用Ctrl+F快捷鍵或Edit菜單下的Find命令。

  我們創建的這個MFC應用程序Test,實際上有兩個窗口。其中一個是CMainFrame類的對象所代表的應用程序框架窗口。該類有一個PreCreateWindow函數,這是在窗口產生之前被調用的。該函數的默認實現代碼如例3-12所示。

  例3-12

  BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
  {
    if( !CFrameWnd::PreCreateWindow(cs) )
      return FALSE;
    // TODO: Modify the Window class or styles here by modifying
    // the CREATESTRUCT cs
    return TRUE;
  }

  從其代碼可知,該函數首先調用CFrameWnd的PreCreateWindow函數。後者的定義位於源文件WINFRM.CPP中,代碼如例3-13所示。

  例3-13

  BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
  {
    if (cs.lpszClass == NULL)
    {
      VERIFY(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;
  }


  我們發現該函數中調用了AfxDeferRegisterClass函數,讀者可以在AFXIMPL.H文件中找到後者的定義,定義代碼如下:

  #define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

  由其定義代碼可以發現,AfxDeferRegisterClass實際上是一個宏,真正指向的是AfxEndDefer-RegisterClass函數。根據前面介紹的內容,我們知道這裡完成的功能就是注冊窗口類。

  在CMainFrame類的PreCreateWindow函數處設置一個斷點,調試運行Test程序,將會發現程序在調用theApp全局對象和WinMain函數之後,到達此函數處。由此,我們知道MFC程序執行的脈絡也是在WinMain函數之後,窗口產生之前注冊窗口類的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved