[.NET Gotcha] Commandline args ending in \" are subject to CommandLineToArgvW whackiness

I recently posted on my confusion when I tried to use commandline arguments ending in \" and got unpredictable results. It seemed that all backslashes before a double quote character needed to be escaped, but if they didn't preceed a doublequote, they didn't need to be escaped.

There's more explanation on the original blog post, but here's a summary:

To pass \\this is a test\\ to a console application, you need to pass in \\this is a test\\\\. The first set of backslashes don't require escaping, but the second set do. Stranger still, adding another backslash to that second set has no effect at all doesn't add a backslash, but adds a doublequote: \\this is a test\\\\\ (with 5 backslashes) yields \\this is a test\\". [thanks for correcting me, Carlos].

Via a comment thread on Raymond Chen's blog, I got some help from Carlos:

"Most apps (including .Net apps) use CommandLineToArgvW to decode their command lines.  It uses crazy escaping rules which explain the behaviour you're seeing."

The explanation on MSDN:

CommandLineToArgvW has a special interpretation of backslash characters when they are followed by a quotation mark character ("), as follows:

  • 2n backslashes followed by a quotation mark produce n backslashes followed by a quotation mark.
  • (2n) + 1 backslashes followed by a quotation mark again produce n backslashes followed by a quotation mark.
  • n backslashes not followed by a quotation mark simply produce n backslashes.

I prefer Carlos' listing of the rules:

Backslash is the escape character; always escape quotes; only escape backslashes if they precede a quote.

2 Comments

  • There's a mistake in your post. The version with five tailing backslashes "\\this is a test\\\\\" yields:

    \\this is a test\\"

    Note the trailing quote. The MSDN docs are slightly wrong. They should read:

    * 2n backslashes followed by a quotation mark produce n backslashes followed by an *unescaped* quotation mark.

    * (2n) + 1 backslashes followed by a quotation mark again produce n backslashes followed by an *escaped* quotation mark.

    An unescaped quotation mark followed by a space terminates the current parameter. Unescaped quotation marks never appear in your argument list. E.g. the parameter "a"b" yields:

    ab

    And finally (just to confuse things further) you can also escape quotes by doubling them up.

  • Thanks for that. It's definitely confusing when .NET doesn't do the "reasonable" thing...

Comments have been disabled for this content.