??xml version="1.0" encoding="utf-8" standalone="yes"?>
http://www.wholetomato.com/
VA?.0一直到现在的VAXQ功能越来越强大Q除了以前版本中的自动识别各U关键字Q系l函敎ͼ成员变量Q自动给入提C,自动更正大小写错误,自动标示错误{等以外Q最新的版本中还?br />
WorkSpaceH口中加入一个VA ViewQ可以更方便的查扑ַE中的文件、类和变量?br />
2.WndTabsQ强烈推荐)
http://www.wndtabs.com/
WndTabs主要是在~辑H口中显CZ所有已l打开的文Ӟ在VC中能够更方便的操作这些文Ӟ比如修改文g属性,copy文g路径、文件名{,q且q开放源代码Q你要是愿意的话Q可以添加自己很兴趣的功能?br />
3.LineCounter
http://www.wndtabs.com/
用来l计整个工程的代码行敎ͼ包括总行数、代码行数、注释行数、空行数{,q且对多个工E一L(fng)计时Q不?x)把相同的文件计多?
4.Spelly
http://www.wndtabs.com/
一个拼写检查的插gQ可以对整个文g或所选部分进行拼写检查,支持C/C++/C#, VB, Fortran 和HTML?br />
5.SourceStyler C++
http://www.sourcestyler.com/
此插件是针对C++的一个格式化工具Q可以针对自q~码?fn)惯Q选择一U编码风|也可以自己定义,而且定义非常详细Q有表达式、指针、模ѝ类、枚丄十几U,肯定能满你的需要?br />
6.Numega BoundsCheckerQ强烈推荐)
下蝲Q百度一?#8230;…
是针对Visual C++6.0应用E序的最为全面的错误工兗BoundsChecker 能自动指出静态,堆栈内存错误和资源泄漏问题。BoundsChecker 能够校验最新的 Windows APIsQ包?nbsp;ActiveX, DirectX, OLE/COM, ODBC{等。能够发C Windows q_兼容性?br />
7.BCGControlBar Library
下蝲Q百度一?#8230;…
非常好的一套应用于vc6的界面扩展类库,L的作?nbsp;vc2003 的界面。ƈ且给了各U界面例子,如vc.net、outlook、更换皮肤等{?br />
8.Comment Wizard
下蝲Q百度一?#8230;…
Visual C++插gQ提供了Visual C++源代码注解标准化与自动化功能。在它的帮助下,(zhn)可快速创建标头文件信息注解,文g中模块注解, C++处理方式Q以?qing)E语言功能与历史校正功能注解,{等?br />
]]>
目录
W一章找回WinMain函数 2
W二章InitApplication()函数 2
W三章InitInstance ()函数 3
W一节:(x)new CSingleDocTemplate 3
W二节:(x)AddDocTemplate(pDocTemplate); 5
W三节:(x)ProcessShellCommand(cmdInfo) 5
W一DA(ch)fxGetApp()->OnCmdMsg(…) 6
W二DOnFileNew(); 6
W四?Qm_pMainWnd->ShowWindow(SW_SHOW); ///昄H口 8
W五?Qm_pMainWnd-> UpdateWindow (); ///重画H口 8
W四章pApp->Run函数 8
W五章ȝ 8
本文针对一个单文来描qMFC的文?视图l构Q他直接打开MFC的源代码q行分析Q在分析q程中去掉了无关的部分。所以第一步就是要创徏一个称为First得工E,文档cd是单文Q下文将围绕q个工程来讲的?br />
W一章找回WinMain函数
首先?a target="_blank">VC的安装\径中扑ֈWINMAIN.CPP文gQAfxWinMain函数是VC~译器的入口Q去掉一些不重要的东西后得到如下得程序?br />
int AFXAPI AfxWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{
int nReturnCode = -1;
CWinApp* pApp = AfxGetApp(); ///获取应用E序cȝ指针与文视图无兟?br />
AfxWinInit(hInstance, hPrevInstance,lpCmdLine,nCmdShow); ///与文视图无兟?br />
pApp->InitApplication(); ///初始化应用程序详见下文?br />
pApp->InitInstance(); ///最重要下面述
nReturnCode = pApp->Run();///消息循环直到应用E序被关闭。与文档视图无关?br />
AfxWinTerm(); ///与文视图无兟?br />
return nReturnCode;///整个应用l束?br />
}
下面分节讲述?br />
W二章InitApplication()函数
在文件Appcore.cpp文g中InitApplication如下Q?br />
BOOL CWinApp::InitApplication()
{
if (CDocManager::pStaticDocManager != NULL) ///q段和我们关pM?暂时不理?br />
{
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocManager;
CDocManager::pStaticDocManager = NULL;
}
if (m_pDocManager != NULL)
m_pDocManager->AddDocTemplate(NULL);
else
CDocManager::bStaticInit = FALSE; /*我们的程序将?x)执行到q句,表示文档cȝ动态方式创?也就是说用RUNTIME_CLASS来创建的(详见下文)?/
return TRUE;
}
说明QCDocManagercL一个不公开的类Q他主要用来理多文模板对象的Q对于单文只有一个文档模板这个类不是很重要,但还是用它管理文模板的Q本文只在相关之处作说明。bStaticInit是它的一个静态成员?br />
W三章InitInstance ()函数
它一般被重蝲Q在First工程中,InitInstance中和文视图cL关的E序有下面的一些:(x)
CSingleDocTemplate* pDocTemplate; ///定义指针
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CFirstDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CFirstView)); ///q条语句的作用见W一D?br />
AddDocTemplate(pDocTemplate);
CCommandLineInfo cmdInfo; ///定义一个对?br /> ParseCommandLine(cmdInfo); ///解析命o(h)行ƈ发送参敎ͼ与文视图无?/p>
if (!ProcessShellCommand(cmdInfo)) ///q是最重要的详见的三段
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOW); ///昄H口
m_pMainWnd->UpdateWindow();
W一节:(x)new CSingleDocTemplate
new CSingleDocTemplate其实是创徏一个CSingleDocTemplate对象q调用他的构造函敎ͼ要讲清楚q句话,首先必须明白RUNTIME_CLASSl构QRUNTIME_CLASSl构定义如下Q?br />
#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
于是q句话展开后如?关于W合##的具体意义参见MSDN)Q?br />
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
(CRuntimeClass*)(&CFirstDoc::classCFirstDoc),
(CRuntimeClass*)(&CMainFrame::classCMainFrame),
(CRuntimeClass*)(&CFirstView::classCFirstView));
q时我们?x)发现CfirstDocQCmainFrameQCfirstView各会(x)多冒Z个静态成员出来,它究竟在哪里呢?查看q三个类的定义我们会(x)发现每个cd义都有一个宏DECLARE_DYNCREATEQ在实现文g中有另外一个宏IMPLEMENT_DYNCREATE。下面把q些宏的展开情况列出如下Q?br />
Q?Q文档类
DECLARE_DYNCREATE(CFirstDoc) 展开后ؓ(f)Q?br />
public:
static const CRuntimeClass classCFirstDoc; ///q就是上面所说的那个静态成?br />
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
IMPLEMENT_DYNCREATE(CFirstDoc, CDocument) 展开后ؓ(f)Q?br />
CObject* PASCAL CFirstDoc::CreateObject()
{ return new CFirstDoc; }
const CRuntimeClass CFirstDoc::classCFirstDoc= {
"CFirstDoc", sizeof(class CFirstDoc), 0xFFFF, CFirstDoc::CreateObject, (CRu
ntimeClass*)(&CDocument::classCDocument), NULL };
CRuntimeClass* CFirstDoc::GetRuntimeClass() const
{ return (CRuntimeClass*)(&CFirstDoc::classCFirstDoc); }
Q?Q视囄
DECLARE_DYNCREATE(CFirstView) 展开后ؓ(f)Q?br />
public:
static const CRuntimeClass classCFirstView;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
IMPLEMENT_DYNCREATE(CFirstView, CView) 展开后ؓ(f)Q?br />
CObject* PASCAL CFirstView::CreateObject()
{ return new CFirstView; }
const CRuntimeClass CFirstView::classCFirstView = {
" CFirstView ", sizeof(class CFirstView), 0xFFFF, CFirstView::CreateObject, (CRu
ntimeClass*)(&CView::classCView), NULL };
CRuntimeClass* CFirstView::GetRuntimeClass() const
{ return (CRuntimeClass*)(& CFirstView::classCFirstView); }
Q?Q主框架c?br />
DECLARE_DYNCREATE(CMainFrame) 展开后ؓ(f)Q?br />
public:
static const CRuntimeClass classCMainFrame;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) 展开后ؓ(f)Q?br />
CObject* PASCAL CMainFrame::CreateObject()
{ return new CMainFrame; }
const CRuntimeClass CMainFrame::classCMainFrame = {
"CMainFrame", sizeof(class CMainFrame), 0xFFFF, CMainFrame::CreateObject, (CRu
ntimeClass*)(& CFrameWnd::classCFrameWnd), NULL };
CRuntimeClass* CMainFrame::GetRuntimeClass() const
{ return (CRuntimeClass*)(&CMainFrame::classCMainFrame); }
q些宏首先在你的定义文g中定义一个以class+cd为名字的静态变量。然后定义一个返回这个静态变量的函数GetRuntimeClassq在实现文g中实C。最后定义ƈ实现一个创建对象的函数CreateObject?/p>
好了Q我们现在就来看看CSingleDocTemplate对象的构造函数做了些什么:(x)下面是他的实?br />
CSingleDocTemplate::CSingleDocTemplate(UINT nIDResource,
CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass,
CRuntimeClass* pViewClass)
: CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)
{
m_pOnlyDoc = NULL;
}
它主要是初始化他的父cCDocTemplate,CDocTemplate做了些什么?如下Q?br />
{
<1>把资源ID?qing)文、框架、视囄三个CRuntimeClassl构的静态成员的地址(也就是传q来的四个参? 保存了v来?br />
<2>LoadTemplate();///为指定的文模板对象装蝲资源
}
xq个new语句ȝ讲完了?br />
W二节:(x)AddDocTemplate(pDocTemplate);
下面是他的实现函?br />
void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)
{
if (m_pDocManager == NULL)
m_pDocManager = new CDocManager; /*创徏一个文管理类Q对于单文档常常只有一个文模板用CDocManagercdƈ不是很重?我们可以忽略q句*/
m_pDocManager->AddDocTemplate(pTemplate); /*把文档模板指针保存在CDocManager实例中由CDocManagerȝ理他,我们只要知道有这个事p?/
}
W三节:(x)ProcessShellCommand(cmdInfo)
q个函数发送的一个命令就是FileNew其他的暂时不他Q其实所有的文c,框架c,视图c都是在q个函数中创建的Q在W一D中已经讲到应用E序cd上三个类的CRuntimeClass一个静态成员地址保存h了,关于CRuntimeClassl构的具体功能参照MSDN?br />
ProcessShellCommand描述如下:
BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
{
BOOL bResult = TRUE;
switch (rCmdInfo.m_nShellCommand)
{
case CCommandLineInfo::FileNew:
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
OnFileNew();
if (m_pMainWnd == NULL)
bResult = FALSE;
break;
case CCommandLineInfo::FileOpen:
if (!OpenDocumentFile(rCmdInfo.m_strFileName))
bResult = FALSE;
break;
……………………………….///q有很多消息处理略去
}
return bResult;
}
W一DA(ch)fxGetApp()->OnCmdMsg(…)
AfxGetApp()->OnCmdMsg主要是派发命令消息,跟我们关pL大的消息是菜单命令ID_FILE_NEWQ下面讲qC的处理函数OnFileNew
W二DOnFileNew();
OnFileNew只是单的调用文理对象的同名函?他的描述如下Q?br />
void CWinApp::OnFileNew()
{
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();///只是调用CDocManager::OnFileNew
}
文理cȝOnFileNewL一些没用的东西后实现如下:(x)
void CDocManager::OnFileNew()
{
CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();/*获得W一个文模?对于单文只有一个文模?/
if (m_templateList.GetCount() > 1)///对单文档q段没用
{
CNewTypeDlg dlg(&m_templateList);
int nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;
else
return; /// none - cancel operation
}
pTemplate->OpenDocumentFile(NULL);/*其实是调用CSingleDocTemplate::OpenDocumentFile函数下面述q里,因ؓ(f)在CDocTemplate cMq个函数是一个纯虚函?/
}
下面qpTemplate->OpenDocumentFile(NULL);q个函数Q?br />
q是最重要的一个函?他执行了如下6个步骤:(x)
<1>pDocument = CreateNewDocument();///创徏一个新文
{
CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();/*q是才真正的创徏文对象Q这里创建的文档对象是上面RUNTIME_CLASS(CFirstDoc),中的对象q是MFC开发h员想出来的一U运行时创徏对象的方法,应该说比较不错的,不知?a target="_blank">C++Builder的是怎样构造的?/
AddDocument(pDocument); ///把创建的对象指针记录下来Q以后还要用的?br />
}
<2> pFrame = CreateNewFrame(pDocument, NULL); /*Ҏ(gu)新文指针创建新文框架,q个比较重要下一D|q?/
<3>SetDefaultTitle(pDocument); ///讄~省标题Q不重要?br />
<4>pDocument->OnNewDocument() ///清除老文内?br />
{
DeleteContents(); ///删除原来的内容而不是否存?br />
SetModifiedFlag(FALSE); ///清除曄修改q的标记
}
<5>pThread->m_pMainWnd = pFrame; ///框架H口作ؓ(f)的指针作ZH口的指?br />
<.6>InitialUpdateFrame(pFrame, pDocument, bMakeVisible); /*使框架中的视囄口接受到OnInitialUpdat的调?q作原始更新?/
xW一D늚OnFileNew函数ȝ讲完。下面讲<2> CreateNewFrame函数
CreateNewFrame是CDocTemplate的成员函数如?个步骤:(x)
<2.1>CCreateContext context; ///创徏CcreateContext对象.也就是我们重载LoadFrame函数的那个CcreateContext的来?/
context.m_pCurrentFrame = pOther; ///保存当前框架Q一般ؓ(f)NULL
context.m_pCurrentDoc = pDoc; ///保存文档对象指针
context.m_pNewViewClass = m_pViewClass; ///保存视图对象指针
context.m_pNewDocTemplate = this; ///保存文模板的指针?br />
<2.2>CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); ///真正创徏框架的对?br />
<2.3>pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
NULL, &context) ///加蝲资源Q这是最重要的,下面讲述
{
<2.3.1> GetIconWndClass(dwDefaultStyle, nIDResource) ///加蝲资源q注册窗?br />
{
AfxFindResourceHandle
::LoadIcon ///加蝲光标资源
CREATESTRUCT cs; ///创徏一个CREATESTRUCTl构实例
PreCreateWindow(cs); /*调用H口预创建函敎ͼq个函数我们可以重蝲?br />
Ҏ(gu)cs调用 AfxReGISterWndClass注册框架H口*/
}
<2.3.2> Create(…) ///创徏框架H口,后面述Q此处暂时不讌Ӏ?br />
<2.3.3> m_hMenuDefault = ::GetMenu(m_hWnd); ///获取q保存菜单句?br />
<2.3.4> LoadAccelTable(MAKEINTRESOURCE(nIDResource)); ///装蝲加速键?br />
}
下面讲Create函数Q如?个步骤:(x)
<2.3.2.1>hMenu = ::LoadMenu(hInst, lpszMenuName); ///加蝲菜单
<2.3.2.2>CREATESTRUCT cs; ///创徏一个CREATESTRUCTl构实例
cs.lpCreateParams = lpParam; ///(此时的lpParam是<2.1>建的context对象指针)
<2.3.2.3> PreCreateWindow(cs); ///调用H口预创建函敎ͼq个函数我们可以重蝲?又调用一?br />
<2.3.2.4>调用API函数::CreateWindowEx真正创徏框架H口Q创E中?x)发出WM_CREATE和W(xu)M_NCCREATE{消息?br />
下面讲接收WM_CREATE消息的消息处理函数CMainFrame::OnCreateQ其他消息不重要
<2.3.2.3.1>CMainFrame::OnCreate最重要的是调用CFrameWnd::OnCreateHelper函数如下:
{
<1>CWnd::OnCreate(lpcs); ///调用~省?br />
<2>调用可重载函数OnCreateClient(lpcs,pContext)函数, 在OnCreateClient函数内只是调用CreateView(pContext, AFX_IDW_PANE_FIRST)函数;
CreateView函数步骤如下Q?br />
{
<2.1> pView=pContext->m_pNewViewClass->CreateObject(); /*创徏视图对象*/
<2.2>pView->Create(…);/*调用视图对象的Create函数真正创徏视图,其更详细的动作可以不理他Q但要知道这里会(x)发生很多事情(跟创建框架窗口类似的)Q其他一些不重要的动作可以不理他Q?/
}
<3>PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);/*发一个WM_SETMESSAGESTRING消息初始化消息串*/
<4>RecalcLayout(); ///重定控制栏等无关动作
}
<2.3.2.3.2> m_wndToolBar.CreateEx; ///创徏工具?br />
<2.3.2.3.3> LoadToolBar; /停靠工具栏等无关动作
xWM_CREATE消息处理讲完Q同时第三段的ProcessShellCommand函数也结束了
W四?Qm_pMainWnd->ShowWindow(SW_SHOW); ///昄H口
W五?Qm_pMainWnd-> UpdateWindow (); ///重画H口
xW二节InitInstance ()函数讲完,
W四章pApp->Run函数
Run函数处理消息循环直到E序推出Q已l有很多书籍讲到他的q程Q本文不描述他?br />
W五章ȝ
从上面的描述中可以看出,文/视图l构的关键在CRuntimeClassl构Q通过CRuntimeClassl构实现动态创建对象?br />
q类问题的出C要在bool CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo);
函数的关键内容:(x) 我们l箋解析cdocmanagerQ它I竟q了些什么? //如果模板列表为空的话 cdoctemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead(); assert(ptemplate != NULL); ptemplate->opendocumentfile(null); 通过上面的代码我们可以看出,cwinapp?/span>onfilenew?/span>onfileopen分别调用cdocmanager的虚拟函?/span>onfilenew?/span>onfileopen。而在cdocmanager里面。通过模板链表选择不同的模板来调用文档模板?/span>opendocumentfile(); 下面我们来看?/span>cdoctemplate::opendocumentfile()它是一个最关键的函数。因Z是虚拟函敎ͼ我们考虑CSingleDocTemplate::OpenDocumentFile的情c(din)?/span> // create frame - set as main document frame 通过观察上面的代码我们很Ҏ(gu)的看?/span>有两个可能出错的原因Q?/span>1 CreateNewDocumentq回?/span>NULL 2 createnewframe q回为空?/span> 先看 CreateNewDocument() 一般来说这个函数很失败。不q在调试时也不能掉以d?/span> 看看create?/span>createex函数的动作就知道怎么回事了?/span> 以上是我分析的出现q样“建立I文档失?/span>”问题的大致原因。也许还有其他的原因。我q里׃一一列D了?/span>
BOOL bResult = TRUE;
switch (rCmdInfo.m_nShellCommand)
{
case CCommandLineInfo::FileNew: // 新徏
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEWQ?/span> 0Q?/span> NULLQ?/span> NULL))
OnFileNew();
if (m_pMainWnd == NULL)
bResult = FALSE;
break;
case CCommandLineInfo::FileOpen:
if (!OpenDocumentFile(rCmdInfo.m_strFileName))
bResult = FALSE;
break;
通过上面的内Ҏ(gu)们可以看出:(x)如果没有?/span>ID_FILE_NEW做映的话出现问题就?/span>OnFileNew();
CWinApp?/span>OnFileNew的默认实现是调用m_pDocManager->OnFileNew();
Q首先说明一?/span>CDocManager它主要的功能是帮?/span>CWinApp是管理文档模杉K表和注册文gcd.Q?/span>
if (m_templateList.IsEmpty())
{
TRACE0("Error: no document templates registered with CWinApp.
");
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); //报错q返?/span>.q里不会(x)报徏立新文出错?/span>
return;
}
if (m_templateList.GetCount() > 1)
{
// more than one document template to choose from
// bring up dialog prompting user
CNewTypeDlg dlg(&m_templateList);
int nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;Mj8F
else
return; // none - cancel operation
}
ASSERT_KINDOF(CDocTemplate Q?/span> pTemplate);
如果传入参数NULL表示新徏文g?/span>
q个函数里面有一D代码:(x)
其中Q?/span>AFX_IDP_FAILED_TO_CREATE_DOC 是字符“建立I文失?/span>”的资?/span>id
// create a new document
pDocument = CreateNewDocument();
ASSERT(pFrame == NULL); // will be created below
bCreated = TRUE;
if (pDocument == NULL)N+
{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
return NULL;
}
ASSERT(pDocument == m_pOnlyDoc);?#Z
if (pFrame == NULL)
{
ASSERT(bCreated);
BOOL bAutoDelete = pDocument->m_bAutoDelete;
pDocument->m_bAutoDelete = FALSE;
// don’t destroy if something goes wrong
pFrame = CreateNewFrame(pDocument Q?/span> NULL);
pDocument->m_bAutoDelete = bAutoDelete;1nD{WwQ
if (pFrame == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);
delete pDocument; // explicit delete on error
return NULL;
}
再看?/span>CreateNewFrame() 里面有一个函?/span>LoadFrame是造成q种“建立新文失?/span>”错误的源泉所在?/span>
只要它返?/span>False׃(x)弹出q样的提C?/span>
我们在来看看LoadFrame() 里面调用CFrameWnd::Create()来创建窗口,创徏H口p|q回Fasle?/span>
q样问题变的比较简单了?/span>
****************************************************************S_zS
1如果找不到菜单资?/span>q回False 同时也弹?/span>“建立I文失?/span>”
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuNameQ?/span> RT_MENU);
if ((hMenu = ::LoadMenu(hInstQ?/span> lpszMenuName)) == NULL)
{
TRACE0("Warning: failed to load menu for CFrameWnd.
");
PostNcDestroy(); // perhaps delete the C++ object
return FALSE;
}
2重蝲?/span>PreCreateWindow而且q回False也会(x)D弹出“建立I文失?/span>”
3?/span>OnCreate 里面q回-1 也会(x)D弹出“建立I文失?/span>”?/span>
******************************************************************
]]>