按惯例,这一篇文章主要还是作者读《深入浅出MFC》整理的一些笔记。
CFrameWnd产生、注册窗口
CFrameWnd类作为最常用的窗口类,其定义在“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc\winfrm.cpp”中。
这里说一些我个人的看法,为什么通过头文件总会绕的云里雾里,就比如说这个CMyWinApp类,内部各函数、各变量,最终都会由头文件统一汇总的,以至于从头文件的角度看CMyWinApp足足由5000行代码之多,代码量达到一篇文献的水平,读懂它就会变得很困难。看山看不全,那么我们就只好沿一条上山的路,看一路的风景,而最简单最基础的一路,就是被MFC所雪藏的winmain函数这一路径(参考之前的博客)。
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
{
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
{
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, ATL_RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
{
TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
}
m_strTitle = lpszWindowName; // save title for later
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))
{
TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
}
return TRUE;
}
类的构造函数,类的一些重要函数,都在这个文件之中。如果你在新版本的VS中使用的是dialog对话框作为你的起始窗口的话,那么久不是frame类了,不论是frame类还是dialog类,都是CWnd的子类,我们可以观察CWnd的内容:“wincore.cpp”。这里我们重点就说标准构造函数:
BOOL CWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext)
{
// can't use for desktop or pop-up windows (use CreateEx instead)
ASSERT(pParentWnd != NULL);
ASSERT((dwStyle & WS_POPUP) == 0);
if (((dwStyle & WS_TABSTOP) == WS_TABSTOP) && (nID == 0))
{
// Warn about nID == 0. A zero ID will be overridden in CWnd::PreCreateWindow when the
// check is done for (cs.hMenu == NULL). This will cause the dialog control ID to be
// different than passed in, so ::GetDlgItem(nID) will not return the control HWND.
TRACE(traceAppMsg, 0, _T("Warning: creating a dialog control with nID == 0; ")
_T("nID will overridden in CWnd::PreCreateWindow and GetDlgItem with nID == 0 will fail.\n"));
}
// About nID: In x64 HMENU is 64 bits while UINT is 32 bits (unfortunately).
// HMENU only actually uses 32 bits, sign extended to 64 bits.
// Those bits are getting dropped in UINT, so sign extend here to restore them.
return CreateEx(0, lpszClassName, lpszWindowName,
dwStyle | WS_CHILD,
rect.left, rect.top,
rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), reinterpret_cast<HMENU>(static_cast<INT_PTR>(nID)), (LPVOID)pContext);
}
}
这是原文的标准构造函数,不论你创立的是何种类型的窗口,都应该走上面这段代码。CWnd的具体内容在文档。
lpszClassName:指向以 null 结尾的字符串的指针,该字符串包含已注册的系统窗口类的名称;或者为预定义的系统窗口类的名称。
lpszWindowName:指向以 null 结尾的字符串的指针,该字符串包含窗口显示名称;否则为 NULL,表示没有窗口显示名称。
dwStyle:窗口样式的按位组合 (OR)。 WS_POPUP 选项不是有效样式。
rect:窗口相对于父窗口左上角的大小和位置。
pParentWnd:指向父窗口的指针。
nID:窗口的 ID。
pContext:指向 CCreateContext 结构的指针,该结构用于自定义应用程序的文档视图体系结构。