July, 2007

  • The Old New Thing

    That leaves more hot German babes for me!

    • 41 Comments

    Controversial new German law requires non-EU members to be able to speak German before they can move to the country to join their spouse.

  • The Old New Thing

    The forgotten common controls: The ShowHideMenuCtl function

    • 17 Comments

    The ShowHideMenuCtl function is one of those functions everybody tries to pretend doesn't exist. You thought MenuHelp was bad; ShowHideMenuCtl is even worse.

    The idea behind ShowHideMenuCtl was that you had a window with a menu as well as controls, and some of the menu items were checkable, indicating whether the corresponding control should be shown. For example, on your View menu you might have options named Toolbar or Status Bar. If the user checks Toolbar, then the toolbar is shown in the main window; if the user unchecks Toolbar, then the toolbar is hidden.

    The parameters to the ShowHideMenuCtl function are a window (the window on which you want to operate), a menu identifier (the menu item you wish to toggle), and a mysterious array of integers. Everything hangs on that mysterious array of integers, which takes the following form (expressed in pseudo-C):

    struct MENUCONTROLINTS {
     int idMenu;
     int idControl;
    };
    
    struct SHOWHIDEMENUCONTROLINTS {
     int idMainMenu;
     HMENU hmenuMain;
     MENUCONTROLINTS rgwMenuControl[];
    };
    

    The MENUCONTROLINTS structure is easier to describe. It merely establishes the correspondence between a menu item and the control that will be shown or hidden. (Exercise: Why do we need two integers? Why can't we just give the menu item and the control the same ID?) The array of MENUCONTROLINTS structures is terminated by a pair whose idMenu is zero.

    The tricky bit is the first two entries, idMainMenu and hmenuMain. The hmenuMain is the handle to the main menu for the window, and the idMainMenu is the item on the menu corresponding to the "Hide menu" entry on the main menu. (That's why hmenuMain need to be passed explicitly. We would normally use GetMenu(hwnd) to get the handle to the main menu, but if we've removed it, then GetMenu(hwnd) will return NULL.) If you don't want to have a "Hide menu" option, you can just put a dummy value in the idMainMenu slot that doesn't correspond to any menu item. (The value -1 is probably most convenient for this. Don't use zero since it terminates the list!)

    When you call the ShowHideMenuCtl function, it searches for the menu item you specified and toggles the check mark next to that item. What happens next depends on what type of item was found.

    • If the item is idMainMenu, then the main menu is attached to or removed from the window (by using the SetMenu function, of course), corresponding to the check box.
    • If the item is idMenu, then the corresponding control is shown or hidden (by using the ShowWindow function, of course), corresponding to the check box.

    That's all there is to it. The rest is up to you. For example, when a control is shown or hidden, it's still up to your program to relayout the visible controls to account for the new window visibility state. For example, if the user shows the toolbar, then the other controls need to move out of the way to make room for the toolbar. The ShowHideMenuCtl function can't do this for you since it has no idea what your window layout is.

    Let's put this information into practice. Start with our scratch program and make the following changes;

    HMENU g_hmenuMain;
    INT rgiMenu[] = {
        100, 0,
        101, 200,
        0, 0,
    };
    
    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
        /* We'll talk about this line more later */
        rgiMenu[1] = (INT)GetMenu(hwnd);
    
        CreateWindow(TEXT("Button"), TEXT("Sample"),
                     WS_CHILD | BS_PUSHBUTTON, 0, 0, 100, 100,
                     hwnd, IntToPtr_(HMENU, 200), g_hinst, 0);
        return TRUE;
    }
    
    void
    OnDestroy(HWND hwnd)
    {
        if (!GetMenu(hwnd))
            DestroyMenu(IntToPtr_(HMENU, rgiMenu[1]));
        PostQuitMessage(0);
    }
    
    
    void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
    {
        switch (id) {
        case 100:
        case 101: ShowHideMenuCtl(hwnd, id, rgiMenu); break;
        }
    }
    
    HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
    
    BOOL
    InitApp(void)
    {
        ....
        wc.lpszMenuName = MAKEINTRESOURCE(1);
        ....
    }
    
    /* add to resource file */
    1 MENU PRELOAD
    BEGIN
        POPUP "&View"
        BEGIN
            MENUITEM "&Menu Bar", 100, CHECKED
            MENUITEM "&Button", 101
        END
    END
    

    Most of the changes are just setting up. We attach a menu to our window with two options, one to hide and show the menu bar, and one to hide and show our custom button. Since our window starts out with the menu bar visible and the button hidden, our menu template checks the "Menu Bar" item but not the "Button" one.

    The OnCreate function finishes setting up up the rgiMenu array by putting the main menu's handle into index 1 in the array of integers, which corresponds to hmenuMain in our pseudo-structure. The OnDestroy function destroys the menu if it isn't attached to the window, since menus attached to a window are destroyed automatically when the window is destroyed. The magic happens in the OnCommand handler. If the user picked one of our two menu items, then we ask ShowHideMenuCtl to hide and show the button or menu.

    The tricky bit is setting up our rgiMenu. Let's break down those integers.

    100 Menu identifier for hiding and showing the menu bar
    0 Placeholder (receives main menu handle in OnCreate handler)
    101 Menu identifier for hiding and showing the menu bar
    200 Control ID for the button that is shown and hidden (passed to the CreateWindow function)
    0, 0 List terminator

    When you run this program, you can use the "Button" menu option to hide and show the button, and you can use the "Menu Bar" menu option to hide and show the window's main menu. Erm, no wait, you can't use it to show the main menu, because the main menu is hidden! Naturally, if your program uses the ability to hide the main menu, you need to provide some alternate mechanism for bringing the main menu back, say via a hotkey or by adding an option to the System menu.

    Okay, now back to that line in the OnCreate function that I promised to talk about. If you have been paying attention, alarm bells should have gone off in your head at the line rgiMenu[1] = (INT)GetMenu(hwnd); because we are casting an HMENU to an integer. On 64-bit machines, a HMENU is a 64-bit value, but integers are only 32-bit. This cast truncates the handle value and consequently is not 64-bit safe. Since the ShowHideMenuCtl function requires an array of integers, you're stuck. You can't shove a 64-bit menu handle into a 32-bit integer. The ShowHideMenuCtl function is fundamentally flawed; it is not 64-bit compatible.

    Fortunately, nobody uses the ShowHideMenuCtl function anyway. Its functionality is so simple, most programs have already written a function that does roughly the same thing, and since you have to write the layout code anyway, the ShowHideMenuCtl function doesn't really save you very much effort anyway. Like MenuHelp, the function is entirely vestigial and isn't something you should be tempted to use in any modern program. It's a leftover from the days of 16-bit Windows.

    Why does such a confusing function exist at all? Well, the shell team thought they were doing you a favor by providing this function back in the 16-bit days. This was originally an internal function used by (I think it was) File Manager, but since it solved a more general problem, the function was exported and documented. In the intervening years, the problem it addressed has been solved in other ways, and the introduction of 64-bit Windows rendered the original solution unworkable anyway, but the function and the code behind it must still linger in the system for backwards compatibility purposes.

    The shell team learned its lesson. It no longer exports every little helper function and custom control for third parties to use. If a future version of Windows no longer needs the helper function, or if a redesign of Windows Explorer removes the need for that custom control (or worse, changes the behavior of that custom control), the shell would still have to carry all the code around for the unused function or control because a function, once documented, becomes a continuing support burden.

  • The Old New Thing

    A modest proposal: Solving the problem of traffic in Seattle caused by sporting events

    • 52 Comments

    Whenever there is a sporting event in Seattle, traffic is reduced to gridlock for hours both before and after the event. This affects not only the people attending the sporting event in question, but also people who get caught up in the traffic as a side-effect.

    To resolve this issue, I present this modest proposal.

    In Berlin, a large museum complex can be found on Museum Island. Similarly, in Munich, Museum Island is the home of the Deutsches Museum.† I remember a conversation with a visitor from Germany to Seattle. She asked for suggestions on what to see, and in response to a museum, she asked, "Is it on an island?"

    Although we don't have the tradition of putting museums on islands here in the United States, we can start a new tradition: Sports Arena Island. Something to think about since the owners of the Seattle Supersonics are looking for a new arena.

    All sporting arenas must be built on an island. The beauty of this solution is not so much in the island-ness, but in how the island is connected to the mainland. (This means that we can have "virtual Sports Arena Islands" in parts of the country where an actual island is impractical.) You see, there will be a hundred lanes of traffic leading into Sports Arena Island, but only one lane of traffic leaving it.

    When there is a sporting event, everybody can get onto the island quickly since there is so much incoming capacity. This means that traffic will not back up onto local streets and highways. And when the event is over, cars can leave the island only one at a time since there is only one exit lane. This prevents the sudden surge of traffic from the game from overwhelming local roads. (The inconvenience of leaving the park would also encourage people to use mass transportation to get to the game.)

    Once we've gotten everybody accustomed to the idea of Sports Arena Island, we can take it to the next level: Floating Sports Arena Island. Here in Seattle, we float everything. Houses, bridges, more bridges (not to be confused with its parallel bridge), and still more bridges. The floating island would travel around the perimeter of Lake Washington like a ferry and make stops according to a fixed schedule. If you wanted to get to the Mariners game, you could get on at Bellevue at 5:30pm, Mercer Island at 6:00pm, or Madrona at 6:30pm. (The island couldn't go further north or south due to time constraints and because there are those bridges in the way, but we could have ferries pick up people from other locations and take them to the island.) This would spread out the event traffic around the entire lake instead of focusing it on one place. Similarly, when the event is over, traffic could be trickled out to the surrounding communities.

    There you have it. Now you can have your football game without seriously disturbing the traffic of the surrounding area. And then we can have the same "oops" that we've had before and sink the structure into the lake.

    Next time (if there is a next time), I'll solve the problem of identity theft.

    Footnote

    †It feels weird for me to write of the Deutsches Museum since it violates the rules for German adjective endings. Since it's the object of the preposition "of" (which is a dative preposition in German), perhaps I should say the Deutschen Museum. But this sounds weird to me because my instinct for adjective endings comes not from the analysis of strong and weak forms but rather on whether the case and gender have already been determined by the article, and since "the" is not declined in English, the answer is no. My instinct therefore tells me it should be of the Deutschem Museum, but that sounds insane the moment I say it. Besides, in German, I would have used the genitive case anyway (des Deutschen Museums). Of course, this is all nonsense since I'm just using a foreign phrase in English, in which case English rules apply. That doesn't mean it still doesn't feel weird.

  • The Old New Thing

    It's not enough to say that something is bad; you have to say what would be better

    • 33 Comments

    I see a lot of feedback that says (roughly), "X is bad," and leaves it at that. That's not useful feedback.

    It's not enough to say that something is bad. you have to say what would be better.

    (Another example. Another.)

  • The Old New Thing

    Redmond Derby Days 2007 this weekend

    • 5 Comments

    Every summer, the city of Redmond stages Derby Days, an annual celebration of... I'm not sure what. But what it does mean is that roads will be closed in the downtown Redmond area, so if you need to get around, you'll have to plan ahead.

    Several years ago, one of my colleagues asked a City of Redmond employee, "What is Derby Days?" He received this very perceptive reply: "Derby Days is a very important cultural event... for the people who organize it."

    My friend :: Wendy :: remarks on the apparent dress code which accompanies the parade that honors... I'm not sure what. Not even the people participating in the parade were able to tell her what Derby Days actually was.

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: If they can run code, then they can run code

    • 24 Comments

    Some people can't get over the initial burst of adrenaline when they think they've found a security vulnerability and rush to file a report with Microsoft so they can get credit for it and add it to their "security vulnerability portfolio" to show that they are so wicked cool.

    Learning that what they found isn't a security vulnerability isn't going to stop them.

    "The SPI_SNAPTODEFBUTTON feature is a security hole. I can write a dialog box that keeps changing its default button, and the mouse will keep moving around to follow the new default button. Tada, I've hijacked your mouse!"

    — Um, no, the "Snap to default button" feature doesn't work that way. It only snaps when the dialog first appears.

    "Okay, well, then I can write a dialog box that hides and shows itself while it's changing its default button. That way, each time it shows, it yanks the mouse to the dialog's default button."

    — That doesn't work either. It's on the first show that the mouse moves.

    "Oh, okay, then I'll create and destroy the dialog in a tight loop. Each time the dialog box appears, it will yank the mouse. Aha, gotcha!"

    — Well, sure, you can do that, but if your goal is to write an annoying program that yanks the mouse around, then this is an awfully inefficient way of doing it. Your annoying program should just call SetCursorPos.

    You shouldn't be surprised that allowing people to run code lets them run code.

    (Episode 1.)

  • The Old New Thing

    Raymond's tips on selecting a memorable greeting card

    • 11 Comments

    My favorite greeting card is one I got from :: Wendy ::. It was a Christmas card with a picture of kids running around while snow fell all around them. Wendy added the message, "Watch out for that 'rogue' snowball from midfield..." I still have that card on my windowsill years later.

    My recommendation for choosing a memorable greeting card is to go to the wrong aisle in the greeting card store. I always start with the "blank cards" aisle since you can look for a picture that sets an interesting scene (like Wendy's snowball fight) and then add a short message inside.

    Last year, I went to the Sympathy aisle to get a birthday card for a friend who was trying not to show his concern over turning 30. After some searching, I found the perfect card. It was your usual sappy sympathy card with flowers and birds on the cover and some text about peace and comfort. And on the inside, it simply said, "Hope you feel better soon." I added, "Happy birthday."

  • The Old New Thing

    QueryPerformanceCounter is not a source for unique identifiers

    • 29 Comments

    This article happened to catch my eye:

    I needed to generate some unique number in my application. I could use GUID, but it was too large for me (I need to keep lots of unique identifiers). I found something like this:

    [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
    private static extern int
        QueryPerformanceFrequency(ref System.Int64 frequency);
    
    [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
    private static extern int
        QueryPerformanceCounter(ref System.Int64 performanceCount);
    
    public static long GenerateUniqueId()
    {
          System.Int64 id = 0;
          QueryPerformanceFrequency(ref id);
          QueryPerformanceCounter(ref id);
          return id;
    }
    

    This code generates Int64 (long) unique number (at least I hope it is unique). The uniqueness is in the scope of process. So two processes can generate the same number, but it should be always unique in a single process (I am not sure about two threads invoking the same GenerateUniqueId() method.

    QueryPerformanceCounter retrieves the current value of the high-resolution performance counter, but there is no guarantee that every call to the function will return a different number.

    The frequency of the high-resolution performance counter is determined by the HAL. You might think that the RDTSC instruction would be perfect for this purpose, since it returns the number of CPU clock ticks, a value that always increases at a very high rate. But there are many problems with RDTSC. For example, variable-speed processors mean that the rate at which CPU clock elapse varies over time. A million clock ticks might take one millisecond when the computer is running on wall power, but two milliseconds when running on battery power.

    If the HAL can't use RDTSC, what does it use instead? Well, as I said, it's up to the HAL to find something suitable. Older motherboards have to make do with the programmable interval timer which runs at 1,193,182 ticks per second (approximately 0.8 microseconds per tick). Newer motherboards can use the ACPI timer which runs at 3,579,545 ticks per second (approximately 0.3 microseconds per tick).

    One of the machines in my office uses the ACPI timer for its high-resolution performance counter, so I threw together a quick program to see how close I can get to outracing the ACPI timer by calling QueryPerformanceCounter in rapid succession. With a 1.80GHz processor, the computer manages to call QueryPerformanceCounter quickly enough that only four ticks of the ACPI timer elapse between consecutive calls. We're getting into shouting range of being able to call QueryPerformanceCounter twice and getting the same value back from the ACPI timer. Of course, if the computer had been using the programmable interval timer, it would have been within spitting distance, and upgrading to a 3GHz processor would have taken us over the top.

    In other words, you may be lucky today that your CPU isn't fast enough to call QueryPerformanceCounter twice and get the same value back, but it sure looks like we're threatening to get there soon.

    Then again, all this back-of-the-envelope calculation is superfluous. All you need is a machine with multiple processors. Get two of the processors to call QueryPerformanceCounter at the same time (or nearly so), and they'll get the same timer value back.

    If you want to generate unique 64-bit values, you can just use InterlockedIncrement64.

  • The Old New Thing

    Holidays for fireworks (and generally blowing up stuff) from around the world

    • 74 Comments

    Today is Independence Day in the United States, known informally as "The Fourth of July", thereby making it the only holiday◊ to be named after its own date. (The next closest candidate is New Year's Day, but nobody calls it "January 1st".)

    The original purpose of this Independence Day holiday have been lost to the mists of time.° Nowadays, it's a day for a barbecue picnic and fireworks.

    I remember asking a Swede when they celebrate their Independence Day. The response was "Independence? From whom?"

    In Sweden, as it probably is in much of the world, the big holiday for setting off fireworks is New Year's Day. (In Asia, Lunar New Year takes precedence.) In England, Guy Fawkes is the traditional excuse for blowing up stuff. In many parts of the world, Christmas appears also to be a big day for fireworks, but for some reason that is not done in the United States.

    What is the holiday for blowing up stuff in your country?

    Nitpicker's corner

    ◊s/the only holiday/the only major U.S. holiday/

    °I was joking about the original purpose of this Independence Day holiday being lost to the mists of time. Everybody knows that it's a commemoration of the invention of the hot dog.

  • The Old New Thing

    The audacity of selling things that don't belong to you

    • 8 Comments

    NPR some time ago reported on a most audacious scam: Selling someone else's property out from under them. But this guy was small potatoes, selling properties owned by churches and other non-profit organizations. The king in this category of fraud is Victor Lustig, the man who sold the Eiffel Tower... twice!

Page 4 of 5 (43 items) 12345