CWinThread::PumpMessage()line 841 + 30 bytes
CWnd::RunModalLoop(unsignedlong 4) line 3478 + 19 bytes
CDialog::DoModal()line 536 + 12 bytes
CDebugApp::InitInstance()line 59 + 8 bytes
AfxWinMain(HINSTANCE__* 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 39 + 11bytes
WinMain(HINSTANCE__ *0x00400000, HINSTANCE__ * 0x00000000, char * 0x00141f00, int 1) line 30
WinMainCRTStartup()line 330 + 54 bytes
KERNEL32! 7c816d4f()
这里,CDebugDialog::OnOK作为整个调用链中最后被调用的函数出现在callstack的最上方,而内核中程序的启动函数Kernel32! 7c816d4f()则作为栈底出现在最下方。
实例二:学习处理方法
微软提供了MDI/SDI模型提供文档处理的建议结构。有些时候,大家希望控制某个环节。例如,我们希望弹出自己的打开文件对话框,但是并不想自己实现整个文档的打开过程,而更愿意MFC完成其他部分的工作。可是,我们并不清楚MFC是怎么处理文档的,也不清楚如何插入自定义代码。
幸运的是,我们知道当一个文档被打开以后,系统会调用CDocument派生类的Serialize函数,我们可以利用这一点来跟踪MFC的处理过程。
我们首先创建一个缺省的SDI工程Test1,并在CTest1Doc::Serialize函数的开头增加一个断点,运行程序,并打开一个文件。这时,我们可以看到调用堆栈是(我只截取了感兴趣的一段):
CTest1Doc::Serialize(CArchive& {...}) line 66
CDocument::OnOpenDocument(constchar * 0x0012f54c) line 714
CSingleDocTemplate::OpenDocumentFile(constchar * 0x0012f54c, int 1) line 168 + 15 bytes
CDocManager::OpenDocumentFile(constchar * 0x0042241c) line 953
CWinApp::OpenDocumentFile(constchar * 0x0042241c) line 93
CDocManager::OnFileOpen()line 841
CWinApp::OnFileOpen()line 37
_AfxDispatchCmdMsg(CCmdTarget* 0x004177f0 class CTest1App theApp, unsigned int 57601, int 0, void (void)*0x00402898 CWinApp::OnFileOpen, void * 0x00000000, unsigned int 12,AFX_CMDHANDLERINFO * 0x00000000) line 88
CCmdTarget::OnCmdMsg(unsignedint 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 302+ 39 bytes
CFrameWnd::OnCmdMsg(unsignedint 57601, int 0, void * 0x00000000, AFX_CMDHANDLERINFO * 0x00000000) line 899+ 33 bytes
CWnd::OnCommand(unsignedint 57601, long 132158) line 2088
CFrameWnd::OnCommand(unsignedint 57601, long 132158) line 317
从上面的调用堆栈看,这个过程由一个WM_COMMAND消息触发(因为我们用菜单打开文件),由CWinApp::OnFileOpen最先开始实际处理过程,这个函数调用CDocManager::OnFileOpen打开文档。
我们首先双击CWinApp::OnFileOpen() line 37打开CWinApp::OnFileOpen,它的处理过程是:
ASSERT(m_pDocManager != NULL);
m_pDocManager->OnFileOpen();
m_pDocManager是一个CDocManager类的实例指针,我们双击CDocManager::OnFileOpen行,看该函数的实现:
voidCDocManager::OnFileOpen()
{
// prompt the user (with all documenttemplates)
CString newName;
if (!DoPromptFileName(newName,AFX_IDS_OPENFILE,
OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE,NULL))
return; // open cancelled
AfxGetApp()->OpenDocumentFile(newName);
// if returns NULL, the user has already beenalerted
}
很显然,该函数首先调用DoPromptFileName函数来获得一个文件名,然后在继续后续的打开过程。
顺这这个线索下去,我们一定能找到插入我们文件打开对话框的位置。由于这不是我们研究的重点,后续的分析我就不再详述。
实例三:内存访问越界
在Debug版本的VC程序中,程序会给每块new出来的内存,预留几个字节作为越界检测之用。在释放内存时,系统会检查这几个字节,判断是否有内存访问越界的可能。
我们借用前一个实例程序,在CTest1App::InitInstance的开头添加以下几行代码:
char * p = new char[10];
memset(p,0,100);
delete []p;
return FALSE;
很显然,这段代码申请了10字节内存,但是使用了100字节。我们在memset(p,0,100);这行加一个断点,然后执行程序,断点到达后,我们观察p指向的内存的值(利用Debug工具条的Memory功能),可以发现它的值是:
CD