September, 2009

  • The Old New Thing

    Windows 95's ticking death


    A few years ago, Larry Osterman explained the famous beeping death. Windows 95 had its own noise-related death, what nobody has called ticking death, but that's what I'm going to call it. (Let's see how long before somebody decide to add it to Wikipedia.)

    When your machine fell into ticking death, each time you moved the mouse or pressed a key, it was acknowledged with nothing more than a tiny click from the speaker. What was the cause of ticking death?

    When the hardware drivers report a mouse or keyboard event on Windows 95, they call the mouse_input or keybd_input function. Since this happens at hardware input time, those functions are very limited in what they can do. All they do is appends the new input to a queue of "input that arrived while I was busy doing something else." When the window manager reaches a stable state, it takes the input from the "input waiting to be processed" queue and farms them out to the appropriate application input queues. The window manager needs to be stable, since mouse input gets routed depending on which window is under the mouse pointer when the pointer moves, and you don't want to do this while some other part of the window manager is in the process of rearranging the windows (and the window tree is consequently unstable).

    For compatibility reasons, the window manager promises not to change anything while 16-bit code is running, so that a 16-bit application doesn't see, for example, a window becoming destroyed behind its back. (Recall that 16-bit Windows is a co-operatively multi-tasked system, which means that applications have control of the CPU until they voluntarily relinquish it.)

    If a 16-bit application hangs, then the buffer for holding all of these "distribute this input to application queues as soon as it is safe to do so" fills up and can't accept any more input. If new input arrives and there's nowhere to save it, the window manager emits a little tick sound as a mini-error message.

    Of course, as the end user, you probably knew something was up because the screen hasn't changed in a long time. Some 16-bit application is not responding and is preventing the window manager from doing anything. To get out of this situation, you can hit Ctrl+Alt+Del and try to kill the hung application.

  • The Old New Thing

    Why doesn't Explorer have an interface for creating hard links?


    Nick asks why Explorer doesn't have UI for creating hard links.

    Heck, while you're at it, why not ask "Why doesn't Explorer have a UI for hex-editing a file?"

    Remember, all features start out with minus 100 points. Explorer is not under any obligation to expose every last NTFS feature, and it's certainly not going to help to expose an NTFS feature that even technical people don't understand. Just look at all the people who ask questions like "How can I tell if a file name is a hard link instead of a normal file?" or online explanations of hard links which claim that "A hard link is only a reference to the original file, not a copy of the file. If the original file is deleted, the information will be lost." I mean, if even a techno-geek doesn't understand hard links, how is your average user supposed to have a chance?

    First, let's see how you would explain a hard link to an end user.

    When you create a hard link, you give the item an additional name. The file can be accessed by either its old name or its new name; they are equivalent. A file is not deleted until all its names are deleted.

    If you open a file by one name, make changes, and then save the file, the update is made to the file, and accessing the file by a second name will show the updated file, because the data for a file is separate from its name.

    Actually, that paragraph above is only true if the application which saves the file does so by writing directly to the name you used when you opened the file. If the application updates the file by creating a temporary file, then renaming the original to a backup name and renaming the temporary file, then updating a file by one name will sever its connection with other names for the file. The other names will continue to refer to the unmodified file; the name you used for the update will refer to the updated file. Different applications handle this situation differently; consult your application documentation for information on how it treats hard links.

    Note also that some backup programs have difficulty with hard links. Consult the documentation for your backup program for information on how it behaves when faced with hard links.

    If a file has multiple names, editing the file by using different names simultaneously may result in data corruption.

    If a file has multiple names, all the names must exist on the same drive.

    Most users clicked Cancel at about the time you said, "When you create a hard link..." You'll probably lose the rest of them while you are busy warning about the potential problems with hard links, and the brave few who managed to stick it out to the end will be completely confused and hit Cancel. (The ones who hit Cancel early on were the smart ones.)

    The problem with backup programs is particularly nasty. A backup program that is not hard-link-aware will miscalculate the necessary size of the backup volume, and when it attempts to restore the files, it will not restore the hard links.

    There was a Windows XP PowerToy for creating hard links, but the backup team recommended that it not be released because so many third party backup programs exploded when they stumbled across files that had multiple names in the file system.

  • The Old New Thing

    When people ask for security holes as features: Privileged execution


    A customer wanted to know if there was a way to execute privileged instructions without having to write a driver.

    "I just need to execute a few instructions, and writing a driver would be overkill since it's only three instructions. Is there a way I can execute these privileged instructions without a driver?"

    The whole point of having a class of modules called drivers is to prevent somebody from doing exactly what you're asking for. Only drivers can execute privileged instructions; that's why they're called privileged instructions.

    "Yeah, but I just need three instructions. Do I have to write a whole driver just for those three instructions?"

    Even just one instruction can pwnz0r a machine. You have to be a driver in order to have that much power over the computer.

    "Maybe there's a driver somebody has already written that I can give the instructions to, and it'll execute them for me?"

    If somebody has written a driver which is designed to execute arbitrary instructions handed to it from user-mode, that person needs to be taken outside and beaten. It's one thing to have a bug that permits arbitrary code execution, but to have it as the purpose of your driver?

    Think of writing a driver as having access to the secure area of a nuclear power plant. People have to be granted the appropriate security clearance before they are allowed into enter the control room. If you want to get into the control room of the nuclear power plant, you'll have to apply for security clearance.

    "But that's so much work. I just need to go in and change a few settings on the control panel."

    Dude, that's why you're not allowed in, so you won't change those settings!

    Your options are either to get security clearance yourself, or convince somebody with security clearance to change the settings for you.

    "Well, do you know somebody who does have security clearance who will change any settings I tell him to?"

    Gosh, I sure hope not.

  • The Old New Thing

    Thanks for identifying the good programmers for us


    Many years ago, my manager told me about a recruiting trip he made. In response to a large number of job applications submitted from a city where a major competing software company had its offices, a small group of Microsofties travelled to that city to interview those applicants and hold a mini-job fair, so that other interested parties could also show up and interview for positions.

    When the company learned that Microsoft was coming to interview people, they called an emergency meeting which all their top programmers were required to attend, timing it to coincide with the job fair. The theory must have been that if their top programmers are at the emergency meeting, then they can't go to the job fair. Problem solved.

    Well, except that the plan backfired. Sure, all the good programmers didn't come to the job fair, but it also told the interviewers which of the applicants were the good ones: They were the ones who didn't show up for their interviews!

  • The Old New Thing

    Woe unto PROGMAN.INI


    Sad but true: Once you document a file format, it becomes a de facto API.

    The Windows 95 team learned this the hard way when they set out to replace Program Manager with Explorer. Not only were the settings in the PROGMAN.INI file documented, so too was the binary file format of *.GRP files. The binary file format was included for diagnostic purposes: If you have a corrupted GRP file, you can use the binary file format documentation to try to recover what you can out of it.

    But many people treated this documentation not as a FYI, but as a backdoor API. Instead of using the formal DDE interface for creating program groups and icons, they just directly edited the PROGMAN.INI file and the applicable GRP files to get the icons and groups they wanted.

    Oh wait, and then you need to reboot in order for the backdoor API to take effect, because all you did was modify the on-disk files, not the in-memory copy held by PROGMAN.EXE.

    Of course, when Windows 95 replaced Program Manager with Explorer, these programs found themselves modifying the data files of a program that no longer was running. Special code had to be added to Explorer to read settings from PROGMAN.INI and even detect that a new GRP file was added and convert it into shortcuts on the Start menu.

    I wouldn't be surprised if that code is still lying around, just in case somebody pulls out an old application from 1994 and installs it.

  • The Old New Thing

    Why do messages posted by PostThreadMessage disappear?


    The only thread message you can meaningfully post to a thread displaying UI is WM_NULL, and even then, it's only because you want to wake up the message loop for some reason.

    A common problem I see is people who use PostThreadMessage to talk to a thread that is displaying UI and then wonder why the message never arrives.

    Oh, the message arrived all right. It arrived and then was thrown away.

    This is actually a repeat of an earlier entry with the title Thread messages are eaten by modal loops, but I'm repeating it with a better subject line to help search engines.

    But since I'm here, I may as well augment the existing article.

    Obvious places where you have modal loops on a UI thread are functions that are explicitly modal like DialogBox or MessageBox or TrackPopupMenuEx(TPM_RETURNCMD) or DoDragDrop. But there are less obvious modal loops, like the modal loop that runs when you click on the caption bar and hold the button or the modal loop that runs when COM is waiting for a cross-thread call to complete.

    And since you don't control those modal loops, when they call DispatchMessage, your thread message will simply be thrown away.

    If you need to communicate reliably with a thread that also displays UI, then create a hidden window and send or post messages to that window.

  • The Old New Thing

    Reading the error message carefully can help you see how the computer misinterpreted what you typed


    The details have been changed since they aren't important but the lesson is the same.

    A customer had the following problem with a command-line tool:

    I've created a taglist but I can't seem to get it to work with the track command. When I ask it to track the taglist, it can't find it. But if I ask for all my taglists, there it is.

    C:\> show taglists
    You have 2 taglists:
     active (8 tags)
     closed (6 tags)
    C:\> track active
    No such tag "active".

    Yes, the track command isn't working, but let's take a closer look at that error message. It says no such tag. Strange, because you are trying to track a taglist, not a tag. Shouldn't the error message be no such taglist?

    Aha, the problem is that the track command takes a list of tags on the command line, not a taglist name. The error message is correct: There is no such tag called active. Because active isn't a tag name; it's a taglist name.

    C:\> track -taglist active
    Taglist "active" is now being tracked.

    Today's lesson: Look carefully at what the error message complaining about; it may not be what you expect.

    Exercise: Diagnose the following error message, given no information about the program being used beyond what is presented here:

    I accidentally made a change (transaction number 12345) to the file XYZ, and I want to back it out. But when I run the backout command, I get an error. Can somebody help me?

    C:\> backout 12345
    12345 - file not found
  • The Old New Thing

    Things I've written that have amused other people, Episode 5


    A question was sent to an internal discussion list for users of the XYZ tool:

    From: Q
    To: XYZ Users

    The GHI function in the JKL tool doesn't work for me. «description of problem deleted»

    I responded with this message:

    To: Q, XYZ Users

    The JKL tool is not part of XYZ. You should contact the author of the JKL tool.

    The reason why people were amused by this is that the author of the JKL tool is me. (Says so right there in the online help.)

    As a final punch line, the person never did contact me.

  • The Old New Thing

    One way to make sure nobody sends you feedback


    Last year, somebody sent out a message to very large group of people describing a change to, well, what it described isn't important to the story. What's important is that the message ended with the following sentence:

    If you have questions, please send them to abcdef.

    If you don't see why this was a brilliant move, go back and check what that "abcdef" link really does.

    One of my cynical colleagues noted, "Maybe this was intentional. That way, when they get no feedback, they can say, 'See, this was an awesome decision. Nobody complained!'"

  • The Old New Thing

    The ways people mess up IUnknown::QueryInterface, episode 2


    Sadly, I get to add another entry to The ways people mess up IUnknown::QueryInterface:

    Blindly responding to everything.

    Some people are just too eager to please.

    HRESULT CSomething::QueryInterface(REFIID riid, void **ppvObj)
      *ppvObj = this;
      return S_OK;

    No matter what the interface is, they say, "Sure, we do that!"

    Furthermore, no matter what you ask for, they always return the same interface. Even if it's not what you asked for.

    Exercise: Some people say that "these problems wouldn't be there if Microsoft Windows had enforced correct behavior to begin with." My exercise to you, commenter "foo", is to come up with a list of all bugs in IUnknown::QueryInterface which Windows should enforce and describe how to enforce it. (If your response is "You should have designed it differently so these bugs are impossible to write", please outline that alternate bug-resistant design. Remember that your design must be language-independent, while still supporting things like tear-offs, aggregation, and remote objects. Oh and it needs to work on typical PC-class computers of the early 1990's, which ran at 25MHz with 4MB of memory.)

Page 1 of 4 (37 items) 1234