Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start a second copy of the program with the same arguments

Tags:

c#

What is the correct way for a application to restart another copy of itself with the same arguments?

My current method is to do the following

static void Main()
{
    Console.WriteLine("Start New Copy");
    Console.ReadLine();

    string[] args = Environment.GetCommandLineArgs();

    //Will not work if using vshost, uncomment the next line to fix that issue.
    //args[0] = Regex.Replace(args[0], "\\.vshost\\.exe$", ".exe");

    //Put quotes around arguments that contain spaces.
    for (int i = 1; i < args.Length; i++)
    {
        if (args[i].Contains(' '))
            args[i] = String.Concat('"', args[i], '"');
    }

    //Combine the arguments in to one string
    string joinedArgs = string.Empty;
    if (args.Length > 1)
        joinedArgs = string.Join(" ", args, 1, args.Length - 1);

    //Start the new process
    Process.Start(args[0], joinedArgs);
}

However it seems like there is a lot of busy work in there. Ignoring the striping of the vshost, I still need to wrap arguments that have spaces with " and combine the array of arguments in to a single string.

Is there a better way to launch a new copy of the program (including the same arguments), perhaps a way just needing to pass in Enviroment.CommandLine or takes a string array for the arguments?

like image 729
Scott Chamberlain Avatar asked Jun 01 '12 17:06

Scott Chamberlain


2 Answers

You would have to quote command line arguments that contain spaces (and perhaps other characters, that I am not sure of). Perhaps something like this:

var commandLine = string.Join(" ", args.Select(s => s.Contains(' ') ? "\"" + s + "\"" : s));
var newProcess = Process.Start("yourapplication.exe", commandLine);

Additionally, rather than using

string[] args = Environment.GetCommandLineArgs();

You could just accept them in your Main method instead:

public static void Main(string[] args)
{
    var commandLine = string.Join(" ", args.Select(s => s.Contains(' ') ? "\"" + s + "\"" : s));
    var newProcess = Process.Start(Environment.GetCommandLineArgs()[0], commandLine);
}

The vshost workaround you have right now seems fine, alternatively you could disable the whole vshost thing by unchecking "Enable Visual Studio hosting process" on the debug tab of your project. Some debugging features do get disabled when do you that. Here is a good explanation of that.

EDIT:

A better way to work around it would be to get the codebase to the entry point assembly:

public static void Main(string[] args)
{
    var imagePath = Assembly.GetEntryAssembly().CodeBase;
    var commandLine = string.Join(" ", args.Select(s => s.Contains(' ') ? "\"" + s + "\"" : s));
    var newProcess = Process.Start(imagePath, commandLine);
}

That will work with or without the vshost enabled.

like image 101
vcsjones Avatar answered Oct 18 '22 03:10

vcsjones


Ok this should work I guess.

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern System.IntPtr GetCommandLine();
static void Main(string[] args)
{
  System.IntPtr ptr = GetCommandLine();
  string commandLine = Marshal.PtrToStringAuto(ptr); 
  string arguments = commandLine.Substring(commandLine.IndexOf("\"", 1) + 2);
  Console.WriteLine(arguments);
  Process.Start(Assembly.GetEntryAssembly().Location, arguments);
}

Reference: http://pinvoke.net/default.aspx/kernel32/GetCommandLine.html

like image 29
Sandeep Singh Rawat Avatar answered Oct 18 '22 03:10

Sandeep Singh Rawat