• The Old New Thing

    What is in the "Windows 95 Special Edition" box?


    At the Windows 95 Launch and at various other marketing events, guests were given a copy of "Windows 95 Special Edition". What is so special about the box?

    Answer: The box.

    The contents of the box are exactly the same as a regular copy of Windows 95. The only thing special about it is the box itself.

  • The Old New Thing

    Lessons from the trenches

    Lessons I learned from working in product support the past few days:
    • If the husband is in the room, hope that he leaves. (He will second-guess everything you do.)
    • If there's a 14-year-old in the room, hope the parents give the phone to him/her. (Teenagers type a lot faster.)
    • Hope you get a grandma.  They're not the fastest typists in the world, but they're so sweet you don't mind.
    • If they don't have a second phone line for their computer, ask if they have a cell phone.  Call them on the cell phone so you can talk them through the rest of the steps.
    • Get a binaural headset as soon as possible.
  • The Old New Thing

    There will be a part 9 in the scrollbar series

    But it's not finished yet. I hope to get to it later this week.
  • The Old New Thing

    Why does Windows 95 have functions called BEAR, BUNNY and PIGLET?

    If you dig back into your Windows 95 files, you'll find that some internal system functions are given names like BEAR35, BUNNY73 and PIGLET12. Surely there is a story behind these silly names, isn't there?

    Of course there is.

    "Bear" is the name of the Windows 3.1 mascot, a stuffed teddy bear seemingly-obsessively carried around by Dave, one of the most senior programmers on the team. If he came into your office, he might bounce Bear on your monitor to get your attention. As a prank, we would sometimes steal Bear and take him on "vacation", in the same way people take garden gnomes on vacation and send back postcards.

    If you play the Windows 3.1 easter egg, one of the pictures you will see is a cartoon of Bear.

    Bear took a lot of abuse. He once had the power cord to a Tempest video game run through his head between his ears. Neil Konzen tried to stick a firecracker up Bear's butt. (Presumably not while it had the power cord in its head.)

    By Windows 95, Bear was in pretty bad repair. (The children of one of the program managers once took pity on Bear and did a very nice job of of getting Bear back in cuddle-able condition.)

    So Bear was retired from service and replaced with a pink bunny rabbit, named Bunny. We actually had two of them, a small one called "16-bit Bunny" and a big one called "32-bit Bunny". Two bunnies means twice as many opportunities for theft, of course, and the two bunnies had their own escapades during the Windows 95 project. (When Dave got married, we helped 32-bit Bunny crash the party and sent back pictures of Bunny drunk on wine.)

    Dave was primarily responsible for the GUI side of things, so you'll see the BEAR and BUNNY functions in the DLLs responsible for the GUI. On the kernel side, Mike had a Piglet plush toy (from Winnie the Pooh). So when we needed to name an internal kernel function, we chose PIGLET. Piglet survived the Windows 95 project without a scratch.

  • The Old New Thing

    A day in the trenches


    I got up at 5 this morning to spend the day at Product Support Services answering phones: today was the day the Blaster worm launched its second wave. And by a startling coincidence, the person at the station next to me was Michael Howard our Senior Security Program Manager and author of Writing Secure Code. Getting Michael Howard to help you secure your computer is like getting Lance Armstrong to help you change a flat tire on your bicycle.

    As enlightening yet humbling experiences go, for a software designer, it's hard to top (1) watching a usability session, and (2) answering product support calls. You get to observe users -- customers, the people your job it is to make more productive -- struggle with the software you helped create.

    Usability sessions are particularly frustrating since you are hidden behind a one-way mirror, watching somebody struggle to accomplish something you designed to be the most obvious thing on the planet. It's a hard lesson to learn: Not everybody is a geek like you. (Watching a usability session is a lot like being a member of the studio audience at The Price Is Right trying to help the contestant on stage guess the price of a new car.)

    Product support calls let you participate in the other end of the pipeline. The software is written, it's out there, and now you have to pay for all your mistakes and bad designs when people call in with their problems. It's software karma.
  • The Old New Thing

    Answer to exercise

    The WM_SIZING handler intercepts only interactive resizing. If the user right-clicks the taskbar and selects "Cascade Windows", this resizes the window directly without going through the interactive WM_SIZING step
  • The Old New Thing

    Windows 95 doesn't boot with more than 1GB of RAM


    Short version

    Windows 95 will fail to boot if you have more than around 480MB of memory. (This was considered an insane amount of memory back then. Remember, Windows 95's target machine was a 4MB 386SX and a powerful machine had 16MB. So according to Moore's law, that gave us seven years before we had to do something about it. One of my friends got 96MB of memory on his machine to test that we didn't tank under "insanely huge memory configurations" and we all drooled.)

    Windows 98 bumped the limit to 1GB because there existed a vendor (who shall remain nameless) who was insane enough to want to sell machines with 1GB of RAM and preinstall Windows 98 instead of the much more suitable Windows NT.

    Long version

    One of the first things that happens in the Windows 95 boot process once you have transitioned into 32-bit mode is to initialize the 32-bit memory manager. But now you have a chicken-and-egg problem: The memory manager needs to allocate some memory in order to keep track of the memory it is managing. (Keeping track of which pages are paged in and which are paged out, that sort of thing.) But it can't allocate memory until the memory manager is initialized. Eek!

    The solution is to initialize the memory manager twice.

    The first time the memory manager is initialized, it gets all its memory from a fixed block of memory preallocated in the init-data segment. It sets up this fixed block as the memory manager heap. So now there is a heap available to satisfy memory allocations.

    Next, the memory manager starts looking for the real memory in the system, and when it finds some, it allocates memory (from the initial fixed block) to keep track of the real memory.

    After the memory manager has found all the real memory in the system, it's time to initialize the memory manager a second time: It carves out a chunk of that real memory to use as the "real heap" and copies the information from the heap that it has been using so far (the fixed-sized heap) to the "real heap".

    Once everything has been copied and all the pointers fixed up, the global memory manager heap pointers are changed to point at the new ("real") heap and the original heap is abandoned.

    The memory consumed by the original heap is reclaimed when the init-data segment is discarded (which happens at the end of system initialization).

    The total RAM limitation occurs because the size of the fixed block in the init-data segment needs to be large enough to satisfy all the memory allocations performed during the memory scan. If you have too much memory, an allocation during the memory scan fails and the system halts.

    The size of the init-data segment was chosen to balance two factors. The larger you make it, the more memory you can have in the system before hitting an allocation failure during the memory scan. But you can't make it too large or machines with small amounts of memory won't even be able to load VMM into memory.

  • The Old New Thing

    Scrollbars part 8 - Integral interactive resizing


    Enforcing integrality solves the fractional-line problem, but notice that when you grab the top or bottom edge and resize the window, the resize feedback doesn't match the actual window you get back if you drag the window to a non-integral size. (You may need to turn off full window drag to see this effect more clearly.)

    The WM_SIZING message lets us adjust the feedback during window resizing. We will adjust the rectangle to match the rectangle that will result when you let go of the mouse.

    void OnSizing(HWND hwnd, WPARAM wmsz, LPRECT prc)
        AdjustSizeRectangle(hwnd, wmsz, prc);
        /* Add to WndProc */
        case WM_SIZING: OnSizing(hwnd, wParam, (LPRECT)lParam); return TRUE;

    Observe that now, when you resize the window, the resizing feedback accurately represents the resulting size of the window. As you drag the mouse vertically or horizontally, the rectangle skips in integral units.

    Exercise: If we are enforcing integrality during resizing, why do we also need to enforce integrality in WM_WINDOWPOSCHANGING, too?

  • The Old New Thing

    Why can't I remove "for test/evaluation purposes only"?


    "Why can't I remove 'for test/evaluation purposes only'? I know I'm running an evaluation edition, I don't need it rubbed in my face."

    This prevents unscrupulous OEMs from selling machines with the evaluation edition of the product instead of the retail version. (Yes, this has happened before. Many times.)

    The "For test purposes only" tag prevents unscrupulous OEMs from selling machines with uncertified drivers. (Driver-cheating has been a big problem, especially video drivers, since... well... forever. Those of you who are gamers know all about driver cheating.) To install an uncertified driver without a warning prompt, you need to install the test root certificate. The presence of the test root certificate causes the "For test purposes only" tag to appear.

    We have also had many cases of corporate customers (and technology reporters!) who have had machines expire because they had forgotten that they were running the evaluation edition.  When the machines expire on them, they are stuck with thousands of machines that don't work. This makes them extremely upset.

  • The Old New Thing

    Scrollbars part 7 - Integrality


    If you play around with resizing the window, you can get a fractional line to appear at the bottom of the screen. This is not normally a problem until you scroll to the very end of the list, say, by pressing the End key, at which point an ugly blank space appears at the bottom. This ugly blank space is particularly disturbing when the fractional line is very nearly an entire line, because it looks like there is an off-by-one bug in the code somewhere.

    We can fix this by forcing the window size to be an exact integral multiple of the line height. Like adding scrollbars, there is the basic idea, followed by a lot of detail work to get it just right.

    The basic idea is to enforce integrality in the window resize code. The right place to do this is in the WM_WINDOWPOSCHANGING handler, which allows you to adjust the placement of the window before it is actually moved. This avoids flicker.

    We'll break the bulk of the work into a helper function, which will prove useful later.

    void AdjustSizeRectangle(HWND hwnd, WPARAM wmsz, LPRECT prc)
        RECT rc;
        int cyClient;
        int cyAdjust;
        /* Compute the resulting client height */
        AdjustWindowRect(&rc, GetWindowStyle(hwnd), FALSE);
        cyClient = (prc->bottom - prc->top) - (rc.bottom - rc.top);
        /* Compute the number of fractional pixels */
        cyAdjust = cyClient % g_cyLine;
         *  Remove the fractional pixels from the top or bottom.
        switch (wmsz) {
        case WMSZ_TOP:
        case WMSZ_TOPLEFT:
        case WMSZ_TOPRIGHT:
            prc->top += cyAdjust;
            prc->bottom -= cyAdjust;

    The WM_WINDOWPOSCHANGNG handler then check if the window size is changing, in which case we adjust the size rectangle to enforce integrality of the client area. We say that the adjustments should be taken from the bottom of the window.

    BOOL OnWindowPosChanging(HWND hwnd, LPWINDOWPOS pwp)
        if (!(pwp->flags & SWP_NOSIZE)) {
            RECT rc = { 0, 0, pwp->cx, pwp->cy };
            AdjustSizeRectangle(hwnd, WMSZ_BOTTOM, &rc);
            pwp->cy = rc.bottom;
        return 0;
        /* Add to WndProc */
        HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, OnWindowPosChanging);
Page 429 of 431 (4,308 items) «427428429430431