我們現在再來看看AfxDeferRegisterClass是什麼樣子的:
#define AfxDeferRegisterClass(fClass) \
((afxRegisteredClasses & fClass) ? TRUE:AfxEndDeferRegisterClass(fClass)
#define afxRegisteredClasses AfxGetModuleState()->m_fRegisteredClasses
BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
{
WNDCLASS wndCls;
wndCls.lpfnWndProc = DefWindowProc;
if(fClass & AFX_WND_REG)
{
wndCls.lpszClassName=_afxWnd;
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDOLECONTROL_REG)
{
wndCls.lpszClassName=_afxWndOleControl;
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDCONTROLBAR_REG)
{
wndCls.lpszClassName=_afxWndControlBar;
AfxRegisterClass(&wndCls);
}else if(fClass & AFX_WNDMDIFRAME_REG)
{
RegisterWithIcon(&wndCls,_afxWndMDIFrame,AFX_IDI_MDIFRAME);
}else if(fClass & AFX_WNDFRAMEORVIEW_REG)
{
RegisterWithIcon(&wndCls,_afxWndFrameOrView,AFX_IDI_STD_FRAME);
}else if(fClass & AFX_WNDCOMMCTLS_REG)
{
InitCommonControls();
}
}
從上面的代碼可以看出,AfxDeferRegisterClass函數首先判斷該窗口類是否注冊,如已注冊則直接返回,否則調用AfxEndDeferRegisterClass進行注冊,即注冊要求的默認窗口類。其中RegisterWithIcon和InitCommonControls最終也是轉化為調用AfxRegisterClass,而AfxRegisterClass函數調用RegisterClass進行注冊,啊,終於看到SDK中的RegisterClass了,看到它總有一種親切感!
有了上面的知識,我們就可以很容易摸清MFC是怎樣注冊窗口類的了!我們知道Windows上所有看得見的東西,在MFC中都是繼承於CWnd類的,而CWnd類創建窗口的成員函數是Create和CreateEx,由於Create最終是調用CreateEx,所以我們只需要看CreateEx函數就行了:
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCSTSTR lpszClassName,
…… LPVOID lpParam)
{
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
… …
cs.lpCreateParams = lpParam;
PreCreateWindow(cs);
AfxHookWindowCreate(this);
HWND hWnd=::CreateWindowEx(cs.dwStyle,cs.lpszClass,…,cs.lpCreateParams);
……
}
啊,一看到CreateWindowEx,親切感又來了,這不是和SDK中的CreateWindow一樣嘛,是創建窗口!既然這樣,那麼注冊窗口肯定在該函數之前,會是誰呢?如果你做過一點MFC程序,你就會對將眼光停留PreCreateWindow上。對!就是它了。
PreCreateWindow函數是CWnd類的一個虛擬函數,提供程序設置待創建窗口的屬性(包括窗口類),這樣繼承於CWnd的類都可以按照自己的要求在PreCreateWindow中設置自己的屬性了,而且我們看到MFC也是這樣做的:
BOOL CWnd::PreCreateWindow(CREATESTRUCT &cs)
{
if(cs.lpszClass = = NULL)
{
AfxDeferRegisterClass(AFX_WND_REG);
cs.lpszClass = _afxWnd;
}
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
if(cs.lpszClass = = NULL)
{
AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
cs.lpszClass = _afxWndFrameOrView;
}
return TRUE;
}
BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
if(cs.lpszClass = = NULL)
{
AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG);
cs.lpszClass = _afxWndMDIFrame;
}
}
BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT &cs)
{
return CFrameWnd::PreCreateWindow(cs);
}
BOOL CView::PreCreateWindow(CREATESTRUCT &cs)
{
if(cs.lpszClass = = NULL)
{
AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
cs.lpszClass = _afxWndFrameOrView;
}
}
就是通過繼承的方法,MFC實現常用類的窗口注冊(代碼並不完全,是從MFC中抽取對我們有意義的一部分代碼)。
四.在MFC中注冊自己的窗口類
在MFC中創建一個窗口,就必須是繼承於CWnd類的,這樣你的CMyWnd類自然就有了PreCreateWindow方法。你想注冊有自己個性的窗口類,那麼就在該函數中進行吧。也就是在PreCreateWindow函數中注冊自己的窗口類,然後將窗口類的類名以及待創建窗口的其它屬性(見CREATESTRUCT結構)填寫cs,然後返回系統,供系統創建你的窗口。