按惯例,这一篇文章主要还是作者读《深入浅出MFC》整理的一些笔记。除此之外,你还可以在Windows文档或者在你的VS库中找到对应的源代码来读一读。Windows文档主要为:https://learn.microsoft.com/zh-cn/cpp/mfc/reference/mfc-classes?view=msvc-160。VS库路径主要为(如果你是找MFC的话)“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc”。
CWnd构造函数
如上面所说,你应该在“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc”里搜索CWnd的构造函数,这很简单,一般类的构造函数就是类名本身,所以你只需要在src文件夹中批量搜索以下关键字就行:“CWnd::CWnd”,具体搜索方法可以用notepad++。下面是找到的在路径\wincore.cpp中描述的CWnd构造函数
CWnd::CWnd() : CWnd(NULL)
{
}
CWnd::CWnd(HWND hWnd)
{
m_hWnd = hWnd;
m_pStdObject = NULL;
m_bEnableActiveAccessibility = false;
m_bIsTouchWindowRegistered = FALSE;
m_pProxy = NULL;
m_hWndOwner = NULL;
m_nFlags = 0;
m_pfnSuper = NULL;
m_nModalResult = 0;
m_pDropTarget = NULL;
m_pCtrlCont = NULL;
m_pCtrlSite = NULL;
m_pMFCCtrlContainer = NULL;
m_ptGestureFrom = CPoint(-1, -1);
m_ulGestureArg = 0;
m_bGestureInited = FALSE;
m_pCurrentGestureInfo = NULL;
m_pRenderTarget = NULL;
m_pDynamicLayout = NULL;
}
意料之外情理之中吧,本身CWnd就是一个很虚的类,想从这里捏造一个实际用的东西还有很多参数要填充,下面那个HWND意思是,如果你new一个CWnd这么写:
CWnd Cw;//会自动执行CWnd()函数
CWnd Cw(HWND hWnd);//会自动执行CWnd(HWND hWnd)函数
CWnd子类主要分为四种:Frame(框架)、Dialog(对话框)、View(视图)、Control(控件)。
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);
}
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
LPVOID lpParam /* = NULL */)
{
// 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(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd->GetSafeHwnd(), reinterpret_cast<HMENU>(static_cast<INT_PTR>(nID)), lpParam);
}
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)
{
ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
AfxIsValidAtom(lpszClassName));
ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
// allow modification of several common create parameters
CREATESTRUCT cs;
cs.dwExStyle = dwExStyle;
cs.lpszClass = lpszClassName;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.x = x;
cs.y = y;
cs.cx = nWidth;
cs.cy = nHeight;
cs.hwndParent = hWndParent;
cs.hMenu = nIDorHMenu;
cs.hInstance = AfxGetInstanceHandle();
cs.lpCreateParams = lpParam;
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);
#ifdef _DEBUG
if (hWnd == NULL)
{
TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8X\n",
GetLastError());
}
#endif
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook
return TRUE;
}
CDialog构造函数
在“…\VS\IDE\VC\Tools\MSVC\14.34.31933\atlmfc\src\mfc”里可以找到CWnd的一个常见子类CDialog
CDialog::CDialog()
{
ASSERT(m_hWnd == NULL);
Initialize();
}
void CDialog::Initialize()
{
m_nIDHelp = 0;
m_lpszTemplateName = NULL;
m_hDialogTemplate = NULL;
m_lpDialogTemplate = NULL;
m_lpDialogInit = NULL;
m_pParentWnd = NULL;
m_hWndTop = NULL;
m_pOccDialogInfo = NULL;
m_bClosedByEndDialog = FALSE;
}
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
{
ASSERT(IS_INTRESOURCE(lpszTemplateName) ||
AfxIsValidString(lpszTemplateName));
m_lpszTemplateName = lpszTemplateName; // used for help
if (IS_INTRESOURCE(m_lpszTemplateName) && m_nIDHelp == 0)
m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);
#ifdef _DEBUG
if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE))
{
ASSERT(FALSE); // invalid dialog template name
PostNcDestroy(); // cleanup if Create fails too soon
return FALSE;
}
#endif //_DEBUG
HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG);
if(hResource == NULL)
{
return FALSE;
}
HGLOBAL hTemplate = LoadResource(hInst, hResource);
if(hTemplate == NULL)
{
return FALSE;
}
BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hInst);
FreeResource(hTemplate);
return bResult;
}
本质上,CWnd类是在跟操作系统打交道,窗口在使用前需要去操作系统注册报道,构造CWnd的时候需要定义类自身变量,等到了使用CWnd的时候,如果没有WinApp之类的其他类帮忙,是需要主动去操作系统注册的。