April, 2004

  • The Old New Thing

    A story about USB floppy drives


    A friend of mine used to work on the development of the USB specification and subsequent implementation. One of the things that happens at these meetings is that hardware companies would show off the great USB hardware they were working on. It also gave them a chance to try out their hardware with various USB host manufacturers and operating systems to make sure everything worked properly together.

    One of the earlier demonstrations was a company that was making USB floppy drives. The company representative talked about how well the drives were doing and mentioned that they make two versions, one for PCs and one for Macs.

    "That's strange," the committee members thought to themselves. "Why are there separate PC and Mac versions? The specification is very careful to make sure that the same floppy drive works on both systems. You shouldn't need to make two versions."

    So one of the members asked the obvious question. "Why do you have two versions? What's the difference? If there's a flaw in our specification, let us know and we can fix it."

    The company representative answered, "Oh, the two floppy drives are completely the same electronically. The only difference is that the Mac version comes in translucent blue plastic and costs more."

    This company was of course not the only one to try to capitalize on the iMac-inspired translucent plastic craze. My favorite is the iMac-styled George Foreman Grill. (I'm told the graphite ones cook faster.)

  • The Old New Thing

    Where does the taskbar get grouped button titles from?


    If the "Group similar taskbar buttons" box is checked (default) and space starts to get tight on the taskbar, then then the taskbar will group together buttons represending windows from the same program and give them a common name. Where does this common name come from?

    The name for grouped taskbar buttons comes from the version resource of the underlying program. You can view this directly by viewing the properties of the executable program and looking on the Version tab.

    To set this property for your own programs, attach a version resource and set the name you want to display as the FileDescription property.

  • The Old New Thing

    A very brief anecdote about Windows 3.0


    In an earlier comment, Larry Osterman described why Windows 3.0 was such a runaway success. He got a little of the timeline wrong, so I'll correct it here.

    Windows 2.0 did support protected mode. And it was Windows/386, which came out before Windows 3.0, which first used the new virtual-x86 mode of the 80386 processor to support pre-emptively multitasked DOS boxes. The old Windows 2.0 program was renamed "Windows/286" to keep the names in sync.

    The three modes of Windows then became "real mode" (Windows 1.0 style), "standard mode" (Windows/286 style) and "enhanced mode" (Windows/386 style). Amazingly, even though the way the operating system used the processor was radically different in each of the three modes, a program written for "real mode" successfully ran without change in the other two modes. You could write a single program that ran on all three operating systems.

    And then Windows 3.0 came out and the world changed. Sales were through the roof. I remember that some major software reseller (Egghead?) was so pleased with the success of Windows 3.0 that it bought bought every Microsoft employee a Dove ice cream bar. (Even the employees like me who were working on OS/2.) I was sitting in my office and some people came in with a big box of ice cream bars and they handed me one. "This is from Egghead. Thank you for making Windows 3.0 a success," they said.

    It was a strange feeling, getting a thank-you for something you not only didn't work on, but something which totally destroyed the project you were working on!

    [Raymond is currently on vacation; this message was pre-recorded.]

  • The Old New Thing

    Reference counting is hard.


    One of the big advantages of managed code is that you don't have to worry about managing object lifetimes. Here's an example of some unmanaged code that tries to manage reference counts and doesn't quite get it right. Even a seemingly-simple function has a reference-counting bug.

    template <class T>
    T *SetObject(T **ppt, T *ptNew)
     if (*ppt) (*ppt)->Release(); // Out with the old
     *ppt = ptNew; // In with the new
     if (ptNew) (ptNew)->AddRef();
     return ptNew;

    The point of this function is to take a (pointer to) a variable that points to one object and replace it with a pointer to another object. This is a function that sits at the bottom of many "smart pointer" classes. Here's an example use:

    template <class T>
    class SmartPointer {
     SmartPointer(T* p = NULL)
       : m_p(NULL) { *this = p; }
     ~SmartPointer() { *this = NULL; }
     T* operator=(T* p)
       { return SetObject(&m_p, p); }
     operator T*() { return m_p; }
     T** operator&() { return &m_p; }
     T* m_p;
    void Sample(IStream *pstm)
      SmartPointer<IStream> spstm(pstm);
      SmartPointer<IStream> spstmT;
      if (SUCCEEDED(GetBetterStream(&spstmT))) {
       spstm = spstmT;

    Oh why am I explaining this? You know how smart pointers work.

    Okay, so the question is, what's the bug here?

    Stop reading here and don't read ahead until you've figured it out or you're stumped or you're just too lazy to think about it.

    The bug is that the old object is Release()d before the new object is AddRef()'d. Consider:

      SmartPointer<IStream> spstm;
      spstm = spstm;

    This assignment statement looks harmless (albeit wasteful). But is it?

    The "smart pointer" is constructed with NULL, then the CreateStream creates a stream and assigns it to the "smart pointer". The stream's reference count is now one. Now the assignment statement is executed, which turns into

     SetObject(&spstm.m_p, spstm.m_p);

    Inside the SetObject function, ppt points tp spstm.m_p, and pptNew equals the original value of spstm.m_p.

    The first thing that SetObject does is release the old pointer, which now drops the reference count of the stream to zero. This destroys the stream object. Then the ptNew parameter (which now points to a freed object) is assigned to spstm.m_p, and finally the ptNew pointer (which still points to a freed object) is AddRef()d. Oops, we're invoking a method on an object that has been freed; no good can come of that.

    If you're lucky, the AddRef() call crashes brilliantly so you can debug the crash and see your error. If you're not lucky (and you're usually not lucky), the AddRef() call interprets the freed memory as if it were still valid and increments a reference count somewhere inside that block of memory. Congratulations, you've now corrupted memory. If that's not enough to induce a crash (at some unspecified point in the future), when the "smart pointer" goes out of scope or otherwise changes its referent, the invalid m_p pointer will be Release()d, corrupting memory yet another time.

    This is why "smart pointer" assignment functions must AddRef() the incoming pointer before Release()ing the old pointer.

    template <class T>
    T *SetObject(T **ppt, T *ptNew)
     if (ptNew) (ptNew)->AddRef();
     if (*ppt) (*ppt)->Release();
     *ppt = ptNew;
     return ptNew;

    If you look at the source code for the ATL function AtlComPtrAssign, you can see that it exactly matches the above (corrected) function.

    [Raymond is currently on vacation; this message was pre-recorded.]

  • The Old New Thing

    Why a really large dictionary is not a good thing


    Sometimes you'll see somebody brag about how many words are in their spell-checking dictionary. It turns out that having too many words in a spell checker's dictionary is worse than having too few.

    Suppose you had a spell checker whose dictionary contained every word in the Oxford English Dictionary. Then you hand it this sentence:

    Therf werre eyght bokes.

    That sentence would pass with flying colors, because all of the words in the above sentence are valid English words, though most people would be hard-pressed to provide definitions.

    The English language has so many words that if you included them all, then common typographical errors would often match (by coincidence) a valid English word and therefore not be detected by the spell checker. Which would go against the whole point of a spell checker: To catch spelling errors.

    So be glad that your spell checker doesn't have the largest dictionary possible. If it did, it would end up doing a worse job.

    After I wrote this article, I found a nice discussion of the subject of spell check dictionary size on the Wintertree Software web site.

    [Raymond is currently on vacation; this message was pre-recorded.]

  • The Old New Thing

    The martial arts logon picture


    Along the lines of Windows as Rorschach test, here's an example of someone attributing malicious behavior to randomness.

    Among the logon pictures that come with Windows XP is a martial arts kick. I remember one bug we got that went something like this:

    "Windows XP is racist. It put a picture of a kung fu fighter next to my name - just because my name is Chinese. This is an insult!"

    The initial user picture is chosen at random from among the pictures in the "%ALLUSERSPROFILE%\Application Data\Microsoft\User Account Pictures\Default Pictures" directory. It just so happened that the random number generator picked the martial arts kick out of the 21 available pictures.

    I'm also frustrated by people who find quirks in spellcheckers and attribute malicious intent to them. You know what I'm talking about. "Go to Word and type in <some name that's not in the dictionary> and tell it to spellcheck. Word will flag the word and recommend <some other word that is somehow opposite to the first word in meaning> instead. This is an insult! Microsoft intentionally taught the spellchecker to suggest <that word> when you type <this word>. This is clear proof of <some bad thing>."

    More on spell checking tomorrow.

    [Raymond is currently on vacation; this message was pre-recorded.]

Page 4 of 4 (36 items) 1234