<div dir="ltr"><div><div><div><div>The Windows <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx">CreateProcess</a> function takes command line arguments as a single string. This detail leaked into the .NET Process class. Windows programs with a <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms633559%28v=vs.85%29.aspx">WinMain</a> entry point typically break that argument string into arguments using <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx">CommandLineToArgvW</a>. With a regular "main" entry point, the C runtime does that for you. Unfortunately there is no ArgvToCommandLine function, which is a shame because CommandLineToArgvW has pretty funky rules for quotes and backslashes. See the docs for <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx">CommandLineToArgvW</a> and Raymond Chen's <a href="http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx">blog post</a> for info. Simply enclosing in quotes and putting a backslash before quotes and backslashes is not good enough for Windows.<br>
<br></div>I was curious about this myself a week or two ago because I had to pass some dynamic arguments to a process so I dove into the Mono source. On Windows Mono passes the argument string as is to CreateProcess. On Unix platforms Mono uses the GNOME <a href="https://developer.gnome.org/glib/2.34/glib-Shell-related-Utilities.html#g-shell-parse-argv">g_shell_parse_argv()</a> function to convert the arg string into an argv before starting the process.<br>
<br></div>Feel free to use the following code taken from <a href="https://bitbucket.org/LHCGreg/dbsc/src/c3cca47e6b190f7b6fad47c12d781e445e962acc/mydbsc/MySqlDbscEngine.cs?at=master">a personal project of mine</a>. It passes the unit tests I threw it.<br>
<br>        private string QuoteCommandLineArg(string arg)<br>        {<br>            if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)<br>            {<br>                return QuoteCommandLineArgUnix(arg);<br>
            }<br>            else<br>            {<br>                return QuoteCommandLineArgWindows(arg);<br>            }<br>        }<br><br>        internal static string QuoteCommandLineArgWindows(string arg)<br>        {<br>
            // If a double quotation mark follows two or an even number of backslashes,<br>            // each proceeding backslash pair is replaced with one backslash and the double quotation mark is removed.<br>            // If a double quotation mark follows an odd number of backslashes, including just one,<br>
            // each preceding pair is replaced with one backslash and the remaining backslash is removed;<br>            // however, in this case the double quotation mark is not removed. <br>            // - <a href="http://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs.aspx">http://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs.aspx</a><br>
            //<br>            // Windows command line processing is funky<br><br>            string escapedArg;<br>            Regex backslashSequenceBeforeQuotes = new Regex(@"(\\+)""");<br>            // Double \ sequences before "s, Replace " with \", double \ sequences at end<br>
            escapedArg = backslashSequenceBeforeQuotes.Replace(arg, (match) => new string('\\', match.Groups[1].Length * 2) + "\"");<br>            escapedArg = escapedArg.Replace("\"", @"\""");<br>
            Regex backslashSequenceAtEnd = new Regex(@"(\\+)$");<br>            escapedArg = backslashSequenceAtEnd.Replace(escapedArg, (match) => new string('\\', match.Groups[1].Length * 2));<br>            // C:\blah\"\\<br>
            // "C:\blah\\\"\\\\"<br>            escapedArg = "\"" + escapedArg + "\"";<br>            return escapedArg;<br>        }<br><br>        internal static string QuoteCommandLineArgUnix(string arg)<br>
        {<br>            // Mono uses the GNOME g_shell_parse_argv() function to convert the arg string into an argv<br>            // Just prepend " and \ with \ and enclose in quotes.<br>            // Much simpler than Windows!<br>
<br>            Regex backslashOrQuote = new Regex(@"\\|""");<br>            return "\"" + backslashOrQuote.Replace(arg, (match) => @"\" + match.ToString()) + "\"";<br>
        }<br><br><br></div>Hope that helps.<br><br></div>- Greg<br><div><div><div><div><div><div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jun 10, 2013 at 3:46 PM, Ian Norton <span dir="ltr"><<a href="mailto:inorton@gmail.com" target="_blank">inorton@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">I kind of already have a thing to do that, feels a bit icky though, especially as there must be some thing lower down that undoes the joined up string into a char** again. :)</div>
<div class=""><div class="h5"><div class="gmail_extra"><br>
<br><div class="gmail_quote">On 10 June 2013 16:06, Michael Hutchinson <span dir="ltr"><<a href="mailto:m.j.hutchinson@gmail.com" target="_blank">m.j.hutchinson@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<p dir="ltr">FWIW, you actually just need to double quote each argument and escape double quotes so you can very easily write a helper to do this in a way that works on both Mono and .NET:</p>
<p dir="ltr">static Process StartProcess (string name, params string[] args)<br>
{<br>
    string a = null;<br>
    if (args != null && args.Length > 0)<br>
        a = "\"" + string.Join (args.Select (s => s.Replace ("\"", "\\\"")).ToArray (), "\" \"") + "\"";<br>
    return Process.Start (<br>
        new ProcessStartInfo (name, a) {<br>
            ShellExecute = false,<br>
        }<br>
    );<br>
}</p>
<p dir="ltr">Obviously this could be done more efficiently with a StringBuilder.</p>
<p dir="ltr">Apologies for any errors, I'm writing this on my phone...</p>
<p dir="ltr">- Michael</p>
<div class="gmail_quote"><div><div>On Jun 6, 2013 1:18 PM, "Ian Norton" <<a href="mailto:inorton@gmail.com" target="_blank">inorton@gmail.com</a>> wrote:<br type="attribution"></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<div><div>
<div dir="ltr">Hiya, I'm aware that I can use Process.Start() but I'd really really like to be able to directly pass a list of strings to my child process as arguments rather than having to escape shell characters and spaces etc.<div>



<br></div><div>Ie, In perl or C I'd do:</div><div><br></div><div>system("df","-m","/home/foo/Documents/Pictures/My Holiday");</div><div><br></div><div>Where in c# I'm forced to escape the space -> "My\ Holiday"</div>



<div><br></div><div>Ian</div></div>
<br></div></div>_______________________________________________<br>
Mono-devel-list mailing list<br>
<a href="mailto:Mono-devel-list@lists.ximian.com" target="_blank">Mono-devel-list@lists.ximian.com</a><br>
<a href="http://lists.ximian.com/mailman/listinfo/mono-devel-list" target="_blank">http://lists.ximian.com/mailman/listinfo/mono-devel-list</a><br>
<br></blockquote></div>
</blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
Mono-devel-list mailing list<br>
<a href="mailto:Mono-devel-list@lists.ximian.com">Mono-devel-list@lists.ximian.com</a><br>
<a href="http://lists.ximian.com/mailman/listinfo/mono-devel-list" target="_blank">http://lists.ximian.com/mailman/listinfo/mono-devel-list</a><br>
<br></blockquote></div><br></div></div></div></div></div></div></div></div>