by Michael S. Kaplan, published on 2007/10/26 10:01 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2007/10/26/5677426.aspx
I was reading Raymond's Superstition: Why is GetFileAttributes the way old-timers test file existence? the other day and all I could think about was the fact that the way that Microsoft Layer for Unicode on Windows 95/98/Me Systems (MSLU) had to drop its usage of this function!
You see, originally we used a GetFileAttributesW call to determine whether we were running on a 9x or an NT-based platform.
MSLU (in the loader) would pass it L"???.???" as a filename, and then after the function failed (which it always did since the filename was invalid) we'd call GetLastError and look for either ERROR_INVALID_PARAMETER on an NT-based platform or ERROR_CALL_NOT_IMPLEMENTED on a Win9x-based platform.
The method being used was actually recommended by several old-timers, interestingly enough. Raymond might even have been one of them though I honestly can't remember; several others definitely did. The theory was simple:
The first few releases of MSLU shipped with this code in its loader and in the DLL.
Then we got an interesting bug report from a product team that was using MSLU (I believe it was Microsoft Picture It!) that was getting random failures trying to use MSLU, on some but not all machines -- NT only!
We had not been having any NT-based bug reports before since the library worked so hard to run as little code as possible on NT-based platforms, so I was understandably freaked by this turn of events....
It was quite difficult to get the repro set up, as no one could isolate when it happened and once I was vigorously looking into it, no one was seeing it anymore.
Finally, I found out that the close-to-headcheck for the filename being invalid was preceded by a closer-to-headcheck for the drive being invalid.
And it just so happens that Picture It! was often setting the CDROM drive to be the current drive, even though someone might remove the disk from the drive prior to any Unicode based functions being called.
And when this happened, the detection was failing and nothing good was happening after that.
We triaged it and looked all kinds of fixes (like always appending a valid path which seemed stupid to have to do for a file that was going to be invalid anyway or detecting the additional case as an NT-based platform and so on) before finally deciding to stop using GetFileAttributesW and finding another way to do the detection. We wanted to be running as little code as possible and adding any code in there was just not really something we wanted to do....
So much for GetFileAttributes being the fastest function, in my mind it will forever be associated with all the rest of the Win32 functions that do too much! :-)
This post brought to you by . (U+002e, a.k.a. FULL STOP)
# Mike Dimmick on 26 Oct 2007 11:34 AM:
Presumably some oddity where CDFS did something differently and returned a different error number? Raymond would tell you that Windows error numbers are not documented so they can be changed in future.
# Michael S. Kaplan on 26 Oct 2007 11:40 AM:
Yup. In fact since the 9x code path was known and fixed, it could have been written smarter to assume all other errors are NT-based. But it still meant the code paath was slower than it had to be, so we gave up and found a faster method (one that would not involve more code running!)....
# BryanK on 26 Oct 2007 3:53 PM:
Could you have just used L"C:\\???.???" instead (providing an absolute path)? Or are there other issues with that route?
(Actually, is the C: drive actually guaranteed to exist in both 9x and NT? I suspect so, but I don't know for sure. It's not guaranteed in ancient windows versions (1.0 at least, and possibly 3.1), as they can (in a pinch) run from a floppy disk only. But I don't think you can do that in 95 and newer anymore.)
# Michael S. Kaplan on 26 Oct 2007 3:56 PM:
Well, we had that worry -- about the drive existing. Mainly it was the notion that this would run a lot of extra code, it kind of freaked us out a bit....
# Igor on 26 Oct 2007 8:40 PM:
So how does the actual code look now?
# Michael S. Kaplan on 26 Oct 2007 10:33 PM:
You mean the actual platfrom detection? Ah, we just look for a function that is only on one platform and never the other (but we don't call it, we just GetProcAddress it to see if it exists)....
# Michael Dunn_ on 28 Oct 2007 10:41 PM:
You can't assume you'll have a C: drive, most notably because of NEC PC-98 hardware where the hard drive is A: *shiver*
# John Elliott on 29 Oct 2007 8:59 AM:
In NT 3.51 it's quite possible to change the letter of the system drive, so you have (for example) only drive E:. NT 3.1 doesn't seem to like existence without a drive C:, and later ones need to have their registries monkeyed with.
Yuhong Bao on 6 Dec 2010 6:42 PM:
"You can't assume you'll have a C: drive, most notably because of NEC PC-98 hardware where the hard drive is A: "
And the floppy was C:. Imagine being prompted for a floppy because some program hardcoded a C: drive!
Michael S. Kaplan on 6 Dec 2010 8:56 PM:
It was only an NT bug, and AFAIK that machine couldn't run NT.
I had one down the hall from me, back in the day....
Yuhong Bao on 7 Dec 2010 12:09 PM:
Yes, it did, up to Win2000.
Yuhong Bao on 10 Dec 2010 10:40 PM:
For the record, it ran Win9x up to 98SE. WinMe did not have a NEC PC-98 version.