September, 2009

  • The Old New Thing

    Windows 95's ticking death

    • 24 Comments

    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?

    • 119 Comments

    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

    • 69 Comments

    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

    Woe unto PROGMAN.INI

    • 17 Comments

    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

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

    • 30 Comments

    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

    Why do messages posted by PostThreadMessage disappear?

    • 8 Comments

    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

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

    • 35 Comments

    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;
      this->AddRef();
      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.)

  • The Old New Thing

    Should I fix the spelling in the United States Constitution?

    • 23 Comments

    Commenter Dave jokingly remarked, "I've grown used to handling characters with ASCII. (If it was good enough to represent every character in the US Constitution, it's good enough for me.)"

    But there's a double-joke in there. You see, not every character in the United States Constitution can be represented in ASCII!

    If you take a close look, you'll see that some words appear to be "misspelled": At the end of the second line, it says "Bleſsings of Liberty", and Article 1 Section 1 declares that "All legislative Powers herein granted shall be vested in a Congreſs of the United States."

    That f-like character is actually a long S, a character which has fallen into disuse in modern English. It also doesn't exist in ASCII.

    My friend The Knitty Professor told me a story of a class she taught many years ago. A student emailed a question:

    When I want to quote an excerpt from Locke in my paper, should I fix the spelling? Some words use f instead of s, and others are incorrectly capitalized.

    Today is Constitution Day, a United States holiday celebrating the United States Constitution. Since 2005, all educational institutions which receive federal funds must teach about the United States Constitution on this day, even hairdresser schools.

  • The Old New Thing

    Two-year-old as finite state machine

    • 10 Comments

    Some time ago I joined a family for dinner, and they had a two-year-old. During dinner, the two-year-old accidentally knocked over her glass, and liquid quickly spread across the table. The adults at the table sprang into action, containing the spill on the table, wiping it up, and checking for leakage onto the floor.

    After all the excitement died down, the two-year-old looked down, saw the empty glass, and threw her hands up in the air, proudly announcing, "I drank it all!"

  • The Old New Thing

    What is the logic behind the thumb size and position calculation in scroll bars?

    • 16 Comments

    Commenter sarathc asks, "How do we implement a custom scroll bar as Windows does? What is the logic behind the thumb size and position calculation? How we could dynamically manage it?"

    Let's look at the three questions in turn.

    To implement a custom scroll bar... don't do it. It's just not worth the effort, and there will almost always be little seams, like not lighting up when the mouse hovers over them.

    The logic behind the thumb size and position calculation I thought I covered in my scroll bar series. The size of the thumb relative to the size of the scroll bar is the same as the page size relative to the scroll bar range. In other words:

    thumb size / scroll bar size = page size / scroll bar range

    A little high school algebra tells you, then, that

    thumb size = scroll bar size * page size / scroll bar range

    There may be some off-by-one errors in the above formula, and some special tweaks for extreme cases (you don't want a thumb smaller than one pixel after all), but that's the basic idea.

    Similarly, the screen position of the thumb relative to the scroll bar is equal to the programmatic thumb position relative to the scroll bar range (roughly).

    To dynamically manage it, use the usual scroll bar functions like SetScrollInfo.

Page 1 of 4 (37 items) 1234