Holy cow, I wrote a book!
Whenever I write an article explaining that programs should avoid
doing X, I can confidently
a comment saying,
Microsoft Product Q does this!" as if
But they're saying "gotcha" to the wrong person.
Because, and I'm sure it's a shock to many people to read this,
I did not personally write every line of software Microsoft ever produced.
(And even if I did write it, I may have written it as a younger
developer, before I learned about said rule.
Because, and I'm sure this is also a shock to many people,
I was once a beginner, too.)
If you find a Microsoft product breaking a rule,
then go complain to that product team.
Complaining to me won't accomplish anything.
I don't have access to their source code, and even if I did,
don't have permission to go in and make changes to their code,
nor do I have the time to go in and learn how their product
works and figure out the right place to make the fix.
and I don't know if you all can handle three shocking revelations in
product teams do not send me every line of code for review.
Indeed, one of the reasons I write here about things programs
should or shouldn't do is because I myself will see a Microsoft
product breaking a rule!
By discussing the problem here rather than in an internal
mailing list, the information gets out to everybody.
And maybe, just maybe, the product team will read the entry and
say, "Oops, I think we do that."
Because (shocking revelation number four) not all Microsoft
programmers are seasoned experts in Win32 user-interface programming.
(Articles where I was consciously tapping my colleagues on the head
my discussion of CallMsgFilter,
the long and sad story of the Shell Folders key,
reminding you to pass unhandled messages to DefWindowProc.
In fact, for every "do/don't do this" article,
I'd say odds are good that
with enough searching, you can
find a Microsoft product that breaks the rule.
And when you do, complain to that product team.
difference between the tray and the notification area
was in part a response to all the other groups that perpetuate the
misuse of the terminology.)
So when I write something like,
"Applications shouldn't do this", go ahead and insert the phrase
"and this means all applications, including those published by Microsoft."
When I write, "some annoying programs", go ahead and
insert the phrase, "which might even include programs
published by Microsoft".
I'm not going to insert those phrases into every sentence I write.
I'm assuming you're smart enough to realize that general statements
apply to everyone regardless of who signs their paychecks.
Of course, if the consensus of my readership is that
I shouldn't tell you not to do things
until every last Microsoft product has been scoured to ensure that none
of them violate that rule either,
then I can abide by that decision.
I'll just stop posting those tips here and keep them on the internal
It's much less work for me.
In the discussions following
why Windows setup lays down a new boot sector,
some commenters suggested that Windows setup could detect
the presence of a non-Windows partition as a sign that
the machine onto which the operating system is being
installed belongs to a geek.
In that way, the typical consumer would be spared
from having to deal with
a confusing geeky dialog box that they
don't know how to answer.
The problem with this plan is that not everybody with
a non-Windows partition type is necessarily a geek.
Many OEM machines ship with a hard drive split
into two partitions,
one formatted for Windows and the second a
small non-Windows partition to be used during
system diagnostics and recovery.
The presence of this small non-Windows partition
is typically not well-known, and it comes into
play only when you boot from the manufacturer's
"system recovery CD".
The upshot of this is that if Windows setup took
the "anybody with a non-Windows partition must be a geek"
it would end up tagging an awful lot of people as geeks
who really aren't.
Now, you might say,
"Well, only geeks install the operating system anyway.
Normal people typically buy a computer with the operating system
The fact that they are running Windows setup proves that they're
a geek in the first place.
Therefore, Windows setup should be optimized for geeks."
Indeed, the premise of this argument—that only geeks
run Windows setup—is true, but only
once you've reached steady state.
In the months immediately following the release of a new
version of Windows,
everybody is installing the operating system,
geeks and non-geeks alike.
(There is also an influx of non-geek people installing Windows
Magazine reviewers are writing boatloads of articles
on the new operating system, and the initial setup experience
is the very first thing they notice about Windows.
It had better be smooth and painless.
Some people have inferred that I don't write about .NET because
I don't like it.
That's not true.
I use it myself.
The reason I don't write about .NET is because
I'm not an expert on it and there are
plenty of other .NET blogs out there,
written by people who are
Maoni Stephens, whose little finger
contains more knowledge about garbage collection
than most people have in their entire brain.)
No point adding to it with my non-expert view.
Indeed, when I hit upon an interesting .NET topic or puzzle,
I usually just forward it off to
Brad for him to put on his blog.
Because people looking for interesting .NET content go to Brad,
The fact that
Rico Mariani was able to
do a literal translation of the original C++ version into C# and blow
the socks off it is a testament to the power and performance of
It took me several days of painful optimization to catch up,
one optimization that introduced a bug,
and then Rico simply had to
do a little tweaking with one hand tied behind his back
to regain the lead.
I eventually won
but look at the cost of that victory.
(I'm told there's one company that has decided against using managed
code because "If Raymond doesn't even want to mention the .NET Framework
then why should we bother to look at it?"
What a strange argument.
I don't mention IPsec;
does that mean you shouldn't use it either?)
But just to dispel the rumor (and to buck both my title and my tag line),
I'm going to declare this week to be .NET week.
All my technical articles this week will be about .NET.
Enjoy it while you can.
Several months ago,
The Washington Post reported that retail companies were no longer collecting
personal information as aggressively.
The poster child for this sort of thing was RadioShack,
which demanded your name and address even if you just stopped in
to buy a pack of AA batteries.
I didn't shop there often, and when I did, I merely refused to give
them any information about myself.
At the store near Microsoft main campus,
after going through this exercise,
the cashier eventually entered my name as "Cash"
and out came the receipt:
123 Main St
Redmond, WA 98052
Thank You, James Cash, for shopping at RadioShack
123 Main St
Redmond, WA 98052
Thank You, James Cash, for shopping at RadioShack
I enjoyed telling this story,
and to my surprise,
one day I got a piece of email from James Cash himself!
(As it turns out, one of my friends actually knew James Cash.)
The story is even
funnier: For years, my pet peeve was the way that RadioShack wanted my
address - and I refused to give it. There was quite a scene a couple of
times, with a salesclerk begging me to give it, and me refusing. Once or
twice I had to walk out of the store rather than give the info. However,
one time I had a roommate who also didn't want to give out his name and
address. His solution? To give my name and address!
So that is how my
name wound up at that RadioShack...
There appears to be some confusion over whether the maximum
size of the environment is 32K or 64K.
Which is it?
The limit is 32,767 Unicode characters,
which equals 65,534 bytes.
Call it 32K or 64K as you wish, but make sure you include the units
in your statement if it isn't clear from context.
While it may be true that
if you know Swedish, the world is funnier,
I have to admit that my knowledge of German only served to create
When I saw the headline that
the head of BetonSports was arrested,
I thought to myself,
"Who the heck would have a web site devoted to sports in concrete?"
the German word
Beton means "concrete" (the construction material)
and the German word
Sport means the same as in English.
It took me a few moments to realize that the company's
name is "Bet on Sports".
The designers of 32-bit Windows didn't have to worry quite so much
about squeezing everything into 256KB of memory.
Since modules in Win32 are based on demand-paging,
all you have to do is map the entire image into memory and then
run around accessing the parts you need.
There is no distinction between resident and non-resident names;
the names of exported functions are just stored in the image,
with a pointer (well, a relative virtual address) to the name
stored in the export table.
the 16-bit ordinal export table,
the 32-bit ordinal export table is not sparse.
If your DLL exports two functions, one as ordinal 10 and one as ordinal 1000,
you will have a 991-entry table that consists of two actual function pointers
and a lot of zeros.
Thus, you should try not to have large gaps in your ordinal exports,
or you will be wasting space in your DLL's export table.
As I noted above, there is only one exported names table,
so you don't have to distinguish between resident and non-resident names.
The exported names table functions in the same manner as the exported
names table in 16-bit Windows, mapping names to ordinals.
Unlike the 16-bit named export tables, where order is irrelevant,
the exported names table in 32-bit Windows is kept sorted so that
a more efficient binary search can be used to locate functions.
As with 16-bit Windows, every named function is assigned an ordinal.
If the programmer didn't assign one in the module definition file,
the linker will make one up for you, and as with 16-bit Windows,
the value the linker makes up can vary from build to build.
However, there is a major difference between the two models:
Recall that named exports in 16-bit Windows were discouraged (on
efficiency grounds), and as a result, every exported function was
explicitly assigned an ordinal, which was the preferred way of
linking to the function.
On the other hand, named exports in 32-bit Windows are the norm,
with no explicit ordinal assignment.
This means that the ordinal for a named export is not fixed.
For example, let's look at the ordinal that got assigned to the
kernel32 function LocalAlloc in the early years:
Now, some people are in the habit of reverse-engineering
import libraries, probably because they can't be bothered to download
the Platform SDK and get the real import libraries.
The problem with generating the import library manually is
that you can't tell whether the ordinal that was assigned to,
say, the LoadLibrary function was assigned by the
module definition file (and therefore will not change from build to build)
or was just auto-generated by the linker (in which case the ordinal
The import library generation tools could just play it safe and
use the named export, since that will work in both cases,
but for some reason,
they use the ordinal
(This is probably a leftover from 16-bit Windows,
where ordinals were preferred over names, as we saw earlier.)
This unfortunate choice on the part of the import library generation tools
to live dangerously has created compatibility
problems for the DirectX team.
(I don't know why DirectX got hit by this harder than other teams.
Perhaps because game developers don't have the time to learn the
fine details of Win32; they just want to write their game.)
Since they used one of these tools, they ended up linking to
DirectX functions like DirectDrawCreate by ordinal
rather than by name, and then when the next version of DirectX came
out and the name was assigned a different ordinal by the linker,
their programs crashed pretty badly.
The DirectX team had to go back to the old DLLs, write down all the
ordinals that the linker randomly assigned, and explicitly assign
those ordinals in the module definition files so they wouldn't
move around in the future.
There are other reasons why you cannot generate an import library
from a DLL; I'll pick up those topics later when I talk about
import libraries in more detail.
Next time, forwarders.
Murphy's Law vindicated again.
The Seattle Monorail has two trains, and last year
they managed to collide.
To get this to happen was particularly tricky, since the trains
run on separate tracks, and there is only one spot on the entire
line where a collision could occur—and they found it.
You can read about it in
this Associated Press article that describes the monorail as
a "mile-high, 43-year-old elevated line".
Wow, a mile high.
Those must've been really long ladders to get people down.
It was supposed to resume operation a few weeks ago, but
the reopening was delayed due to a glitch in the emergency-braking system.
We can't get anything right around here.
While it's true that I often ride the bus and often ride my
bicycle, I do not often ride my bicycle onto a bus.
This means that I forget how it's done and have to refresh
uses the same bike rack design as we do here in
Metro King County,
so I can refer to
their detailed pictures
which leave a bit to be desired.
It's not that hard, really.
There are instructions on the rack itself for most of the steps.
You squeeze the handle where it says "pull here",
lower the rack,
place the front tire where it says "front tire",
the back tire where it says "back tire", and put the
support arm into place.
Two details are omitted from the instruction on the rack:
First, if you're the first bicycle on the rack,
use the slot furthest away from the bus.
And second, how do you use that support arm?
I'm always baffled by the support arm.
It won't fit over the tire!
Oh, wait, because it's on a spring.
You have to pull outwards in order extend the clamp.
Then it will fit over your tire, and then you let it retract
and hold the tire in place.
on how to prepare your bicycle and the protocol to follow with
the bus driver.
One bus driver mentioned that the rack was designed by
"some guy in Bellevue, or maybe Kirkland".
Following up on this information led me to
bike rack trivia:
The racks are manufactured by
Sportworks in the nearby town of Woodinville.
Here's the Sportworks version of the story.
(And another Metro Transit tip:
If you want a series of options clustered around a particular
time, you can use the
commuter trip planner,
handy if you don't know exactly what time you will be returning.
There's also the
point to point schedule maker
if you want a custom bus schedule between two stops.
And no discussion of Metro Transit planning tools is complete
without a plug for
When I wrote that
the symbolic name for the imported function table entry for
a function is called __imp__FunctionName,
the statement was "true enough" for the discussion at hand,
but the reality is messier, and
the reason for the messy reality is function name decoration.
When a naive compiler generates a reference to a function,
the reference is
decorated in a manner consistent with its architecture, language,
and calling convention.
(Some time ago,
I discussed some of the decorations you'll see on x86 systems.)
For example, a naive call to the GetVersion function
results in the compiler generating code equivalent to
call _GetVersion@0 (on an x86 system; other architectures
The import library therefore must have an entry for the
symbol _GetVersion@0 in order for the external reference
to be resolved.
To correspond to the stub function whose real name is
_GetVersion@0 is the import table entry whose name
In general, the import table entry name is __imp_
prefixed to the decorated function name.
The fact that names in import libraries are decorated means
that it is doubly crucial that you use the official import library
for the DLL you wish to use rather than trying to manufacture
one with an import library generation tool.
As we noted earlier, the tool won't know whether the ordinal
assigned to a named function was by design or merely coincidental.
But what's more, the tool won't know what decorations to apply
to the function (if the name was exported under an undecorated name).
Consequently, your attempts to call the function
will fail to link since the decorations will most likely not match up.
In that parenthetical, I mentioned exporting under undecorated names.
Doesn't that mean that you can also export with a decorated name?
Yes you can, but as I described earlier,
you probably shouldn't.
For as I noted there, if you export a decorated name, then that
name cannot be located via GetProcAddress unless you
also pass the decorated name to GetProcAddress.
But the decoration schema changes from language to language,
from architecture to architecture, and even from compiler vendor
to compiler vendor,
so even if you manage to pass a decorated name to the
GetProcAddress function, you'll have to wrap it
inside a huge number of #ifdefs so you pass the
correct name for the x86 or ia64 or x64, accordingly,
as well as changing the name depending on whether you're using
the Microsoft C compiler, the Borland C compiler, the Watcom
C compiler, or maybe you're using one of the C++ compilers.
And woe unto you if you hope to call the function from Visual Basic
or C# or some other language that provides interop facilities.
Just export those names undecorated.
Your future customers will thank you.
(Exercise: Why is it okay for the C runtime DLLs to use