目录
AfxEndDeferRegisterClass 函数,窗口类的注册(wincore.cpp):
PreCreateWindow函数(MainFrm.cpp):
AfxDeferRegisterClass函数(afximpl.h):
接上:VC++MFC程序中的WinMain函数(五)InitInstance函数
接下:MFC框架窗口(二)AfxEndDeferRegisterClass 函数(wincore.cpp)
MFC框架窗口
1.设计和注册窗口
有了 WinMain 函数,根据创建 Win32应用程序的步骤,接下来设计窗口类和注册窗口类。MFC已经为我们预定义了一些默认的标准窗口类,只需要选择所需的窗口类,然后注册就可以了。窗口类的注册是由 AfxEndDeferRegisterClass 函数完成的,该函数的定义位于 wincore.cpp 文件中,如下。
AfxEndDeferRegisterClass 函数,窗口类的注册(wincore.cpp):
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;
}
...
}
连接:MFC框架窗口(二)AfxEndDeferRegisterClass 函数
从以上代码可知,AfxEndDeferRegisterClass函数首先判断窗口类的类型,然后赋予其相应的类名(wndcls.lpszClassName变量),这些类名都是MFC预定义的。之后调用AfxRegisterClass函数注册窗口类,后者的定义也位于wincore.cpp 文件中,代码如下。
AfxRegisterClass函数,注册窗口类:
// like RegisterClass, except will automatically call UnregisterClass
// 和RegisterClass一样,except会自动调用UnregisterClass
BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)
{
WNDCLASS wndcls;//获得窗口类信息
if (GetClassInfo(lpWndClass->hInstance, lpWndClass->lpszClassName,
&wndcls))
{
// class already registered
return TRUE;//如果该窗口类已经注册,则直接返回一个真值
}
if (!RegisterClass(lpWndClass))//如果尚未注册,就调用RegisterClass函数注册该窗口类
{
TRACE(traceAppMsg, 0, _T("Can't register window class named %Ts\n"),
lpWndClass->lpszClassName);
return FALSE;
}
BOOL bRet = TRUE;
if (afxContextIsDLL)
{
AfxLockGlobals(CRIT_REGCLASSLIST);
TRY
{
// class registered successfully, add to registered list
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_strUnregisterList+=lpWndClass->lpszClassName;
pModuleState->m_strUnregisterList+='\n';
}
CATCH_ALL(e)
{
AfxUnlockGlobals(CRIT_REGCLASSLIST);
THROW_LAST();
// Note: DELETE_EXCEPTION not required.
}
END_CATCH_ALL
AfxUnlockGlobals(CRIT_REGCLASSLIST);
}
return bRet;
}
AfxRegisterClass函数首先获得窗口类信息。如果该窗口类已经注册,则直接返回一个真值;如果尚未注册,就调用RegisterClass函数注册该窗口类。
小技巧: 如果在当前文件中查找某个函数或字符串,那么可以使用“Ctrl+F”快捷键。
MFC 应用程序 Test,实际上有两个窗口。其中一个是CMainFrame类(MainFrm.h)的对象所代表的应用程序框架窗口,该类有一个PreCreateWindow函数,这是在窗口产生之前被调用的。该函数的默认实现代码如下所示。
PreCreateWindow函数(MainFrm.cpp):
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return TRUE;
}
该函数首先调用CFrameWnd的PreCreateWindow函数。后者的定义位于源文件winfrm.cpp中,代码下。
/
// CFrameWnd second phase creation
// CFrameWnd第二阶段创建
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)
cs.style |= FWS_PREFIXTITLE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
return TRUE;
}
该函数中调用了AfxDeferRegisterClass函数,读者可以在afximpl.h文件中找到后者的定义,定义代码如下:
AfxDeferRegisterClass函数(afximpl.h):
#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)
AfxDeferRegisterClass 实际上是一个宏,真正指向的是AfxEndDeferRegisterClass函数。这里完成的功能就是注册窗口类。在CMainFrame类的PreCreateWindow函数处设置一个断点,调试运行Test程序,将会发现程序在调用theApp全局对象和WinMain函数之后,到达此函数处。由此知道MFC程序执行的脉络也是在WinMain函数之后、窗口产生之前注册窗口类的。