2.創建窗口
按照Win32程序編寫步驟,設計窗口類並注冊窗口類之後,應該是創建窗口了。在MFC程序中,窗口的創建功能是由CWnd類的CreateEx函數實現的,該函數的聲明位於AFXWin.h文件中,具體代碼如下所示。
BOOL CreateEx(DWord dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWord dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL);
其實現代碼位於WINCORE.CPP文件中,部分代碼如例3-14所示。
例3-14
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;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
……
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);
……
}
CFrameWnd類的Create函數的聲明也位於AFXWin.h文件中,具體代碼如下所示。
BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWord dwStyle = WS_OVERLAPPEDWINDOW,
const RECT& rect = rectDefault,
CWnd* pParentWnd = NULL, // != NULL for popups
LPCTSTR lpszMenuName = NULL,
DWord dwExStyle = 0,
CCreateContext* pContext = NULL);
其定義位於在WINFRM.CPP文件中,部分代碼如例3-15所示。
例3-15
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWord dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWord dwExStyle,
CCreateContext* pContext)
{
……
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE0("Warning: failed to create CFrameWnd.n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
……
}
CFrameWnd類派生於CWnd類。從上述聲明代碼可知,CWnd類的CreateEx函數不是虛函數。另外,CFrameWnd類中也沒有重寫這個函數。根據類的繼承性原理,CFrameWnd類就繼承了CWnd類的CreateEx函數。因此,例3-15所示CFrameWnd類的Create函數內調用的實際上就是CWnd類的CreateEx函數。讀者可以在這兩個函數的定義處都設置斷點,然後調試運行Test程序以驗證這一點。
再回到例3-14所示CWnd類的CreateEx函數實現代碼中,可以發現該函數中又調用了PreCreateWindow函數,後者是一個虛函數。因此,這裡實際上調用的是子類,即CMainFrame類的PreCreateWindow函數。之所以在這裡再次調用這個函數,主要是為了在產生窗口之前讓程序員有機會修改窗口外觀,例如,去掉窗口的最大化按鈕等,PreCreateWindow函數的參數就是為了實現這個功能而提供的。該參數的類型是CREATETRUCT結構,我們可以把這個結構體與CreateWindowEx函數的參數作一個比較,圖3.19是CREATETRUCT結構和CreateWindowEx函數聲明的一個對比,注意左邊結構體成員與右邊函數參數的對應關系。
圖3.19 CREATETRUCT結構和CreateWindowEx函數定義的對比
可以發現,CREATETRUCT結構體中的字段與CreateWindowEx函數的參數是一致的,只是先後順序相反而已。同時,可以看到PreCreateWindow函數的這個參數是引用類型。這樣,在子類中對此參數所做的修改,在其基類中是可以體現出來的。再看看前面例3-14所示CWnd類的CreateEx函數代碼,如果在子類的PreCreateWindow函數中修改了CREATESTRUCT結構體的值,那麼,接下來調用CreateWindowEx函數時,其參數就會發生相應的改變,從而就會創建一個符合我們要求的窗口。
知識點 MFC中後綴名為Ex的函數都是擴展函數。
3.顯示窗口和更新窗口
在Test程序的應用程序類(CTestApp)中有一個名為m_pMainWnd的成員變量。該變量是一個CWnd類型的指針,它保存了應用程序框架窗口對象的指針。也就是說,是指向CMainFrame對象的指針。在CTestApp類的InitInstance函數實現內部有如下兩句代碼。
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
這兩行代碼的功能是顯示應用程序框架窗口和更新這個窗口。