July, 2007

  • The Old New Thing

    Not my finest hour: Driving a manual transmission

    • 81 Comments

    Sara Ford messed up her leg last month; you can see her on ScooterCam-1 at TechEd 2007. The best part of the name ScooterCam-1 isn't the ScooterCam; it's the 1. That just gives it that extra little kitchy space technology feel that turns a good name into a great name.

    Anyway, she asked around if somebody with a car with an automatic transmission would be willing to swap with her manual transmission car until her leg got better. To me, driving a stick shift is like changing a flat tire: It's something that everybody should know how to do, but it's not something that anybody is expected to enjoy doing. I offered my car and (long boring part of story deleted) we met at her place and exchanged keys. I got into her car, backed out of the parking space, and... stalled right in front of her.

    Great job there. I really know how to instill confidence.

  • The Old New Thing

    How are window manager handles determined in Windows NT?

    • 29 Comments

    We left off our story last time by raising the problem of programs that send messages to windows that have already been destroyed and how window handle re-use exacerbates the problem. Although this is clearly a bug in the programs that use window handles after destroying the window, the problem is so widespread that the window manager folks in Windows NT decided to take a more proactive approach.

    (Reiterating in case you couldn't figure it out: This entry goes "behind the scenes". Behavior described here falls into the category of "implementation detail" and is subject to change at any time.)

    In Windows NT, the 32-bit HWND was broken into two parts. The bottom 16 bits acted like the window handle of Windows 95: It was an index into a table. But whereas Windows 95 left the upper 16 bits zero for compatibility with 16-bit programs, Windows NT used the top bits as a "uniquifier".

    For example, the first time entry 0x0124 in the table was used, the handle corresponding to that entry was 0x00010124. After that window is destroyed and a new one created in slot 0x0124, the handle for the new entry is 0x00020124. Each time the entry is re-used, the uniquifier increments by one.

    But what about those 16-bit programs?

    When a 16-bit program used a window handle, the window manager would just use that value as the index into the table. There was no uniquifier, so the window manager just ran with whatever was in that slot. After all, the uniquifier is wasn't essential to correct operation of the window manager; it was added merely to cover for buggy programs. Consequently, 16-bit programs were just as susceptible to the "handle re-use problem" as they were in Windows 3.1 and Windows 95. Only 32-bit programs got the extra protection.

    But since the window handle was an index, the full 16-bit range of window handles became available (minus special values like NULL), for a theoretical maximum of around 65,000 windows. Well, except that the actual theoretical maximum is is half that, around 32,700 windows. Why did we lose half of the window handles? Because there are programs out there that assume that window handles are always even numbers!

    Next time, we'll look at the magical 10,000 per-process handle limit.

  • The Old New Thing

    Creative armed robbery defense: Political asylum

    • 9 Comments

    Step 1: Rob bank.

    Step 2: Flee the country.

    Step 3: Claim political asylum because the robbery was a form of political protest.

    It's creative, I have to grant you that. The theory is that Canadian law prohibits extradition for political crimes. Though it's a strange defense to say "If I did it, it was politically motivated." Isn't the whole point of a political protest to openly admit to the crime and invite the authorities to arrest you? If you deny doing it, then it isn't much of a political statement, now, is it?

    I mean, you don't hear on the news, "A bomb exploded in ABC today. The radical group DEF said that if they were responsible, it was in retaliation for GHI."

    (For more background, you can read a "the story so far" story from the Seattle Times.) In March, the others accused of being involved in the heist pled guilty to armed robbery, which definitely weakens the "We did it as a form of political protest" argument.

    And fleeing from house arrest while awaiting an extradition hearing certainly doesn't help either.

    Neither does running a stock scam.

  • The Old New Thing

    How are window manager handles determined in 16-bit Windows and Windows 95?

    • 18 Comments

    (Prefatory remark: The following information is of the "behind the scenes" nature and does not constitute formal documentation. Actually, nothing I write counts as formal documentation, so I shouldn't have needed to write that, but people sometimes intentionally play stupid and interpret all forms of the future tense as if I were making some sort of "guarantee" on behalf of Microsoft Corporation. I assure you that I have no such authority! It's times like that that I'm tempted to just give up writing.)

    Let's start with 16-bit window handles. Those are simple: They are just pointers into the window manager's data segment, cast to the HWND data type. Since the window manager had a single 64KB data segment, all of these pointers were 16-bit values.

    In Windows 95, the window manager moved several categories of objects out of the default data segment into their own custom heaps. (And those were 32-bit heaps so they could be bigger than 64KB.) Window classes, menus, and windows each got their own "big" heap. There may have been other categories of objects that moved out of the default data segment, but those are the ones I remember.

    But since Windows 95 still had to support 16-bit programs, it needed a way to return 16-bit window handles back to those programs. To do this, the window manager allocated the memory in the 32-bit heap as "movable", which as we learned some time ago isn't actually movable. The purpose of allocating it as movable memory was to get that local memory handle, the HLOCAL.

    No, wait, but that doesn't actually solve the problem, because a local handle in a 32-bit heap is still a 32-bit value. How do we get a 16-bit value out of that?

    When the window manager created the 32-bit heap, it asked the 32-bit heap manager very nicely if it could give back 16-bit handles instead of 32-bit handles. The heap manager did this by pre-allocating a 64KB block of memory and allocating its handles out of that memory block, using the offset into the block as the handle.

    Since each entry in the handle table is four bytes (a 32-bit pointer), the 64KB handle table can hold up to 16384 entries. This is why the documentation for CreateWindowEx includes the following remark:

    Windows 95/98/Me: The system can support a maximum of 16,384 window handles.

    Actually, it was a little bit less than that because some of the entries were lost to bookkeeping overhead. For example, the handle value of zero could not be used because that would be confused with NULL.

    Now, you may have asked, "Well, if all the window handles are multiples of four, why not divide by four and then you can get the full range of 65535 window handles?"

    Well, remember that Windows 3.1 could handle only around 700 windows. Increasing this to 16,384 was enormous progress already. I mean, it's more than 23 times as much as what you had before. A hundred windows was already considered excessive at the time, so the window manager already could accommodate 163 abusive, badly-written programs. There's really no reason to bump that up to 655 badly-written programs. That'd just be encouraging programs to behave badly.

    Both the 16-bit Windows technique and the Windows 95 technique did suffer from the problem of handle re-use. When a window is destroyed, its memory is freed (as well as its handle on Windows 95). When a new window is created, there's a good chance that the memory or handle will get re-used, and consequently the numerical value of the window handle once again becomes valid, but refers to a different window.

    It so happens that boatloads of programs (and "boatloads" is a technical term) contain bugs where they use window handles after the window has been destroyed. When a window handle is re-used, that program sends a message to the window it thinks is still there, but instead it sends the message to a completely unrelated window. This doesn't bode well for the program, and it usually doesn't bode well for the new window that received the message by mistake either.

    Next time, we'll look at how the Windows NT folks addressed this problem of window handle re-use.

    Nitpicker's corner

    "Boatloads" is not a technical term. That was a joke.

    The initial version of this article accidentally omitted the word "not" from the opening sentence. Kudos to the people who were able to exercise their brain and figure this out from context instead of robotically taking everything at face value. There may be hope for the world yet.

  • The Old New Thing

    The dangers of conversation fragments: Overheard on the Burke-Gilman trail

    • 18 Comments

    This past weekend, a group of us went on one last training ride before the STP, which begins tomorrow. The Burke-Gilman is a multipurpose trail, with bicyclists sharing the path with walkers, joggers, inline skaters, sometimes even people on horseback. (Inline nitpicker's corner: The horseback riders are on the Sammamish River Trail, which is technically a different trail from the Burke-Gilman even though the two connect seamlessly.)

    As you cycle past a group, you can sometimes catch a few words of conversation. Usually, those words are not noteworthy at all. "...said to her..." or "...opened up..." or "...whenever the..."

    Except when I passed one pair of walkers, I heard one of them say "...concentration camp..."

    Traffic alert

    According to the Washington State Department of Transportation Construction Updates web site, "Crews will completely close SR 520 between Montlake Blvd. and 108th Avenue NE from 11 p.m. Friday to 5 a.m. Monday for the annual maintenance and inspection." Curiously, this isn't losted on the SR 520 Travel Alerts page.

  • The Old New Thing

    I was sort of interested at first, but now I'm not so sure any more

    • 26 Comments

    Some time ago, there was a product under development that was starting to get some buzz, so I thought I'd go check it out. I went to the product's Web site, but the product was so new that they didn't have any substantial information available. The only way to learn about the product was to download the documentation. And before they would let me do that, I had to register with my email address and some demographic information.

    I closed the window and never went back.

    Now, if the registration page had told me why they wanted this information, I might have offered it. Maybe because the product was still under development and they wanted to notify me of any significant changes. Maybe because they wanted to know what type of people were interested in their product. Maybe because they wanted to send me advertising about their other products. I'll never know, because the registration page didn't say.

    If you're going to ask for my email address and demographic information, you have to tell me what's in it for me. I was only sort of interested in your product in the first place, but asking for personal information quickly put me into the "I'm not interested any more" category.

    I'd also like to take this opportunity to highlight a new ground rule, one which I hoped people would figure out by watching the pattern but apparently needs to be made explicit: Do not identify companies, programs, and people. You may have noticed that as a general rule, I do not identify the programs or companies whose products I discuss in computer-related entries, because my purpose is not to mock and ridicule the computer industry but rather to highlight a problem. Here, we discuss problems and solutions, but we don't point and say "ha-ha, Company X is such a moron!" If you want to mock and ridicule, you can do it on your own Web site.

  • The Old New Thing

    Seattle street signs for sale, used, but for ten bucks you can't complain

    • 13 Comments

    The city of Seattle has begun a nine-year program of upgrading its street signs, and the city has decided to make the old signs available to the public for purchase. When you see the signs on your street replaced, you can go to the Buy a Sign page to buy the old one. It looks like signs in average condition are going for $10, whereas signs in below average condition go for $5.

    Unsold signs will be turned to scrap. Signs for famous streets such as Pike and Pine will be auctioned off on eBay.

    If street signs aren't your thing, you can buy old parking meters for $10–$15 (listed under "Miscellaneous").

  • The Old New Thing

    If you want a modeless dialog, then create a modeless dialog already

    • 29 Comments

    Somebody I'd never heard of sent me email with a general programming question. (This is one of the top ways of instantly making me not interested in talking to you.)

    I have a modal dialog box which I hide with ShowWindow(SW_HIDE), and I want to enable the parent window so the parent window will get focus and keyboard input. Is this possible? If so, how do I do it? MSDN says "Although a dialog box procedure could potentially enable the owner window at any time, enabling the owner defeats the purpose of the modal dialog box and is not recommended." How do I go about enabling the parent window?

    This is like asking for a cheeseburger and then trying to peel every last bit of cheese off the patty to turn it into a plain hamburger. Since the cheese has already melted into the crevices of the burger, you're going to be picking off tiny flecks of cheese for a long time. If you want a modeless dialog box, then just make a modeless dialog box. (This is what MSDN is trying to tell you in slightly more polite language.)

  • The Old New Thing

    Those who do not understand history are doomed to repeat it... on YouTube

    • 15 Comments

    What happens if you build a wooden horse, put some soldiers inside it, and then ask security guards if you can leave it overnight inside their complex?

  • The Old New Thing

    How to check for errors from SetFilePointer

    • 25 Comments

    The SetFilePointer function reports an error in two different ways, depending on whether you passed NULL as the lpDistanceToMoveHigh parameter. The documentation in MSDN is correct, but I've discovered that people prefer when I restate the same facts in a different way, so here comes the tabular version of the documentation.

    If lpDistanceToMoveHigh == NULL If lpDistanceToMoveHigh != NULL
    If success retVal != INVALID_SET_FILE_POINTER retVal != INVALID_SET_FILE_POINTER ||
    GetLastError() == ERROR_SUCCESS
    If failed retVal == INVALID_SET_FILE_POINTER retVal == INVALID_SET_FILE_POINTER &&
    GetLastError() != ERROR_SUCCESS

    I'd show some sample code, but the documentation in MSDN already contains sample code both for the lpDistancetoMoveHigh == NULL case as well as the lpDistancetoMoveHigh != NULL case.

    A common mistake is calling GetLastError even if the return value is not INVALID_SET_FILE_POINTER. In other words, people ignore the whole retVal == INVALID_SET_FILE_POINTER part of the "did the function succeed or fail?" test. Just because GetLastError() returned an error code doesn't mean that the SetFilePointer function failed. The return value must also have been INVALID_SET_FILE_POINTER. I will admit that the documentation in MSDN could be clearer on this point, but the sample code hopefully resolves any lingering ambiguity.

    But why does SetFilePointer use such a wacky way of reporting errors when lpDistanceToMoveHigh is non-NULL? The MSDN documentation also explains this detail: If the file size is greater than 4GB, then INVALID_SET_FILE_POINTER is a valid value for the low-order 32 bits of the file position. For example, if you moved the pointer to position 0x00000001`FFFFFFFF, then *lpDistanceToMoveHigh will be set to the high-order 32 bits of the result (1), and the return value is the low-order 32 bits of the result (0xFFFFFFFF, which happens to be the numerical value of INVALID_SET_FILE_POINTER). In that case (and only in that case) does the system need to use SetLastError(ERROR_SUCCESS) to tell you, "No, that value is perfectly fine. It's just a coincidence that it happens to be equal to INVALID_SET_FILE_POINTER".

    Why not call SetLastError(ERROR_SUCCESS) on all success paths, and not just the ones where the low-order 32 bits of the result happen to be 0xFFFFFFFF? That's just a general convention of Win32: If a function succeeds, it is not required to call SetLastError(ERROR_SUCESS). The success return value tells you that the function succeeded. The exception to this convention is if the return value is ambiguous, as we have here when the low-order 32 bits of the result happen to be 0xFFFFFFFF.

    You might argue that this was a stupid convention, But what's done is done and until time travel has been perfected, you just have to live with the past. (Mind you, UNIX uses the same convention with the errno variable. Only if the previous function call failed is the value of errno defined.)

    Looking back on it, the designers of SetFilePointer were being a bit too clever. They tried to merge 32-bit and 64-bit file management into a single function. "It's generic!" The problem with this is that you have to check for errors in two different ways depending on whether you were using the 32-bit variation or the 64-bit variation. Fortunately, the kernel folks realized that their cleverness backfired and they came up with a new function, SetFilePointerEx. That function produces a 64-bit value directly, and the return value is a simple BOOL, which makes checking for success or failure a snap.

    Exercise: What's the deal with the GetFileSize function?

Page 3 of 5 (43 items) 12345