January, 2012

  • The Old New Thing

    News flash: Work-at-home job offers are mostly just scams

    • 8 Comments

    McClatchy Newspapers discovers, to everyone's surprise, that work-at-home job offers are mostly just scams. Of course, this is something Rob Cockerham discovered years ago. (He also has a rundown of all his articles on the subject, in case you haven't gotten enough.)

  • The Old New Thing

    You can use backups for things other than restoring

    • 23 Comments

    A customer wanted to know the internal file format of Visual SourceSafe databases. (That wasn't the actual question, but I've translated it into something equivalent but which requires less explanation.) They explained why they wanted this information:

    We are doing some code engineering analysis on our project, so we need to extract data about every single commit to the project since its creation. Things like who did the commit, the number of lines of code changed, the time of day... We can then crank on all this data to determine things like What time of day are most bugs introduced? and possibly even try identify bug farms. Since our project is quite large, we found that generating all these queries against the database creates high load on the server. To reduce the load on the server, we'd like to just access the database files directly, but in order to do that, we need to know the file format.

    Oh great, directly accessing a program's internal databases while they're live. What could possibly go wrong?

    I proposed an alternative:

    Take a recent backup of your project and mount it on a temporary server as read-only. Run your data collection scripts against the temporary server. This will spike the load on the temporary server, but who cares? You're the only person using the temporary server; the main server is unaffected. After you collect all your data from the temporary server, you can then perform a much smaller number of queries against the live server to get data on the commits that took place since the last backup.
  • The Old New Thing

    From the research journal Duh: To lose weight, eat less

    • 28 Comments

    Researchers have determined that the key to losing weight is to consume fewer calories.

    Okay, it's actually more interesting than the summary suggests. The researchers compared a variety of different popular diets and found that it didn't matter what diet you were on; the weight loss (and regain) was the same. The controlling factor was how many calories you consumed.

  • The Old New Thing

    What were some of the abandoned features of Explorer back in its prototype days?

    • 21 Comments

    Chris asked for some stories about what Explorer was like in the early days.

    Well, one thing is that the original name of Explorer was Cabinet, continuing the folder/document metaphor by taking all your folders and documents and putting them inside a virtual filing cabinet. (Cabinet was viewed as an update to the Windows 3.1 File Manager program, whose icon as we all know was a filing cabinet.) Some remnants of this old name can be found in places like the CABINETSTATE structure. (Note that this old sense of Cabinet is unrelated to the CAB file format, which is also called Cabinet.)

    In the early versions of Cabinet, shortcuts were indicated not by a little arrow overlay but by appending >> to the end of the name. For example, you might see an icon on the desktop called My Computer>>.

    The first icon in each folder was a special icon that consisted of an upward-pointing arrow with the name Up One Folder. This was really just a leaky abstraction, exposing the .. directory entry as if it were a real directory.

    We saw what the original Start menu and taskbar looked like some time ago, back before it was a taskbar, and also saw the precursor to the Start menu.

  • The Old New Thing

    It must totally suck to live near Abbey Road

    • 14 Comments

    I feel sorry for the people who live near Abbey Road or who have to take that road as part of their daily routine, because tourists keep blocking traffic to recreate the cover of the eponymous Beatles album.

    The recording studio has a webcam on the intersection so you can watch the mayhem as it happens.

    Update: Just this morning, I checked out the webcam and within two minutes, another group of tourists posed in the zebra crossing.

  • The Old New Thing

    Why did HeapFree fail with ERROR_POSSIBLE_DEADLOCK?

    • 17 Comments

    A customer reported that they were receiving some assertion failures because the Heap­Free function was failing with what they believed to be a valid heap block, and the Get­Last­Error function reported that the reason for failure was ERROR_POSSIBLE_DEADLOCK. What's going on?

    One of my colleagues asked the psychic question, "Is the process exiting?"

    "Why yes, in fact it is. How did you know?"

    Recall how processes exit. One of the first things that happens is that all the other threads in the process are forcible terminated, which has as a consequence that any synchronization resources owned by those threads are now orphaned. And in this case, the synchronization resource in question was the heap.

    When the function calls Heap­Free, the heap code tries to take the heap lock but finds that it can't because the heap lock was owned by another thread. And that other thread no longer exists. (Perhaps it was terminated while it was in the middle of its own Heap­Free operation.) The heap code detects this and instead of deadlocking on its own custom synchronization object, it fails with the error ERROR_POSSIBLE_DEADLOCK.

    By the same logic, you can demonstrate that you cannot reliably allocate memory at process shutdown either. So now you can't allocate memory; you can't free memory. As we saw last time, when you are told that the process is exiting, you should not do any cleanup at all. The memory will get freed when the process address space is torn down. No need to free it manually; that's just a waste of time.

  • The Old New Thing

    A joke for mathematicians: On the Weyl schism

    • 10 Comments

    In one of my mathematics classes, the professor noted (and freely admitted that the joke was not original with him), "There are essentially two groups of mathematicians: Those that have read Weyl and those that have not. And once you enter the first group, you will never be understood by anyone in the second group."

    I guess it's only funny to mathematicians.

  • The Old New Thing

    When DLL_PROCESS_DETACH tells you that the process is exiting, your best bet is just to return without doing anything

    • 52 Comments

    When the Dll­Main function receives a reason code of DLL_PROCESS_DETACH, the increasingly-inaccurately-named lpReserved parameter to is used to indicate whether the process is exiting.

    And if the process is exiting, then you should just return without doing anything.

    No, really.

    Don't worry about freeing memory; it will all go away when the process address space is destroyed. Don't worry about closing handles; handles are closed automatically when the process handle table is destroyed. Don't try to call into other DLLs, because those other DLLs may already have received their DLL_PROCESS_DETACH notifications, in which case they may behave erratically in the same way that a Delphi object behaves erratically if you try to use it after its destructor has run.

    The building is being demolished. Don't bother sweeping the floor and emptying the trash cans and erasing the whiteboards. And don't line up at the exit to the building so everybody can move their in/out magnet to out. All you're doing is making the demolition team wait for you to finish these pointless housecleaning tasks.

    Okay, if you have internal file buffers, you can write them out to the file handle. That's like remembering to take the last pieces of mail from the mailroom out to the mailbox. But don't bother closing the handle or freeing the buffer, in the same way you shouldn't bother updating the "mail last picked up on" sign or resetting the flags on all the mailboxes. And ideally, you would have flushed those buffers as part of your normal wind-down before calling Exit­Process, in the same way mailing those last few letters should have been taken care of before you called in the demolition team.

    I regularly use a program that doesn't follow this rule. The program allocates a lot of memory during the course of its life, and when I exit the program, it just sits there for several minutes, sometimes spinning at 100% CPU, sometimes churning the hard drive (sometimes both). When I break in with the debugger to see what's going on, I discover that the program isn't doing anything productive. It's just methodically freeing every last byte of memory it had allocated during its lifetime.

    If my computer wasn't under a lot of memory pressure, then most of the memory the program had allocated during its lifetime hasn't yet been paged out, so freeing every last drop of memory is a CPU-bound operation. On the other hand, if I had kicked off a build or done something else memory-intensive, then most of the memory the program had allocated during its lifetime has been paged out, which means that the program pages all that memory back in from the hard drive, just so it could call free on it. Sounds kind of spiteful, actually. "Come here so I can tell you to go away."

    All this anal-rententive memory management is pointless. The process is exiting. All that memory will be freed when the address space is destroyed. Stop wasting time and just exit already.

  • The Old New Thing

    Misleading advertisement: Passports or green cards?

    • 20 Comments

    I happened to spot an online advertisement for a company that will help you enter the lottery for a United States Permanent Resident Card, commonly known as a Green Card (even though they card isn't green any more). The advertisement was illustrated with a picture of a United States passport.

    Um, a Green Card is not the same as a passport, nor does a Green Card authorize you to obtain a passport. Passports are for citizens, not alien permanent residents.

  • The Old New Thing

    Creating context menus on menus

    • 12 Comments

    Last week we looked at menu drag/drop. Another little-used menu feature added in Windows 2000 is the ability to show context menus on menus. The message is WM_MENU­RBUTTON­UP and the flag is TPM_RECURSE. Let's demonstrate with a simple program.

    Start with the scratch program, and add the Move­Menu­Item function just so our context menu can do something.

    // resource header file
    #define IDM_MAIN 1
    #define IDM_POPUP 2
    #define IDC_MOVEUP 200
    #define IDC_MOVEDOWN 201
    
    // resource file
    1 MENU PRELOAD
    BEGIN
        POPUP "&Test"
        BEGIN
            MENUITEM "&Red",    100
            MENUITEM "&Orange", 101
            MENUITEM "&Yellow", 102
            MENUITEM "&Green",  103
            MENUITEM "&Blue",   104
            MENUITEM "&Violet", 105
        END
    END
    
    2 MENU PRELOAD
    BEGIN POPUP ""
        BEGIN
            MENUITEM "Move &Up",   IDC_MOVEUP
            MENUITEM "Move &Down", IDC_MOVEDOWN
            MENUITEM SEPARATOR
            MENUITEM "&Cancel",    IDCANCEL
        END
    END
    
    // scratch.cpp
    #define HANDLE_WM_MENURBUTTONUP(hwnd, wParam, lParam, fn) \
        ((fn)((hwnd), (UINT)(wParam), (HMENU)(lParam)), 0L)
    
    void OnMenuRButtonUp(HWND hwnd, UINT uPos, HMENU hmenu)
    {
     if (hmenu == GetSubMenu(GetMenu(hwnd), 0)) {
      HMENU hmenuPopup = LoadMenu(g_hinst, MAKEINTRESOURCE(IDM_POPUP));
      if (hmenuPopup) {
       if (uPos == 0) {
        EnableMenuItem(hmenuPopup, IDC_MOVEUP, MF_DISABLED | MF_GRAYED);
       }
       if (uPos == GetMenuItemCount(hmenu) - 1) {
        EnableMenuItem(hmenuPopup, IDC_MOVEDOWN, MF_DISABLED | MF_GRAYED);
       }
       DWORD dwPos = GetMessagePos();
       UINT idCmd = TrackPopupMenuEx(GetSubMenu(hmenuPopup, 0),
                     TPM_RECURSE | TPM_RETURNCMD,
                     GET_X_LPARAM(dwPos),
                     GET_Y_LPARAM(dwPos), hwnd, NULL);
       switch (idCmd) {
        case IDC_MOVEUP:
         MoveMenuItem(hmenu, uPos, uPos - 1);
         break;
        case IDC_MOVEDOWN:
         MoveMenuItem(hmenu, uPos, uPos + 2);
         break;
       }
       DestroyMenu(hmenuPopup);
      }
     }
    }
    
        HANDLE_MSG(hwnd, WM_MENURBUTTONUP, OnMenuRButtonUp);
    
    // InitApp function
        wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAIN);
    

    When we receive the WM_MENU­RBUTTON­UP message and confirm that the menu is the one we support, we create the popup menu and display it at the mouse location (obtained via Get­Message­Pos) with the TPM_RECURSE flag, indicating that this is a pop-up menu for a pop-up menu. (We also use TPM_RETURN­CMD, but that's nothing new.) If the user chose to move the item up or down, we move it up or down.

    That's all. There really isn't much here, but I figured I'd just write a sample program just to show how it's done.

Page 3 of 4 (34 items) 1234