• The Old New Thing

    On nearly getting pickpocketed in both Lisbon and Madrid

    • 15 Comments

    My trip to Lisbon introduced me to another tourist phenomenon: pickpockets.

    It was around 10:30 in the morning, and I got on the train to head into town, planning to climb the steps through the Alfama district to visit the castle which looms over the city. The morning rush was over, and the Metro car was nearly empty.

    Just before the doors closed, a group of about four twentysomething guys stumbled onto the train, walking unsteadily and talking quite loudly among themselves. I found this immediately suspicious. They are acting drunk, but who is drunk at 10:30 in the morning? At 10:30, you're hung over, not drunk. And even if you are drunk, you are drunk in the comfort of your home, not stumbling around the subways.

    Even though the subway car had only about three people, and there was plenty of room to spread out, this group of pretend-drunks hung around close to me. I went on high alert.

    A few seconds later, one of the guys "stumbled" into me and thrust his hand into my pants pocket. I immediately grabbed his hand and yanked it back out, making sure he didn't get anything, adding a shout of "Hey!" (I don't speak Portuguese, so I couldn't say anything more eloquent.)

    Still keeping up the ruse of just being a bunch of loud-mouthed drunks, the group of would-be pickpockets stumbled off the train just as the doors closed. Well, three of them did. One of them didn't quite get off in time and stood with his face against the wall until the train reached its next stop, at which point he ran off.

    After Lisbon, I headed over to Madrid, and on the Metro I was on one of the long escalators connecting between two train lines, and I caught the person behind me surreptitously trying to unzip an outside pocket on my shoulder bag. He hadn't made much progress, but just to make sure he didn't get anything, I said hello and shook his hand.

    Bonus chatter: Getting targeted by thieves in Europe seems to be a tradition for me. During the Berlin phase of a previous visit to the continent, a thief tried unsuccessfully to steal the camera out of my hand. Sweden treats me well, though. I don't get targeted by pickpockets; just people trying to recruit me into some sort of organization.

    [Raymond is currently away, possibly being pickpocketed this very moment.]

  • The Old New Thing

    I saw a fascinating documentary about bugs

    • 7 Comments

    In the September 20, 2007 Dilbert comic, Dilbert says to his date, "I saw a fascinating documentary about bugs."

    A Year in the Life of Ants.

  • The Old New Thing

    When asked to choose among multiple options, the politician will pick all of them

    • 14 Comments

    During the run-up to a local election some time ago, the newspaper posed the same set of questions to each of the candidates and published the responses in a grid format so the readers could easily compare them.

    The candidates agreed on some issues, had opposing positions on others, but the question whose answers struck me was one of the form "If budget cuts forced you to eliminate one of the following four programs, which would you cut?"

    • Candidate 1: "I have no intention of letting our budget get into a situation in which this would become an issue. All of these programs are very important to our community, and under my leadership, they will continue to be funded."
    • Candidate 2: "I don't believe we need to eliminate any of these popular programs. If we review our financial situation, we will find that we can continue to provide for all of them."
    • Candidate 3: "Much as I personally enjoy Program X, it ranks as a lower priority to me than the other options. Program X was originally a community-run program, and I would encourage residents and the business community to step forward and keep alive this program which has greatly benefited our community over the years."

    Notice that the first two candidates, when asked to make a tough decision, opted to make no decision at all. (Compare another election in which the mainstream candidates rated everything as high priority.) The first candidate said, "This would never happen." The second candidate said, "It's not happening." The third candidate is the only one who sat down and made the call to cut one of the programs. The first two were playing politics, afraid to make a decision for fear that it would alienate some portion of the electorate. The third understood the situation and made the hard decision.

    I voted for the third candidate.

    Today is Election Day in the United States. Don't forget to vote. (Void where prohibited.)

  • The Old New Thing

    What is the proper handling of WM_RENDERFORMAT and WM_RENDERALLFORMATS?

    • 4 Comments

    Jeremy points out that the documentation for Set­Clipboard­Data says that the clipboard owner must not call Open­Clipboard when responding to the WM_RENDER­FORMAT and WM_RENDER­ALL­FORMATS messages. On the other hand, the documentation for WM_RENDER­ALL­FORMATS says that the owner must call Open­Clipboard and Empty­Clipboard. Which is it?

    It's none of them!

    Let's start with WM_RENDER­FORMAT. The reference implementation for a WM_RENDER­FORMAT handler goes like this, with all error handling deleted for expository purposes:

    case WM_RENDERFORMAT:
     CLIPFORMAT cf = (CLIPFORMAT)wParam;
     hData = GenerateFormat(cf);
     SetClipboardData(cf, hData);
     return 0;
    

    In response to WM_RENDER­FORMAT, you simply place the format on the clipboard. No opening is required. In fact, attempting to open will fail because the clipboard is already open: It has been opened by the application whose call to Get­Clipboard­Data triggered the delay-render!

    Next comes WM_RENDER­ALL­FORMATS. The original reference implementation goes like this, again with error checking deleted:

    // code in italics is wrong -- see discussion below
    case WM_RENDERALLFORMATS:
     OpenClipboard(hwnd);
     SendMessage(hwnd, WM_RENDERFORMAT, CF_FORMAT1, 0);
     SendMessage(hwnd, WM_RENDERFORMAT, CF_FORMAT2, 0);
     CloseClipboard();
     return 0;
    

    In response to WM_RENDER­ALL­FORMATS, you open the clipboard, then render all your formats into it, and then close the clipboard. And one to render your formats is simply to send yourself a fake WM_RENDER­FORMAT message, which gets the code in the earlier code block to generate the format and place it on the clipboard.

    So you see that everybody is wrong!

    The WM_RENDER­ALL­FORMATS handler does call Open­Clipboard—if you tried it without the Open­Clipboard call, you'd notice that the data never made it to the clipboard—and it doesn't call Empty­Clipboard. (If you did, you'd notice that the Empty­Clipboard would have wiped out your non-delay-rendered data!)

    Where did I get these reference implementations from? I got them from the Windows 3.1 SDK. (And that explains the bug; read on.)

    In real life, you probably would also listen for the WM_DESTROY­CLIPBOARD message so you would know that you are no longer the clipboard owner, in which case you wouldn't bother rendering anything.

    I haven't written code in a while, so let's write some code. Start with our scratch program and make these changes. We'll start by writing it incorrectly:

    BOOL
    OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
    {
     if (OpenClipboard(hwnd)) {
      EmptyClipboard();
      SetClipboardData(CF_UNICODETEXT, NULL);
      CloseClipboard();
     }
     return TRUE;
    }
    
    
    const WCHAR c_szText[] = L"hello";
    
    HANDLE
    OnRenderFormat(HWND hwnd, UINT fmt)
    {
     if (fmt == CF_UNICODETEXT)
     {
      HGLOBAL hglob;
      if (SUCCEEDED(CreateHGlobalFromBlob(
                                c_szText, sizeof(c_szText),
                                GMEM_MOVEABLE, &hglob))) {
       if (!SetClipboardData(fmt, hglob)) GlobalFree(hglob);
      }
     }
     return 0;
    }
    
    void
    OnRenderAllFormats(HWND hwnd)
    {
     if (OpenClipboard(hwnd)) {
      OnRenderFormat(hwnd, CF_UNICODETEXT);
      CloseClipboard();
     }
    }
    
        HANDLE_MSG(hwnd, WM_RENDERFORMAT, OnRenderFormat);
        HANDLE_MSG(hwnd, WM_RENDERALLFORMATS, OnRenderAllFormats);
    

    This program puts delay-rendered text on the clipboard when it starts up, When the request for text arrives, we just return the word hello. If we are asked to render all our formats, we render all our formats by calling our internal function once for each format we support. (All one of them.)

    There's a tiny race condition in that implementation above, though. What if somebody takes ownership of the clipboard while you're trying to render all your formats? Let's force the race condition. Set a breakpoint on the On­Render­All­Formats function, run the program, and close the window. The breakpoint will hit.

    Switch away from the debugger and open Notepad. Type 123 into Notepad, then select it and type Ctrl+C to copy it to the clipboard.

    Notepad will hang for a while, since the window manager is trying to send a WM_DESTROY­CLIPBOARD message to tell the previous clipboard owner that it is no longer responsible for the data on the clipboard. Let the call time out, at which point Notepad will wake back up and put 123 text on the clipboard. Now resume execution of the scratch program, so that it puts the Unicode word hello onto the clipboard.

    Okay, go back to Notepad and hit Ctrl+V. Look, it pasted hello instead of 123. Oops, our delay-rendering program destroyed the clipboard as it exited. If the application had put something more complicated on the clipboard, then our scratch program would have created a mishmash of old and new data.

    To protect against this race condition, make the following small change:

    void
    OnRenderAllFormats(HWND hwnd)
    {
     if (OpenClipboard(hwnd)) {
      if (GetClipboardOwner() == hwnd) {
        OnRenderFormat(hwnd, CF_UNICODETEXT);
      }
      CloseClipboard();
     }
    }
    

    After opening the clipboard, we check if we are still the window responsible for the clipboard contents. Only if so do we render our delay-rendered formats.

    Exercise: Why is the Get­Clipboard­Owner test done after the Open­Clipboard? Wouldn't it be better to bail out quickly if we are not the clipboard owner and avoid opening the clipboard in the first place?

  • The Old New Thing

    What states are possible in a DRAWITEMSTRUCT structure?

    • 24 Comments

    The DRAW­ITEM­STRUCT structure has an item­State member which contains a number of bits describing the state of the item being drawn. How do those states map to the underlying control?

    Most of the states are rather obvious. For a list box item to be selected, it means that the item is part of the selection. But what does selected mean for a button?

    Since people like tables, I'll put the answer in a table:

    Menu Listbox Combobox Button
    CtlType ODT_MENU ODT_LISTBOX ODT_COMBOBOX ODT_BUTTON
    itemID menu item ID item index or −1 item index or −1
    ODS_SELECTED Selected Selected Selected Pushed
    ODS_GRAYED Grayed
    ODS_DISABLED Disabled Disabled Disabled Disabled
    ODS_CHECKED Checked
    ODS_FOCUS Focus Focus Focus
    ODS_DEFAULT Default menu item
    ODS_HOTLIGHT Hover
    ODS_INACTIVE Inactive
    ODS_NOACCEL HideAccel HideAccel HideAccel HideAccel
    ODS_NOFOCUSRECT HideFocus HideFocus HideFocus
    ODS_COMBOBOXEDIT Is edit control
    Static Header Tab Listview Status
    CtlType ODT_STATIC ODT_HEADER ODT_TAB ODT_LISTVIEW
    itemID item index item index item index part index
    ODS_SELECTED Pushed Selected Selected
    ODS_GRAYED
    ODS_DISABLED Oops
    ODS_CHECKED AutoChecked
    ODS_FOCUS Focus
    ODS_DEFAULT
    ODS_HOTLIGHT Hover
    ODS_INACTIVE
    ODS_NOACCEL HideAccel
    ODS_NOFOCUSRECT
    ODS_COMBOBOXEDIT

    Okay, now that it's all in a table, how do I read the table?

    A box is blank if the corresponding flag is not currently used by the control type. (No guarantees about the future.) For example, as of this writing, button controls do not set an itemID, nor do they ever ask for ODS_GRAYED.

    You may have noticed that the box for CtlType is blank for status controls. That's an oops. The status bar control forgot to set the CtlType when it sends the WM_DRAW­ITEM message, so the value is uninitialized garbage. The way to detect a status bar control is to check the window handle. (This works in general. You can always detect a control by checking the window handle.)

    For list boxes and combo boxes, the itemID can have the special value -1 to mean "I am drawing a list box/combo box where no item is selected." For list boxes, this happens when the list box is empty. For combo boxes, this happens when the user types text into the edit box that does not match any of the items in the list portion of the combo box.

    Most of the other box entries are self-explanatory. For the most part, the flag name matches the conditions under which the corresponding flag is set. For example, the ODS_FOCUS flag is set when the list box item being drawn is the selected item.

    Note that the ODS_SELECTED flag is used for button and header controls to indicate that the control should be drawn in the pushed state. For example, the user may have put focus on a button control and pressed the space bar and not yet released it, or the application may have manually set the BST_PUSHED state. Header controls can get into a pushed state if you enable the HDS_BUTTONS style.

    List view controls set the ODS_CHECKED flag if a check box should be drawn over the item. This happens if the LVS_EX_AUTO­CHECK­SELECT extended style is specified and the item is selected. (Normally, the check box is drawn to the side as a state image.)

    The ODS_COMBO­BOX­EDIT flag is used only by combo box controls. It is set if the item being drawn is the edit portion of a combo box control. If not set, then the item being drawn is in the list box portion of the combo box control.

    Finally, there is a box marked Oops.

    The static control is supposed to set ODS_DISABLED if the static control is disabled. And that's what happens if you are using the classic static control. However, there is a typo in the the fancy themed static control, and it sets the ODS_DISBALED flag incorrectly. If you are owner-drawing a themed static control, and you want to draw differently depending on whether the control is disabled, then you should ignore the ODS_DISABLED flag and instead draw the disabled state based on the result of calling Is­Window­Enabled function.

    The bug in the themed static control cannot be fixed for compatibility reasons. I can pretty much guarantee that there is some application which doesn't draw correctly if the ODS_DISABLED flag is not set.

  • The Old New Thing

    Meta-content: Suggestion Box 4 will open sometime next year

    • 22 Comments

    Yesterday, I finished composing the last entry taken from an item in Suggestion Box 3. My prediction that the backlog would clear in early 2010 was off by exactly one year: The last Suggestion Box 3 entry is scheduled to be posted on January 3, 2011.

    I figure I'll open Suggestion Box 4 sometimes next year. But I'll leave it open for only a little while, to avoid the problem with Suggestion Box 3 where I left it open for so long that it took six years to clear out.

    (Then again, maybe I should stick to a six-year cycle for emptying the Suggestion Box. That would certainly discourage people from putting "Please help me with my problem" type entries into it. Unless they're willing to wait six years for a response...)

  • The Old New Thing

    The Essential Guide To Dim Sum

    • 4 Comments

    The folks over at BuzzFeed Food have put together this marvelous Essential Guide To Dim Sum. The field guide includes pictures of dim sum offerings, organized by food preparation style, then sub-categorized by physical appearance. Each dish is accompanied by its name in three languages (English, Mandarin Chinese, and Cantonese), along with symbolic information similar to a clothing care tag that encodes information like recommended method of eating.

    Save some radish cakes for me.

    Via Tony Chor.

  • The Old New Thing

    Raymond misreads newspaper headlines, episode 2

    • 13 Comments

    I have a strange tendency to misread newspaper headlines. This week, I read the headline Rogan Sets 200 Back World Record, and I thought, "There's a world record for running 200 meters backward?"

    Well, actually there is, but this article was actually about the 200 meter backstroke (swimming).

    Once I figured that out, I was not confused by the next headline: Lochte Sets 100 IM World Record.

  • The Old New Thing

    Why can't you use the space bar to select check box and radio button elements from a menu?

    • 17 Comments

    Nektar wants to know why you can't use the space bar to select check box and radio button elements from a menu.

    The short answer is "Because it's a menu, not a dialog box."

    The check mark and radio button are just visual adornments provided by the menu manager as a courtesy; they do not affect the behavior of the menu itself. Notice, for example, that there is no way to specify "radio button groups" in a menu, so the menu manager wouldn't know which items needed to be deselected when you select a radio button menu item. (I guess it could infer them from separators, but then you would have people saying "I want my radio button group to exclude item number 4, but I don't want to put a separator in between; that looks ugly.")

    And then how would a program reject an auto-selected check box or radio button? E.g., the user pushes the space bar to turn on Show the Widget Bar and an error occurs trying to show the Widget Bar. If the program displays an error dialog, that would dismiss the menu. So maybe the program would just silently re-uncheck the box, which leaves the user puzzled as to why the space bar "doesn't work" for turning on the Widget Bar. Or worse, what if hiding the Widget Bar causes the menu to reconfigure itself? (Maybe there are some menu items that are visible only when the Widget Bar is selected; if the user hides the Widget Bar, those menu items need to be deleted.) Windows doesn't have a precedent for menus reconfiguring themselves while they're being displayed. What if one of the items that gets deleted when you hide the Widget Bar is the menu item that contains the Widget Bar checkbox? ("I turned off the Widget Bar, and my menu disappeared!")

    That said, there is no technical reason these design issues couldn't be overcome. You could have a style like MF_GROUP that behaves like WS_GROUP to establish the scope of menu radio buttons; you could have some way to mark a menu item as "this is an unselected check box" or "this is an unselected radio button"; you could come up with a way for a program to reject a user's attempt to change the check box status; you could design a way for menus to be dynamically reconfigured while they are open; you could even design a way for menus to respond in some vaguely reasonable way when the item the user just selected gets dynamically deleted! But all of these features take effort, and they detract from the simple design of a menu as "Here's a list of things you can do. Pick one. Once you pick one, the menu dismisses." Every feature starts out with minus 100 points and needs to beat out the other 200 items on the list.

  • The Old New Thing

    Viral video: Pianotrappan

    • 12 Comments

    Yes, it's an advertisement for Volkswagen, but still, it's a fun video, and it features Scarlatti's keyboard sonata in C (K159) as a bonus.

    Even the old guy who shuffles along slowly at 1:23 tries the stairs.

    Double bonus: You can watch the original Swedish version.

Page 388 of 444 (4,432 items) «386387388389390»