Windows has the additional complication that the arguments of a program are actually handled as a single string, instead of a string array as in Unix, so the programs parse the command line into arguments. This is done by the libc for most programs, but not all programs use that, so there are sometimes differences how the same command line is split into arguments depending on the receiving program. This also means that there are bugs in applications supplying command line flags to other applications due to missing or incorrect quoting, since CreateProcess and .NET Process expect a single string as the command line.
Indeed. Splitting, quotes and globs are all handled by the application rather than the shell.
Furthermore, you don't just have the two categories of "programs that use libc" and "programs that wing it", but also the third category of "programs that use shell32". Windows ships with two cmdline->argv implementations - one in MSVCRT and the other in shell32. Both are first-party but don't split args the same in all cases.
What is an example of a command line string that is split differently by Shell32 and MSVCRT? In D, we use CommandLineToArgvW. I'm guessing it's related to Unicode?
(Nothing to do with unicode. I haven't got a Windows machine to test, but I assume WinMain will behave the same as main wrt quotes and spaces.)
(Note that Rust doesn't use CLTAW any more; it switched to "winging it" ie its own implementation. Among other things, this allowed it to drop the dependency on shell32, which is useful for running compiled binaries in nanoserver containers.)
MSDN has this blurb with sounds rather... weird to me:
> CommandLineToArgvW has a special interpretation of backslash characters when they are followed by a quotation mark character ("). This interpretation assumes that any preceding argument is a valid file system path, or else it may behave unpredictably.
This also of course leads to inconsistencies in quoting and escaping and makes secure scripting practically impossible. But hey! It certainly was a little easier 30 years ago!
Be sure to check out the related blog article at the bottom concerning DLL injection, too -- it is some severe faceplam that "c:\windows \system32\" is considered a trusted directory for auto escalation (after what I presume was `inputdir.ReplaceAll(" ", "").Equals(...)`)