October, 2003

  • The Old New Thing

    Why highlighting by inverting colors is a bad idea

    • 14 Comments

    Often people will say, "Oh, we can highlight by inverting the color."

    This may have worked great on two-color black-and-white displays, but in the world of 32-bit color this no longer is effective.

    Consider the following picture. See if you can guess which one is inverted.

     
     
    OneTwo

    Answer: The one on the right is inverted.

    The background color is gray, #808080. The box labelled "two" is highlighted by inversion. The inverse of #808080 is #7F7F7F, which is practically the same color.

    Even if your eyes happen to be good enough to spot the difference, it's still not a very obvious difference.
  • The Old New Thing

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

    • 19 Comments

    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

    Drawing an active-looking caption even when not active

    • 20 Comments

    "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

    When vendors insult themselves

    • 14 Comments

    During Windows 95, when we were building the Plug and Play infrastructure, we got an angry letter from a hardware vendor (who shall remain nameless) complaining that we intentionally misspelled their company name in our INF files in a manner that made their company name similar to an insulting word.

    This is of course a very serious accusation, and we set to work to see what happened. It didn't take long to find the misspelling. The question now was why we spelled it wrong.

    Further investigation revealed that the reason the company name was misspelled is that they misspelled their own name in their hardware devices' firmware. When Plug and Play asked the device for its manufacturer name, it replied with the misspelled name. So of course our INF file had to have an entry with the misspelled name so that we could identify the device when the user connected it. (The name displayed to the user did not contain the misspelling.)

    We sent a very polite letter to the company explaining the reason for the misspelling. As far as I am aware, they never brought up the subject again.

  • The Old New Thing

    Getting a custom right-click menu for the caption icon

    • 2 Comments

    Explorer does it. Now you can too.

    It's a simple matter of detecting a context menu on the caption icon and displaying a custom context menu. Here are the simple changes to our scratch program to display a rather pointless one-item menu.

    // Add to WndProc
        case WM_CONTEXTMENU:
            if (lParam != -1 &&
                SendMessage(hwnd, WM_NCHITTEST,
                            0, lParam) == HTSYSMENU) {
                HMENU hmenu = CreatePopupMenu();
                if (hmenu) {
                    AppendMenu(hmenu, MF_STRING, 1,
                               TEXT("Custom menu"));
                    TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN |
                                          TPM_RIGHTBUTTON,
                                   GET_X_LPARAM(lParam),
                                   GET_Y_LPARAM(lParam), 0, hwnd, NULL);
                    DestroyMenu(hmenu);
                }
                return 0;
            }
            break;
    

    When we receive a WM_CONTEXTMENU message, we check that it did not come from the keyboard (lParam != -1) and that the mouse is on the caption icon (called HTSYSMENU because it displays the system menu by default). If so, then we create a little popup menu and display it. Don't forget to return 0 instead of passing the message to DefWindowProc, because the default behavior is to display the system menu.

    Of course, in real life, you probably would use LoadMenu to get the menu so you could just use the resource editor to create it, rather than creating it in code.
  • The Old New Thing

    Being the Nobel Peace Prize

    • 12 Comments

    For Hallowe'en this year, I'm going to be the Nobel Peace Prize. (I like being things that people would never even think of as a possible Hallowe'en costume. Last year, I was an inter-office envelope. People addressed me from place to place.)

    I chose the Nobel Peace Prize in part because I'm studying Swedish so I thought it would be fun to be something Swedish. Except that the Nobel Peace Prize is Norwegian! Oh, the horror!

    But what's done is done. I already made the medal and have started making the diploma, but I hit a snag: Whose name should be on the Prize?

    I could go historical and reproduce the 2002 Nobel Peace Prize awarded to Jimmy Carter. (He's my favorite of the recent Peace Prize recipients.)

    Or I could go surreal and create an imaginary award to be bestowed upon Jennifer Lopez or maybe David Hasselhoff.

    Or I could just leave the space blank and invite people to nominate a winner.

    My other problem is making the check for SEK 10,000,000. I asked my friend in Sweden what a check looks like and he says he's never seen one. He doesn't know anybody who actually writes checks. The closest I could find is this novelty check but it doesn't look very convincing. (There's no bank name or check number, for example.) So I'm asking you for help. Can somebody describe what a Swedish check looks like?

  • The Old New Thing

    Kinder Überraschungen

    • 14 Comments

    Laura John entertains her colleagues with Kinder Surprise eggs. I love these things.

    I understand that Kinder Surprise eggs are illegal in the US for two reasons.

    1. Small parts. But that can be fixed by labelling the egg as "for ages 3 and up".

    2. The FDA has a rule banning "inedible material completely enclosed by edible material". Apparently they think somebody is going to stupidly pop the entire egg in their mouth and try to swallow it hole? Psst, FDA, maybe you should ban peaches, too. I understand the pit is inedible.

    Whenever I go to Germany I smuggle some Kinder Überraschungen into the States. (Yes, they're also available in Canada, but if you got them from Canada, they wouldn't be in German now would they?) (Yes, I know that the candy is originally from Italy.)

    I'm told that in Germany, children will often buy Überraschungen on the playground from a street vendor, who asks them whether they prefer "Etwas zu sammeln oder etwas zu bauen?" - "Something to collect (a figurine) or something to build?" But how do they know?

    They guess by shaking the egg and listening to the rattling.

    If you ask for something to build and you end up getting something to collect, the excuse is, "Well, our regular shaker is sick today."
  • The Old New Thing

    Why Daylight Savings Time is nonintuitive

    • 32 Comments
    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

    Writing a sort comparison function

    • 8 Comments

    When you are writing a sort comparison function (say, to be passed to ListView_SortItems or *gasp* to be used as an IComparer), your comparison function needs to follow these rules:

    • Reflexivity: Compare(a, a) = 0.
    • Anti-Symmetry: Compare(a, b) has the opposite sign of Compare(b, a), where 0 is considered to be its own opposite.
    • Transitivity: If Compare(a, b) ≤ 0 and Compare(b, c) ≤ 0, then Compare(a, c) ≤ 0.

    Here are some logical consequences of these rules (all easily proved). The first two are obvious, but the third may be a surprise.

    • Transitivity of equality: If Compare(a, b) = 0 and Compare(b, c) = 0, then Compare(a, c) = 0.
    • Transitivity of inequality: If Compare(a, b) < 0 and Compare(b, c) < 0, then Compare(a, c) < 0.
    • Substitution: If Compare(a, b) = 0, then Compare(a, c) has the same sign as Compare(b, c).

    Of the original three rules, the first two are hard to get wrong, but the third rule is often hard to get right if you try to be clever in your comparison function.

    For one thing, these rules require that you implement a total order. If you merely have a partial order, you must extend your partial order to a total order in a consistent manner.

    I saw somebody get into trouble when they tried to implement their comparison function on a set of tasks, where some tasks have other tasks as prerequisites. The comparison function implemented the following algorithm:

    • If a is a prerequisite of b (possibly through a chain of intermediate tasks), then a < b.
    • If b is a prerequisite of a (again, possibly through a chain of intermediate tasks), then a > b.
    • Otherwise, a = b. "Neither task is a prerequisite of the other, so I don't care what order they are in."

    Sounds great. Then you can sort with this comparison function and you get the tasks listed in some order such that all tasks come after their prerequisites.

    Except that it doesn't work. Trying to sort with this comparison function results in all the tasks being jumbled together with apparently no regard for which tasks are prerequisites of which. What went wrong?

    Consider this dependency diagram:

       a ----> b
     
       c
    

    Task "a" is a prerequisite for "b", and task "c" is unrelated to both of them. If you used the above comparison function, it would declare that "a = c" and "b = c" (since "c" is unrelated to "a" or "b"), which in turn implies by transitivity that "a = b", which contradicts "a < b", since "a" is a prerequisite for "b". If your comparison function is inconsistent, you will get garbled results.

    Moral of the story: When you write a comparison function, you really have to know which items are less than which other items. Don't just declare two items "equal" because you don't know which order they should be in.

  • The Old New Thing

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

    • 22 Comments

    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 ...".

Page 1 of 4 (37 items) 1234