• The Old New Thing

    Why is there a special PostQuitMessage function?

    • 12 Comments

    Why is there a special PostQuitMessage function? Because it's not really a posted message.

    Commenter A. Skrobov asked, "What's the difference between PostQuitMessage and PostThreadMessage(GetCurrentThreadId, WM_QUIT)?"

    They are not equivalent, though they may look that way at first glance. The differences are subtle but significant.

    Like the WM_PAINT, WM_MOUSEMOVE, and WM_TIMER messages, the WM_QUIT message is not a "real" posted message. Rather, it is one of those messages that the system generates as if it were posted, even though it wasn't. And like the other messages, the WM_QUIT message is a "low priority" message, generated only when the message queue is otherwise empty.

    When a thread calls PostQuitMessage, a flag in the queue state is set that says, "If somebody asks for a message and there are no posted messages, then manufacture a WM_QUIT message." This is just like the other "virtually posted" messages. WM_PAINT messages are generated on demand if there are any invalid regions, WM_MOUSEMOVE messages are generated on demand if the mouse has moved since the last time you checked, and WM_TIMER messages are generated on demand if there are any due timers. And since the message is "virtually posted", multiple calls coalesce, in the same way that multiple paint messages, multiple mouse motions, and multiple timer messages also coalesce.

    Why is WM_QUIT handled like a low-priority message?

    Because the system tries not to inject a WM_QUIT message at a "bad time"; instead it waits for things to "settle down" before generating the WM_QUIT message, thereby reducing the chances that the program might be in the middle of a multi-step procedure triggered by a sequence of posted messages.

    If you PeekMessage(..., PM_NOREMOVE) a WM_QUIT message, this returns a WM_QUIT message but does not clear the flag. The WM_QUIT message virtually "stays in the queue".

    As another special behavior, the generated WM_QUIT message bypasses the message filters passed to the GetMessage and PeekMessage functions. If the internal "quit message pending" flag is set, then you will get a WM_QUIT message once the queue goes quiet, regardless of what filter you pass.

    By comparison, PostThreadMessage just places the message in the thread queue (for real, not virtually), and therefore it does not get any of the special treatment that a real PostQuitMessage triggers.

  • The Old New Thing

    Look what the hurricanes blew into Lafayette, LA

    • 3 Comments

    NPR reports that the influx of people into Lafayette has resulted in the city experiencing in one week the growth it had projected for fifteen to twenty years. It has also revived the singles scene. "Some young women say they're finding people to date for the first time in years."

  • The Old New Thing

    To be a leader you must know when to follow

    • 17 Comments

    Many people misinterpreted my use of the term "reluctant" to describe the attitude of the designers in changing the way the Date/Time control panel functions. It was a reluctance of shame, not a reluctance of defiance.

    Your software is there for the users, not vice versa. If you find that your users are using the software in a manner contrary to its intended purpose, your first reaction may be to try to educate users not to do whatever it is they're doing. But eventually you reach a point where the efforts in convincing people not to do something dangerous outweighs the cost of just making it less dangerous. (Even though this may annoy those who genuinely want to perform that dangerous activity.)

    You may not do it with a smile on your face (hence the reluctance), but you know deep in your heart that it's the right thing to do.

    Side note: Why did the Date/Time control panel apply changes immediately anyway? Historical artifact. That's the way the Date/Time control panel has worked since Windows 1.0. In fact, originally, the Date/Time control panel didn't even have a Cancel button. Any changes you made to the time took effect immediately and irrevocably. (Mind you, MS-DOS and the original Macintosh did the same thing.) It wasn't until after Windows 95 shipped that this behavior started being a problem.

  • The Old New Thing

    Blog design as a form of reality programming

    • 12 Comments

    On one of our internal blogging aliases, some people were interested in ways of making their blog look spiffier, and the Max team's blog was pointed out as an example of a "pimped out blog". This in turn led to exchange of tips and tricks and someone even proposed an informal Pimp My Blog contest. What next? Extreme Blog Makeover? Trading MSN Spaces?

  • The Old New Thing

    Found blog: The Piehole

    • 8 Comments

    I have no idea who this person is, but she's all attitude all the time. Like this entry from October 18, 2005 when Jennifer was recovering from a foot injury:

    Men love a girl who can't run away quickly

    I got "wooey!"-ed by a garbage man on my way back to the office from lunch today... Because I'm so HAWT hobbling down the street. He could not resist my hobbling! I am hobbleicious! Sssssssss! *

    And just so you know, being followed down the street by a garbage truck with someone screaming "YEAH BABY!" and "what's your phone number?" is TOTALLY CLASSY!

    * This is the sound of me sizzling!

    It's the asterisk that's the icing on the cake.

    From that web site's blogroll you can springboard to a whole new world of outrageous content. Like My Boyfriend is a Twat or Inappropriately Dressed.

  • The Old New Thing

    Why is inline autocomplete disabled by default?

    • 33 Comments

    Earlier versions of Internet Explorer used inline autocomplete, but newer versions use drop-down autocomplete that requires you to press the down-arrow key to select an item from the drop-down. Why the change?

    Because it interferes with normal keyboard operation.

    Suppose http://www.microsoft.com/windows/ is in your history, but you want to go to http://www.microsoft.com/. As you type the desired destination, inline autocomplete kicks in and fills in the remainder of the URL for you, http://www.microsoft.com/windows/. If you aren't watching the screen and just hit Enter, you end up going to the autocompleted URL instead of the URL you typed. Oops.

    To me, this is a fatal flaw, namely that one has to be watching the screen to perform an operation that one would think consisted purely of typing. In particular, this creates problems for people with limited visual capability who necessarily "type blind" most of the time.

    Even using Tab as the autocomplete character suffers from the same flaw. Consider the Run dialog or IE's address bar. In those places, the Tab key moves you around the window. (To the OK, Cancel, and Browse buttons on the Run dialog, or into the web page itself for IE.) If the Tab key were the autocomplete completion key, it wouldn't be possible to Tab around the dialog/window any more. For example, suppose you want to browse around your C drive, so you type C:\ into the Run dialog and hit Tab three times to get to the Browse button. But, oops, the Tab key autocompletes, so instead of browsing C:\, you're browsing whatever directory in your C: drive the autocomplete engine decided to show you.

  • The Old New Thing

    Bicycling from Mercer Island to Microsoft main campus

    • 8 Comments

    I asked four people who commute by bicycle eastbound over the I-90 bridge to Microsoft main campus what route they take, and they gave three different answers. I've given them meaningless names just to tell them apart.

    The yellow route

    First half (markers A1 through A5) | Second half (markers B1 through B5).
    Animated version: Click markers 1 through 5 in order then markers 1 through 5 in order.
    Pro: Avoids downtown Bellevue
    Con: You're stuck on Bel-Red

    • Get to the I-90 bridge eastbound.
    • After crossing the bridge, stay on the trail when it twists under I-90; do not get off into the neighborhood. You will be on a trail parallel to SE Lake Rd (marker A1).
    • You will reach a fork in the trail. Bear right and take the bridge.
    • Ride through the park until the trail ends, putting you on 118th Ave SE (marker A2).
    • Turn left (north). Bellevue Transportation Department recommends riding on west (left) side to reach bike path.
    • Turn right onto SE 8th St (marker A3) and go under I-405.
    • Cross Lake Hills Connector; the road name changes to SE 7th Pl.
    • Turn left onto 128th Ave SE (marker A4).
    • The road turns to trail after NE 7th St; turn right onto NE 8th St (marker A5 = marker B1).
      • Alternate route: Turn right onto Main St. and zig-zag through the neighborhood for a less hilly approach.
    • Turn left onto 132nd Ave NE or 134th Ave NE, depending on traffic (marker B2).
    • Turn right onto Bel-Red Road (marker B3).
    • Take Bel-Red Road to Microsoft main campus (markers B4 and B5).

    The blue route (two votes)

    First half (markers C1 through C5) | Second half (markers D1 through D5).
    Animated version: Click markers 1 through 5 in order then markers 1 through 5 in order.
    Pro: Avoids downtown Bellevue and Bel-Red
    Con: Extremely hazardous intersection at the end

    • Get to the I-90 bridge eastbound.
    • After crossing the bridge, stay on the trail when it twists under I-90; do not get off into the neighborhood. You will be on a trail parallel to SE Lake Rd (marker C1).
    • You will reach a fork in the trail. Bear right and take the bridge.
    • Ride through the park until the trail ends, putting you on 118th Ave SE (marker C2). Turn right (south).
    • Hazardous crossing - busy street, look both ways: Immediately after the underpass, turn left to get back on the I-90 trail (marker C3). Note: hill climb.
    • Cross Richards Road, ascend hill, turn left at 142nd Pl SE (marker C4).
    • Take the 142nd Pl bridge into Bellevue Community College and meander through the campus to 145th Pl SE (marker C5 = marker D1).
    • Turn right onto Lake Hills Blvd (marker D2).
    • Take Lake Hill Blvd across 148th, 156th, turning left onto 164th Ave SE (marker D3).
    • Follow 164th Ave SE until it ends at NE 30th St (marker D4).
    • Turn left and stop at Bel-Red Road (marker D5).
    • Extremely hazardous intersection. Cross Bel-Red, taking the back entrance to Microsoft main campus.

    You can avoid the hazardous intersection by taking a left onto NE 24th St. and turning right onto 156th Ave NE.

    The brown route

    First half (markers E1 through E5) | Second half (markers F1 through F5).
    Animated version: Click markers 1 through 5 in order then markers 1 through 5 in order.
    Pro: Overall low exposure to traffic
    Con: Tricky left turn in Factoria, extremely hazardous intersection at the end

    • Get to the I-90 bridge eastbound.
    • After crossing the bridge, stay on the trail when it twists under I-90; do not get off into the neighborhood. You will be on a trail parallel to SE Lake Rd (marker E1).
    • You will reach a fork in the trail. Bear right and take the bridge.
    • Ride through the park until the trail ends, putting you on 118th Ave SE (marker E2). Turn right (south).
    • Hazardous crossing - busy street, look both ways: Immediately after the underpass, turn left to get back on the I-90 trail (marker E3). Note: hill climb.
    • Turn left at Richards Road (marker E4).
    • Immediately after underpass, turn right onto Eastgate Way (marker E5 = marker F1). Note: hill climb.
    • Turn left at 161th Ave SE (marker F2).
    • When the road ends, turn right onto SE 24th St (marker F3).
    • Follow the road as it winds its way counter-clockwise around Phantom Lake; its name changes to 168th Ave SE and SE 16th St as it turns.
    • Turn right onto 164th Ave SE (marker F4).
    • Follow 164th Ave SE until it ends at NE 30th St (marker F5).
    • Turn left and stop at Bel-Red Road.
    • Extremely hazardous intersection. Cross Bel-Red, taking the back entrance to Microsoft main campus.

    As with the blue route, you can avoid the hazardous intersection by taking a left onto NE 24th St. and turning right onto 156th Ave NE.

    I haven't tried any of these routes myself since I live on the north side of town, and if I need to head to Mercer Island, I start from my house, not from work. Still, these are useful routes to know, so I'm recording them here for reference.

  • The Old New Thing

    Välkommen till Saerige?

    • 4 Comments

    Ballard is the Scandinavian neighborhood in Seattle, and they ordered some stone slabs for a new seating area in Bergen Place Park. What they didn't expect was that the Swedish stone would read S∀ERIGE. I mean, yeah, those Swedes do strange things with their A's, like put dots and circles over them, but I'm pretty sure they don't turn them upside-down and treat them as V's.

  • The Old New Thing

    The COM interface contract rules exist for a reason

    • 17 Comments

    Some people believe that the COM rules on interfaces are needlessly strict. But the rules are there for a reason.

    Suppose you ship some interface in version N of your product. It's an internal interface, not documented to outsiders. Therefore, you are free to change it any time you want without having to worry about breaking compatibility with any third-party plug-ins.

    But remember that if you change an interface, you need to generate a new Interface Identifier (IID). Because an interface identifier uniquely identifies the interface. (That's sort of implied by its name, after all.)

    And this rule applies even to internal interfaces.

    Suppose you decide to violate this rule and use the same IID to represent a slightly different interface in version N+1 of your program. Since this is an internal interface, you have no qualms about doing this.

    Until you have to write a patch that services both versions.

    Now your patch is in trouble. It can call IUnknown::QueryInterface and ask for that IID, and it will get something back. But you don't know whether this is the version N interface or the version N+1 interface. If you're not even aware that this has happened, your patch will probably just assume it has the version N+1 interface, and strange things happen when it is run on version N.

    Debugging this problem is not fun. Neither is fixing it. Your patch has to use some other cues to decide which interface it actually got back. If your program has been patched previously, you need to have the version numbers of every single patch so that you can determine which version of the interface you have.

    Note that this dependency can be hidden behind other interfaces. Consider:

    [
        uuid("ABC")
    ]
    interface IColorInfo
    {
        HRESULT GetBackgroundColor([out] COLORREF *pcr);
        ...
    };
    
    [
        uuid("XYZ")
    ]
    interface IGraphicImage
    {
        ...
        HRESULT GetColorInfo([out] IColorInfo **ppci);
    };
    

    Suppose you want to add a new method to the IColorInfo interface:

    [
        uuid("DEF")
    ]
    interface IColorInfo
    {
        HRESULT GetBackgroundColor([out] COLORREF *pcr);
        ...
        HRESULT AdjustColor(COLORREF clrOld,
                            COLORREF clrNew);
    };
    
    [
        uuid("XYZ")
    ]
    interface IGraphicImage
    {
        ...
        HRESULT GetColorInfo([out] IColorInfo **ppci);
    };
    

    You changed the interface, but you also changed the IID, so everything is just fine, right?

    No, it isn't.

    The IGraphicImage interface is dependent upon the IColorInfo interface. When you changed the IColorInfo interface, you implicitly changed the IGraphicImage::GetColorInfo method, since the returned interface is now the version N+1 IColorInfo interface.

    Consider a patch written with the version N+1 header files.

    void AdjustGraphicColorInfo(IGraphicImage* pgi,
                                COLORREF clrOld, COLORREF clrNew)
    {
     IColorInfo *pci;
     if (SUCCEEDED(pgi->GetColorCount(&pci)) {
      pci->AdjustColor(clrOld, clrNew);
      pci->Release();
     }
    }
    

    If run against version N, the call to IGraphicImage::GetColorCount will return a version N IColorInfo, and that version doesn't support the IColorInfo::AdjustColor method. But you're going to call it anyway. Result: Walking off the end of the version N vtable and calling into space.

    The quick solution is to change the IID for the IGraphicImage function to reflect the change on the IColorInfo interface on which it depends.

    [
        uuid("UVW")
    ]
    interface IGraphicImage
    {
        ...
        HRESULT GetColorInfo([out] IColorInfo **ppci);
    };
    

    A more robust fix would be to change the IGraphicImage::GetColorInfo method so that you pass the interface you want to receive.

    [
        uuid("RST")
    ]
    interface IGraphicImage
    {
        ...
        HRESULT GetColorInfo([in] REFIID riid,
                             [iid_is(riid), out] void** ppv);
    };
    

    This allows interfaces on which IGraphicImage depends to change without requiring a change to the IGraphicImage interface itself. Of course, the implementation needs to change to respond to the new value of IID_IColorInfo. But now the caller can feel safe in the knowledge that when it asks for an interface, it's actually getting it and not something else that coincidentally has the same name.

  • The Old New Thing

    Night of the Knitting Dead

    • 1 Comments

    Okay, wrong zombie movie, but I couldn't resist the pun. Knit zombies reenact Dawn of the Dead. Now playing on Flickr.

Page 362 of 457 (4,568 items) «360361362363364»