让MFC程序支持命令行参数

时间:2021-04-05 14:32:27

让MFC程序支持命令行参数

一般情况下,如果我们的VC工程是Console控制台类型或者是Win32类型的情况下,这两类的工程类型比较容易获得命令行参数,即,通过其入口点函数

  1. int main(int argc, char *argv[])
  2. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
复制代码

但是,如果我们的工程类型是MFC对话框或单文档类型的话,如何让我们的程序支持命令行参数呢?系统没有为我们提供好,那我们只有自己获取了……

一般情况下,需要在MFC程序的主线程初始化函数中进行处理,主线程的初始化函数即:BOOL CProjCleanerApp::InitInstance(),这里面我们假设工程的名字是ProjCleaner,CProjCleanerApp 即主线程类。在 BOOL CProjCleanerApp::InitInstance() 函数中进行程序的初始化以及对话框界面的显示工作,其大致代码如下:

  1. BOOL CProjCleanerApp::InitInstance()
  2. {
  3.         //省略的其他代码……;
  4.         CWinApp::InitInstance();
  5.         //省略的其他代码……;
  6.        
  7.         CProjCleanerDlg dlg; //新建主对话框类型对象;
  8.         m_pMainWnd = &dlg;
  9.         INT_PTR nResponse = dlg.DoModal(); //进行模态对话框的显示;
  10.         if (nResponse == IDOK)
  11.         {
  12.                 // TODO: Place code here to handle when the dialog is
  13.                 //  dismissed with OK
  14.         }
  15.         else if (nResponse == IDCANCEL)
  16.         {
  17.                 // TODO: Place code here to handle when the dialog is
  18.                 //  dismissed with Cancel
  19.         }
  20.         return FALSE;
  21. }
复制代码

我们要获取程序的命令行参数,一般是在主对话框界面显示之前,即 CProjCleanerDlg dlg; 之前获取。获取的方法主要是调用 GetCommandLine 和 CommandLineToArgvW 函数。

GetCommandLine 函数的原型定义如下:

  1. LPTSTR WINAPI GetCommandLine(void);
复制代码

没有参数,返回值是一个LPTSTR类型的字符串指针,即命令行参数的字符串。

默认情况下,每个程序都会有一个命令行参数,即可执行程序本身的路径,第二个参数才是真正的附加命令行参数。举个例子,调用GetCommandLine函数获取到的命令行参数的字符串大致如下:

  1. "E:/SoftWare/ProjCleaner.exe" "-help"
复制代码

其中,"E:/SoftWare/ProjCleaner.exe" 为可执行文件的路径,"-help" 为附加的参数。

调用完 GetCommandLine 函数获取到了命令行参数之后,我们就要调用 CommandLineToArgvW 函数去分解得到的命令行参数字符串,CommandLineToArgvW 函数的原型定义如下:

  1. LPWSTR *CommandLineToArgvW(
  2.     LPCWSTR lpCmdLine,
  3.     int *pNumArgs
  4. );
复制代码

他有两个参数,第一个参数 lpCmdLine 即通过 GetCommandLine 函数获取到的命令行参数字符串指针,第二个参数是一个 int 类型的指针,用这个参数返回命令行参数中的参数个数,默认情况下,pNumArgs 会返回1,如果有附加的命令行参数,该值会大于1,比如:

  1. "E:/SoftWare/ProjCleaner.exe" "-help"
复制代码

则,pNumArgs 会返回2。

CommandLineToArgvW 函数的返回值是一个宽字节LPWSTR类型的字符串指针数组,数组中的每一个字符串指针代表着一个命令行参数,根据上面的示例,
设返回值为:LPWSTR *lpszArgv,则 lpszArgv[0] 就是 "E:/SoftWare/ProjCleaner.exe",lpszArgv[1] 就是 "-help",这样大家明白了吧?

通过 GetCommandLine、CommandLineToArgvW 两个函数就可以成功的获取并拆分命令行参数了。

下面再给大家演示一个小例子……

前言:《工程目录清理器》是我前段时间写的一个小软件:
帖子地址:http://www.cctry.com/thread-254-1-1.html

功能简介:大家可能会遇到:当写好一个工程想与其他人分享源码或从网络上下载工程源码时,压缩工程目录后得到的压缩文件会很大,携带或网络上传输很不方便,本程序默认可清理由Microsoft Visual C++ 编译器在编译、链接过程中所产生的中间文件,如:obj、ilk 等等。将其清除,如果大家设定好目录树结构后,可以支持其他各种编译器:VB、C#、Delphi 等等。之后还可以保存成 xml 文件,下次加载即可。

可有部分网友说:“这样的软件使用起来感觉麻烦,我就用一个批处理,而且集成到文件夹的右键菜单里面,点一下就清理了,比你这个方便。”
刚开始我还不以为然,可是最近从网上搜集到了一些软件的例子源码,想转帖到我们 VC驿站 - WwW.CcTry.CoM ,在清理工程目录过程中确实感到有点不方便,于是我就想也让我的这个《工程目录清理器》支持命令行参数,同时集成到文件夹的系统右键菜单里面,这样执行起来就方便多了。说做就做,于是把《工程目录清理器》的代码修改了一下,主要的核心代码就是上面提到的。此外,再给大家说一下如何集成到文件夹的系统右键菜单:

1、在[HKEY_CLASSES_ROOT/Directory/shell] 分支下建立一个自己命名的子键,例如,我的叫做:ProjCleaner;
2、将新建子键ProjCleaner下的默认键值设置为你想在文件夹右键菜单中显示的字符串,比如我的设置为:工程目录清理器;
3、在刚才新建的子键ProjCleaner下面再新建一子键,但是名字必须是command;
4、将刚才新建子键command下面的默认键值设置为:E:/SoftWare/ProjCleaner.exe "%1",其中 E:/SoftWare/ProjCleaner.exe 是工程目录清理器软件所在的路径,这个大家可以根据自己的程序位置来写,但是后面的 "%1" 大家一定要记得加上,他代表的就是右键单击文件夹所在的路径,即我们调用 GetCommandLine 函数所获得的附加参数。
具体,见如下两幅图:



经过了以上4个步骤之后,当我们右键单击某个文件夹之后,在弹出的菜单中就已经有我们添加的一项即“工程目录清理器”,如下图:


修改后的 InitInstance() 函数代码如下:

  1. BOOL CProjCleanerApp::InitInstance()
  2. {
  3.         //省略的其他代码……;
  4.         CWinApp::InitInstance();
  5.        
  6.         //省略的其他代码……;
  7.         //for the command line;
  8.         int argc = 0;
  9.         LPWSTR *lpszArgv = NULL;
  10.         LPTSTR szCmdLine = GetCommandLine(); //获取命令行参数;
  11.         lpszArgv = CommandLineToArgvW(szCmdLine, &argc); //拆分命令行参数字符串;
  12.         if (argc >= 2) {
  13.                 WCHAR szPath[500] = {0};
  14.                 swprintf(szPath, _T("%s%s%s"), _T("确定要清理 [ "), lpszArgv[1], _T(" ] 目录吗?")); //格式化字符串;
  15.                 if (MessageBox(NULL, szPath, _T("友情提示"), MB_OKCANCEL|MB_ICONQUESTION) ==  IDOK) { //进行删除提示;
  16.                         m_bStartFromCmd = TRUE;
  17.                         CleanStart(...); //调用CleanStart函数进行工程目录的清理工作;
  18.                 }
  19.                 return FALSE;
  20.         }
  21.         //command line end;
  22.         CProjCleanerDlg dlg;
  23.         m_pMainWnd = &dlg;
  24.         INT_PTR nResponse = dlg.DoModal();
  25.         if (nResponse == IDOK)
  26.         {
  27.                 // TODO: Place code here to handle when the dialog is
  28.                 //  dismissed with OK
  29.         }
  30.         else if (nResponse == IDCANCEL)
  31.         {
  32.                 // TODO: Place code here to handle when the dialog is
  33.                 //  dismissed with Cancel
  34.         }
  35.         return FALSE;
  36. }
复制代码

具体代码见《工程目录清理器》帖子地址:http://www.cctry.com/thread-254-1-1.html 中的源码信息。

具体开启关联文件夹右键菜单的设置在:运行“工程目录清理器”-> “设置信息”按钮 -> “关联文件夹右键菜单”勾上 -> "应用设置" 即可!

说道这里也差不多讲完了,大家有什么问题再跟帖提问吧……