DRIVE_GetUnixCwd and drives other than the current one
Troy Rollo
wine at troy.rollo.name
Tue Jul 22 20:48:27 CDT 2003
It appears that Wine is storing and using a "current directory" for each DOS
drive. According to some testing we have just done on Windows 2000 and
Windows 98, Windows only stores a current directory for the current drive.
"But CMD.EXE seems to remember drives, and their children too", comes the
reply.
Well, sort of. The documentation for CreateProcess talks about environment
variables used to hold the current directory for each drive, with an
environment variable with a name of the form "=C:" having the value, say
"C:\WINDOWS". That documentation suggests you must make sure all these
environment variables are set if you construct a new environment block, and
that you need to get the values of them using "GetFullPathName". Shock,
horror, the Windows documentation is wrong.
What actually happens is that CMD.EXE and COMMAND.COM independently set those
environment variables when you change directories in those shells.
SetCurrentDirectory has no effect on those environment variables - either in
the current process or in child processes. It is the responsibility of the
application to set them if it wants the children to have access to its
current directory on drives other than its current drive.
However, SetCurrentDirectory("D:") (assuming a starting point of drive "C")
will read those environment variables to determine which directory of drive
"D" to go to. You can even 'SetEnvironmentVariable("=D:", "\\foo")' to make
the next 'SetCurrentDirectory("D:")' end up in "D:\foo".
GetFullPathName also picks up the environment variable if the path requested
is not on the current drive (although it also checks that the path is valid,
so 'GetFullPathName("A:\\", ...)' will rattle drive A if drive A is empty).
If there's no environment variable, both GetFullPathName and
SetCurrentDirectory assume "x:\".
If the drive in question is the current drive, SetCurrentDirectory and
GetFullPathName both ignore the environment variables and use the value from
GetCurrentDirectory. So, for example:
// Start with no "=D:" variable in environment
SetCurrentDirectory("d:\\bar");
SetCurrentDirectory("c:");
SetCurrentDirectory("d:");
// Current directory now d:\
SetCurrentDirectory("d:\\bar");
SetCurrentDirectory("c:");
SetEnvironmentVariable("=D:", "\\foo");
SetCurrentDirectory("d:");
// Current directory now "d:\\foo";
SetEnvironmentVariable("=D:", "\\bar");
SetCurrentDirectory("d:");
// Current directory still d:\\foo
The Borland C++ run-time libraries have code in their chdir functions that
sets these variables, but it's inside a "#if 0" section, presumably
reflecting an attempt to be compatible with MSC.
I'm not aware of anything that relies on this perverse behaviour, so whether
Wine needs to be adjusted to mimic it may be an open question. It is probably
of more interest to people who want to pass an environment block to
CreateProcess. If you're doing that, ignore what the documentation says about
including "=C:" & etc environment variables in the environment block - simply
start with the environment block returned by GetEnvironmentBlock and make the
desired changes, ensuring the block is sorted according to instructions I
gave previously on one of the Cygwin mailing lists.
More information about the wine-devel
mailing list