##

CCommandLineInfo cmdInfo;//定义命令行
ParseCommandLine(cmdInfo);//解析命令行
// 调度在命令行中指定的命令。如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo)) //程序启动时创建新文档
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOW);// 唯一的一个窗口已初始化,因此显示它并对其进行更新
m_pMainWnd->UpdateWindow();

这几行代码是程序启动时创建新文档的关键代码 .

1: 我们首先来看看让CCommandLineInfo类是个什么东西:( 部分源代码 )

//in afxwin.h
class CCommandLineInfo : public CObject
{
public:
// Sets default values
CCommandLineInfo();
BOOL m_bShowSplash;
BOOL m_bRunEmbedded;
BOOL m_bRunAutomated;
enum { FileNew, FileOpen, FilePrint, FilePrintTo, FileDDE, AppRegister,
AppUnregister, FileNothing = - } m_nShellCommand;
// not valid for FileNew
CString m_strFileName;
. . .
~CCommandLineInfo();
. . .
};

这里要重点注意enum {FileNew, . . . , FileNothing = -1 }m_nShellCommand;
这里联合类型定义的m_nShellCommand就是外壳程序执行的命令类型
如果m_nShellCommand设置为FileNew ,那么程序就会创建新文档 .
如果想在文档开始时不创建新文档 , 就必须将m_nShellCommand设置为FilleNothing

下面我们再看看CCommandLineInfo的构造函数 .

//in appcore.cpp
CCommandLineInfo::CCommandLineInfo()
{
m_bShowSplash = TRUE;
m_bRunEmbedded = FALSE;
m_bRunAutomated = FALSE;
m_nShellCommand = FileNew;
}

这里很明白的看出 , 构造函数中 , 缺省将 m_nShellCommand设置为 FileNew .

2:再来看看ParseCommandLine(cmdInfo)函数

void CWinApp::ParseCommandLine(CCommandLineInfo& rCmdInfo)
{
for (int i = ; i < __argc; i++) // extern int __argc;
{
LPCTSTR pszParam = __targv[i]; //extern char ** __argv;
extern wchar_t ** __wargv;
difine __targv __wargv
BOOL bFlag = FALSE;
BOOL bLast = ((i + ) == __argc); //参数是否是最后一个
if (pszParam[] == '-' || pszParam[] == '/') //是否有-或'/'? 并过滤
{
bFlag = TRUE;
++pszParam;
}
rCmdInfo.ParseParam(pszParam, bFlag, bLast);
}
}

可以看出ParseCommandLine主要是对输入的命令行参数做一些分析 , 并调用ParseParam来进行处理 .继续分析 ParseParam函数 , 查看如下源代码:

void CCommandLineInfo::ParseParam(const TCHAR* pszParam,BOOL bFlag,BOOL bLast)
{
if (bFlag)
{
USES_CONVERSION;
ParseParamFlag(T2CA(pszParam));
}
else
ParseParamNotFlag(pszParam);
ParseLast(bLast);
}

其它的函数撇开不看 , 我们重点来分析一下ParseParamFlag()和ParseLast()函数 .

void CCommandLineInfo::ParseParamFlag(const char* pszParam)
{
// OLE command switches are case insensitive, while
// shell command switches are case sensitive
if (lstrcmpA(pszParam, "pt") == )
m_nShellCommand = FilePrintTo;
else if (lstrcmpA(pszParam, "p") == )
m_nShellCommand = FilePrint;
else if (lstrcmpiA(pszParam, "Unregister") == ||
lstrcmpiA(pszParam, "Unregserver") == )
m_nShellCommand = AppUnregister;
else if (lstrcmpA(pszParam, "dde") == )
{
AfxOleSetUserCtrl(FALSE);
m_nShellCommand = FileDDE;
}
else if (lstrcmpiA(pszParam, "Embedding") == )
{
AfxOleSetUserCtrl(FALSE);
m_bRunEmbedded = TRUE;
m_bShowSplash = FALSE;
}
else if (lstrcmpiA(pszParam, "Automation") == )
{
AfxOleSetUserCtrl(FALSE);
m_bRunAutomated = TRUE;
m_bShowSplash = FALSE;
}
}

ParseParamFlag判断传过来的字符串 ,判断它的参数类型 , 并根据参数类型做不同的处理 .

//ParseLast会判断是否是是FileNew打开新文档 , 如果是打开新文档 , 并且打开的文档名不为空的话, 就假定用户想打开这个文档 , 把命令设置为FileOpen .
void CCommandLineInfo::ParseLast(BOOL bLast)
{
if (bLast)
{
if (m_nShellCommand == FileNew && !m_strFileName.IsEmpty())
m_nShellCommand = FileOpen;
m_bShowSplash = !m_bRunEmbedded && !m_bRunAutomated;
}
}

最后 , 我们可以总结一下ParseCommandLine的作用 . ParseCommandLine的作用主要是分析命令行参数,如果没有命令行参数,ParseCommandLine()就假定用户想新建一个文档,于是设置一个FileNew命令,如果命令行参数中有一个文件名,ParseCommandLine()就假定用户想打开该文件,于是设置一个FileOpen命令。

3: 最后 , 我们来重点看看外壳命令解析的主角 : ProcessShellCommand ();(部分源代码)

BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)
{
BOOL bResult = TRUE;
switch (rCmdInfo.m_nShellCommand)
{
case CCommandLineInfo::FileNew:
if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, , NULL, NULL))
OnFileNew();
if (m_pMainWnd == NULL)
bResult = FALSE;
break;
case CCommandLineInfo::FileOpen: . . .
case CCommandLineInfo::FilePrintTo: . . .
case CCommandLineInfo::FilePrint: . . .
case CCommandLineInfo::FileDDE: . . .
case CCommandLineInfo::AppRegister: . . .
case CCommandLineInfo::AppUnregister: . . .
. . .
}
}

代码看到这里 , 一切都很明白了 . ProcessShellCommand分析m_nShellCommand ,并根据m_nShellCommand不同的类型值进行不同的处理 .
再来分析下面两行代码:

CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
  • 当CCommandLineInfo cmdInfo进行定义时 , 首先调用构造函数 , 构造函数中m_nShellCommand被设置为FileNew
  • 然后执行ParseCommandLine(cmdInfo);对命令进行分析 .
  • 最后执行ProcessShellCommand (cmdInfo) , ProcessShellCommand ()判断m_nShellCommand为FileNew , 于是调用OnFileNew()创建了一个新的文档 .

这也就是创建新文档的来龙去脉 .

最后, 我们看怎么样解决不想在应用程序启动时的创建新文档的问题:

直接在InitInstance()函数中用如下代码代替原来的几行即可:

CCommandLineInfo cmdInfo;
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;
ParseCommandLine(cmdInfo);
       if (!ProcessShellCommand(cmdInfo)) return FALSE;

CCommandLineInfo类的更多相关文章

  1. MFC命令行及CCommandLineInfo类

    获取命令行的方法: 1.GetCommandLine() 获取输入的所有信息,包括程序所在路径及参数 2.AfxGetApp()->m_lpCmdLine 只包含参数 一般情况下,获取到命令行后 ...

  2. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  3. MFC的命令行

    一个程序,我们通过输入不同的命令行参数,就可以实现一个可执行文件,多种功能,通过命令行来控制它的行为,例如,我们在控制台的时候,就是遇到最多的,如一个exe程序,加入为test..exe,我们可以设置 ...

  4. MFC中SDI程序创建流程的回顾

    SDI程序创建流程的回顾 从CWinApp.InitialInstance()开始, 1.首先应用程序对象创建文档模板; CSingleDocTemplate* pDocTemplate; pDocT ...

  5. MFC中小笔记(二)

    6.有三个API函数可以运行可执行文件WinExec.ShellExecute和CreateProcess.  关于这三者的概述总结,有好几篇,自己选择. 1.CreateProcess因为使用复杂, ...

  6. MFC中获取命令行参数的几种方法

    在MFC程序中,可以用以下几种方法来获取命令行参数. 为方便说明,我们假设执行了命令:C:\test\app.exe -1 -2 方法一 ::GetCommandLine(); 将获取到 " ...

  7. MFC类目录及头文件(转)

    类 描述 头文件 CAnimateCtrl 自动化通用控件 afxcmn.h CArchive afx.h CArchiveException afx.h CArray afxtempl.h CAsy ...

  8. Visual C++中最常用的类与API函数

    这篇文章能让初学者快速了解visual C++ MFC中常见的核心的类与函数,虽然全部看下来有点枯燥,但对初学者快速了解MFC的框架结构很有好处. 常用类 CArchive类:用于二进制保存档案 CB ...

  9. C++ 可配置的类工厂

    项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性.传统的工厂实现如下: class Widget { public: virtual i ...

随机推荐

  1. WebApi的过滤器

    代码: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System ...

  2. JwtBearerAppBuilderExtensions.UseJwtBearerAuthentication(IApplicationBuilder

    netcore从1.1升级到2.0时,出的错,因为使用的时Jwt token参考https://github.com/aspnet/Security/issues/1310#issuecomment- ...

  3. VS2013中Nuget程序包管理器控制台使用入门(一)-准备环境(原创)

    准备环境: 1.打开VS2013IDE集成开发环境. 2.新建一个Asp.net Mvc的项目,比如命名为:MvcApplication1 3.打开 菜单"工具"->&quo ...

  4. Linux定时任务Crontab使用 提示no crontab for root

    使用命令查询crontab 任务时,一直提示:no crontab for root .查看了一些资料,说是crontab在初始时,设置了一次编辑方式,所以试了一下crontab -e的方式编辑,即在 ...

  5. MFC 一个无参线程的CreateThread 使用

    最近想把c#的一个工作中用到的软件用MFC 实现出来, 刚下手 要了解的东西挺多,不但要对c++的语法,大体看一遍. 还要看MFC 内一些窗体,之类的相关的定义,比如cpp ,.h 内的类的定义方式等 ...

  6. C++中stl的map

    总结: 在map中插入数据有三种方法: 1.用insert插入pair数据: mapstudent.insert(pair<int,string>(1,"studentone&q ...

  7. 性能(js)

    1.避免全局查找: <script type="text/javascript"> function updateUI(){ var imgs=document.get ...

  8. web前端学习笔记:文本属性

    今天的web前端笔记主要讲述文本属性,希望能帮助到正在学习web前端开发的初学者们,废话不多说了,一起来看看文本属性的相关内容吧. 文本属性 文本缩进 将Web页面上的一个段落第一行缩进,这是一种最常 ...

  9. 使用iTEXT库生成pdf

    iTEXT下载地址 https://sourceforge.net/projects/itext/files/ 选择绿色的按钮,下载最新版本,解压后是一些jar包 为了使用方便,将文件夹放到JAVA_ ...

  10. Spring 循环引用(一)一个循环依赖引发的 BUG

    Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...