简体   繁体   中英

Executing custom commands from command prompt in winform C#

I have a third party executable command which is being bundled into my winform application. The command is placed inside a directory called "tools" from the directory where the application is being executed.

For example, if my winform mytestapp.exe is placed in D:\\apps\\mytestapp directory, then the path to the third party command is D:\\apps\\mytestapp\\tools\\mycommand.exe. I'm using Application.StartupPath to identify the location of mytestapp.exe, so that it can be run from any location.

I'm executing this command by starting a process - System.Diagnostics.Process.Start and executing the same using command prompt. There are additional parameters to be passed to run the command.

The problem I'm facing is, if the path to my application and the command does not have any white spaces in it, it works fine

For example, if my app and command is placed like below, it works D:\\apps\\mytestapp\\mytestapp.exe D:\\apps\\mytestapp\\tools\\mycommand.exe "parameter1" "parameter2" - this works

however if I have a white space in the path, it fails

C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe "parameter1" "parameter2" - doesnt work C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe "parameter1 parameter2" - doesnt work "C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe" "parameter1 parameter2" - doesnt work "C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe parameter1 parameter2" - doesnt work

I tried using double quotes for executing the command as shown above and it doesn't work. So, how do I execute my custom command. Any inputs or work around for this issue? Thanks in advance.

Here is the code for starting the process

try
        {
            System.Diagnostics.ProcessStartInfo procStartInfo =
                new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
            procStartInfo.RedirectStandardOutput = true;
            procStartInfo.UseShellExecute = false;
            procStartInfo.CreateNoWindow = true;
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo = procStartInfo;
            proc.Start();
            proc.WaitForExit();
        }
        catch (Exception objException)
        {
            // Log the exception
        }

Try to extract the Working directory from your command and set the WorkingDirectory property for the ProcessStartInfo object. Then in your command pass only the filename.

This example assumes that command contains only the full filename.
Need to be adjusted for your actual command text

string command = "C:\Documents and settings\mytestapp\tools\mycommand.exe";
string parameters = "parameter1 parameter2";

try
{
    string workDir = Path.GetDirectoryName(command);
    string fileCmd = Path.GetFileName(command);
    System.Diagnostics.ProcessStartInfo procStartInfo =
        new System.Diagnostics.ProcessStartInfo("cmd", "/c " + fileCmd + " " + parameters);
    procStartInfo.WorkingDirectory = workDir;
    procStartInfo.RedirectStandardOutput = true;
    procStartInfo.UseShellExecute = false;
    procStartInfo.CreateNoWindow = true;
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo = procStartInfo;
    proc.Start();
    proc.WaitForExit();
}
catch (Exception objException)
{
    // Log the exception
}

I believe the following works: "C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe" "parameter1" "parameter2"

You may have something else wrong. Try to debug and check whether quote is used twice, or if there are quotes in the middle.

I think it could be because quotes are needed in args (and command) strings that refer to paths that contain whitespace; also they need to be escaped when defined non-verbatim (ie no @ preceding the string) in-code, so the command string would be defined like this:

var command = "\"C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe\"";
             // ^ escaped quote                                              ^ escaped quote

Specifically for starting processes I wrote this method not long ago, it could be a little bit too specialized for this specific case, but one could easily take it as is and/or write overloads with different parameters for different flavors of setting up a process:

private ProcessStartInfo CreateStartInfo(string command, string args, string workingDirectory, bool useShellExecute)
{
    var defaultWorkingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty;
    var result = new ProcessStartInfo
    {
        WorkingDirectory = string.IsNullOrEmpty(workingDirectory) 
                                 ? defaultWorkingDirectory 
                                 : workingDirectory,
        FileName = command,
        Arguments = args,
        UseShellExecute = useShellExecute,
        CreateNoWindow = true,
        ErrorDialog = false,
        WindowStyle = ProcessWindowStyle.Hidden,
        RedirectStandardOutput = !useShellExecute,
        RedirectStandardError = !useShellExecute,
        RedirectStandardInput = !useShellExecute
    };
    return result;
}

I'm using it like below; here the _process object could be any Process - having it as an instance variable might not be valid for your use case; also the OutputDataReceived and ErrorDataReceived event handlers (not shown) only log the output string - but you could parse it and base some course of action upon it:

public bool StartProcessAndWaitForExit(string command, string args, 
                     string workingDirectory, bool useShellExecute)
{
    var info = CreateStartInfo(command, args, workingDirectory, useShellExecute);            
    if (info.RedirectStandardOutput) _process.OutputDataReceived += _process_OutputDataReceived;
    if (info.RedirectStandardError) _process.ErrorDataReceived += _process_ErrorDataReceived;

    var logger = _logProvider.GetLogger(GetType().Name);
    try
    {
        _process.Start(info, TimeoutSeconds);
    }
    catch (Exception exception)
    {
        logger.WarnException(log.LogProcessError, exception);
        return false;
    }

    logger.Debug(log.LogProcessCompleted);
    return _process.ExitCode == 0;
}

The args string you pass is exactly how you would enter it at the command-line, so in your case that might look like:

CreateStartInfo("\"C:\\Documents and settings\\mytestapp\\tools\\mycommand.exe\"", 
                "-switch1 -param1:\"SomeString\" -param2:\"Some\\Path\\foo.bar\"",
                string.Empty, true);

If you instead put the path/command strings in a settings file, you can store them without needing to escape quotes and backslashes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM