zoukankan      html  css  js  c++  java
  • [C#] cmdarg_ui:“简单参数命令行程序”的通用图形界面

      我们有时需要写一些小工具,或者是需要写一些简短的测试程序,这时编写命令行程序会比较方便。但是命令行程序用起来不太方便,比如——
    1.查看信息困难。有时候我们需要观察命令行程序的输出结果,但是在默认情况下,命令行程序执行完毕后会自动关闭窗口,来不及观察信息。这时可以采取“在程序中等待按键”、“手工打开命令提示符输入命令”、“在批处理中等待按键”、“批处理重定向”等方法,但是都比较麻烦。
    2.命令参数困难。某些命令行程序需要参数,这时只有手工打开命令提示符输入命令。有时要键入文件的全限定名,那就更花功夫了。

      怎么解决以上难题呢?
      首先想到的是把那些小程序改写为图形界面程序,或者为命令行程序分别开发图形界面。但这两个方案的开发成本都太高了,这仅仅只是简短测试程序,很不值得。
      所以,我编写了一个通用的图形界面,专门解决这些命令行程序的使用问题。


    一、设计

    1.1 如何关联

      首先,怎么将图形界面与原来的命令行程序关联起来呢?
      传统的做法是使用配置文件,在配置文件中指定原来的命令行程序的文件名和路径等信息。但这样做配置起来比较麻烦,因为现在有大量的命令行程序,逐个逐个的修改配置文件就太麻烦了。
      于是我决定不使用配置文件,设计两种关联方式——根据自身文件名、根据命令行参数。

    1.1.1 根据自身文件名(“*_ui.exe”)

      用法:假设某命令行程序的文件名为“filesize.exe”,那么将“cmdarg_ui.exe”复制到该目录下并改名为“filesize_ui.exe”,然后就可以利用“filesize_ui.exe”来操作“filesize.exe”了。
      优点:配置十分方便,复制、改名就行了,不需要切换窗口。而且可以为每一个命令行程序分别配置图形界面,方便以后随时双击打开。
      缺点:对于每一个命令行程序都需要配置一次。


    1.1.2 根据命令行参数(鼠标拖曳)

      在很多时候只需要看一次就行了。为了看一次而建立“*_ui.exe”,随后又删掉“*_ui.exe”,那就有些啰嗦了。
      于是设计了另一种关联方式——根据命令行参数。

      用法:A)打开命令提示符,输入“cmdarg_ui.exe <空格> <命令行程序>”启动cmdarg_ui。
         B)在资源管理器中选择命令行程序,然后按住鼠标左键拖曳,将其放置在“cmdarg_ui.exe”的文件图标上,于是资源管理器会启动“cmdarg_ui.exe”,并将刚才拖曳的命令行程序作为参数。
      优点:操作十分简单,只需鼠标拖曳一下。
      缺点:每次启动时都需要拖曳。如果需要频繁使用时,建议还是使用上面的办法(复制、改名“*_ui.exe”)。


    1.1.3 特例:“*_wui.exe”会显示命令行窗口,适用于等待按键的命令行程序

      在使用图形界面时,我们一般不希望再弹出命令行窗口。
      但是,某些命令行程序需要等待按键。而现在没有命令行窗口,会导致程序一直等待,不会结束。
      最简单的解决办法是让显示命令行窗口,然后按键使程序继续运行,直至结束。
      这时可以改名为“*_wui.exe”,会自动切换到“显示命令行窗口”模式。


    1.2 命令行参数

      对于小工具和测试程序来说,很多是没有参数的,或者是参数格式很简单。例如只有一个输入参数,用于传递文件名。
      于是我设计了两种参数模式——
    1.文件。使用文件对话框选择文件,确定后自动运行。
    2.自定义。在文本框中手动填好参数,然后点击“运行”。


    1.3 其他特性

      为了方便使用,还设计了这些功能——
    接收文件:当文件拖曳到窗口上时,将该文件作为参数来调用命令行程序。因为在很多时候,文件拖曳比打开对话框用起来方便一些。
    实时优先级:调用命令行程序时,自动将它的进程优先级设为实时。因为某些测试程序需要实时优先级,如果每次在任务管理器中配置的话就太麻烦了。


    二、cmdarg_ui的代码

      编程语言为C#。开发工具是VS2005。

      界面如下——

      代码如下——

    using System;
    //using System.Collections.Generic;
    //using System.ComponentModel;
    //using System.Data;
    using System.Drawing;
    //using System.Text;
    using System.Windows.Forms;
    using System.Diagnostics;
    using System.IO;
    
    namespace cmdarg_ui
    {
        public partial class FrmCmdarg_ui : Form
        {
            /// <summary>
            /// 命令行程序的文件名
            /// </summary>
            private string _FileExe;
    
            public FrmCmdarg_ui()
            {
                InitializeComponent();
            }
    
            private void FrmCmdarg_ui_Load(object sender, EventArgs e)
            {
                _FileExe = string.Empty;
    
                // 计算命令行程序的文件名——根据自身文件名
                string sFile = Application.ExecutablePath;    // 全限定文件名
                string sFileBase = Path.GetFileNameWithoutExtension(sFile);    // 文件基本名(无扩展名、无路径)
                this.Text = sFileBase;    // 以基本名作为窗口标题
                int n = sFileBase.LastIndexOf('_');    // 在基本名中查找下划线
                if (n > 0)
                {
                    // 存在下划线,文件名有效
                    // 解析后缀参数
                    for (int i = n + 1; i < sFileBase.Length; ++i)
                    {
                        char ch = char.ToUpper(sFileBase[i]);
                        switch (ch)
                        {
                            case 'W':
                                mnuRunNoWindow.Checked = false;
                                break;
                        }
                    }
                    // 计算命令行程序的文件名
                    _FileExe = sFile.Substring(0, sFile.LastIndexOf(Path.DirectorySeparatorChar) + 1 + n) + ".exe";
                    // 检查文件是否存在
                    if (!File.Exists(_FileExe)) _FileExe = string.Empty;
                }
    
                // 计算命令行程序的文件名——根据命令行参数
                if (string.IsNullOrEmpty(_FileExe))
                {
                    string[] lst = Environment.GetCommandLineArgs();
                    if (lst.Length >= 2)
                    {
                        _FileExe = lst[1];
                        // 检查文件是否存在
                        if (!File.Exists(_FileExe)) _FileExe = string.Empty;
                    }
                }
    
                if (string.IsNullOrEmpty(_FileExe))
                {
                    // 文件名无效
                    btnRun.Enabled = false;
                    txtOut.Text = "Invalid file path!";
                }
                ttpMain.SetToolTip(btnRun, _FileExe);
                mnuRunName.ToolTipText = _FileExe;
            }
    
            private void FrmCmdarg_ui_FormClosed(object sender, FormClosedEventArgs e)
            {
                //
            }
    
            private void btnRun_Click(object sender, EventArgs e)
            {
                string sAll;
    
                if (string.IsNullOrEmpty(_FileExe)) return;    // 文件无效
    
                // 参数
                string sArg = txtFile.Text;
                if (optCmd.Checked) sArg = txtCmd.Text;
    
                // 执行
                Process p = new Process();
                p.StartInfo.FileName = _FileExe;
                p.StartInfo.Arguments = sArg;
                p.StartInfo.UseShellExecute = false;
                //p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                //p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = mnuRunNoWindow.Checked;
                Cursor = Cursors.WaitCursor;
                try
                {
                    p.Start();
                    if (mnuRunRealTime.Checked)
                    {
                        p.PriorityClass = ProcessPriorityClass.RealTime;
                    }
                    try
                    {
                        sAll = p.StandardOutput.ReadToEnd();
                    }
                    finally
                    {
                        p.Close();
                    }
                }
                catch (Exception ex)
                {
                    sAll = ex.ToString();
                }
                finally
                {
                    Cursor = Cursors.Default;
                }
    
                // 显示
                txtOut.Text = sAll;
            }
    
            private void btnRunEx_Click(object sender, EventArgs e)
            {
                mnuRun.Show(btnRunEx, new Point(0, btnRunEx.Height));
            }
    
            /// <summary>
            /// 更新文件
            /// </summary>
            /// <param name="sFile"></param>
            private void updateFile(string sFile)
            {
                Debug.WriteLine(sFile);
                if (string.IsNullOrEmpty(sFile)) return;
    
                // 加上双引号,改善对长文件名的支持性
                if ('\"' != sFile[0])
                {
                    sFile = "\"" + sFile + "\"";
                }
    
                // 更新
                txtFile.Text = sFile;
                txtFile.SelectionStart = txtFile.Text.Length;    // 优先显示最后面的,便于识别文件名
                if (mnuRunAutoFile.Checked)
                {
                    btnRun_Click(btnRun, null);
                }
            }
    
            private void btnFile_Click(object sender, EventArgs e)
            {
                if (dlgOpen.ShowDialog(this) == DialogResult.OK)
                {
                    updateFile(dlgOpen.FileName);
                }
            }
    
            private void FrmCmdarg_ui_DragEnter(object sender, DragEventArgs e)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Link;
            }
    
            private void FrmCmdarg_ui_DragDrop(object sender, DragEventArgs e)
            {
                string[] lst = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (lst.Length > 0)
                {
                    optFile.Checked = true;
                    updateFile(lst[0]);
                }
            }
    
            private void mnuRunName_Click(object sender, EventArgs e)
            {
                Clipboard.SetText(_FileExe);
            }
        }
    }


      其实原理很简单,利用Process类运行程序,并配置StartInfo.RedirectStandardOutput进行重定向,然后使用StandardOutput.ReadToEnd()获得所有输出信息。


    三、测试程序的代码(filesize)

      为了检测参数传递与信息显示,编写了一个小测试程序,功能是显示文件的大小。

      编程语言为C语言。开发工具是VC6。

      代码如下——

    #include <stdlib.h>
    #include <stdio.h>
    #include <tchar.h>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        long fileSize = 0;
        FILE* pFile;
    
        // 检查参数个数
        if (argc<2)
        {
            // 没有给出文件参数。提示语法
            _tprintf(_T("filesize [filename]\n"));
            return 1;
        }
    
        // 显示文件名
        _tprintf(_T("file:\t%s\n"), argv[1]);
    
        // 获取文件大小
        pFile = _tfopen(argv[1], _T("rb"));
        if ( pFile == NULL )
        {
            _tprintf(_T("[error] File open failed!\n"));
        }
        else
        { 
            fseek(pFile, 0L, SEEK_END );    // 将指针定位到文件末尾
            fileSize = ftell( pFile );    // 返回当前位置
            fclose(pFile);
            _tprintf(_T("size:\t%d\n"), fileSize);
        }
        
        return 0;
    }


    四、测试

    4.1.1 测试filesize

      filesize具有一个文件名输入参数。所以我们主要测试文件参数。

      测试A——
    将“filesize.exe”放在“test”文件夹。
    复制“cmdarg_ui.exe”至“test”文件夹,并改名为“filesize_ui.exe”。
    双击“filesize_ui.exe”启动图形界面。
    “文件”单选框模式是已勾选的,这时点击右侧的“...”按钮弹出文件对话框,选择一个文件。便可发现成功的调用“filesize.exe”,并正确的返回了文件大小信息。
    点击“自定义”单选框,然后在右侧文本框中输入参数,再点击“运行”。便可发现下面的文本框更新了,如果手工输入的参数不正确的话,“filesize.exe”会报告“[error] File open failed!”。
    在资源管理器中选择一个文件,将其拖曳到本程序。可发现“文件”单选框自动被勾选了,成功的将该文件作为参数调用了“filesize.exe”。

      测试B——
    在资源管理器中选择“filesize.exe”,然后按住鼠标左键拖曳,将其放置在“cmdarg_ui.exe”的文件图标上。于是“cmdarg_ui.exe”会启动,并关联“filesize.exe”。
    “文件”单选框模式是已勾选的,这时点击右侧的“...”按钮弹出文件对话框,选择一个文件。便可发现成功的调用“filesize.exe”,并正确的返回了文件大小信息。
    其他测试同上。


    4.1.2 测试noifVC6s.exe

      noifVC6s.exe是我以前写的一个测试程序(http://www.cnblogs.com/zyl910/archive/2012/04/12/noifopex8.html),没有参数,它需要等待按键。

      测试C——
    将“noifVC6s.exe”放在“test”文件夹。
    复制“cmdarg_ui.exe”至“test”文件夹,并改名为“noifVC6s_wui.exe”。(注意这里是_wui)
    双击“noifVC6s_wui.exe”启动图形界面。
    界面启动后,点击“运行”按钮右侧的“V”按钮,可以观察到“无窗口”菜单项没有勾选。此时不需操作,点击空白地方关闭菜单。
    因为“noifVC6s.exe”没有命令行参数,可以直接点“运行”按钮。弹出“noifVC6s_wui.exe”的命令行窗口,这时按两下空格键时期继续运行,运行结束可发现正确的返回了输出信息。

      测试D——
    在资源管理器中选择“noifVC6s.exe”,然后按住鼠标左键拖曳,将其放置在“cmdarg_ui.exe”的文件图标上。于是“cmdarg_ui.exe”会启动,并关联“noifVC6s.exe”。
    界面启动后,点击“运行”按钮右侧的“V”按钮,可以观察到“无窗口”菜单项已经勾选。这时应该点击“无窗口”菜单项,使其取消勾选。
    因为“noifVC6s.exe”没有命令行参数,可以直接点“运行”按钮。弹出“noifVC6s_wui.exe”的命令行窗口,这时按两下空格键时期继续运行,运行结束可发现正确的返回了输出信息。

    五、小结

      本程序能方便命令行程序的使用,而且配置使用非常简单。

      例如将它关联到“checksimd64_2010.exe”(http://www.cnblogs.com/zyl910/archive/2012/05/25/checksimd64.html),也是简单的复制、改名就行了,如图——

      以后编写命令行程序时,只需把这个程序放过去就行了,能极大的方便测试和使用。

    (完)


    源码下载——
    https://files.cnblogs.com/zyl910/cmdarg_ui.rar

  • 相关阅读:
    两种方法生成随机字符串
    cmd命令总结
    NOI前乱写
    多校模拟9
    字符串 口胡
    HEOI2020游记
    省选模拟104
    省选模拟103
    省选模拟102
    省选模拟101
  • 原文地址:https://www.cnblogs.com/zyl910/p/cmdarg_ui.html
Copyright © 2011-2022 走看看