⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 03.2.2 mfc框架窗口(1).txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
字号:
3.2.2  MFC框架窗口
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 %s\n",

            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] = '\0';

            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函数之后,窗口产生之前注册窗口类的。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -