October, 2003

  • The Old New Thing



    In a previous entry I discussed the story behind the functions with the funny names BEAR, BUNNY and PIGLET. But what about the ones with goofier names like BOZOSLIVEHERE and TABTHETEXTOUTFORWIMPS?

    For this, you need a deeper history lesson.

    Back in the old days of real-mode Windows, all callback functions had to be exported. This was necessary for complicated technical reasons I may bother to explain if anybody really cared but I doubt anybody does any more. So the window procedures for all of the standard window classes (edit controls, list boxes, check boxes, etc.) were exported from USER. So too were various other callback functions like timer procedures. This was in addition to the usual collection of internal functions so USER, KERNEL and GDI could coordinate their efforts.

    Some people reverse-engineered all these internal functions and printed books on how they worked, and as a result there were a lot of programs that actually used them. Which was quite a surprise to us because they were internal functions. And then when we wanted to redesign these internal functions (for example, to add a parameter, or if we decided that we didn't need it any more and tried to delete it), we found found that the progams stopped working.

    So we had to put the functions back, with their old behavior. The new features were were contemplating had to be redesigned, redirected, or possibly even abandoned entirely. (If we wanted to delete a function, then the work could continue, but the old function had to stay around with its old behavior. It was basically dead code from the OS's point of view, hanging around just because some random app or other decided to cheat and bypass the documented way of doing things.) But to teach people a lesson, they often got given goofy names.

    For example, BOZOSLIVEHERE was originally the window procedure for the edit control, with the rather nondescript name of EditWndProc. Then some people who wanted to use the edit control window procedure decide that GetWindowLong(GWL_WNDPROC) was too much typing, so they linked to EditWndProc directly. Then when Windows 2.0 (I think) removed the need to export window procedures, we removed them all, only to find that programs stopped working. So we had to put them back, but they got goofy names as a way of scolding the programs that were doing these invalid things.

    Things got even worse in Windows 95, when all our window procedures were converted to 32-bit versions. The problem is that the old window procedures were only 16-bit. So we couldn't even simply export the 32-bit window procedure under the name BOZOSLIVEHERE. We had to write a conversion function that took an illegal 16-bit function call and converted it to the corresponding illegal 32-bit function call.

    This is just the tip of the iceberg with respect to application compatibility. I could probably write for months solely about bad things apps do and what we had to do to get them to work again (often in spite of themselves). Which is why I get particularly furious when people accuse Microsoft of maliciously breaking applications during OS upgrades. If any application failed to run on Windows 95, I took it as a personal failure. I spent many sleepless nights fixing bugs in third-party programs just so they could keep running on Windows 95. (Games were the worst. Often the game vendor didn't even care that their program didn't run on Windows 95!)
  • The Old New Thing

    Why Daylight Savings Time is nonintuitive

    Welcome Knowledge Base article 932955 readers! Remember, the information on this Web site is not official Microsoft documentation.

    Daylight Savings Time ends this weekend in most of North America and Europe, so it seems a good time to discuss the whole problem of Daylight Savings Time and timestamps.

    A common complaint is that all the time zone conversion functions like FileTimeToLocalFileTime apply the current Daylight Savings Time (DST) bias rather than the bias that was in effect at the time in question.

    For example, suppose you have a FILETIME structure that represents "1 January 2000 12:00AM". If you are in Redmond during the summertime, this converts to "31 December 1999 5:00PM", seven hours difference, even though the time difference between Redmond and UTC was eight hours at that time. (I.e., when people in London were celebrating the new year, it was 4pm in Redmond, not 5pm.)

    The reason is that the time got converted from "1 January 2000 12:00AM UTC" to "31 December 1999 5:00PM PDT". So, technically, the conversion is correct. Of course, nobody was using PDT on December 31, 1999 in Redmond; everybody was on PST.

    Why don't the time zone conversion functions use the time zone appropriate for the time of year?

    One reason is that it means that FileTimeToLocalFileTime and LocalFileTimeToFileTime would no longer be inverses of each other. If you had a local time during the "limbo hour" during the cutover from standard time to daylight time, it would have no corresponding UTC time because there was no such thing as 2:30am local time. (The clock jumped from 2am to 3am.) Similarly, a local time of 2:30am during the cutover from daylight time back to standard time would have two corresponding UTC times.

    Another reason is that the laws regarding daylight savings time are in constant flux. For example, if the year in the example above was 1977 instead of 2000, the conversion would have been correct because the United States was running on year-round Daylight Savings Time due to the energy crisis. Of course, this information isn't encoded anywhere in the TIME_ZONE_INFORMATION structure. Similarly, during World War 2, the United States went on DST all year round. And between 1945 and 1966, the DST rules varied from region to region.

    DST rules are in flux even today. The DST cutover dates in Israel are decided on a year-by-year basis by the Knesset. As a result, there is no deterministic formula for the day, and therefore no way to know it ahead of time.

    (Warning: .NET content ahead; two days in a row, what's gotten into me!?)

    Compare the output of FileInfo.LastWriteTime.ToString("f") with what you see in the property sheet for a file that was last written to on the other side of the DST transition. For example, suppose the file was last modified on October 17, during DST but DST is not currently in effect. Explorer's file properties reports Thursday, October 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, 2003, 9:45 AM.

    En gang til for prins Knud: Win32 does not attempt to guess which time zone rules were in effect at that other time. So Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific Standard Time. Even though October 17 was during Pacific Daylight Time, Win32 displays the time as standard time because that's what time it is now.

    .NET says, "Well, if the rules in effect now were also in effect on October 17, 2003, then that would be daylight time" so it displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time.

    So .NET gives a value which is more intuitively correct, but is also potentially incorrect, and which is not invertible. Win32 gives a value which is intuitively incorrect, but is strictly correct.

    I suspect that the .NET behavior was for compatibility with Visual Basic, but I don't know for sure.

  • The Old New Thing

    Why doesn't the clock in the taskbar display seconds?


    Early beta versions of the taskbar clock did display seconds, and it even blinked the colon like some clocks do. But we had to remove it.


    Because that blinking colon and the constantly-updating time were killing our benchmark numbers.

    On machines with only 4MB of memory (which was the minimum memory requirement for Windows 95), saving even 4K of memory had a perceptible impact on benchmarks. By blinking the clock every second, this prevented not only the codepaths related to text rendering from ever being paged out, it also prevented the taskbar's window procedure from being paged out, plus the memory for stacks and data, plus all the context structures related to the Explorer process. Add up all the memory that was being forced continuously present, and you had significantly more than 4K.

    So out it went, and our benchmark numbers improved. The fastest code is code that doesn't run.
  • The Old New Thing

    I'm doing this instead of writing a book


    Some commenters mentioned that I should write a book. It turns out that writing a book is hard.

    A few years ago, MS Press actually approached me about writing a book for them. But I declined because the fashion for technical books is to take maybe fifty pages of information and pad it to a 700-page book, and I can't write that way. None of my topics would ever make it to a 100-page chapter. They're just little page-and-a-half vignettes. And it's not like the world needs yet another book on Win32 programming.

    So I'll just continue to babble here. It's easier.

  • The Old New Thing

    What do the text label colors mean for files?


    Blue means compressed; green means encrypted.

    This is an example of one of those "come on, it's a tiny, simple feature" requests. Yes, the code to do this isn't particularly complicated, but it adds another element of "Ha ha, I'm going to do something in a way that you will never be able to figure out unless somebody tells you."

    We get a lot of these little requests. If we accepted them all, you'd have icons with so many incomprehensible decorations you'd never be able to figure out what all the colors and markers mean.

    So the next time you say to yourself, "Windows should change the appearance of X if simple condition Y," imagine what it would be like if we actually did even twenty of those simple things.

    As my last example: What does it mean if an item on your Start menu is grey?
  • The Old New Thing

    What is the Alt+Tab order?


    What determines the order in which icons appear in the Alt+Tab list?

    The icons appear in the same order as the window Z-order. When you switch to a window, then it comes to the top of the Z-order. If you minimize a window, it goes to the bottom of the Z-order. The Alt+Esc hotkey (gosh, does anybody still use Alt+Esc?) takes the current top window and sends it to the bottom of the Z-order (and the window next in line comes to the top). The Alt+Shift+Esc hotkey (I bet you didn't know that hotkey even existed) takes the bottom-most window and brings it to the top, but does not open the window if it is minimized.

    The presence of "always on top" windows makes this a little more complicated. The basic rule is that an "always on top" window always appears on top of a "not always on top" window. So if the above rules indicate that a "not always on top" window comes to the top, it really just goes as high as it can without getting on top of any "always on top" windows.

    You may have run across the term "fast task switching". This was the term used to describe the precursor to the current Alt+Tab switching interface. The old way of switching via Alt+Tab (Windows 3.0 and earlier) was just like Alt+Esc, except that the window you switched to was automatically opened if it had been minimized. When the new Alt+Tab was added to Windows 3.1, we were concerned that people might prefer the old way, so there was a switch in the control panel to set it back to the slow way. (There is also a setting SPI_SETFASTTASKSWITCH that lets you change it programmatically.) It turns out nobody complained, so the old slow way of task switching was removed entirely and the setting now has no effect.

    This does highlight the effort we take to try to allow people who don't like the new way of doing something to go back to the old way. It turns out that corporations with 10,000 employees don't like it when the user interface changes, because it forces them to spend millions of dollars retraining all their employees. If you open up the Group Policy Editor, you can see the zillions of deployment settings that IT administrators can use to disable a variety of new Windows UI features.

  • The Old New Thing

    What's the deal with those reserved filenames like NUL and CON?


    Set the wayback machine to DOS 1.0.

    DOS 1.0 didn't support subdirectories, lowercase, or filenames longer than 8.3.

    When you ran the assembler (or compiler if you were really fancy) the conversation went something like this:

    A>asm foo    the ".asm" extension on "foo" is implied
    Assembler version blah blah blah
    Source file: FOO.ASM
    Listing file [FOO.LST]:
        just hit Enter to accept the default
    Object file [FOO.OBJ]:     just hit Enter to accept the default
    Assembler cranks away

    You only had to type the base name of the file; the ".LST" and ".OBJ" extensions were appended automatically. In fact, I don't think you could disable the extensions; they were always added.

    But what if you didn't want a listing file? The assembler demanded a filename, and if you didn't type any filename at all, it created one with the same basename as your source file.

    That's where the magic filenames come in. Suppose you wanted the listing file to go straight to the printer. You didn't want to create a file on your floppy drive because there might not be enough space to hold it, or just because you didn't want to waste the time creating a file just to delete it anyway. So you typed "PRN" as the filename.

    Now, the assembler doesn't know about these magic filenames. So the assembler will try to create the file "PRN.LST" and then start writing to it. Little does the assembler realize that the output is actually going to the printer.

    If you wanted to discard the output entirely, you would type "NUL", of course. And if you wanted it to go to the screen, you would type "CON".

    Now, if you followed closely, you can see that the above story explains two things already:

    • Why are the magic filenames magical even if I add an extension?

      Answer: If an extension removed the magic, then when the assembler added ".LST" to the filename, it would no longer be recognized as magical, thereby defeating the purpose of the magic.

    • Why do these magic files exist in every directory?

      Answer: Because DOS 1.0 didn't have subdirectories. There was only one directory, which today we would call the root directory, but back then, since there was no such thing as a subdirectory, there was no need to talk about directories in the first place, much less give the only one you have a name. It was just called "the files on your disk". If magic files didn't work in subdirectories, then when you tried to, for example, chdir into a subdirectory and then run the assembler, you wouldn't be able to type "NUL" as the filename and get the magic.

    But why do we carry these magic filenames forward even today?

    Because everybody still relies on them. Just look at all the batch files that do things like redirect to >NUL or test if a directory exists by asking "if exist directoryname\nul", or all the documentation that says to create a file with "copy CON ...".

  • The Old New Thing

    Drawing an active-looking caption even when not active


    "Why would somebody ever want to do that?" you might ask. Well, this is a common appearance for floating toolbars. (But aside from that case, I can't think of any other valid reason to draw a window as active even though it isn't.)

    Fortunately this is easy to do. Just add this line to the WndProc of our scratch program:

        case WM_NCACTIVATE: if (wParam == FALSE) wParam = TRUE; break;

    This says, "If Windows asks me to paint my caption bar in the inactive state, turn around and draw it in the active state."

  • The Old New Thing

    I thought you said people don't know how to read analog clocks


    I had mentioned in passing in a comment on 10/10/2003 10:07PM that one of the reasons the clock on the taskbar isn't analog is that some disturbingly high percentage of people (30%? 40%? I forget exactly) do not know how to read an analog clock.

    Yet there is is in the Longhorn sidebar. What gives?

    Ah but if you look more closely, the digital time is printed immediately below it.

    That was our compromise.
  • The Old New Thing

    Why can't I use &-accelerators on the Start menu?


    The first letter of the program is the accelerator and there's nothing you can do about it. So if you have ten programs by Microsoft, they all use the accelerator "M". (Yes I hate this too. The first thing I do after installing a Microsoft program is go into the Start menu and delete the word "Microsoft" from the front.)

    For Win32 menus, the ampersand character acts as the marker for the menu accelerator. For example, you would set your menu text to "Save &As" to set Alt+A as the accelerator for the menu item.

    This isn't done for the Start menu and for the Favorites menu because the ampersand appears in program names occasionally. Otherwise, "AT&T Internet" would end up displaying as "ATT Internet". (This was a real problem in Windows 95, where the Start menu was constructed from your old Program Manager groups, and occasionally we'd run across one that had an ampersand in its name.)
Page 1 of 4 (37 items) 1234