September, 2008

  • The Old New Thing

    News flash: Doing something that requires your attention reduces your ability to do other things at the same time which also require your attention

    • 28 Comments

    The New York Times points out that if you engage in an activity that requires your attention, then it reduces your ability to do other things at the same time which also require your attention. For some reason, however this is news when one of those things is sending text messages.

    I wonder if, had contemporary news editors existed back in the days when books were invented, they would have published big scary articles expounding on the dangers of reading a book while riding a horse or chopping firewood.

  • The Old New Thing

    I've seen why people steal the foreground window for their dialog box

    • 45 Comments

    Now, it may very well be true that many people who use GetForegroundWindow() as the owner for a dialog box because they don't know any better, but I'm not convinced that everyone who does so did it out of ignorance; I'm sure there's some malice in there, too. Here's how it may have gone down:

    Bug: I start the product setup, and then I go and work on something else, and then setup hits a problem, but the error message can't be seen because it's hidden behind another window.

    Result: Setup fails to complete.

    Expected: Error dialog is visible so user can address the problem and allow setup to complete.

    The programmer who is told to fix the bug, of course, tries to figure out how to fix the bug, and since the bug report said that the error dialog needs to be visible even when other programs are running, the programmer gives a shrug and does what the bug report says should happen.

    And that's how the installation program ends up disabling Task Manager.

    (Commenter Jamie has another very plausible scenario.)

  • The Old New Thing

    Steamy coffee leaves grounds for concern

    • 12 Comments

    I'm embarrassed for the bad pun,¹ but the subject is serious. Two stories appeared in the two major local newspapers on the same day.

    Sure, it may have been a coincidence, but I considered it a cautionary tale.

    Follow-ups

    Baristas resign en masse when the coffee stand owner decides to adopt a provocative dress code.

    Over a year later, NPR picks up the story.

    Footnotes

    ¹I'm not embarrassed for making a pun, just that it's a bad pun. (Some people would argue that there's no such thing as a good pun.)

  • The Old New Thing

    How can I tell that a directory is weird and should be excluded from the user interface?

    • 18 Comments

    Last time, we looked at a customer who wanted to know how to tell whether a given folder was a Recycle Bin folder or not. We answered the question as stated, but made the mistake of not looking at the problem the customer was trying to solve.

    I need to know which folders are Recycle Bin folders so I can skip over them when searching the drive for content.

    Ah, the real question isn't "How can I tell whether a directory is a Recycle Bin folder?" but rather "How can I tell whether a directory contains weird stuff that we shouldn't be showing to the user (of which Recycle Bin files are just one example)?"

    The way to mark a folder as containing stuff that you shouldn't bother the user with is to set both the FILE_ATTRIBUTE_HIDDEN and FILE_ATTRIBUTE_SYSTEM attributes. In addition to Recycle Bin directories, this also prevents you from searching weird things like System Restore points. (Though for some reason it doesn't stop you from searching Temporary Internet Files; I don't know whether that is a bug or a feature.)

    Therefore, the answer to "How can I tell whether a directory contains weird stuff that we shouldn't be showing to the user?" is to test for the hidden and system attributes.

    BOOL IsWeirdDirectory(LPCTSTR pszDir)
    {
      DWORD dwAttr = GetFileAttributes(pszDir);
      return dwAttr != INVALID_FILE_ATTRIBUTES &&
             ((dwAttr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))
                     == (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN));
    }
    
  • The Old New Thing

    How can I tell that a directory is really a recycle bin?

    • 20 Comments

    Here's a question inspired by an actual customer question:

    I need a function that, given a path, tells me whether it is a Recycle Bin folder. I tried using functions like SHGetSpecialFolderPath with CSIDL_BITBUCKET, but that doesn't work because the Recycle Bin is a virtual folder that is the union of the Recycle Bins of all drives.

    The customer noted that they don't want to hard-code the words RECYCLED and RECYCLER, which is a good decision because the name of the directory depends on many things. I mentioned earlier that it depends on the file system. It also depends on whether the drive is accessed locally or remotely; network-based Recycle Bin folders follow yet another naming scheme. It may even depend on what operating system the user is running. No, hard-coding the name of the Recycle Bin folders is not a good idea.

    The SHDESCRIPTIONID structure tells you a little more about a shell folder. In addition to the "description ID", it also gives you a CLSID, and it is the CLSID that is relevant here.

    #include <windows.h>
    #include <shlobj.h>
    #include <tchar.h>
    #include <stdio.h>
    
    HRESULT
    GetFolderDescriptionId(LPCWSTR pszPath, SHDESCRIPTIONID *pdid)
    {
      HRESULT hr;
      LPITEMIDLIST pidl;
      if (SUCCEEDED(hr = SHParseDisplayName(pszPath, NULL,
                                            &pidl, 0, NULL))) {
        IShellFolder *psf;
        LPCITEMIDLIST pidlChild;
        if (SUCCEEDED(hr = SHBindToParent(pidl, IID_IShellFolder,
                                        (void**)&psf, &pidlChild))) {
          hr = SHGetDataFromIDList(psf, pidlChild,
                         SHGDFIL_DESCRIPTIONID, pdid, sizeof(*pdid));
          psf->Release();
        }
        CoTaskMemFree(pidl);
      }
      return hr;
    }
    
    int __cdecl wmain(int argc, WCHAR **argv)
    {
      SHDESCRIPTIONID did;
      if (SUCCEEDED(GetFolderDescriptionId(argv[1], &did)) &&
          did.clsid == CLSID_RecycleBin) {
        printf("is a recycle bin\n");
      } else {
        printf("is not a recycle bin\n");
      }
      return 0;
    }
    

    The GetFolderDescriptionId function takes the path to a folder and converts it to an ITEMIDLIST just so it can call SHGetDataFromIDList to obtain the SHDESCRIPTIONID. All we care about in this case is whether the CLSID is the Recycle Bin or not.

    C:\> checkrecycle C:\Windows
    is not a recycle bin
    C:\> checkrecycle C:\RECYCLER\S-1-5-21-2127521184-1604012920-1887927527-72713
    is a recycle bin
    

    Of course, now that I told you how to do it, I have to tell you that this is not how to do it. This is another example of a customer having a problem, solving half of it, and asking for help with the other half, unaware that they are approaching the problem from the wrong direction. Next time, we'll look at the customer's real problem.

  • The Old New Thing

    Well at least that's one fewer program that relies on window handles being even numbers

    • 29 Comments

    Earlier this year I received a piece of email from a programmer at a major software firm, reprinted below (suitably redacted) with permission. It was a sort of a mea culpa. (Remember: no guessing allowed.)

    Hi, Raymond.

    I'm a dev on Product X and recently we were sitting around having a beer after work, discussing the long and sordid history of our code base, and an interesting factoid came up that you might be interested in. Apparently, when we were writing Version 1 of our program many years ago when buffalo roamed the earth, window handles were always even numbers for whatever reason. We relied on that when we created our user interface library and interpreted any handle that was odd as coming from our library and even ones as belonging to Windows. This "functionality" has been sitting in our code base through all our releases.

    Just letting you know that we finally got rid of this dependency. You can finally use those odd handles once the next version of Product X comes out and the current version falls out of support. Should only take five years, ten tops.

    Sorry about all the trouble this caused. I'm surprised (and grateful) that you guys keep working as hard as you do on what I'll call Stupid-Dependencies-On-Undocumented-Features.

    One down, who-knows-how-many to go.

  • The Old New Thing

    The purpose of charts is normally to make information easier, not harder, to understand

    • 23 Comments

    In a presentation a few years ago, there was a pie chart, but not just any pie chart, but a pie chart that appeared to be specifically designed to convey no information whatsoever. (The presenter didn't realize this, of course, and probably thought it was awesomely cool.)

    The pie chart consisted of five wedges, each of which was a slightly different shade of green. No, wait, that's not right. Each wedge was a gradient from a common shade of green to a slightly different shade of green for each wedge. Accompanying the chart was a legend that described what each shade of green represented. It was completely useless. (Inspired by this story, my friend :: Wendy :: created her own monochromatic pie chart.)

    If you're going to make a chart with a legend, then the items labelled by the legend should be colors which are unlikely to be confused with each other. And for goodness' sake, don't make them all subtly different shades of the same base color. (For bonus points, consider the color-blind members of your audience. And for double bonus points, also consider the blind members of your audience. But that's another topic for another day.)

  • The Old New Thing

    I no longer have to remind the payroll department to gear up for annual raises

    • 23 Comments

    September 15 is the date on which annual raises take effect. This means that on the 15th, the payroll servers are swamped with people eyeballing their new paycheck breakdown to see what has changed.

    And every year, on September 15th, the servers would become overloaded and people would be unable to connect. Instead they'd get a message like this:

    Due to unexpectedly high demand, the payroll servers are unable to service your request. Please try again later.

    We apologize for the inconvenience.

    Unexpectedly high demand? This happens every year on exactly the same date! How could it be unexpected?

    For a few years, I set myself a recurring task for August 15th that said, "Remind the payroll department to increase capacity for September 15th."

    I don't know if my reminders helped any, but it appears that the payroll department finally figured out on their own the elusive pattern to their high demand days and added additional capacity accordingly. I no longer have to remind them.

  • The Old New Thing

    The terms of service you have to accept before you can see them

    • 30 Comments

    I had a few hours to kill at the airport a few years ago before my flight was ready for boarding, so I turned on my laptop and connected to the airport's wireless network. Like most pay services, they way you sign up is to fire up a web browser and go to any web site. Regardless of what site you go to, you are redirected to the "Here's how to buy a day's worth of wireless networking" site.

    So far so good.

    At the sign-up page, they asked for the usual information and also had a reminder that signing up for the service implies that you have read and accepted their terms of service. There was a link to their terms of service.

    Except that when you clicked the link, you were redirected to the sign-up page since you haven't signed up yet.

    In order to sign up, you have to accept the terms of service that you can't see until you sign up.

    I didn't sign up.

    Apparently I'm not the only person who's run into this Catch-22.

    Pre-emptive snarky comment: "Microsoft's license agreement for a bloated, inefficient and unreliable operating system is evil, anti-competitive, and offensive." When the legal department asks me to write a product license agreement, I'll keep your feedback in mind.

  • The Old New Thing

    Who is responsible for destroying the font passed in the WM_SETFONT message?

    • 4 Comments

    The WM_SETFONT message tells a control which font you would like the control to use for its text. This message is a convention, not a rule. For example, our scratch program doesn't pay attention to the WM_SETFONT message. If somebody sends it a WM_SETFONT, nothing happens. The scratch program just ignores the caller and uses whatever font it wants.

    Although supporting the WM_SETFONT message is optional, if you do choose to support it, you would be well-served to adhere to the following convention: The WM_SETFONT message does not alter font ownership. In other words, whoever was responsible for destroying the font before the WM_SETFONT message is sent is still responsible for destroying it after the message is sent.

    Corollary: If you tell somebody to use a specific font, don't destroy the font while they're still using it, because they're counting on you to keep the font valid.

    Example: The dialog manager creates the dialog box font and sends the WM_SETFONT message to each control to tell it what font it should use. The dialog manager keeps the font valid until the dialog box is destroyed, at which point the font is destroyed as well.

    But what font does a control use before it receives a WM_SETFONT message? Whatever font it wants. Some controls have particular ideas about the font they will use by default; the list view, for example, uses the icon label font. In those cases, it is the control's responsibility to destroy that default font when the control is destroyed. This is true even if the parent window creates another font and sends a WM_SETFONT to change to that font. There are now two fonts involved: the original default font (which is the control's responsibility to destroy) and the font set by WM_SETFONT (which is the parent's responsibility to destroy).

    Now this may all sound complicated, but remember the basic rule: The WM_SETFONT message does not change who is responsible for destroying a font. Let's look at that scenario again, but take out the WM_SETFONT message. (I've crossed it out below.) A control creates a default font. The parent window creates another font. The parent window sends the WM_SETFONT message to the control.

    Now, without that crossed-out sentence, the ownership rules are crystal clear. The control is responsible for destroying the default font it created, and the parent is responsible for destroying its own font.

    The same principle applies to the WM_GETFONT message. You can send WM_SETFONT and WM_GETFONT messages all day long; it has no effect on who is responsible for destroying the font at the end of the day.

Page 2 of 4 (33 items) 1234