续: 浅谈 MFC 的子类化机制和该机制的一个应用( 1 )
BOOL CDumpMsgBox::OnDumpOut(LPSTR pszDumpBuffer, UINT nBufferSize)
{
ASSERT(pszDumpBuffer != NULL && nBufferSize != 0);
ASSERT(AfxIsValidString(pszDumpBuffer, nBufferSize));
// calculate '\n' occur times in buffer.
int nPosition, nLine = 0;
for (nPosition = 0; nPosition < (int)nBufferSize; nPosition ++)
{
if (pszDumpBuffer[nPosition] == '\0')
break;
if (pszDumpBuffer[nPosition] == '\n')
nLine ++;
}
// alloc enough memory for convert.
TCHAR *pszBuffer = (TCHAR*)malloc(sizeof (TCHAR) * (nPosition + nLine + 64));
// convert all '\n' '\r' or '\n\r' to '\r\n':
TCHAR *pszConvert = pszBuffer;
for (nPosition = 0; nPosition < (int)nBufferSize; nPosition ++)
{
if (pszDumpBuffer[nPosition] == '\0')
break ;
if (pszDumpBuffer[nPosition] == '\r')
continue ;
if (pszDumpBuffer[nPosition] == '\n')
{
*pszConvert = _T('\r');
pszConvert ++;
}
*pszConvert = (TCHAR)pszDumpBuffer[nPosition];
pszConvert ++;
}
// set end of string.
*pszConvert = '\0';
// set converted dump buffer to the edit control.
m_editDump.AssertValid();
m_editDump.SetWindowText(pszBuffer);
free(pszBuffer);
return TRUE;
}
int CDumpMsgBox::DoMessageBox(UINT nIDPrompt, UINT nType, UINT nIDHelp)
{
CString string;
if (!string.LoadString(nIDPrompt))
{
TRACE1("CDumpMsgBox::DoMessageBox error: failed to load message box prompt string 0x%04x.\n",
nIDPrompt);
ASSERT(FALSE);
}
if (nIDHelp == (UINT)-1)
nIDHelp = nIDPrompt;
return DoMessageBox(string, nType, nIDHelp);
}
int CDumpMsgBox::DoMessageBox(LPCTSTR lpszText, UINT nType, UINT nIDHelp)
{
int nRetCode;
// not call PreCreateWindow to initialize CREATESTRUCT data.
AfxHookWindowCreate(this );
nRetCode = AfxMessageBox(lpszText, nType, nIDHelp);
if (!AfxUnhookWindowCreate())
PostNcDestroy();
return nRetCode;
}
void CDumpMsgBox::DoDumpObject(CObject* pDumpObject)
{
m_fileDump.AssertValid(); // dump target must exist.
ASSERT(pDumpObject != NULL);
CRuntimeClass* pClass = pDumpObject->GetRuntimeClass();
if (pClass == NULL)
return ; // unexpect runtime-class value.
if (AfxIsValidAddress(pDumpObject, pClass->m_nObjectSize, TRUE))
{
#ifdef _DEBUG
pDumpObject->Dump(m_dumpContext);
#else // ! _DEBUG
m_dumpContext << "a " << pClass->m_lpszClassName <<
" at " << (void*)pDumpObject;
m_dumpContext << "\nHex Dumps: " << pClass->m_nObjectSize <<
" bytes long.\n";
m_dumpContext.HexDump(_T("HEX"), (BYTE*)pDumpObject,
pClass->m_nObjectSize, 8);
#endif // _DEBUG
}
}
#ifdef _DEBUG
void CDumpMsgBox::AssertValid() const
{
CWnd::AssertValid();
if (m_editDump.GetSafeHwnd())
m_editDump.AssertValid();
ASSERT(AfxIsValidAddress(&m_dumpContext, sizeof(CDumpContext), TRUE));
m_fileDump.AssertValid();
}
void CDumpMsgBox::Dump(CDumpContext& dc) const
{
if (m_hWnd == NULL)
{
CObject::Dump(dc);
dc << "m_hWnd = NULL\n";
}
else
CWnd::Dump(dc);
if (0 < dc.GetDepth())
{
dc << "include ";
if (NULL == m_editDump.GetSafeHwnd())
{
m_editDump.CObject::Dump(dc);
dc << "m_hWnd = NULL\n";
}
else
m_editDump.Dump(dc);
dc << "include ";
m_fileDump.Dump(dc);
}
}
#endif // _DEBUG
代码较为简单,为 MessageBox 增加了一个 Edit Control ,属性为 ES_MULTILINE , ES_READONLY , ES_AUTOVSCROLL ,并且拥有 WS_EX_CLIENTEDGE 属性。
该 Edit Control 的内容通过 CMemFile 和 CDumpContext 生成。构造函数 CDumpContext( CFile* pFile ) 可以生成一个以 CMemFile 为目标的 CDumpContext 实例,然后调用 CObject::Dump ,最后通过 CMemFile::Detach 得到包含输出字符串的缓冲区。
以下是 CDumpMsgBox 的应用示例:
CDumpMsgBox msgBox; // declare intsance
msgBox.DoDumpObject(&msgBox); // dump itself
msgBox.DoMessageBox(_T("This message box used class CDumpMsgBox."), MB_OKCANCEL); // display
以上代码在 MS Visual C++ 6.0, Win98 下调试通过。