May, 2009

  • The Old New Thing

    When advanced users outsmart themselves: The device removal notification icon

    • 135 Comments

    A customer submitted a suggestion to the user interface team about the device removal notification icon.

    The device removal notification icon is far too hard to use. When I click on it, I get a menu that says Safely Remove Hardware, and when I click on that menu item, I get a dialog box that lists all the removable devices, with vague names like USB Mass Storage Device and propeller-beanie details like Connected on Port 0006, Hub 0004. When I click the Display device components check box, I'm presented with a tree view of hardware devices that only a geek could love.

    This is far too complicated. When I click on the device removal notification icon, I expected to get a simple menu that listed the devices that could be removed in an easy-to-identify manner, such as USB Mass Storage Device on Drive E:. Please consider making this improvement in the next version of Windows.

    Um, actually, that menu you are describing is already there, on the left click menu. Because, according to the traditional rules for notification icons (and the device removal icon was written back in Windows 95, when the traditional rules were operative), left clicking gives you the simple menu and right clicking gives you the advanced menu. This customer was so accustomed to right-clicking on notification icons that the idea of left-clicking never even occurred to him.

    When I tell this story to other advanced users, I often get the same reaction: "What? You can left-click on that thing and it does something different from right clicking? Dude, why didn't anybody tell me this? I've been doing it the hard way all this time!"

    I find this story interesting for a few reasons. First, it shows that differentiating the left click from the right click on notification icons as a way to determine whether to show the simple menu or the advanced menu is now obsolete. Just show the same menu for either click, because users (and these are advanced users, mind you, not just novices) don't even realize that a left click and a right click are different operations at all! And second, it highlights the ineffectiveness of having an Expert mode. These were all advanced users. If there were an Expert setting, they would have set it. And then they not only would have found themselves having to micro-manage the process of removing hardware devices, but also would have asked for a feature that was the same as restoring the novice UI.

    Update: Remember, this is part three of a series. Don't forget to read the other two parts.

  • The Old New Thing

    How do I get a window back on the screen when it moved far, far away?

    • 63 Comments

    Commenter Aggravated notes that some programs remember their location when the window is closed and restore to that location when the window is reopened, even if that position is off the screen. These programs clearly were using screen coordinates instead of workspace coordinates to save and restore the window.

    Okay, so you've got a program that restored its window position incorrectly and ended up putting it off the screen. Now what do you do?

    The keyboard interface comes to the rescue.

    Switch to the application, say by clicking on its taskbar button or by Alt+Tab'ing to it. Then type Alt+Space to call up the System menu: You should get a window floating at the edge of the screen. Type M to select Move, then press an arrow key to enter Move mode. (Doesn't matter which.)

    At this point, you could stick with the keyboard motif and hold down the appropriate arrow key to move the window back onto the screen. Or you can pull a little magic trick: Wave the mouse around. Boom, the window leaps to the mouse like one of those cheapo magic tricks where something leaps into your hand.

    I'm like 95% sure they use string. But it could be magic. No, I'm going with the string.

  • The Old New Thing

    I'm sorry, you don't have permission to know where this shortcut file should show up in the Explorer window

    • 26 Comments

    Commenter Gabe suggested that the shortcut file should contain a bit that indicates whether the target of the shortcut is a folder, so that shortcuts to folders can sort with real folders. "That would allow them to sort properly without doing any additional work beyond that required to see its icon." (Commenter Josh agreed that "The performance reason doesn't really apply here, since explorer is already looking at the target to get the icon," rejecting commenter AndyC's argument that performance may have been a concern.)

    Well, first of all, shortcuts do remember whether the target is a file or a folder, or at least whether it was a file or folder at the time the shortcut was created: IShellLink::GetIDList + IShellFolder::GetAttributesOf tells you this and more about the shortcut target.

    But saying that this isn't more work than what's necessary to see the icon misses a few points about file icons: First, you can't sort by icon, so the consequences of getting the wrong icon (or never getting the icon at all) are purely visual. What? Never getting the icon at all? Well, yes, if the file has been archived to tape, Explorer won't bother recalling the file just to get its icon and will instead just use its generic type icon, or if there is no generic type icon, a generic document icon. After all, you don't want viewing a folder in Explorer to recall all the files from tape. That sort of defeats the purpose of archiving the files to tape.

    Even if Explorer decides to get the icon, it performs that operation at low priority and in the background. By comparison, you don't want to decide where the item should appear in the list as a low priority background task. If you do, then you either show nothing until all the sort information is ready (in other words, show nothing for a very long time, possibly forever if the file has been archived to tape), or you show everything, but move items around as better information arrives. Neither is a particularly pleasant experience for the user.

    What's more, it means that where an item sorts depends on who asks. If you don't have read permission on the shortcut file, then you don't have enough permission to find out whether it's a shortcut to a folder or not, and then Explorer has to decide where "don't know" files go. Do they go with the non-folders by default? Do you create a third "don't know" category? No matter what you choose, the result is that the location of the file changes depending on who asks. "Hey, where did that shortcut file go? Oh, there it is. What's it doing over there? Computers are so hard to use."

    Commenter Leo Davidson noted that determining whether the target of a shortcut is a file or folder is cheap if the target is a local hard drive that is not spun down, but that's an awful lot of ifs. Does this mean that you sort shortcuts to local hard drives that are not spun down differently from shortcuts to network drives or shortcuts to drives that are spun down? Won't users find this confusing? "Hey, where did that shortcut file go? Oh, there it is. What's it doing over there? Why does this shortcut file show up half of the time in one location and half of the time in that other location? Computers are so hard to use."

    Now, even if it's a shortcut and the target is on a local hard drive that has not spun down, that still doesn't mean that you can determine whether or not it is a file or a folder: The target may no longer exist. The act of resolving a broken shortcut is deferred until shortcut is launched, a form of lazy evaluation which avoids having to undertake an expensive search operation until the result is actually needed. If you want to sort shortcuts based on the attributes of the target, you'd have to resolve all the broken shortcuts to see where the target moved to and whether it's a file or a folder.

    Now, you might decide that broken shortcuts are already broken, so who cares what happens? But there are scenarios where almost all shortcuts are broken and the user relies on the resolution process to fix them up. But you knew this already. If the Start menu profile roams from one machine to another, the shortcuts are all broken, but when the user decides to launch the shortcut, the resolution process patches them up so they launch the correct program; it just takes a little longer the first time.

    I suspect that when Leo Davidson runs the program which sorts shortcuts to folders along with the folders and includes the shortcut target in the column description with "no noticeable effect on performance", he doesn't try running it against a server halfway around the world with a 500ms ping time. If you have a folder with 100 shortcuts over a network with 500ms latency, it'll take you nearly a minute just to sort the items. It'll be even worse if you have a folder full of files which have been archived to tape. Maybe that scenario isn't important to him, but it's important to a lot of people. In fact, one might say that the Explorer folks don't pay enough attention to these scenarios, because at every release of Windows, you can count on those people submitting streams of complaints that the most recent version of Explorer sucks even more on their international corporate network, and then the Explorer team has to do a little redesign work to get things to suck less.

  • The Old New Thing

    You can tell which people listed blogging as a performance review goal

    • 36 Comments

    I had been kind of baffled by some of the Microsoft employee blogs that appear to consist almost entirely of rehashes of Knowledge Base articles, or sometimes even just "A new Knowledge Base article on topic X has been published." Now, that's useful information to have if you're interested in topic X, but is it really something you can build a blog around? Can't you just sign up for KB notifications manually? (That's probably how the blog author found them anyway.) And then there are the head-scratcher blog entries like There are no new KB articles this week.

    But I never really thought too much about them. They merely registered as noise to me. Baffling noise, but still noise.

    And then I learned why these types of blogs exist: Because somebody put down blogging as a goal on their annual performance review. If you want to say that one of your goals for the next year is to maintain a blog, you have to specify how to determine whether that goal was met. As I've noted earlier, Microsoft is obsessed with measurement, so the way to tell whether your blog was a "success" is to come up with some sort of metric for success. These people naturally chose Number of blog postings per month as their metric. Running behind this month? No problem, just crank out a few Hey, here's a Knowledge Base article you might be interested in postings and you've filled your quota.

    This is another example how deciding how you're going to measure something affects the people you're measuring: They alter their behavior to maximize the metric rather than the concept the metric is supposed to be tracking. If you decide that you want to expand the Knowledge Base and set numeric goals for employees on how many Knowledge Base articles they should write each year, don't be surprised if you find that in the waning weeks of the year, there's a spurt of largely useless Knowledge Base articles.

    In an internal discussion of this topic, I wrote, "Blogging to improve your review score is like entering politics to get rich." While it may be true that politicians tend to get rich, and many people enter politics in order to get rich (or more legally, enter politics in order to exit politics in order to get rich), I believe that getting rich shouldn't be the motivation for entering politics. And improving your review score shouldn't be the motivation for blogging.

  • The Old New Thing

    Microspeak: T-shirt sizing

    • 16 Comments

    Larry Osterman discussed the buzzword T-shirt sizing, which means "making extremely rough estimates in terms of a small number of predefined categories." The term comes from the traditional way T-shirt sizes are specified in the United States. Instead of having T-shirts in sizes 4, 5, 6 and so on, there are only a small number of sizes: Small, medium, large, and extra-large. (Sometimes augmented by extra-small, extra-extra-large, etc.)

    Forcing the estimate into one of a fixed set of sizes allows the process to go quickly while still producing a result that is at least within the same zip code as a more detailed answer. The idea is not to pin down the schedule precisely but rather to get a back-of-the-envelope feel for whether a project is a two-week project, a two-month project, or a two-year project.

    The size breakdowns vary depending on the scope of the project. For a small project, small might mean "less than a day", whereas for a large project, small might mean "less than a week". People can usually come up with a gut feeling as to whether something will take "less than a week" much more quickly than they can say whether something will take one day, two days, or three days.

    As the concept of T-shirt sizing spread through Microsoft, it inevitably became the source of a new set of derived jargon. I've seen T-shirt costing on a meeting agenda. Though thankfully I have yet to see T-shirting.

  • The Old New Thing

    Writing a sort comparison function, redux

    • 47 Comments

    Prerequisites: Experience with sort functions such as qsort.

    Overqualifications: Familiarity with sort algorithms.

    If you break the rules for sort comparison functions, then don't expect the result of a sort call to be meaningful. In fact, if you really mess it up, you can corrupt memory or go into an infinite loop.

    My program hangs when I used this sort comparison function (pseudocode):

    int compare(x, y)
    {
     return x >y ? +1 : -1;
    }
    

    What's even more strange is that sometimes instead of hanging, the program crashes. It all works correctly if I add one line:

    int compare2(x, y)
    {
     if (x == y) return 0; // added
     return x >y ? +1 : -1;
    }
    

    What's going on? The array I am sorting contains no duplicate elements, so the two items x and y should never be equal.

    First of all, your first comparison function clearly violates the requirements for being a comparison function: It must return zero if the two items compare equal. As a result, the behavior is undefined, and hanging, crashing, or returning an incorrect result are all legitimate behavior.

    But let's dig a little deeper to see why hanging and crashing are plausible responses to an invalid sort comparison function.

    A common sorting algorithm is quicksort. I'll leave you to go off and learn on your own how the quicksort algorithm works. Come back when you're done.

    Okay, welcome back. The central step in quicksort is the partition, and some variants of the quicksort algorithm rely on the partition element comparing equal to itself in order to remove a comparison from the inner loop. For example, an index may walk through the array looking for an element greater than or equal to the partition, fully expecting at least one such element to be found because in the worst case, it will find the partition itself. But if your comparison function fails to report the partition as equal to itself, this search may run off the end of the array and eventually crash with an access violation when it reaches invalid memory.

    That explains the crash, but what about the hang? Well, notice that the comparison function is also inconsistent. In particular, the anti-symmetry rule is violated: compare(x, y) and compare(y, x) return the same value (as opposed to the opposite value) if x==y. The function returns -1 both times, saying "x is less than y" and "y is less than x" simultaneously. This inconsistency can easily send a sort algorithm running back and forth trying to find the right place for the partition.

    The moral of the story is the same: Your comparison function must meet the criteria for a proper comparison function. If you fail to do this, then the results you get will be very strange indeed.

  • The Old New Thing

    The social skills of a thermonuclear device: Why did you hang up?

    • 45 Comments

    One morning I'm working in my office and I'm interrupted by a telephone call. The caller-ID shows that it came in through the switchboard. (I.e., somebody called the main Microsoft number and asked for me by name.)

    Me: Hello?

    Caller: [angrily] Mr. Chen, why did you hang up?

    I don't recognize the voice, and I haven't received a phone call in several days, so I have no idea who this person is or what he's talking about. But if somebody starts out rude to me, that doesn't put me in the friendliest of moods. Still, I use a polite tone of voice.

    Me: Oh, I'm sorry. I'll do it again. [click]

    A few minutes later, my phone rang again. The caller-ID shows that it is once again a call from the switchboard. I let it go to voice mail.

    Shortly thereafter, I received a notification that I have a new voicemail message. Here's a transcript:

    [swearing in a language I don't recognize] Why do you keep hanging up on me? I asked you, are you Raymond Chen, and then I talk to you, and you hang up. Are you stupid or something? [click]

    Now I kind of feel bad that the caller probably got the wrong person. There are at least four people at Microsoft who share my name (or a name very similar to it).

  • The Old New Thing

    When you subclass a window, it's the original window procedure of the window you subclass you have to call when you want to call the original window procedure

    • 23 Comments

    When you subclass a window, you set the window procedure to a function of your choosing, and you remember the original window procedure so you can pass it to the CallWindowProc function when your subclass function wants to pass the message to the original window procedure. For example, if you subclass a window like this:

    SubclassWidgetDialog(HWND hdlgWidget)
    {
      HWND hwndButton = GetDlgItem(hdlgWidget, ...);
      wndProcOrig = (WNDPROC)
         SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)SubclassWndProc);
      // -or-
      // wndprocOrig = SubclassWindow(hwndButton, SubclassWndProc);
      ...
    }
    

    then your subclass function should go something like this:

    LRESULT CALLBACK SubclassWndProc(
        HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
    {
      switch (wm) {
      ...
      default:
        return CallWindowProc(wndprocOrig, hwnd, wm, wParam, lParam);
      }
    }
    

    The window procedure you pass to CallWindowProc is the one which was the window procedure of that window before you subclassed it, not the window procedure from some other window. In the same way that when you create a derived C++ class, you pass method calls along to your base class, not to somebody else's base class:

    class DerivedClass : public BaseClass {
     ...
     // override base class: do some extra stuff
     int Method(int param)
     {
      ExtraDerivedStuff();
      return BaseClass::Method(param);
     }
    };
    

    When you are finished with your customization in DerivedClass::Method, you let the base class do what normally would have happened if you hadn't overridden the method in the first place by calling BaseClass::Method and not by calling SomeOtherClass:Method.

    This sounds blatantly obvious, but you'd be surprised how often people mess this up. For example, if you subclass multiple widget dialogs, you have to save the old window procedure in a different place for each one, because each button may have had a different window procedure by the time you got around to subclassing it. For example, one of them might be a plain button, whereas another of them was subclassed in order to provide a tooltip. If you make wndprocOrig a global or static variable, then you're assuming that every widget button has the same window procedure. You are subclassing a window and forgetting to handle the case where the window is already subclassed! You forgot that somebody else could have done exactly what you're doing.

    There is a popular commercial program that comes preinstalled on many computers which creates a common file open dialog box and subclasses both the file name combo box and the file type combo box, and figures that, well, since they're both combo boxes, they must have the same window procedure, right? Unfortunately, there's no guarantee that they do, because the common file dialog is free to subclass them in order to provide custom behavior like autocomplete. It so happens that the program grabs the window procedure from the subclassed combo box window and uses it for all combo boxes. (These are probably the same folks who would have called the BOZOSLIVEHERE function if given the chance.)

    This makes for very exciting crashes when they take the original window procedure from the subclassed combo box and use it for the other, unsubclassed, combo box. The subclass window procedure finds itself handed a window that it never subclassed. As a result, it not only can't perform its own subclass behavior, but can't even just fall back and say "Well, I can't do my custom stuff, so I'll just forward to the original window procedure" since it can't figure out what the original window procedure was either. It's the window manager version of writing this strange C++ code:

    class SiblingClass : public BaseClass { ... };
    class DerivedClass : public BaseClass {
     ...
     // override base class: do some extra stuff
     // then pass method to the WRONG base class
     int Method(int param)
     {
      ExtraDerivedStuff();
      return ((SiblingClass*)this)->Method(param);
     }
    };
    

    When you subclass a window, and you want to call the original window procedure, make sure you call the correct original window procedure: The one that was the window procedure of that window before you subclassed it.

  • The Old New Thing

    Chicken chicken chicken chicken

    • 43 Comments

    Chicken chicken chicken chicken. [pdf]

    Chicken: Chicken chicken chicken.

  • The Old New Thing

    First, try reading the error message: Episode 1

    • 61 Comments

    Quite some time ago, a customer had forgotten that they were using an evaluation edition of Windows, and they were awakened one morning with the following error message:

    The evaluation period for this installation of Windows has expired. This system will shut down in 1 hour. To restore access to this installation of Windows, please upgrade this installation using a licensed distribution of this product.

    The customer submitted an urgent request for assistance. "Please advise how we can get this machine working again. We need it to run a demo for a major client later this week."

    In the customer's panic, they forgot to read the actual error message, which tells them what they need to do:

    To restore access to this installation of Windows, please upgrade this installation using a licensed distribution of this product.

    In other words, get a non-evaluation edition of Windows and perform an upgrade install. (Kick it off as soon as you finish booting up so you don't get the rug yanked out from under you if you dawdle and take more than an hour to get through setup.) This will preserve all your existing data while upgrading it from an evaluation edition to the real thing.

    Pre-emptive snarky comment: "The existence of evaluation editions with expiration dates proves that Microsoft is evil."

Page 1 of 3 (29 items) 123