从用户字符串中拆分文件名和参数

Split filename and arguments from user string

我正在用 C# 编写一个工具箱程序,它的一个功能是模拟 Windows 开始菜单 "Run" 对话框,还允许用户在需要时提升权限。

为此,我有一个简单的 WinForm,带有一个文本框(用户在其中键入内容)和一个复选框(如果选中,请添加 "runas" 动词)。当然还有 3 个按钮:确定、取消和浏览(打开文件对话框)。所以我的代码看起来像这样:

var psi = new ProcessStartInfo(textBox1.Text, "");
psi.CreateNoWindow = true;
psi.UseShellExecute = true;
if (checkBox1.Checked == true)
{
    psi.Verb = "runas";
}
try
{
    Process.Start(psi);
}
catch (System.ComponentModel.Win32Exception ex)
{
    // do something
    MessageBox.Show("Error : " + ex.Message);
}

如果用户键入 "notepad" 或 "notepad.exe" 或 "c:\whatever\path\notepad",它会起作用。传递参数时开始出现问题:"notepad test.txt" 不起作用。

我的第一个想法是在遇到 space 时拆分 textBox1.Text,然后将第一部分用于 ProcessStartInfo.Filename,将第二部分用于参数。 "notepad test.txt" 就可以了。但是,如果用户使用文件对话框 select 路径 and/or 文件名包含 space (或键入它)的文件,当然字符串将被拆分并且一切都会出错.

不幸的是,ParseStartInfo 需要文件名和参数(可以是空字符串),但文件名不能包含参数...使用引号(对于整个 textBox1.Text 作为文件名)不起作用要么。

所以,有没有人有解决方案:

  1. 要么正确拆分 textBox1.Text 到有效的文件名 + 参数, 正如 Windows 开始 - 运行 对话框那样

  1. 也许可以使用 Shell32.FileRun() 但在这种情况下,如何请求 随意提升(UAC 提示)?

编辑:添加了 MessageBox.Show 以显示错误消息

你仍然可以使用 split 方法,而不是使用 "first string"(从 split 方法返回的数组的第一个元素)作为命令,然后重新连接其他字符串以组成名称文件。

虽然我通常不喜欢将较长的代码转储到 SO 上,但也许这次它对您还是有些帮助。

这是我自己的函数,多年来我一直在使用它来拆分:

/// <summary>
/// Splits the file name if it contains an executable AND an argument.
/// </summary>
public static void CheckSplitFileName( ref string fileName, ref string arguments )
{
    if ( !string.IsNullOrEmpty( fileName ) )
    {
        if ( fileName.IndexOf( @"http://" ) == 0 ||
            fileName.IndexOf( @"https://" ) == 0 ||
            fileName.IndexOf( @"ftp://" ) == 0 ||
            fileName.IndexOf( @"file://" ) == 0 )
        {
            // URLs not supported, skip.
            return;
        }
        if ( File.Exists( fileName ) )
        {
            // Already a full path, do nothing.
            return;
        }
        else if ( Directory.Exists( fileName ) )
        {
            // Already a full path, do nothing.
            return;
        }
        else
        {
            // Remember.
            string originalFileName = fileName;

            if ( !string.IsNullOrEmpty( fileName ) )
            {
                fileName = fileName.Trim();
            }

            if ( !string.IsNullOrEmpty( arguments ) )
            {
                arguments = arguments.Trim();
            }

            // --

            if ( string.IsNullOrEmpty( arguments ) &&
                !string.IsNullOrEmpty( fileName ) && fileName.Length > 2 )
            {
                if ( fileName.StartsWith( @"""" ) )
                {
                    int pos = fileName.IndexOf( @"""", 1 );

                    if ( pos > 0 && fileName.Length > pos + 1 )
                    {
                        arguments = fileName.Substring( pos + 1 ).Trim();
                        fileName = fileName.Substring( 0, pos + 1 ).Trim();
                    }
                }
                else
                {
                    int pos = fileName.IndexOf( @" " );
                    if ( pos > 0 && fileName.Length > pos + 1 )
                    {
                        arguments = fileName.Substring( pos + 1 ).Trim();
                        fileName = fileName.Substring( 0, pos + 1 ).Trim();
                    }
                }
            }

            // --
            // Possibly revert back.

            if ( !string.IsNullOrEmpty( fileName ) )
            {
                string s = fileName.Trim( '"' );
                if ( !File.Exists( s ) && !Directory.Exists( s ) )
                {
                    fileName = originalFileName;
                }
            }
        }
    }
}

我的使用方式如下:

var fileName = textBox1.Text.Trim();
var arguments = string.Empty;
CheckSplitFileName( ref fileName, ref arguments );

然后,将其传递给 ProcessStartupInfo class:

var info = new ProcessStartInfo();
info.FileName = fileName;
info.Arguments = arguments;

我会尝试像这样拆分 TextBox 字符串:

  1. string[] elements1 = textBox1.Text.Split(new string[] {"\"}, StringSplitOptions.RemoveEmptyEntries); 你会得到路径元素
  2. string[] elements2 = elements1[elements1.length-1].Split(new string[] {" "}, StringSplitOptions.RemoveEmptyEntries); 所以 elements2[0] 包含应用程序名称(例如记事本)和其他元素文件名
  3. string filename = String.Concat(elements2[1], " ", elements2[2], " ", ...)