Excellent Thanks!
On 11 June 2013 01:59, Greg Najda <gregna...@gmail.com> wrote: > The Windows > CreateProcess<http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx>function > takes command line arguments as a single string. This detail > leaked into the .NET Process class. Windows programs with a > WinMain<http://msdn.microsoft.com/en-us/library/windows/desktop/ms633559%28v=vs.85%29.aspx>entry > point typically break that argument string into arguments using > CommandLineToArgvW<http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx>. > 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 > CommandLineToArgvW<http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx>and > Raymond Chen's blog > post<http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx>for > info. Simply enclosing in quotes and putting a backslash before quotes > and backslashes is not good enough for Windows. > > 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 > g_shell_parse_argv()<https://developer.gnome.org/glib/2.34/glib-Shell-related-Utilities.html#g-shell-parse-argv>function > to convert the arg string into an argv before starting the process. > > Feel free to use the following code taken from a personal project of > mine<https://bitbucket.org/LHCGreg/dbsc/src/c3cca47e6b190f7b6fad47c12d781e445e962acc/mydbsc/MySqlDbscEngine.cs?at=master>. > It passes the unit tests I threw it. > > private string QuoteCommandLineArg(string arg) > { > if (Environment.OSVersion.Platform == PlatformID.Unix || > Environment.OSVersion.Platform == PlatformID.MacOSX) > { > return QuoteCommandLineArgUnix(arg); > } > else > { > return QuoteCommandLineArgWindows(arg); > } > } > > internal static string QuoteCommandLineArgWindows(string arg) > { > // If a double quotation mark follows two or an even number of > backslashes, > // each proceeding backslash pair is replaced with one > backslash and the double quotation mark is removed. > // If a double quotation mark follows an odd number of > backslashes, including just one, > // each preceding pair is replaced with one backslash and the > remaining backslash is removed; > // however, in this case the double quotation mark is not > removed. > // - > http://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs.aspx > // > // Windows command line processing is funky > > string escapedArg; > Regex backslashSequenceBeforeQuotes = new Regex(@"(\\+)"""); > // Double \ sequences before "s, Replace " with \", double \ > sequences at end > escapedArg = backslashSequenceBeforeQuotes.Replace(arg, > (match) => new string('\\', match.Groups[1].Length * 2) + "\""); > escapedArg = escapedArg.Replace("\"", @"\"""); > Regex backslashSequenceAtEnd = new Regex(@"(\\+)$"); > escapedArg = backslashSequenceAtEnd.Replace(escapedArg, > (match) => new string('\\', match.Groups[1].Length * 2)); > // C:\blah\"\\ > // "C:\blah\\\"\\\\" > escapedArg = "\"" + escapedArg + "\""; > return escapedArg; > } > > internal static string QuoteCommandLineArgUnix(string arg) > { > // Mono uses the GNOME g_shell_parse_argv() function to > convert the arg string into an argv > // Just prepend " and \ with \ and enclose in quotes. > // Much simpler than Windows! > > Regex backslashOrQuote = new Regex(@"\\|"""); > return "\"" + backslashOrQuote.Replace(arg, (match) => @"\" + > match.ToString()) + "\""; > } > > > Hope that helps. > > - Greg > > > > On Mon, Jun 10, 2013 at 3:46 PM, Ian Norton <inor...@gmail.com> wrote: > >> 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. :) >> >> >> On 10 June 2013 16:06, Michael Hutchinson <m.j.hutchin...@gmail.com>wrote: >> >>> 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: >>> >>> static Process StartProcess (string name, params string[] args) >>> { >>> string a = null; >>> if (args != null && args.Length > 0) >>> a = "\"" + string.Join (args.Select (s => s.Replace ("\"", >>> "\\\"")).ToArray (), "\" \"") + "\""; >>> return Process.Start ( >>> new ProcessStartInfo (name, a) { >>> ShellExecute = false, >>> } >>> ); >>> } >>> >>> Obviously this could be done more efficiently with a StringBuilder. >>> >>> Apologies for any errors, I'm writing this on my phone... >>> >>> - Michael >>> On Jun 6, 2013 1:18 PM, "Ian Norton" <inor...@gmail.com> wrote: >>> >>>> 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. >>>> >>>> Ie, In perl or C I'd do: >>>> >>>> system("df","-m","/home/foo/Documents/Pictures/My Holiday"); >>>> >>>> Where in c# I'm forced to escape the space -> "My\ Holiday" >>>> >>>> Ian >>>> >>>> _______________________________________________ >>>> Mono-devel-list mailing list >>>> Mono-devel-list@lists.ximian.com >>>> http://lists.ximian.com/mailman/listinfo/mono-devel-list >>>> >>>> >> >> _______________________________________________ >> Mono-devel-list mailing list >> Mono-devel-list@lists.ximian.com >> http://lists.ximian.com/mailman/listinfo/mono-devel-list >> >> >
_______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list