##

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. Oracle高级查询之OVER

    注释:为了方便大家学习和测试,所有的例子都是在Oracle自带用户Scott下建立的 oracel的高级用法:rank()/dense_rank() over(partition by ...orde ...

  2. zh-cn 与 zh-hans 是什么关系、有什么区别

    回答一: 作者:知乎用户 链接:https://www.zhihu.com/question/21980689/answer/19923726 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权 ...

  3. ES6 Proxy的应用场景

    一.相关API Proxy Reflect 二.Proxy应用场景 1.数据校验 表单提交的时候做数据校验,例如年龄是不是满足条件,数据类型是不是满足要求等等,这场场景非常适合使用Proxy. 下面展 ...

  4. PAT 1067 试密码(20)(代码)

    1067 试密码(20 分) 当你试图登录某个系统却忘了密码时,系统一般只会允许你尝试有限多次,当超出允许次数时,账号就会被锁死.本题就请你实现这个小功能. 输入格式: 输入在第一行给出一个密码(长度 ...

  5. 三分钟分布式CAP理论

    分布式系统架构理论,定义了三种指标,理论说我们最多只能满足两个. ## 分布式系统 首先我们这个理论所说的分布式系统,是指系统内会共享数据,互相有连接有交互,才能完成系统功能的的分布式系统.而这个理论 ...

  6. Autel MaxiSys MS906TS tire pressure settings Lexus LS460h

    Use AUTEL MaxiSYS MS906TS error reader to install tire pressure Lexus LS460h in Vung Tau. Make : Lex ...

  7. 各种平台的表达芯片跟mRNA-seq数据比较

    各种平台的表达芯片跟mRNA-seq数据比较 RNA-Seq 表达谱 芯片数据分析 文章见:http://journals.plos.org/plosone ... ournal.pone.00786 ...

  8. vue 动态路由按需加载的三种方式

    在Vue项目中,一般使用vue-cli构建项目后,我们会在Router文件夹下面的index.js里面引入相关的路由组件,如: import Hello from '@/components/Hell ...

  9. 【已处理完】Centos 6.5版本,df -h出来的容量与du -sh的容量不对应是怎么会事呢?

    问题如题,df -h 出来的容量与du -sh 查看的容量信息不一样,是那里出了问题了吗? 下面分别是du -sh *与df -h出来的结果 [root@mail /]# du -sh * 6.2M ...

  10. windows无法停止 服务 错误1053 服务没有及时响应

    windows无法停止 服务 错误1053 服务没有及时响应 服务程序.exe -st