January, 2008

  • The Old New Thing

    Email tip: Don't use a rude subject line just to make your message easier to spot

    • 62 Comments

    Here are some subject lines I've seen over the past few years (suitably redacted):

    • !!! BLOCK WRITING TO CD DRIVE !!!
    • ___] Kernel objects naming convention [___
    • [QQ] - Question about job objects

    Sure, using exclamation points, all capital letters, or strange eye-catching punctuation marks makes it easier for you to spot replies to your message in your inbox, but it's also rude to your readers, who almost certainly do not consider your message as important as you do.

    Imagine if everybody did this.

    If it's that important that it easy for you to spot replies to your message, set up a mail filter rule that highlights them.

    And, just because I collect these things, here are some unhelpful subject lines that I've seen in the past six months:

    • need help
    • Need help!
    • customer question
    • customer question -
    • customer questions
    • Need help on two questions
    • SR# 1 - 61803399
    • RE: [RESENDING] [QUERY] RE: SR# 1 - 61803399
    • Windows 2003 IIS issue
    • MSCS
    • Looking for a way to do this
    • Is this a bug?
    • Microsoft question
    • Vista question
    • Questions about using Vista
    • Quick Question!
    • Customer Question
    • here's my question for the XYZ team

    Sometimes, the people who commit the sin of the useless subject line also follow up with the second sin of repeating their question verbatim because nobody answered it. Nobody answered it because the subject line was not obviously in anybody's specific area of expertise.

  • The Old New Thing

    The Windows 95 volume control almost went to eleven

    • 31 Comments

    The movie This Is Spinal Tap introduced the world to the phrase going to eleven. The people over at Windows Media Player were not immune to its charms, alluding to the catchphrase in their advertising campaign.

    Back in Windows 95, I know that there was at least one person who lobbied the multimedia team to give the Volume Control program eleven notches in its control slider as a tribute. Alas, their efforts were ultimately unsuccessful, but it was cute to know that somebody considered the possibility.

  • The Old New Thing

    If they had felt a little more mischievous when they titled the article Excerpts from Fischer-Spassky games

    • 12 Comments

    In response to the recent passing of chess celebrity Bobby Fischer, the Associated Press published an article titled Excerpts from Fischer-Spassky Games. The article consists of excerpts from the organization's coverage of the so-called Match of the Century in 1972.

    But given the title, I wondered whether the article had merely gone like this:

    Game 3: 27. Qd2 Rbe8 28. Re3 h5 29. R3e2 Kh7 30. Re3 Kg8

    Game 6: 17. Be2 Nd7 18. Nd4 Qf8 19. Nxe6 fxe6

    There you go, excerpts from Fischer-Spassky games.

  • The Old New Thing

    When computer programmers dabble in economics: Paying parking tickets

    • 40 Comments

    One of my colleagues has a degree in economics, and sometimes it manifests itself in strange ways.

    My colleague moved to a new apartment building and rented a parking space in the building's garage. After a month of noticing that there was usually an empty parking space or two on the street, my colleague made the economic calculation that the risk of not finding a parking space nearby was outweighed by the savings of not paying for a monthly parking space.

    After a few more months, my colleague started experimenting with the alternate side of the street parking rules and noticed that they tended not to be enforced early in the morning. Once again, after some mental calculations, the extra few hours of sleep were deemed worth the additional cost of the occasional parking ticket.

    The saga continues. My colleague then determined that the city doesn't really care that much if you don't pay your parking ticket. (I personally find this hard to believe, but that's how my colleague described it, so there you have it.) The unpaid tickets piled up.

    And then something happened to put an end to this little scheme: The prospect of home ownership. My friend planned to move out of the apartment building and buy a house in a different part of the city.

    While the city may not care about unpaid parking tickets, banks definitely do, and it was adversely affecting the interest rates on the home loan offers. My colleague sat down and did the math and calculated that the time-discounted savings over the life of the loan outweighed the present cost of paying off all the parking tickets.

    Off to the parking ticket payment office we go. "Hi. I'd like to pay my parking tickets." The person at the desk took down the pertinent information and went to the computer to print out the tickets so they could be paid. This was back in the days of dot matrix printers and tractor-feed paper, so the printer buzzed noisily and could be heard throughout the room.

    The tickets printed.

    And printed.

    And printed.

    People in the office started to take notice, wandered over to the printer to see what was going on, and then, once they realized what was happening, began to clap and cheer. Handing over the check to pay for the tickets earned my colleague a standing ovation.

    (By the way, today is a parking holiday in Seattle.)

    [Note: An incomplete version of this article was mistakenly published a day early. It has been updated to the finished version and moved to its correct publication date.]

  • The Old New Thing

    Can't sing? Can't dance? Can't act? Try the opera.

    • 4 Comments

    Writer Shannon Dunn can't sing, can't act, can't even dance a little, but she was determined to perform in the opera. And being rejected at the audition didn't stop her. It's a fascinating story.

  • The Old New Thing

    Why do registry keys have a default value?

    • 36 Comments

    In addition to all the named values you can create underneath a registry key with the RegSetValueEx function, there is also the so-called default value which you obtain by passing NULL or a pointer to a null string as the lpValue. This default value is also the value set and retrieved when you call RegSetValue and RegQueryValue. What's the deal with this default value?

    The original 16-bit registry didn't have named values. All it had were keys, and associated with each key was a single piece of data: a string. The functions that operated on this data were RegSetValue and RegQueryValue, which explains why those functions (1) don't have a lpValue parameter and (2) set and retrieve only string data. Because back in the 16-bit world, that's all you had.

    In the conversion to Win32, the registry gained new capabilities, such as storing data in formats beyond simple strings, and storing multiple pieces of data under a single key, using a name to distinguish them. What used to be called simply "the value of a registry key" (for since there was only one, there was no need to give it a name) now goes by the special name the default value: It's the value whose name is null.

    There's nothing particularly special about the default value aside from its unusual name. A named value need not exist, and if it exists, the data type could be anything. Similarly, the default value need not exist, and its type can be anything. At this point, it's just a value with a strange name.

  • The Old New Thing

    How did registry keys work in 16-bit Windows?

    • 22 Comments

    Back in 16-bit Windows, the registry was a very different beast. Originally, the only registry hive was HKEY_CLASSES_ROOT, and the only things it was used for were COM object registration and file type registration. (Prior to the registry, file type registration was done in WIN.INI, and the only verb you could register for was "open".) The registry was stored in a single file, REG.DAT, which could not exceed 64KB in size.

    But back to registry keys. In 16-bit Windows, the registry was much simpler. The first program to call RegOpenKey caused the registry to be loaded, and the registry kept a running count of how many registry keys were open. When the matching number of RegCloseKey calls was made, the registry was written back to disk and unloaded from memory. (Yes, this means that if a program leaked a registry key, then the registry never got unloaded. Welcome to 16-bit Windows, which trusted software developers not to be stupid.) The registry key itself was just an index into the raw registry data.

    This backgrounder is really just a boring set-up for this little quirk of the RegOpenKey function in Win32:

    If this parameter [lpSubKey] is NULL or a pointer to an empty string, the function returns the same handle that was passed in.

    This is an example of over-documentation, documenting the implementation rather than the contract. That the same handle was returned in 16-bit Windows is just a side effect of the fact that a registry key was an index. Opening the same key twice leads to the same key, which consequently has the same index (since it's the same thing). Therefore, opening the same key more than once yields the same numeric value for the handle.

    On the other hand, in 16-bit Windows, even if you reopened the key and got the same numeric value back, it nevertheless increased the "number of open registry keys" counter, and consequently you had to call RegCloseKey for each successful call to RegOpenKey, even if the numerical handle values were the same (which you shouldn't care about since handles are opaque).

    The people designing the 32-bit registry found themselves in a pickle. What should RegOpenKey do if asked to open the same key that was passed in? Should it return a new key which also must be closed with RegCloseKey? Or should it preserve the inadvertently contractual 16-bit behavior and return the same numeric key back? Since kernel handles are not reference-counted, returning the same numeric value back means that when the caller closes the key, they close both that key and the original key passed in (since they are the same thing).

    The Win32 folks went for the second option: RegOpenKey on the same key returns the same numeric value back, which must not be closed (for doing so would close the original key as well). Personally, I would have gone for the first option (returning a new handle), but presumably the people who made this decision did so for a good reason. I suspect application compatibility played a major role.

    What does this mean for you? It means that you should just plain avoid the RegOpenKey function, since it becomes harder to predict whether you need to close the returned key or not. Sure, if you pass a hard-coded string as the subkey name you can tell, but if the subkey name is dynamically-generated, then there's a possibility that the subkey name is a null string, in which case the returned key shouldn't be closed. Instead, use RegOpenKeyEx, which—since it is a new function in Win32—does not have the compatibility constraints of RegOpenKey. The key returned by RegOpenKeyEx is a brand new key and must be closed. Doesn't matter whether the subkey name is blank or not. Open with RegOpenKeyEx and close with RegCloseKey, end of story.

  • The Old New Thing

    Jerry Springer: The Opera crosses the pond to visit Carnegie Hall

    • 12 Comments

    Back in 2002, I noted with some fascination the opening of Jerry Springer: The Opera in London. (Here's coverage in the New York Times. If you're going to skim the article, at least skim all the way to the end, wherein the real Jerry Springer is asked for his opinion.)

    Opening with the onstage studio audience chanting "Jer-ry! Jer-ry!", a parade of guests sing about being jilted by a lesbian dwarf or having a diaper fetish or wanting to start a career as a lap dancer as Jerry Springer himself presides over the mayhem. Amid the chaos, the host is shot and killed.

    And that's just Act One.

    Jesus doesn't appear until Act Two.

    I am not making this up.

    And now it's made it across the Atlantic for a special two-night engagement at Carnegie Hall.

    Pre-emptive snarky comment: "Steve Ballmer should go on the Jerry Springer show."

  • The Old New Thing

    Use WM_WINDOWPOSCHANGING to intercept window state changes

    • 5 Comments

    The WM_WINDOWPOSCHANGING message is sent early in the window state changing process, unlike WM_WINDOWPOSCHANGED, which tells you about what already happened. A crucial difference (aside from the timing) is that you can influence the state change by handling the WM_WINDOWPOSCHANGING message and modifying the WINDOWPOS structure.

    Here's an example that prevents the window from being resized.

    BOOL OnWindowPosChanging(HWND hwnd, WINDOWPOS *pwp)
    {
        pwp->flags |= SWP_NOSIZE;
        /* Continue with default handling */
        return FORWARD_WM_WINDOWPOSCHANGING(hwnd, pwp, DefWindowProc);
    }
    
    HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, OnWindowPosChanging);
    

    Before the WM_WINDOWPOSCHANGING message was invented, programs had to enforce window size constraints inside their WM_SIZE and WM_MOVE handlers, but since those messages are sent after the change is complete, the result was flicker as the window changed to one size, then the WM_SIZE handler resized it to a better size. Intercepting the window size change in WM_WINDOWPOSCHANGING allows you to enforce constraints before the sizing happens, thereby avoiding flicker.

    The WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED pair of messages is just one example of the more general *CHANGING/*CHANGED pattern. (Other examples are WM_STYLECHANGING/WM_STYLECHANGED and LVN_ITEMCHANGING/LVN_ITEMCHANGED.) The *CHANGING half is sent before the change takes place, and as a general rule, you can change the parameters of the notification to enforce some type of constraint. After you return from the *CHANGING notification, the actual change takes place, and then you receive a *CHANGED to indicate that the change is complete.

  • The Old New Thing

    Use WM_WINDOWPOSCHANGED to react to window state changes

    • 20 Comments

    The documentation for the WM_SHOWWINDOW message points out that the message is not sent under certain circumstances. But what if you want to know when the window is shown, including in the cases where you don't get WM_SHOWWINDOW?

    The WM_WINDOWPOSCHANGED message is sent at the end of the window state change process. It sort of combines the other state change notifications, WM_MOVE, WM_SIZE, and WM_SHOWWINDOW. But it doesn't suffer from the same limitations as WM_SHOWWINDOW, so you can reliably use it to react to the window being shown or hidden. The handler would go something like this:

    void OnWindowPosChanged(HWND hwnd, const WINDOWPOS *pwp)
    {
        if (pwp->flags & SWP_SHOWWINDOW) {
           window_was_shown();
        }
        if (pwp->flags & SWP_HIDEWINDOW) {
           window_was_hidden();
        }
        if (!(pwp->flags & SWP_NOMOVE)) {
           window_moved_to(pwp->x, pwp->y);
        }
        if (!(pwp->flags & SWP_NOSIZE)) {
           window_resized_to(pwp->cx, pwp->cy);
        }
    }
    
    HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, OnWindowPosChanged);
    

    Note also that if you don't pass the WM_WINDOWPOSCHANGED message to DefWindowProc, then you won't get WM_MOVE or WM_SIZE messages, since it is DefWindowProc that converts WM_WINDOWPOSCHANGED into the WM_MOVE and WM_SIZE messages.

    "If WM_WINDOWPOSCHANGED is redundant with WM_MOVE, WM_SIZE, and WM_SHOWWINDOW, then why do we have those other messages anyway?"

    The WM_WINDOWPOSCHANGED message wasn't invented until Windows 3.1. Prior to that, you had no choice but to react to those other messages. You can think of those other three messages as legacy messages now. There's nothing wrong with them, but they're kind of old-fashioned now.

    Next time, we'll look at the companion message WM_WINDOWPOSCHANGING.

    Postscript: This entry was inspired by an actual customer question regarding the cases where WM_SHOWWINDOW message is not sent if the program is run with the SW_SHOWMAXIMIZED state. Unfortunately, one detail I missed in the customer's question was the remark that they need to know when the window is shown because it is "critical for the application to initialize its state." I didn't follow up on that little remark, but I should have, because it's very strange to do initialization work when a window is shown. What if the window is never shown? Does this mean that the program will never initialize itself? (For example, somebody might have run your program with the SW_HIDE state.) The WM_NCCREATE and WM_CREATE are the more traditional places to do window initialization.

Page 2 of 4 (35 items) 1234