CCommandLineInfo詳解 和 ProcessShellCommand(cmdInfo)函數功能

在我們用嚮導創建MFC應用程序時,在App::InitInstance()中總會出現下面這樣的代碼到底是什麼意思呢,我差了很多資料終於使其漏出廬山真面目。

CCommandLineInfo cmdInfo;//定義命令行 
ParseCommandLine(cmdInfo);//解析命令行

// 調度在命令行中指定的命令。如果 
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 啓動應用程序,則返回 FALSE。 
if (!ProcessShellCommand(cmdInfo)) //程序啓動時創建新文檔 
   return FALSE; 
// 唯一的一個窗口已初始化,因此顯示它並對其進行更新 
m_pMainWnd->ShowWindow(SW_SHOW); 
m_pMainWnd->UpdateWindow();


這幾行代碼是程序啓動時創建新文檔的關鍵代碼 .

CCommandLineInfo : 
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 = -1 } 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的構造函數:

下面我們再看看CCommandLineInfo的構造函數 . 
//in appcore.cpp 
CCommandLineInfo::CCommandLineInfo() 

         m_bShowSplash   = TRUE; 
         m_bRunEmbedded   = FALSE; 
         m_bRunAutomated = FALSE; 
         m_nShellCommand = FileNew; 

這裏很明白的看出 , 構造函數中 , 缺省將 m_nShellCommand設置爲 FileNew .

ParseCommandLine(cmdInfo)函數:
2:再來看看ParseCommandLine(cmdInfo); 函數 . 
void CWinApp::ParseCommandLine(CCommandLineInfo& rCmdInfo) 

// extern int __argc;           /* count of cmd line args */
     for (int i = 1; i < __argc; i++)
     { 

//extern char ** __argv;/* pointer to table of cmd line args */
//extern wchar_t ** __wargv; /* pointer to table of wide cmd line args */
//difine __targv   __wargv
         LPCTSTR pszParam = __targv[i]; 
         BOOL bFlag = FALSE; 
         BOOL bLast = ((i + 1) == __argc); 
         if (pszParam[0] == '-' || pszParam[0] == '/') 
         { 
             // remove flag specifier 
             bFlag = TRUE; 
             ++pszParam; 
         } 
         rCmdInfo.ParseParam(pszParam, bFlag, bLast); 
     } 

可以看出ParseCommandLine主要是對輸入的命令行參數做一些分析 , 並調用ParseParam來進行處理 .繼續分析 ParseParam函數 , 查看如下源代碼:

CCommandLineInfo::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()函數 .

CCommandLineInfo::ParseParamFlag(...): 
void CCommandLineInfo::ParseParamFlag(const char* pszParam) 

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

ParseParamFlag判斷傳過來的字符串 ,判斷它的參數類型 , 並根據參數類型做不同的處理 .

CCommandLineInfo::ParseLast(...):
void CCommandLineInfo::ParseLast(BOOL bLast) 

     if (bLast) 
     { 
         if (m_nShellCommand == FileNew && !m_strFileName.IsEmpty()) 
             m_nShellCommand = FileOpen; 
         m_bShowSplash = !m_bRunEmbedded && !m_bRunAutomated; 
     } 

ParseLast會判斷是否是是FileNew打開新文檔 , 如果是打開新文檔 , 並且打開的文檔名不爲空的話, 就假定用戶想打開這個文檔 , 把命令設置爲FileOpen .


最後 , 我們可以總結一下ParseCommandLine的作用 . ParseCommandLine的作用主要是分析命令行參數,如果沒有命令行參數,ParseCommandLine()就假定用戶想新建一個文檔,於是設置一個FileNew命令,如果命令行參數中有一個文件名,ParseCommandLine()就假定用戶想打開該文件,於是設置一個FileOpen命令。 
3: 最後 , 我們來重點看看外殼命令解析的主角 : ProcessShellCommand ();(部分源代碼)

CWinApp::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:       . . . 
         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;

   1: 當CCommandLineInfo cmdInfo進行定義時 , 首先調用構造函數 , 構造函數中m_nShellCommand被設置爲FileNew 
 2: 然後執行ParseCommandLine(cmdInfo);對命令進行分析 . 
   3: 最後執行ProcessShellCommand (cmdInfo) , ProcessShellCommand ()判斷m_nShellCommand爲FileNew , 於是調用OnFileNew()創建了一個新的文檔 . 
   這也就是創建新文檔的來龍去脈 . 
最後, 我們看怎麼樣解決不想在應用程序啓動時的創建新文檔的問題: 
直接在InitInstance()函數中用如下代碼代替原來的幾行即可: 
CCommandLineInfo cmdInfo; 
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing; 
ParseCommandLine(cmdInfo); 
if (!ProcessShellCommand(cmdInfo))

       return FALSE;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章