April, 2009

  • The Old New Thing

    Windows 95 almost had floppy insertion detection but the training cost was prohibitive


    One feature which Windows 95 almost had was floppy disk insertion detection. In other words, Windows 95 almost had the ability to detect when a floppy disk was present in the drive without spinning up the drive.

    The person responsible for Windows 95's 32-bit floppy driver studied the floppy drive hardware specification and spotted an opportunity. Working through the details of the specification revealed that, yes, if you issued just the right extremely clever sequence of commands, you could determine whether a disk was in the floppy drive without spinning up the drive. But there was a catch.

    The floppy drive hardware specification left one aspect of the drive behavior unspecified, and studying the schematics for various floppy drive units revealed that about half of the floppy drive vendors chose to implement it one way, and half the other way. Here's the matrix:

    Floppy Style Disk present Disk absent

    The results were completely reliable within each "style" of floppy drive, but the two styles produce exactly opposite results. If you knew which style of drive you had, then the results were meaningful, but the hard part was deciding which style of drive the user had.

    One idea was to have an additional "training" step built into Setup:

    • "Please insert a floppy disk into the drive and click Next."

    Once the disk was in, we could run the algorithm and see whether it returned 0 or 1; that would tell us which style of floppy drive we had.

    Unfortunately, this plan fell short for many reasons. First of all, a user who bought a computer with Windows 95 preinstalled would have bypassed the training session. You can't trust the OEM to have gone through the training, because OEMs change suppliers constantly depending on who gave them the best deal that week, and it's entirely likely that on the floor of the warehouse are a mix of both styles of floppy drive. And you certainly don't want to make the user go through this training session when they unpack their computer on Christmas morning. "Thank you for using Window 95. Before we begin, please insert a floppy disk in drive A:." You can't just try to figure out what type of drive the user has by comparing the clever technique against the boring "turn on the floppy drive light and make grinding noises" technique, at least not without displaying a warning to the user that you're about to do this—users tend to freak out when the floppy drive light turns on for no apparent reason. "Thank you for using Windows 95. Before we begin, I'm going to turn on your floppy drive light and make grinding noises. Press OK."

    Floppy disk insertion detection is not a sufficiently compelling feature that users will say, "I appreciate the benefit of going through this exercise."

    Sadly, floppy insertion detection had to be abandoned. It was one of those almost-features.

  • The Old New Thing

    When people ask to disable drag and drop, they often are trying to disable accidental drag and drop


    We occasionally get customers who ask, "How do I disable drag and drop?" This is an odd request, so we ask the frequent follow-up question, "What are you really trying to do?" For many of these customers, the answer goes something like this:

    We've found that our employees often accidentally move or copy items around on the desktop and in Explorer windows because the act of pressing the mouse button causes the mouse itself to slide slightly across the table, resulting in a drag operation instead of a single click. We then have to spend a good amount of time searching for where those files ended up and trying to get their system back to its original state. We'd therefore like to disable drag and drop to avoid this problem.

    They aren't really trying to disable drag and drop. They are merely trying to disable accidental drag and drop.

    To avoid accidental drag and drop, adjust the drag sensitivity so that it takes a greater effort to trigger a drag and drop operation. By default, the mouse needs to travel four pixels with the button held down for a drag operation to be initiated. To make it harder to initiate an accidental drag operation, just crank this number higher.

    This particular customer might decide to crank the drag threshold to 50 or 100 pixels, so that the mouse has to move quite a significant distance before it is interpreted as a drag operation.

    By the way, the function for changing the drag threshold is SystemParametersInfo; check out the SPI_SETDRAGHEIGHT and SPI_SETDRAGWIDTH parameters.

    Pre-emptive correction: Do not modify the registry directly. Use the API. That's why it's there.

  • The Old New Thing

    The frustration of people who are not interested in why something works but only interested in the magic phrase they need to type


    It's frustrating when people who are presumably smart (or who are at least pretending to be) have a problem and are satisfied to receive the magic phrase they need to type with no interest at all in understanding why the magic phrase works. For example, here's a question sent to an internal mailing list for users of something I'll call Program Q.

    From: X

    Why is it that after I use program Q to create a table, nothing else works? Here's a batch file I've written:

    q create table newtable
    q create table newtable2

    The pause command never executes; in fact, nothing in the batch file executes after the first line. How can I create multiple tables from a batch file?

    My psychic powers didn't need very much charging up to solve this one. Program Q is a popular one, and some teams like to create a wrapper around it for whatever reason.

    My psychic powers tell me that the first "q" on the path is not q.exe.

    Another person on the mailing list knew what I was getting at and picked up the ball.

    From: Y

    Try using call q create table newtable instead.

    (Maybe you too can figure out what my psychic powers told me the problem was.)

    The response:

    From: X

    Thanks, that did the trick. I put a call in front of the first line and now the entire batch file runs.

    I replied:

    Dear X. Please confirm that the first q on the path is in fact a batch file, in order to confirm that you understand the reason why you were encountering the problem, that it has nothing to do with Program Q, and that you understand why the fix works. Don't just copy the answer from your neighbor.

    I've already decided that I'm going to blog about people who accept an answer without bothering to understand why it works. Here's your chance to at least look good when that blog entry comes out.

    There was no response.

    Update: This was a mailing list for a programmer's tool. And if you're a programmer, you'd better understand what you're doing when you do it, not just cargo-cult your way through your job. Especially since this particular problem had nothing to do with Program Q in the first place. (On the other hand, I don't blame non-programmers for being satisfied with magic phrases.)

  • The Old New Thing

    What kind of uncle am I?


    Like every language, English has its own collection of words to express family relationships. There are the easy ones like mother, father, brother, and sister. Also comparatively easy are cousin, aunt, uncle, niece and nephew. But most people don't know about this "removal" part, beyond the fact that your "first cousin twice removed" is somebody you probably met once at a wedding ten years ago.

    It's really not that complicated. Some people think removal has to do with estrangement, but actually it has to do with generations. The children of your Nth cousin are your Nth cousins once removed. Their grandchildren are your Nth cousins twice removed. In general, to find your Nth cousin K times removed, go to your Nth cousin and then follow their children K times.

    You can also look at it from the point of view of the younger relative: Your Nth cousin K times removed is the Nth cousin of your Kth direct ancestor, where K = 1 is your parent, K = 2 is your grandparent, etc. For example, your father's second cousin is your second cousin once removed. There's a nice chart at genealogy.com that depicts many of these more complicated relationship terms.

    In practice, these relationship terms are considered unnecessarily formal. In casual conversation, two such relatives who are comparable in ages are called distant cousins. If one is significantly older than the other, then the older relative is called a distant aunt/uncle of the younger one.

    In many cultures, the terms for aunt and uncle can be applied more generally to any close friend of your parents. When I mentioned to my mother that the children of one of my friends call me Uncle Raymond, she asked me, "Which uncle?" This question puzzled me initially, but then I realized that in my parents' native language, as with most other Chinese dialects, there are several types of family relationships which in English all get lumped together as uncle. The term to use depends on whether the uncle is paternal or maternal, whether the uncle is older than or younger than your parent, and whether the uncle is by blood or by marriage. For example, you can use the word for husband of father's older sister or, if you wanted to be more respectful or if you need to resolve ambiguity, you can say the word that means husband of father's older sister number two. One of the reasons for so many fine distinctions for family relationships is that it is considered disrespectful to address someone older than you by name. (Compare United States culture, where it is considered disrespectful to address one's parents by name.) Consequently, resolving ambiguity cannot be accomplished as it is in Western cultures by appending the relative's name (Aunt Carol or Uncle Bob); it must be done by using a more specific title.

    But since my friend's children speak English, they can just address me as Uncle and not have to worry about which kind of uncle I am. (To my Chinese-speaking nieces, however, I am 大姑丈.)

  • The Old New Thing

    On the almost-feature of floppy insertion detection in Windows 95


    Gosh, that floppy insertion article generated a lot of comments.

    First, to clarify the table: The table is trying to say that if you had a Style A floppy drive, then issuing the magic series of commands would return 1 if a floppy was present, or 0 if the floppy was not present. On the other hand, if you had a Style B floppy drive, then issuing the magic series of commands would return 0 if a floppy was present, or 1 if the floppy was not present. That's what I was trying to say in the table. The answer was consistent within a floppy style, but you first had to know what style you had.

    The downside of waiting until the user uses a floppy for the first time is that you have the it sometimes works and sometimes doesn't problem. Dad buys a new computer and a copy of the Happy Fun Ball game for his son. Dad turns on the computer, and then follows the instructions that come with the Happy Fun Ball package: "Just insert the floppy and follow the instructions on the screen." Dad inserts the floppy and... nothing happens because this is the first time Dad used the floppy, and he was expecting autodetection to work.

    Dad says, "Stupid program doesn't work."

    Dad complains to his co-workers at work. "He loves this game Happy Fun Ball when he visits his cousin's house, so I bought a computer and a copy of Happy Fun Ball, and it doesn't work!"

    Dad tries again that evening and this time it works, because in the meantime, he inserted a floppy to do something else (say, create an emergency boot disk). Bizarre. This just reinforces Dad's impression that computers are unpredictable and he will never understand how to use them.

    One could say that a feature that mysteriously turns itself on and off is worse than a feature that simply doesn't work. At least when it doesn't work, it predictably doesn't work. Human beings value predictability.

    You can't perform the test "the first time the drive is installed" because there is no way to tell that a drive has been installed. (Classic floppy drives are not Plug-and-Play.) Even worse, you can't tell that the user has replaced the Style A floppy drive with a Style B floppy drive. The user will see that floppy insertion detection stopped working and return the drive to the store. "This drive is broken. Floppy insertion detection doesn't work."

    It is also not the case that the ambiguity in the specification indicated a flaw in the specification. The C++ language specification, for example, leaves a lot of behaviors at the discretion of the implementation. This allows implementations to choose a behavior that works best for them. The no-spin-up floppy presence detection algorithm relied on several behaviors which were covered by the specification, and one that was not. It was not part of the original charter for the floppy specification committee to support spinless presence detection; it's just something that my colleague discovered over a decade after the specification was written.

    But the main reason for not bothering is that the benefit was minuscule compared to the cost. Nobody wants floppy drives to spin up as soon as a disk is inserted. That just makes them think they've been attacked by a computer virus. It'd all just be a lot of work for a feature nobody wants. And then you'd all be posting, "I can't believe Microsoft wasted all this effort on floppy insertion detection when they should have fixed insert favorite bug here."

  • The Old New Thing

    Being able to call a function without using GetProcAddress is not a security vulnerability


    Another genre in the sporadic category of dubious security vulnerability is people who find an unusual way of accomplishing something perfectly normal but declare it a security vulnerability because they found an unusual way of doing it.

    Security is important to all computers users, from families at home to employees of government agencies, and people who use Microsoft Windows are no exception. Trojans, backdoors, and spyware (collectively known as malware) have taken many forms, most recently those of so-called rootkits, which modify the operating system itself in order to prevent their detection. Firewalls are an important tool in the defense against malware.

    Through the following sequence of tricks, we can obtain the address of any function without using the GetProcAddress function. Once that address is obtained, the function can be called in the normal manner. First, obtain the module base address by calling the LoadLibrary function. The headers of the image are mapped into memory at the base address. From there, you can parse the headers of the module, look for the export directory, then manually parse the exported function name table until you find the function you want. In this way you can call functions like RegSetValue without detection.

    Well, sure, you can manually perform all the operations that the GetProcAddress would perform, but what's the point? Once you call RegSetValue all the normal registry security checks take place. You haven't bypassed anything. If you were so keen on calling functions surreptitiously, you could scan memory looking for the byte pattern that corresponds to the function you're looking for, or heck, just cut out the middle man and just take the code from the DLL you are trying to gain secret access to and copy it into your program!

    In other words, you just found a complicated way of doing something perfectly mundane. You can't make up for the absence of any actual vulnerability by piling on style points and cranking up the degree of difficulty.

  • The Old New Thing

    Why is the animation common control limited to RLE8-compressed animations?


    The animation common control is very limited in the type of animations it can play. The animation must be in AVI format, it cannot have any sound, and it must be either uncompressed or use RLE8 compression. Why so many restrictions?

    Because if it could handle other file formats, play sound, and support arbitrary codecs, it would just be a reimplementation of the multimedia animation control. (We saw this principle earlier when discussing why you can't do everything with registry values that you can do with registry keys.)

    The point of the animation common control is to play very simple animations without the overhead and accompanying complexity of the full generality of the multimedia animation control. Think of it as the 1040EZ of animation. If your animation is comparatively simple and you don't need very much control over its playback at all, then go ahead and use the animation common control, which is designed to be a simple playback control for simple animations. But if your animation is complicated, uses an advanced compression scheme, or contains audio, then you've left the world of simple animations and need to move up to the full-sized 1040 form. There's no point adding support for everything to the simplified control, because once you've added support for everything, you have the complex control that the simplified control was trying to simplify!

    Okay, fine, so the animation common control can't be a full-featured animation control or that would have defeated its purpose for existing. But why those specific limitations?

    Because those were just barely enough features to play the animations that the shell team needed to play. The animation common control was written by the Windows 95 shell team, and it supports only enough features to be able to play the animations that the Windows 95 Explorer used. After the control was written, the shell team figured, hey, we already wrote it, we may as well do other people a favor and let them call it, too. The downside of this is that even though the shell doesn't use these simple animations any more, it still has to ship the animation control because other applications rely on it. What started out as a courtesy has turned into a support burden.

  • The Old New Thing

    Clap and the filter graph claps with you


    One of my colleagues was a fount of ideas, some of them crazy, some of them clever, and some of them both. I think this one counts as both.

    To render multimedia content with DirectShow, you build a so-called filter graph. A filter graph represents a series of transformations that are applied to data as it travels through the graph. For example, bytes from a video file may go through a splitter filter which separates the audio from the video data, then the two data streams each go through a respective audio and video decoder, which converts the compressed data into uncompressed sound or video data, and then to a render device which actually plays the sound samples out the speaker or puts the video image on the screen.

    One of the components of a filter graph is the reference clock. The purpose of the reference clock is to keep track of time, so that all the parts of the filter graph produce their output in a synchronized manner. If there weren't something keeping track of this, the audio would fall out of sync with the video.

    My colleague decided to create an unusual reference clock. Whereas most reference clocks are based off of real-world time, my colleague's reference clock started by taking input from the microphone. It did some analysis of the volume of the incoming sound stream and detected when there were loud impulses of sound. It then generated a stream of clock ticks based on the rate at which those impulses were detected.

    In other words, the clock was driven by clapping.

    I was lucky enough to be one of the first people to see this crazy reference timer in action. First, you started up the application and picked a video clip. The video clip just sat there. As you started clapping, the video clip started playing. If you clapped at about 80 beats per minute, the video clip played at its normal speed. If you clapped faster, the video clip ran faster. If you clapped slower, the video clip ran slower. If you stopped clapping, the video clip stopped.

    It was freaky cool.

    Totally useless, but freaky cool.

    Update: Commenter hexatron pointed out that the Metronome sample does the same thing as my colleague's crazy reference clock. I don't know if it's literally the same code, but it's functionally equivalent.

  • The Old New Thing

    Why are there two values for PSH_WIZARD97?


    Welcome, Slashdot readers. Remember, this Web site is for entertainment purposes only.

    If you go cruising through the commctrl.h header file, you'll find that there are two different definitions for PSH_WIZARD97:

    #if (_WIN32_IE >= 0x0400)
    #if (_WIN32_IE < 0x0500)
    #define PSH_WIZARD97            0x00002000
    #define PSH_WIZARD97            0x01000000

    Why are there two values for PSH_WIZARD97?

    Set the wayback machine to 1997. (Note: Dates are approximate.) The user interface design team studied how Windows 95 wizards have been faring and have begun using what they've learned to develop the next version of the wizard interface, which they have code-named "Wizard 97". Development in comctl32.dll proceeds based their designs, what with exterior and interior pages, headers and sub-headers, watermarks, all that jazz. Meanwhile, work on Internet Explorer 4 reaches the homestretch, and it's a race to the finish line.

    Internet Explorer 4 wins the race and is ready to ship before the work on Wizard 97 is complete. What do you do? Do you say "Um, hi, Internet Explorer team. Could you slip your schedule by about half a year so we can finish our work on this new wizard design?" Yeah, like the Internet Explorer team are going to say, "Oh, sure, no hurry, take your time. We'll wait. It's not like we're going to get ridiculed for being another six months late."

    And monkeys might fly out of my butt.

    Out the door it goes, with a Wizard 97 design that hadn't gone through a full usability review. To discourage programmers from using this half-finished wizard, put the sentence "Don't use this flag" in the documentation. Boy, that was a close call.

    Since they already "missed the boat", the urgency to complete the work on Wizard 97 vanished. One of the things that came up during the usability review was that the full-page watermark wasn't such a great idea after all. It made the text hard to read, users had difficulty figuring out what they should do, various problems like that. The design for Wizard 97 changed; now the watermark was just a small picture that goes in the corner of the wizard. Of course, the changes weren't just design changes; there were also bug fixes. All the work was done in time for Windows 2000, yippee.

    And then the compatibility bugs started coming in.

    Wait, compatibility bugs? How can there be compatibility bugs? Nobody is using Wizard 97 yet; there's nobody to be compatible with!

    Well, it turns out that programs were indeed using the PSH_WIZARD97 flag from Internet Explorer 4 and expecting to get that old half-baked Wizard 97 design. (After some investigation, I believe we discovered that somebody somewhere had told the MFC folks, "Hey, there's this cool Wizard 97 thing you should use. It's pretty awesome." That someone was overcome with excitement and didn't realize that the work on Wizard 97 was not yet finished and that Wizard 97 was not yet ready for prime time. People who used MFC to write their programs then said, "Hey, look, MFC has support for this new type of wizard!" and started using it.)

    Oh, great, how do you fix this?

    It wasn't pretty, but it had to be done. (The preferred first choice, using a time machine, was unavailable.) The fix was to have two types of Wizard 97; there's the "Internet Explorer 4 version" and the "Windows 2000 version". Of course, nobody wants to officially admit that the Internet Explorer 4 version exists, since during its brief lifetime, it was documented as "Don't use me!" All the changes that were made after Internet Explorer 4 shipped had to be revisited. Each time there was a code change (either to support a new design or just to fix a bug), a test against the wizard flavor had to be made, and the old behavior restored if the old flag was used.

    If new code was added for the Windows 2000 version of Wizard 97, whether it be due to a design change or a bug fix, then it had to be placed behind a check:

        if (program asked for Windows 2000-style Wizard 97) {
            // new behavior here

    Conversely, if code was deleted, it had to be brought back with a version check:

        if (program asked for Internet Explorer 4-style Wizard 97) {
            // old behavior here

    And if behavior changed, you need to have both versions:

        if (program asked for Internet Explorer 4-style Wizard 97) {
            // old behavior here
        } else {
            // new behavior here

    Giving the old and new Wizard 97 flags different values allows the property sheet wizard code to tell whether the program was designed for the bogus Internet Explorer 4 pre-release version of Wizard 97 or the finished Windows 2000 version.

  • The Old New Thing

    Taxes redux: You can't open the file until the user tells you to open it


    One of the so-called taxes of software development on Windows is being respectful of Hierarchical Storage Management. You can't open a file until the user tells you to open it. This rule has consequences for how Explorer extracts information about a file, because what you definitely don't want is for opening a folder full of archived files in Explorer to result in all the files being recalled from tape. (Actually, file recall is just an extreme case of the cost of opening the file. You run into a similar problem if the file is on a slow medium or over a slow network connection. But just to motivate the discussion, I'll continue with the tape scenario.)

    What information does Explorer need in order to display a file in a folder? Well, it needs the file name. Fortunately, that can be determined without opening the file, since the file name is how you identify the file in the first place! When you want to open a file, you pass its name. There, you have the name. If you are showing the contents of a folder, you used a function like FindFirstFile to get a list of all the files, and the list comes in the form of names. Okay, so the name is easy. (There are still subtleties here, but they are not relevant right now.)

    Okay, what's next. The icon. Well, in order to get the icon, we need to know the file type, so let's put the icon on hold for now.

    The file creation and modification times can be obtained without opening the file; they come out as part of the FindFirstFile, or if you started with a file name, you can recover them with GetFileAttributesEx. Either way, you can get that without opening the file. Same goes for the file size.

    The other properties, like Title, Author, Summary... They all require that the file be opened, so Explorer disables the property for files that have been archived to tape. You don't want to recall a file from tape just to show its Author in Explorer.

    Okay, that leaves just the file type (and the icon, which depends on the file type). Consider the possibilities for how the file type could be determined.

    What do these problems tell us? The first problem, that reading bytes from a file forces a recall, means that file type information cannot be based on the file contents. The second problem, that reading alternate data streams also force a recall, means that you can't put it in an alternate data stream either. All that's left is storing the type in the metadata.

    But the third problem tells us that there isn't much metadata to choose from. Whatever mechanism you use needs to be able to survive being sent as an email attachment or being uploaded to an FTP site. Email attachments in particular are extremely limited. Most email programs, when asked to save an attachment, preserve only one piece of metadata: The filename. (They often don't even preserve the last modified time. And good luck getting them to preserve other ad-hoc metadata.)

    All of these problem conspire to rule out all the places you can squirrel away type information, leaving just the filename. It's a sucky choice, but it's the only choice left.

    And it means that changing a file's extension means the file type information is destroyed (which, from an end user's point of view, may as well be corruption).

Page 1 of 3 (28 items) 123