September, 2006

  • The Old New Thing

    Things you already know: How do I wait until my dialog box is displayed before doing something?

    • 53 Comments

    One customer wanted to wait until the dialog box was displayed before displaying its own dialog box. (Personally, I think immediately displaying a doubly-nested dialog box counts as starting off on the wrong foot from a usability standpoint, but let's set that issue aside for now.) The customer discovered that displaying the nested dialog box in response to the WM_INITDIALOG message was premature, because as we all know, the WM_INITDIALOG is sent before the dialog box is displayed. The question therefore is, "How do I want until my dialog box is displayed before doing something?"

    One proposed solution was the following code fragment:

    case WM_INITDIALOG:
        PostMessage(hDlg, WM_APP, 0, 0);
        return TRUE;
    
    case WM_APP:
        ... display the second dialog ...
        break;
    

    1. Why is this wrong? Hint: You definitely know the answer to this already.
    2. What is the correct solution? You probably know this already.
  • The Old New Thing

    It's that season again: The Microsoft Company Meeting

    • 16 Comments

    Today is the 2006 Microsoft Company Meeting, and with it the continuation of what I consider to be one of the most annoying Company Meeting traditions: The group that cheers wildly any time their project name is mentioned.

    It's never the same group year to year. Instead, a different group (or groups) independent decides to be the annoying one for any particular meeting. For illustrative purposes, let's call the 2006 group "Project Nosebleed". (All project names in this entry are fictitious and are used solely for illustrative purposes. Any similarity to actual projects is purely coincidental. But I mean, really, you asked for it when you named your project after a medical ailment.) The Project Nosebleed folks decide to cheer wildly any time anybody says the word "Nosebleed" at the Company Meeting. Let's see what happens when one presenter mentions their project name:

    We have a lot of products that are poised to make a splash
    in the upcoming year. For the home user, we have Project
    Vertigo, which will help them organize their time and schedule.
    On the small-business side, Project Nosebleed will bring the
    ease-of-use that people have come to expect from their PC Woohoo! Yippee! Rah! Rah! Rah! NoseBleed Number One!  
    to the unwilling IT guy. Meanwhile, Bunion will do the same Nose-Bleed! Nose-Bleed! Yay! Yay!  
    for the educational market. So you see, there are a lot of
    exciting things waiting in the wings.

    Thank you, Nosebleed team. You shouted down the presenter telling the rest of the company what your project is, as well as drowning out the introduction of another team's project. All the rest of the company will remember about your project is "Those annoying Nosebleeders kept screaming so I couldn't hear what the presenter was saying." Well, not all the rest of the company. The Bunion folks will remember a little more. "Those annoying Nosebleeders kept screaming so nobody could hear what our project was about!"

    I remember one year, the team that cheered wildly at every mention of their project did it a bit too mindlessly. A pre-recorded interview was being screened, and the interviewee mentioned their project in a negative way, but they cheered anyway.

    Way to go, Project Nosebleed.

  • The Old New Thing

    If you don't trust your administrators, you've already lost

    • 34 Comments

    Occasionally, a customer will ask for a way they can restrict what the administrator can do. The short answer to this is, "Um, no, that's why they're called 'Administrator'." You can try to set up roadblocks, say, ACL files to revoke access to a file you don't want the administrator to read, but the Administrator can always take ownership of the file and read the contents that way. At the end of the day, the Administrator owns the local machine.

    Often, people ask this question because they want to grant certain employees selected subsets of the full set of capabilities available to the Administrator. The way to do this is not to make the user an administrator and then try to rope off the parts you don't want them to use. Rather, you take the things that you do want them to be able to do and delegate that permission and only that permission to them (discretionary access control).

    For more information, check out this column on trustworthy administrators (based, I am told, on a TechEd presentation) by Steve Riley (and his uncredited co-presenter Jesper Johansson).

  • The Old New Thing

    It is as if our leaders have not been educated in orbital space colonization

    • 7 Comments

    Yesterday were held the primary elections in the state of Washington. Most of the partisan positions were uncontested, so there wasn't much to research. The one with the most candidates was for one of the state's Senate seats, and among those candidates were some who might be considered "a bit unorthodox".

    • Michael Goodspaceguy Nelson. Since election law requires that candidates file under their legal names, Mr. Nelson's middle name must really be Goodspaceguy. (I will assume that he was not born with that name.) Mr. Nelson's position appears to be that we should focus our efforts on constructing orbital space colonies around the earth, the moon, and Mars. In his statement, he bemoans the lack of progress made along these lines:

      Unfortunately, much of our space money has been wasted. It is as if our leaders have not been educated in orbital space colonization. The waste and destruction of taxpayers space property show a lack of understanding of space colonization.

      Mr. Nelson has not one but two blogs. I'm not sure what the difference is, but you can check them out yourself. Blog the first. Blog the second.

    • Mike The Mover. Mr. Mover's position statement is incoherent, but that's okay, because there's a method to his madness. You see, Mr. Mover pays the $1360 filing fee so that he can get his face and name in front of every registered voter in the state. The result of this name recognition is about $150,000 in extra business for his moving company.

    • William Edward Chovil. Mr. Chovil looks like the cranky old man who lives down the street, and his statement does nothing to dispel this perception. His fixation on communism (oops, sorry, Communism with a capital C) and the New World Order conspiracy seems quaintly out of place in today's political climate. Sort of a throwback to the Cold War years.

    • Gordon Allen Pross. Mr. Pross's statement reads like one of those convoluted math problems you got in school, but with an added obsession with "red headed Lincoln pennies" and Congress apparently legislating pennies to people. I think. His argument is hard to follow, but when he starts doing percentages, that's when he loses me completely.

      USA splits the one Taxed Lincoln cent equally three ways Federal, State and Local Governments receive a third, 33.3% times 3 equals 99.99%. With 00.01% left over for campaign finance reform.

      It's so simple it just might work: Funding the government through rounding errors.

    None of these candidates appears to have won their respective election, so we won't be seeing much more of them this election season. But that's okay. All four of these candidates are "regulars" on the ballot, so they'll almost certainly be back in two years if not sooner.

  • The Old New Thing

    Don't forget to unregister your window classes when your DLL shuts down dynamically

    • 11 Comments

    If your DLL is unloaded dynamically, you need to make sure you have unregistered your window classes. (You can tell whether the DLL_PROCESS_DETACH is due to a dynamic unload or whether it's due to process termination by checking the lpReserved parameter to your DllMain function.) If you forget to unregister your window classes, all sorts of bad things can happen:

    First, if you registered any of those classes as a CS_GLOBALCLASS, then people will still be able to create a window of that class by passing its class name to the CreateWindowEx function (or any other function that leads to CreateWindowEx). Since your DLL is no longer in memory, the moment it receives a window message (like, say, WM_NCCREATE), the process will crash since the window procedure has been unloaded. This manifests itself in crashes with the instruction pointer in no-man's land—these are typically not easy to debug, and the Windows error reports that are generated by these crashes won't even be assigned to your DLL since your DLL is long gone.

    Second, even if you registered the classes as private classes, you are still committing namespace pollution, leaking the class into a namespace that you no longer own. If another DLL gets loaded at the same base address as your DLL (thereby receiving the same HINSTANCE, it inherits this dirty namespace. If that DLL wants to register its own class that happens to have the same name as the class you leaked, its call to RegisterClassEx will fail with ERROR_CLASS_ALREADY_EXISTS. This typically leads to the DLL failing to initialize or (if the problem is not detected) an attempt to create a window of that class creating instead a window of your leaked class, with a window procedure whose address now resides somewhere in the middle of this new DLL. This is even worse than an instruction pointer in no-man's land; instead, control goes to a random instruction in the new DLL and probably will manage to execute for a little while before finally keeling over. What's worse, not only does the crash not get reported against your DLL (which is no longer in memory), but it gets erroneously reported against the new DLL since it is the new DLL's code that was executing when the crash finally occurred. Congratulations, you just created work for somebody you never met. Those poor victims are going to be scratching their heads trying to figure out how control ended up in the middle of a totally random function with completely nonsense values on the stack and in the registers.

    Third, the namespace you pollute can be your own. Suppose you registered a class as a CS_GLOBALCLASS, then your DLL gets unloaded and you forget to unregister the class. Later, your DLL gets reloaded, but due to changes in the virtual address map, it gets loaded at a new address. Now your DLL attempts to re-register its CS_GLOBALCLASS classes, and the call fails with ERROR_CLASS_ALREADY_EXISTS. If you're lucky, your DLL detects the error and fails to load, resulting in missing functionality. If you're unlucky, you fail to detect the error and succeed the load anyway. Then the code that did the LoadLibrary will try to create a window with that class, but instead of getting your DLL's window class (which failed to register), it gets the window class left over by that first copy of your DLL! Since that DLL no longer exists, you get a crash with the instruction pointer off in no-man's land.

    This is not a purely theoretical problem. The shell common controls library contained this bug of neglecting to unregister all its classes when dynamically unloaded, and we had to issue a hotfix because the crashes caused by it were actually occurring on real users' machines. Don't be the one responsible for having to issue a hotfix for your product. Unregister your classes if the process is going to continue running after your DLL unloads. Because it's the right thing to do.

    (Now, you might notice that this goes against the rule of not calling out to other DLLs during your DLL_PROCESS_ATTACH. The solution for this is to have a "cleanup" function that people must call before calling FreeLibrary on your library to balance the "initialization" function that they had to call to register your control classes. On the other hand, if you failed to plan ahead for this, such as the shell common control did with its InitCommonControlsEx function without a matching UninitCommonControls function, then you have to decide between the lesser of two evils.)

  • The Old New Thing

    The tale of the radioactive Boy Scout

    • 7 Comments

    Under no circumstances should you attempt this at home.

  • The Old New Thing

    Why doesn't the Shutdown dialog use Alt to get alternate behavior?

    • 59 Comments

    When you select "Shut Down" from the Start menu, a dialog appears with three options: "Stand By", "Turn Off" and "Restart". To get the secret fourth option "Hibernate" you have to press the shift key. Would the Alt key be the more obvious choice for revealing alternate options?

    You might think so, but it so happens that Alt already has meaning. In this dialog, the Alt key would be a disaster, because the underlined letters indicate keyboard accelerators, which are pressed in conjunction with the Alt key. In other words, from the Shut Down dialog, you can type Alt+S to stand by, Alt+U to turn off, or Alt+R to restart. Since the Alt key was already taken, the Shift key had to be used to reveal the bonus options. Using the Shift key to reveal bonus options is not uncommon. You can hold the Shift key while right-clicking on a file to get an extended context menu, and of course there's the Shift+No option in file copy dialogs to mean "No to all".

    In fact, you don't need to press the Alt or Shift keys at all. Recall that the rules for dialog box navigation permit omitting the Alt key if the focus control does not accept character input; since the only things on the Shut Down dialog are pushbuttons, there is no character input and you can just press "S", "U" or "R" without the Alt key. What's more, you don't need to hold the Shift key if you want to shut down; you can just type "H" and the Hibernate option will be invoked, because hotkeys for hidden controls are still active.

  • The Old New Thing

    Project Update 2: Voyage to Our Hollow Earth

    • 12 Comments

    If everything went according to plan, the trip to the hole in the Arctic Ocean should have completed a few months ago. I went to the web site to see what they found, only to discover that it's been postponed another year, to June 26, 2007.

    This is clearly the handiwork of the world government attempting to suppress the release of information they have all held in secret for decades. All their attempts to prevent the discovery of the polar opening only serves to confirm its existence!

  • The Old New Thing

    Sometimes my psychic powers are weak

    • 11 Comments

    Why does my MFC program exit unexpectedly? The stack trace at the point we hit ExitInstance goes like this:

    CClientConsoleApp::ExitInstance
    CWinThread::Run+0x88
    AfxWinMain+0x84
    _wWinMainCRTStartup+0x138
    BaseThreadInitThunk+0xe
    _RtlUserThreadStart+0x23
    

    Thanks.

    You can already see some of what's going on, but clearly more information is needed. My first psychic suggestion was to examine MFC's message pump to see what causes it to exit. Then follow the money backwards.

    That's what we want to know and what we want to find out.

    MFC comes with source code so you can do this yourself. Don't expect somebody to do your debugging for you. You have the tools to do it yourself: You have the source code and you have a brain.

    Once you figure out what conditions make MFC's message pump exit, then try to figure out which of those conditions is actually occurring, and then set breakpoints to try to catch the condition being achieved.

    I don't have the MFC source code memorized and I didn't feel like installing it just to help somebody solve their own problem, so I resorted to wild guessing in the guise of psychic powers:

    I don't know what MFC's message pump looks like but my psychic powers tell me that it stops when it gets a WM_QUIT message. My psychic powers are losing strength from being so heavily stressed so early in the morning... I see a shadow, a vague form, it's not all that clear, kind of hazy, it might be... yes I think it says "PostQuitMessage"... hard to tell... connection fading...

    (Sorry, I can't finish up this story with a snappy ending. It happened so long ago I forget what the problem was.)

  • The Old New Thing

    Disaster averted, thanks to international time zones

    • 14 Comments

    Boy, the world has been really lucky this year. After successfully avoiding a massive tsunami in the Atlantic Ocean, the world narrowly escaped global disaster as predicted by Yisrayl Hawkins, leader of the organization The House of Yahweh. What saved us? Well, I'll let Mosheh Sang, leader of the organization in Kenya, explain:

    According to Sang, a nuclear war between the US and North Korea only failed to kick off Tuesday as expected due to difference in international time zones.

    But they're not giving up yet. According to another leader, Eleazor Kamotho Mugwe:

    It can take up to seven years from now for the said nuclear war to take place because the prophecy talks about September 12.

    To play it safe, they're going to stay underground for a year. In a sense, then, BoingBoing reader Dave Kriesel got it right. He predicted that the response would be, "Did I Say 9-12-2006? I meant to say 9-12-2007."

    Assuming the world hasn't been destroyed by then, we'll try to remember to check back on them next year, see how they're doing.

Page 2 of 4 (37 items) 1234