June, 2008

  • The Old New Thing

    Why is there a menu show delay, anyway?


    One of the reactions to my note on how the window manager uses the double-click time as a way to tell how good your reflexes are is bemusement, well okay, not so much bemusement as outrage, over why we need a menu show delay in the first place.

    Imagine, you're navigating a deeply-nested menu hierarchy and then you want to move to one of the items in the most recent fly-out, but instead of moving the mouse directly to the right then down, you move it ever so slightly diagonally down. Boom, the entire menu collapses and you have to start over. There's a place for maddeningly fiendish mouse dexterity games, but trying to create a pivot table is not it.

    I run into this problem all the time on the Web. Web site designers forget to incorporate a menu show delay, resulting in frustration when trying to navigate around them. For example, let's look at the navigation bar on the home page of The Discovery Channel. Hover over TV Shows, and the menu appears. Suppose you want to go to Koppel on Discovery, but instead of moving the mouse straight downward, the way you hold your arm on the desk moves the mouse in an arc that happens to swing to the right before it arcs downward. You touch TV Schedules and your navigation is screwed up. You have to start over and make sure to move the mouse exactly straight down.

    This phenomenon is even worse for sites that position their submenus as a horizontal bar below the main navigation bar, such as EVA Air or NBC. On the NBC site, for example, hover over Schedule and a band appears below the navigation bar with more options. But you can't move the mouse diagonally to, say, Pacific; if you do, you'll accidentally touch News & Sports and the Schedule submenu will be disappear. If you just move and click in one motion, then boom, congratulations, you just clicked on Access Hollywood. You have to carefully move your mouse straight down (being careful not to touch anything else that might open a different menu or cause the existing menu to auto-dismiss), and then straight sideways (being careful not to accidentally move it upward three pixels, causing the secondary navigation bar to be replaced with a different submenu). It's like its own miniature mouse dexterity game. But one you didn't elect to play.

    The folks over at TechNet Magazine did take the menu show delay into account, though it's still not as long as I'd like. Hover over the word TechCenters in the navigation bar, and a submenu appears. If you move toward Script Center and happen to touch TechNet Magazine ever so briefly (like one Planck time), the TechCenters menu stays up. On the other hand, the menu animation is abysmally slow if you use Firefox, so one step forward, one step back.

  • The Old New Thing

    MSDN-speak: What does it mean when a parameter contains a value?


    I've seen some confusion over this, heck I've been confused by this, so I figured I'd share what I've learned.

    In MSDN, you may see wording like this:

    pdwResult [out] When the function returns, contains a pointer to a DWORD value that contains the result of the computation.

    What they're trying to say is that the pdwResult is a pointer to a DWORD that receives the result of the computation. Personally, I take issue with both uses of the word "contains", but they tell me that that is their standard for describing [out] parameters, so you'd better get used to it.

    When they say that the parameter contains a value, they mean that the you passed that value as the parameter. I prefer to think of the parameter being the value; the parameter is just a convenient name for the value that the caller passed. The MSDN approach is to think of the parameter as its own variable which therefore contains a value, as variables do. In this specific case, they are saying that pdwResult "contains a pointer" to mean that the parameter is itself a pointer that you pass in.

    Now on to the second half. When they say that the pointed-to value contains the result, they mean that the function itself writes to the pointed-to value. The opening phrase "when the function returns" is intended to indicate this, but I have two issues with that approach.

    First, it seems to modify the wrong verb. Since it's at the beginning of the sentence, the temporal clause appears to modify the first "contains" and not the second. "When the function returns, the parameter contains a pointer...", suggesting that perhaps when you initially called the function, the parameter didn't contain the pointer and that the statement becomes true only when the function returns.

    Second, it doesn't emphasize that the function itself sets the value. You can read the sentence passively, as if to say, "Well, when the function returns, there's stuff there, who knows how it got there, maybe it was there all along, maybe you were expected to put it there first, sometimes things just happen to be that way, you know?" Sort of like, "When I get home, the lights are on." Maybe you turned on the lights remotely from work before you left for home. Maybe they are on a timer so they turn on at the same time every day. Maybe they were on all day. Heck, you're not even ruling out the possibility that the lights have psychic powers and turn themselves on as a way of welcoming you home.

    Anyway, now you know what that sentence means when you read it in MSDN. It's not how I would've written it, but I'm not the chief editor of MSDN.

  • The Old New Thing

    Microspeak: Pricing uplift


    In a conference call with investors last year, investor relations general manager Colleen Healy described the effect of business editions of Windows thus:

    As we shared with you previously, Windows Vista business generates over five times the pricing uplift over Windows Vista Home Basic than does Windows Vista Home Premium.

    Also known as profit.

  • The Old New Thing

    Blinding bank robbers with kindness


    Despite the friendliness of people in the Pacific Northwest (or perhaps because of it), bank robberies in the area are above the national average. But in the Seattle area they went down by nearly half in the beginning of 2007. The reason isn't known for certain, but one factor may be a new approach to thwarting bank robbers by employing "aggressive friendliness" and rattling the nerves of a would-be robber.

    Scott Taffera sensed something was wrong when a man walked into the Ballard bank branch he manages wearing garden gloves, a hat and sunglasses.

    But instead of following the nonconfrontational strategy used by most banks with suspicious people, Taffera approached the man with a hearty greeting and an offer to help. He invited him to remove his hat and sunglasses, and guided him to an equally bubbly teller.

    In the end, the oddly dressed man requested a roll of quarters before slinking out the door.

    By the end of 2007, bank robberies in the state hit a 20-year low, dropping the state from fourth most robbed in the nation to eleventh.

  • The Old New Thing

    How do the common controls convert between ANSI and Unicode?


    Commenter Chris Becke asks how the common controls convert ANSI parameters to Unicode, since the common controls are Unicode internally.

    Everything goes through CP_ACP, pretty much by definition. The ANSI code page is CP_ACP. That's what ACP stands for, after all.

    Now, there are some function families that do not use ANSI. The console subsystem, for example, prefers the OEM character set for its 8-bit strings, and file system functions can go either way, based on the setting controlled by the SetFileAPIsToANSI and SetFileAPIsToOEM functions.

    In the scenario Chris describes, I suspect that the problem is not the ANSI-to-Unicode conversion but rather that the font selected into the listview didn't support the necessary characters.

  • The Old New Thing

    Sometimes it's easier just to let the native speaker win


    My entry last month about that virus that is responsible for the top six Explorer crashes prompted me to check out the blog of the Anti-Malware Engineering Team, and at the bottom of a report from Microsoft TechEd Boston is a photo of a few members of the Anti-Malware Engineering Team.

    I've worked with some of those people, and I had forgotten where they had gone to after we fell out of touch. Nice to know they're still working to make the world a better place.

    I was reminded of a funny story told to me by one of those former colleagues. He studied Japanese in college (I think he may have majored in it), his wife is from Japan, their language of conversation at home is Japanese. You might figure that his Japanese is pretty good.

    But don't say that to a native Japanese speaker!

    He tells me that when he goes back to Japan and strikes up a conversation with a new acquaintance, the native speaker will start testing him on his knowledge of Japanese, refusing to believe that a foreigner could learn their deep and subtle language. Usually, the quiz focuses on the written form of the language.

    "Do you know this character?"

    — Yes, that's "dog".

    "Oh, very good. How about this one?"

    — That's "hospital".

    "Ah yes, your Japanese is quite good. But what about this one?"

    — That's "mushroom".

    It isn't long before my colleague gets tired of this game and gets one wrong on purpose.

    "I bet you don't know this one."

    — Um, I'm not sure. I think it's "soul".

    "Aha, not quite. The character for 'soul' is this one. [Writes the character.] But that is the character for 'clump'. The two are very similar, I admit, so I'm not surprised that you confused them."

    Both sides get what they want: The native Japanese speaker gets to feel superior, and my colleague gets to change the topic to something more interesting.

  • The Old New Thing

    Don't be helpless: You can find information, too, if you try


    Here's a question that floated past my view:

    Anybody know if there exists a library for computing MD5 hashes from unmanaged code? MSDN has information about .NET classes, but nothing about the unmanaged side.

    Hm, let's see.

    C:\Windows SDK\Include> grep MD5 *.h
    wincrypt.h:#define ALG_SID_MD5                     3
    wincrypt.h:#define ALG_SID_SSL3SHAMD5              8
    wincrypt.h:#define CALG_MD5                (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)
    wincrypt.h:#define CALG_SSL3_SHAMD5        (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
    wincrypt.h:#define KP_PRECOMP_MD5          24
    wincrypt.h:#define szOID_RSA_MD5RSA        "1.2.840.113549.1.1.4"
    wincrypt.h:#define szOID_RSA_MD5           "1.2.840.113549.2.5"

    Wow, those hits sure look promising. Perhaps a search on Windows Live or Google¹ will turn up something. Oh hey, how about that, sample code.

    Exercise: Use this exact same technique to answer this commenter's question on how the C# ++ operator works. Hint: Since this is a question about the C# language, the C# language specification would be a good starting point.

    Exercise: Use this technique to answer this commenter's question on how to connect to a process as a debugger.



  • The Old New Thing

    Email tip: Pronouns in the subject line are in the eye of the beholder


    This applies to email, but it applies even more to meetings and appointments, which are typically arranged via email or similar workflow.

    It may seem obvious at the time, but messages with pronouns like me or you in the subject line tend to be harder to understand when you come back to the message a little while later.

    I was reminded of this by a colleague who received a meeting reminder alert that simply read:

    Title: One-on-one chat
    Start time: May 9, 2007 4:00 PM
    Location: my office

    Whose office is my office?

    This is a generalization of choosing a subject line that is meaningful to the recipient. You want a subject line that is meaningful to everybody involved.

    And here's the round-up of some unhelpful or rude subject lines I've seen in the past five months:

    • Question
    • A question
    • Two questions
    • Can someone help me !!!!
    • Need help regarding SRQ141421
    • Need assistance//SRQ0314159
    • SRX602214179-23
    • Need some help guys
    • Need assistance with the following issue
    • Need help on a few things.
    • newbie question
    • Guidance/Help
    • A C# question (sent to a C# discussion list)
    • C++ Error (bonus points: This was also sent to a C# discussion list)
    • Strange Error
    • Erratic behavior
    • Sorry about wide distribution
  • The Old New Thing

    If you say that you don't care about something, you shouldn't be upset that it contains garbage


    There are many situations where you pass a structure to a function, and the function fills in the structure with information you request. In some cases, the function always fills in the entire structure (example: GlobalMemoryStatus). In other cases, you tell the function which bits of information you care about, to save the function the effort of computing something you weren't interested in anyway (example: TreeView_GetItem).

    In the latter case, if you say that you aren't interested in certain parts of the structure, and then you change your mind and start paying attention to them, don't be surprised if you find that there's nothing interesting there. After all, you said you didn't care.

    For example, if you call TreeView_GetItem and set the mask to TVIF_IMAGE | TVIF_PARAM, this means that you want the function to set the iImage and lParam members of the TVITEM structure and that you don't care about the rest. After the call returns, the values of those two members are defined, since you said that's what you wanted, and the remainder of the output fields are undefined. They might contain useful information, they might contain garbage, you're not supposed to care since you said that you didn't.

    Why might fields you said you didn't care about still contain information (correct or incorrect)? It might be that the value is so easy to compute that checking whether the value should be set takes more work than actually setting it! In such a case, the function might choose to set the value even if you didn't say that you needed it.

    On the other hand, the value might be an artifact of a translation layer: You pass a structure saying, "I'm interested in two out of the four members." The function in turn calls a lower lever function with a different structure, saying, "I'm interested in two out of the five members of this different structure." After the call returns, the middle-man function converts the lower-level structure to the higher-level structure. Sure, it may also "convert" stuff that was never asked for, but you said you weren't interested, so they just get garbage. In other words, the function you're calling might be defined like this:

    // The pinfo parameter points to this structure
    struct FOOINFO {
     DWORD dwInUse;
     DWORD dwAvailable;
     DWORD dwRequested;
     DWORD dwDenied;
    // The dwMask parameter can be a combination of these values
    #define FOOINFO_INUSE     0x0001
    #define FOOINFO_AVAILABLE 0x0002
    #define FOOINFO_REQUESTED 0x0004
    #define FOOINFO_DENIED    0x0008
    BOOL GetFooInfo(FOOINFO *pinfo, DWORD dwMask);

    Now, the GetFooInfo function might just be a middle man that talks to another component to do the real work.

    // lowlevel.h
    struct LOWLEVELSTATS {
     DWORD dwUnitSize;
     DWORD dwUnitsInUse;
     DWORD dwUnitsAvailable;
     DWORD dwUnitsRequested;
     DWORD dwUnitsGranted;
     DWORD dwTotalRequests;
    // The dwMask parameter can be a combination of these values
    #define LLSTATS_UNITSIZE  0x0001
    #define LLSTATS_INUSE     0x0002
    #define LLSTATS_AVAILABLE 0x0004
    #define LLSTATS_REQUESTED 0x0008
    #define LLSTATS_GRANTED   0x0020
    #define LLSTATS_REQUESTS  0x0040
    BOOL GetLowLevelStatistics(LOWLEVELSTATS *pstats, DWORD dwMask);

    The resulting GetFooInfo function merely translates the call from the application into a call to the GetLowLevelStatistics function:

    BOOL GetFooInfo(FOOINFO *pinfo, DWORD dwMask)
     DWORD dwLowLevelMask = LLINFO_UNITSIZE;
     if (dwMask & FOOINFO_INUSE)
      dwLowLevelMask |= LLSTATS_INUSE;
     if (dwMask & FOOINFO_AVAILABLE)
      dwLowLevelMask |= LLSTATS_AVAILABLE;
     if (dwMask & FOOINFO_REQUESTED)
      dwLowLevelMask |= LLSTATS_REQUESTED;
     if (dwMask & FOOINFO_DENIED)
     if (!GetLowLevelStats(&info;stats, dwLowLevelMask))
      return FALSE;
     // Convert the LOWLEVELSTATS into a FOOINFO
     pinfo->dwInUse = stats.dwUnitSize * stats.dwUnitsInUse;
     pinfo->dwAvailable = stats.dwUnitSize * stats.dwUnitsAvailable;
     pinfo->dwRequested = stats.dwUnitSize * stats.dwUnitsRequested;
     pinfo->dwDenied = stats.dwUnitSize *
                       (stats.dwUnitsRequested - stats.dwUnitsGranted);
     return TRUE;

    Notice that if you ask for just FOOINFO_DENIED, you still get the dwRequested as a side effect, since computing the number of requests that were denied entails obtaining the total number of requests. On the other hand, you also get garbage for dwInUse since the call to GetLowLevelStats didn't ask for LLSTATS_INUSE, but the code that converts the LOWLEVELSTATS to a FOOINFO doesn't know that and converts the uninitialized garbage. But since you said that you didn't care about the dwInUse member, you shouldn't be upset that it contains garbage.

    You now know enough to answer this person's question.

    (Note of course that I'm assuming we are not returning uninitialized garbage across a security boundary.)

  • The Old New Thing

    Simply attach a piano to the end of the trebuchet


    As easy as 1-2-3.

    What's really scary is that they are hardly the only people to have done this. An Internet search will reveal many other people who've expressed similar musical talent.

    Or you can build one out of an industrial robot and hurl flaming bowling balls.

Page 2 of 4 (32 items) 1234