May, 2007

  • The Old New Thing

    Suggestion Box 3


    Post suggestions for future topics here instead of posting off-topic comments. Note that the suggestion box is emptied and read periodically so don't be surprised if your suggestion vanishes. (Note also that I am under no obligation to accept any suggestion.)

    Topics I are more inclined to cover:

    • Windows history (particularly the Windows 95 era).
    • Windows user interface programming in Win32, and shell programming in particular.
    • General programming topics (selectively).
    • Issues of general interest.
    • My personal hobbies.

    Topics I am not inclined to cover:

    • The blog software itself. You can visit the Community Server home page and cruise their support forums.
    • Internet Explorer. You can try the IE folks.
    • Visual Studio. You can try one of the Visual Studio blogs.
    • Managed code. This is not a .NET blog. I do not work on .NET technologies. As far as .NET is concerned, I'm just another programmer like you. Occasionally I touch a .NET-related topic, but I do not bring any expertise to the subject.
    • Non-software Microsoft topics, such as product support policies, marketing tactics, jobs and careers, legal issues.
    • Microsoft software that isn't Windows. (Exchange, Office, ...)
    • Windows topics outside user interface programming. (Plug and Play, Terminal Services, Windows Messenger, Outlook Express, SQL, IIS, remoting, SOA...)
    • User interface programming in anything other than Win32. (Because I know nothing about it.)
    • Debugging a specific problem. (Not of general interest.)
    • Predictions for the future. (What's the title of this blog again?)
    • Participation in Internet memes.

    You can also send feedback on Microsoft products directly to Microsoft. All the feedback gets read, even the death threats.

    Suggestions should be between two and four sentences in length. As you can see, there are hundreds of them already, so you have three seconds to get your point across. Please also search the blog first because your suggestion may have already been covered. And remember, questions aren't suggestions.

    Note the enormous topic backlog. Consequently, the suggestion box has been closed temporarily and will reopen once the existing backlog has cleared, which I estimate will happen sometime in early 2010. If your suggestion is that important, I'm sure you'll remember it when the suggestion box reopens.

  • The Old New Thing

    The administrator is an idiot


    Nearly all computer administrators are idiots.

    That's not because the personnel department is incompetent or because it's impossible to train competent administrators. It's because, for a consumer operating system, the computer administrator didn't ask to be one. In nearly all cases, the computer administrator is dad or grandma.† They didn't ask to be to be the computer administrator. They just want to surf the web and read email from Jimmy.‡

    All this means is that you can't say, "Well, if the user is an administrator, as opposed to a normal user, then it's okay to show them all these dangerous things (such as critical operating system files) because they know what they're doing." Grandma doesn't know what she's doing.

    For a consumer operating system, a friendly user interface means protecting the administrators from themselves.

    Nitpicker's corner

    Sigh. One article without a nitpicker's corner and look what happens.

    †The words "dad" and "grandma" refer to archetypes for non-technical home users and are not intended to be interpreted as literally dad and grandma.

    ‡Not all grandchildren are named Jimmy.

  • The Old New Thing

    How my lack of understanding of how processes exit on Windows XP forced a security patch to be recalled


    Last year, a Windows security update got a lot of flack for causing some machines to hang, and it was my fault. (This makes messing up a demo at the Financial Analysts Meeting look like small potatoes.)

    The security fix addressed a category of attacks wherein people could construct shortcut files or other items which specified a CLSID that was never intended to be used as a shell extension. As we saw earlier, lots of people mess up IUnknown::QueryInterface, and if you pass the CLSID of one of these buggy implementations, Explorer would dutifully create it and try to use it, and then bad things would happen. The object might crash or hang or even corrupt memory and keep running (sort of).

    To protect against buggy shell extensions, Explorer was modified to use a helper program called verclsid.exe whose job was to be the "guinea pig" and host the shell extension and do some preliminary sniffing around to make sure the shell extension passed some basic functionality tests before letting it run loose in Explorer. That way, if the shell extension went crazy, the victim would be the verclsid.exe process and not the main Explorer process.

    The verclsid.exe program created a watchdog thread: If the preliminary sniffing took too long, the watchdog assumed that the shell extension was hung and the watchdog told Explorer, "Don't use this shell extension."

    I was one of the people brought in to study this new behavior, poke holes in its design, poke holes in its implementation, review every line of code that changed and make sure that it did exactly what it was supposed to do without introducing any new bugs along the way. We found some issues, testers found some other issues, and all the while, the clock was ticking since this was a security patch and people enjoy mocking Microsoft over how long it takes to put a security patch together.

    The patch went out, and reports started coming in that machines were hanging. How could that be? We created a watchdog thread specifically to catch the buggy shell extensions that hung; why isn't the watchdog thread doing its job?

    That was a long set-up for today's lesson.

    After running its sanity tests, the verclsid.exe program releases the shell extension, un-initializes COM, and then calls ExitProcess with a special exit code that means, "All tests passed." If you read yesterday's installment, you already know where I messed up.

    The DLL that implemented the shell extension created a worker thread, so it did an extra LoadLibrary on itself so that it wouldn't get unloaded when COM freed it as part of CoUninitialize tear-down. When the DLL got its DLL_PROCESS_DETACH, it shut down its worker thread by the common technique of setting a "clean up now" event that the worker thread listened for, and then waiting for the worker thread to respond with a "Okay, I'm all done" event.

    But recall that the first stage in process exit is the termination of all threads other than the one that called ExitProcess. That means that the DLL's worker thread no longer exists. After setting the event to tell the (nonexistent) thread to clean up, it then waited for the (nonexistent) thread to say that it was done. And since there was nobody around listening for the clean-up event, the "all done" event never got set. The DLL hung in its DLL_PROCESS_DETACH.

    Why didn't our watchdog thread save us? Because the watchdog thread got killed too!

    Now, the root cause for all this was a buggy shell extension that did bad things in its DLL_PROCESS_DETACH, but blaming the shell extension misses the point. After all, it was the fact that there existed buggy shell extensions that created the need for the verclsid.exe program in the first place.

    Welcome Slashdot readers. Since you won't read the existing comments before posting your own, I'll float some of the more significant ones here.

    The buggy shell extension was included with a printer driver for a printer that is no longer manufactured. Good luck finding one of those in your test suite.

    The security update was recalled and reissued in a single action, which most people would call an update or refresh, but the word recall works better in a title.

  • The Old New Thing

    Don't be helpless: At least look at the function you're using


    Sometimes I see people ask a question and get an answer, but the answer doesn't quite work. But instead of trying to understand the answer in order to see why it doesn't work and develop a better solution, they just play stupid. Here's an example. The names have been changed but the story's the same.

    How do I get a handle to a bright pink elephant? We have a dialog box that talks about elephants, and we'd like to put some information about the bright pink ones on it.

    An answer came back rather quickly.

    Use GetElephantHandle(EPHNT_BRIGHTPINK).

    Some time later, the customer came back with a follow-up question.

    I can't get it to work. I get a compiler error:
    error C2065: 'EPHNT_BRIGHTPINK' : undeclared identifier

    Am I missing a header file?

    (So much for people knowing what to do when they get this error message.)

    Don't be helpless. Your head isn't just for looks. At least pretend to try to understand what you're doing. In this case, the function is GetElephantHandle, and you're having trouble because the EPHNT_BRIGHTPINK value we want isn't defined. Why not check out the values that are defined?

    #define EPHNT_DUMBO         0
    #define EPHNT_BABAR         1
    #define EPHNT_WHITE         2
    #define EPHNT_BRIGHT_PINK   3

    Wow, I bet the person who wrote EPHNT_BRIGHTPINK really meant EPHNT_BRIGHT_PINK.

    Armed with this new skill, perhaps you can solve this person's problem:

    Somebody recommended that I add the DS_SHELLEXT style to my property sheet dialog template to fix a sizing problem, but when I try that, I get an error that tells me that DS_SHELLEXT is not defined. Is there a file I have to include?
  • The Old New Thing

    Why are console windows limited to Lucida Console and raster fonts?


    In Windows 95, we experimented with other fonts for the console window, and it was a disaster.

    In order to be a usable font for the console window, the font needs to be more than merely monospace. It also needs to support all the characters in the OEM code page. Testing this is easy for SBCS code pages, since they have only 256 characters. But for DBCS code pages, testing all the characters means testing tens of thousands of code points. The OEM code page test already rules out a lot of fonts, because the 437 code page (default in the United States) contains oddball characters like the box-drawing characters and a few astronomical symbols which most Windows fonts don't bother to include.

    But checking whether the font supports all the necessary characters is a red herring. The most common reason why a font ends up unsuitable for use in a console window is that the font contains characters with negative A- or C-widths. These A- and C-width values come from the ABC structure and represent the amount of under- and overhang a character consumes.

    Consider, for example, the capital letter W. In many fonts, this character contains both under- and overhang:

    X      X       X
    X     X  X     X
     X    X  X    X 
     X    X  X    X 
     X    X  X    X 
      X  X    X X   
      X  X    X X   
      X  X    X X   
        X      X    
        X      X    

    Notice how the left and right stems "stick out" beyond the putative cell boundaries.

    I wrote code in Windows 95 to allow any monospace font to be used in console windows, and the ink was hardly even dry on the CD before the bugs started pouring in. "When I choose Courier New as my font, my console window looks like a Jackson Pollock painting with splotches of pixels everywhere, and parts of other characters get cut off." (Except that they didn't use words as nice as "splotches of pixels".)

    The reason is those overhang pixels. The console rendering model assumes each character fits neatly inside its fixed-sized cell. When a new character is written to a cell, the old cell is overprinted with the new character, but if the old character has overhang or underhang, those extra pixels are left behind since they "spilled over" the required cell and infected neighbor cells. Similarly, if a neighboring character "spilled over", those "spillover pixels" would get erased.

    The set of fonts that could be used in the console window was trimmed to the fonts that were tested and known to work acceptably in console windows. For English systems, this brought us down to Lucida Console and Terminal.

    "Why isn't there an interface for choosing a replacement font, with a big annoying message box warning you that 'Choosing a font not on the list above may result in really ugly results. Don't blame me!'?"

    First of all, because we know that nobody reads those warnings anyway. Second, because a poor choice of font results in the console window looking so ugly that everybody would rightly claim that it was a bug.

    "No, it's not a bug. You brought this upon yourself by choosing a font that results in painting artifacts when used in a console window."

    "Well, that's stupid. You should've stopped me from choosing a font that so clearly results in nonsense."

    And that's what we did.

    Of course, if you're a super-geek and are willing to shoulder the blame if the font you pick happens not to be suitable for use in a console window, you can follow the instructions in this Knowledge Base article to add your font to the list. But if you end up creating a work of modern art, well, you asked for it.

    Nitpicker's corner

    In the title of this entry, s/console windows/Windows console windows/†

    †s/Windows console windows/Windows console windows when displayed inside a GUI window, as opposed to consoles that have gone to hardware fullscreen, which is another matter entirely/.

  • The Old New Thing

    Performing an operation in each subdirectory of a directory tree from batch


    To execute a command in each subdirectory of a directory tree from a batch file, you can adapt the following:

    for /f "delims=" %%i in ('dir /ad/s/b') do echo %%i

    (If you want to play with this command from the command prompt, then undouble the percent signs.)

    The /F option enables various special behaviors of the FOR command. The most important change is that a string in single-quotation marks causes the contents to be interpreted as a command whose output is to be parsed. (This behavior changes if you use the usebackq option, but I'm not using that here.) Therefore, the FOR command will run the dir /ad/s/b command and parse the output. The dir /ad/s/b command performs a recursive listing of only directories, printing just the names of the directories found.

    The option we provide, delims= changes the default delimiter from a space to nothing. This means that the entire line is to be read into the %i variable. (Normally, only the first word is assigned to %i.) Therefore, the FOR loop executes once for each subdirectory, with the %i variable set to the subdirectory name.

    The command request to be performed for each line is simply echoing the directory name. In real life, you would probably put something more interesting here. For example, to dump the security descriptor of each directory (which was the original problem that inspired this entry), you can type this on the command line:

    for /f "delims=" %i in ('dir /ad/s/b') do cacls "%i" >>"%TEMP%\cacls.log"

    Nitpicker's corner

    I doubt anybody actually enjoys working with batch files, but that doesn't mean tips on using it more effectively aren't valid.

  • The Old New Thing

    Unexpected consequences of self-checkout


    I heard an interesting report on Marketplace on surprises in the self-checkout lane. Impulse buying is down, and stores have come up with other ways to entice you into buying something you hadn't planned. And it turns out that fears from retailers that customers would cheat at the self-checkout turned out to be misplaced:

    The reality of the situation is that most losses or theft come from the employees themselves. One of the things that we're realizing is actually that customers are more honest than the people that are working there.
  • The Old New Thing

    You're not my manager, so I'm not going to ask how high when you tell me to jump


    This happens a lot. I'm minding my own business and then I start getting nag mail from somebody I've never heard of. It usually is marked "High Priority" and the content has lots of boldface and wording that makes it sound like the world is going to end tomorrow. (Pretend "elephant"† is some new buzzword.)


    Your component has not completed its Elephant review. Elephant-readiness is a release criterion. You must visit http://elephantready/?id=16384 and fill out an Elephant compliance form by the end of the week.

    When you go to the web site, it asks you to confirm a few pages of statements like this:

    Component does not assume rhinos.
    Component does not cover animals with a blanket (elephants are big).
    Component supports a variable amount of peanuts.
    Component does not require animal to have a horn.
    Component does not reject animals with tusks.
    All interfaces exposed by component can operate on elephants.

    Okay, so I get this mail and my first reaction is "What's an elephant?"

    I lied. That's not my first reaction. My first reaction is "Who the hell are you? Who died and made you my manager?"

    Note to managers: Sending out random mail like this won't make you any friends. It turns out people don't like it when somebody creates work for them. Especially when it comes out of nowhere without warning. and double especially when they've never even heard of your feature. So far, you haven't given them any indication why they care aside from "You should care because I said so."

    And you are who again?

    Often when I look at these checklists, I can't even answer them. I mean, sure, I didn't write any code that assumes rhinos, but my component relies on other components, and I don't know whether those other components assume rhinos. Similarly, my code doesn't care about horns or tusks, but maybe one of the components I rely on does. I don't know.

    As a result, I usually skip the questionnaire filled with questions I can't answer and just wait for the next round of urgent messages. That way, I can ignore the second round, too.

    For you see, my manager decides what tasks I should be working on, not you. If you think my manager is doing a bad job of prioritizing those tasks, then feel free to have a little meeting with my manager and work out some sort of agreement. Until then, don't bug me. I have work to do.

    For those new to this web site (and a reminder to those with poor memory):

    †I disguise the name because (1) it's not important to the story, and because (2) the goal is not to ridicule but rather to illustrate a point. Attempts to guess what "elephant" is will be deleted. Don't make me delete further stories in this series like I did with "Stories about Bob."

  • The Old New Thing

    Session 0 isolation: Where backward compatibility loses to security


    One of the major changes to services in Windows Vista is session 0 isolation. After reading the summary, you can follow that first supplementary link, Impact of Session 0 Isolation on Services and Drivers in Windows Vista, to dig deeper and receive guidance on how you need to modify your service.

    Then again, some of the questions I see regarding session 0 reveal that they were relying on behavior that wasn't true even in Windows XP. Many people† assume that session 0 is the one connected to the physical keyboard, but there is no such guarantee. If you turn on Fast User Switching and have multiple users logged on, the second and subsequent users will be on sessions other than session 0, even though they are at the physical keyboard when they log in. Conversely, if you use Remote Desktop Connection to connect to a Windows XP machine, you can connect to session 0 remotely. So whatever they were doing, it was already broken.

    Nitpicker's corner

    †The phrase "many people" means "many people". Microsoft employees fall under the category of people. (I can't believe people are nitpicking the nitpicker's corner.)

  • The Old New Thing

    The unidentified award


    I have in front of me a small bag of a trail mix type of concoction. On the bag it proudly proclaims, "Award Winning Snack". First of all, there's a missing hyphen. (It should be "Award-Winning Snack" since "Award-Winning" is a phrasal adjective. The snack won an award. The award isn't winning a snack.)

    But what award is it? There is no mention of it on the bag or on the company's web site, so I called them. (Update: I checked again a few weeks later and now it says so.) The product won the 2006 Automatic Merchandiser Reader's Choice Product of the Year for Salted Snack of the Year. Automatic Merchandiser is the magazine of the vending industry, and you can check out the complete list of winners. It's not clear to me what the criteria are. Are people in the industry voting for the snack they personally like best? The one they most admire? The one they would most like to stock? I don't know.

Page 1 of 5 (44 items) 12345