Holy cow, I wrote a book!
messed up her leg
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.
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
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
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.
Flee the country.
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."
fleeing from house arrest while awaiting an extradition hearing
certainly doesn't help either.
running a stock scam.
(Prefatory remark: The following information is
of the "behind the scenes" nature and does not constitute
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.
"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.
This past weekend, a group of us went on one last training ride
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..."
Except when I passed one pair of walkers,
I heard one of them say
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.
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
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
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
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 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,
buy old parking meters for $10–$15
(listed under "Miscellaneous").
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?
"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
What happens if you build a wooden horse,
put some soldiers inside it,
ask security guards if you can leave it overnight inside their complex?
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.
lpDistanceToMoveHigh == NULL
lpDistanceToMoveHigh != NULL
retVal != INVALID_SET_FILE_POINTER
retVal != INVALID_SET_FILE_POINTER ||
GetLastError() == ERROR_SUCCESS
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
lpDistancetoMoveHigh == NULL
lpDistancetoMoveHigh != NULL
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
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
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
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
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
Only if the previous function call failed is the value of
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
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,
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.
What's the deal with the GetFileSize function?