Date: | September 29, 2006 / year-entry #333 |
Tags: | tipssupport |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20060929-06/?p=29533 |
Comments: | 28 |
Summary: | The purpose of quotation marks is to allow a character that would normally be interpreted as a delimiter to be included as part of a file name. Most of the time, this delimiter is the space. The CreateProcess function uses a space to separate the program name from its arguments. Most programs separate their command... |
The purpose of quotation marks is to allow a character that would normally be interpreted as a delimiter to be included as part of a file name. Most of the time, this delimiter is the space. The This means that if you want to add a directory with spaces in its name to the path, you don't need quotation marks since spaces mean nothing to the On the other hand, if the directory you want to add contains a semicolon in its name, then you do need the quotation marks, because it's the semicolon that you need to protect. |
Comments (28)
Comments are closed. |
Actually, sometimes the quotes do hurt. I’ve run into a couple of programs recently (can’t remember which now) that refused to load until I took the quotation marks out of the path variable. That took a while to figure out…
They also hurt because they are characters in what is sometimes a very limited resource (on Win9x at least).
There is a limit on length of env vars in Win9x (at least)
I must admit I have never nor had thought of using ; in a dir. I for some reason thought that was a forbidden character.
Why wasnt |(pipe) or * or some other invalid char used as the separator?
In the past project, I had to place set of strings in a config file. The way I went about placing it was like this:-
Strings=<len1>=<string1><len2>=<string2>….
so the basic unit over there was <len>=<string>
let us say the two strings were "hello" and "world" then in the config file, I place it like this:-
Strings=5=Hello5=world
And what happens if a program unaware of long paths parses PATH variable which contains spaces?
Igor,
If I recall correctly, Windows fakes up some environment variables for 16-bit processes, including the PATH. It contains the short versions of the filenames from the perspective of such programs.
I always thought the semicolon was an invalid character for files and directories; but it is not. I just did an experiment on Windows XP.
From cmd.exe, mkdir test1;test2 creates two directories but mkdir "test1;test2" creates one directory.
Explorer does not complain at all and creates a folder named test1;test.
Recently I came across a directory ending in a space. Explorer had no problem peering inside, however the command prompt could not even with quotes. This piqued my interest so I decided to see how .Net would handle it.
System::IO::GetDirectories on the parent enumerated the folder. Its name included the trailing space. Using GetFiles on the folder threw DirectoryNotFoundException. I then tried to encapsulate the space using quotes and finally appending a slash to no avail.
jamiej: that’s when dir’s /x switch comes in handy…
Well, we all can understand the implication of using | or > or <.
But * ?
SET P=*.*
sets P to.. *.*. So no expansion is done and it could easily be used when the system was designed as a separator.
mikedodd, I had exactly the same problem just last week. Turned out the DirectX SDK inserted its UtilitiesBinx86 folder at the start of my PATH and used quotes.
Rational’s ClearMake and IAR’s C compiler threw fits until we quoted the PATH environment variable. Windows itself doesn’t mind but other people’s code who uses it may not interpret it right.
Ben Cooke (& hobbes78 too):
Windows NTx does (and sometimes even can) not place the dreaded short filenames in environment variables or the registry: NTFS knows a setting "NTFSDisable8dot3NameCreation"!
I’d encourage EVERY developer to turn this setting on (as early as possible, i.e. per modification of the SETUPREG.HIV on the installation media) to catch errors of bad installers!
JFTR: PowerPoint 2003 Viewer and Excel 2003 Viewer both have errors in their installation routines (they come as *.msi; it’t sad that there is no automatic check in the tools or even the msiexec.exe) and don’t place " around the paths they write to the registry.
Trustworthy computing in Redmond?
Raymond, this reminds me of something kind of similar that I ran into recently. .NET console applications seem to have problems with arguments which end in “, and I can’t tell if it’s a .NET thing, a Windows thing, something in between, or boneheadedness on my part. Care to comment?
http://weblogs.asp.net/jgalloway/archive/2006/09/13/Command-Line-Confusion.aspx
Re: Command line parsing, I understand that it’s the program’s responsibility, but it appears that my program’s not being given the arguments correctly. See my post for more details, but here’s an example that shows what I’m talking about. In this case, the Environment.CommandLine property is correct, but args[] (which is populated by the .NET framework) is missing characters.
C:Temp>CommandLineArgumentsTest.exe “\test\” “\test\”
Environment.CommandLine: CommandLineArgumentsTest.exe “\test\” “\test\”
args[0]: \test
args[1]: \test”
.net is an os component.
It’s should not be the app developer’s duty to parse the command line.
Well no, actually, it isn’t. It’s an optional addon, see where Windows Update / Microsoft Update put it.
See also this blog’s tagline:
Now:
There I agree; that’s why I think the way that Unix-like OSes do it is better. Your main() function gets handed an array of strings, rather than one long string; the shell has already done the parsing, and the kernel has kept the array-of-strings setup all the way through until it starts your program. (Or in the case of Windows, either cmd.exe or explorer.exe has done the parsing.)
Now I realize the reason this doesn’t happen is because cmd.exe used to be command.com, and it used to be that DOS only had 640K of RAM available, and command.com had to use as little of that as possible. But that argument just means that each program had to include the same parsing code over and over again (and get it wrong in many cases! apparently including .net for some odd command lines); it didn’t mean the parsing code could go away. Well, unless the program didn’t care about its arguments; then it could go away.
For some reason, it just seems like a bad tradeoff…
Tuesday, October 03, 2006 9:09 AM by BryanK
>
Prior to Vista that’s true, it’s not a critical integrated component like IE. However, the quoted poster was correct for Vista.
Of course that’s true. Now I’m wondering how some .NET stuff sneaked into this blog a few months ago.
And since there is no such thing as Vista yet, only betas (and RCs?), it is still true. And depending on how many times Vista gets pushed back again before it finally gets released, it may be true for quite some time yet.
(OK, yes, I’m being pedantic now. You’re right, I wasn’t paying any attention to Vista when I made that comment.)
Regarding the "not actually a .NET blog" comment, my point was that since the issue is with .Net’s command line parsing code, and Raymond is on the shell team, he (1) probably has no way of even looking into the problem, and (2) very likely can’t do anything about it.
Carlos commented on my blog post and set me straight. It turns out that it’s not just a .NET thing, it’s a CommandLineToArgvW thing.
"Most apps (including .Net apps) use CommandLineToArgvW to decode their command lines. It uses crazy escaping rules which explain the behaviour you’re seeing."
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/commandlinetoargv.asp
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 recently posted on my confusion when I tried to use commandline arguments ending in " and got unpredictable
A quick note about CommandLineToArgvW — these easiest way to get the command-line back in properly parsed form is—-to use the __argc and __argv global variables that *all* C (and C++) program are allowed to access.
They aren’t documented very much, but they work like a charm. And yes, I already reported to Microsoft that they should be mentioned more in the documentation :-)
windows.net (server2k3) has .net framework installed, correct? At least it is bundled with windows ce .net, including windows mobile.
When .net framework is installed, it’s an os component, much like directx (wasn’t bundled with win95a/b – but could be installed).
> Those internal variables are specific to the Microsoft Visual C runtime.
Because argc & argv are broken, you are thus suggesting it would be better to use unportable OS specific functions (CommandLineToArgvW/GetCommandLineW)?
If you use some other company’s OS you may not have those functions. But you knew that, right? I mean, you wouldn’t recommend people do stuff that might break in the future, would you?
> Now your code is portable to all compilers
No, now your code is portable to all *Windows* compilers. Unless Unix (i.e. “some other company’s OS”) has a CommandLineToArgvW call that acts the way Windows’ does, that I’ve missed? ;-P
Using the values that the C library startup routine passes to your main() function is *supposed* to work on any OS that has a C compiler.
(Now, if the program’s C library uses CommandLineToArgvW to get these values, it still won’t be portable as far as the user is concerned. They’ll pass “\” on the command line, and expect one backslash and no quotes. “\” will be expected to give one backslash and one quote (and not terminate the command line). Or at least, this is what happens under any Bourne shell, and it seems a *heck* of a lot more logical to me. But, the code will at least *compile* on other OSes.)
(To clarify: I suspect that “use the standard please” meant that you should use the arguments to main(), not the undocumented __argc and __argv variables provided by only the Microsoft C library. But I don’t know what he meant for sure, so maybe I shouldn’t assume it. And since you were talking about the undocumented variables, it seems that his argument doesn’t make much sense in the context it was presented.)
CommandLineToArgvW was somebody else’s suggestion. -Raymond]
PingBack from http://blogs.msdn.com/michkap/archive/2006/12/13/1275292.aspx