Holy cow, I wrote a book!
When I go to a baseball game, I try to remember to watch the
They move around in a counter-intuitive way:
They don't run toward the ball.
They don't run toward the runner.
Even when the ball is far away,
the umpire runs from what appears to be one irrelevant
position on the field to another equally irrelevant position.
Yet no matter what eventually happens,
there's always an umpire there to make the necessary call.
(As opposed to the players on the field, who sometimes
forget to cover third base.)
That's because the umpires aren't playing the game of baseball
as it happens on the field.
They're playing a different game altogether:
They are continuously positioning themselves to see what needs
to be seen right now (did the runner leave the bag too soon?)
as well as
anticipating what they will need to see
five seconds from now.
One of my colleagues is also a Little League umpire,
so I get to satisfy my curiosity about this
underappreciated profession at the lunch table.
I learned that a large part of the job is actually psychology,
convincing the players that your decisions should be accepted.
And that umpires are watching for things that players and fans
take for granted (like making sure the runner touches all the bases).
One thing that I found interesting is that the umpires don't know
what the score of the game is.
They are worried about strikes, balls, and outs.
The score is entirely irrelevant to the job of an umpire
until the game reaches the final inning,
when it becomes time to decide when the game is over.
And then if you're near the scorer's table, you may hear the
Umpire: "What's the score?"
Scorekeeper: "22 to 2."
Umpire: "And who's winning?"
One of the repeating principles I noticed in the rules of baseball
is that starting the next play implies acceptance of the results
of the previous play.
For example, pitching to the next batter removes your right to
claim that a runner failed to touch a base or left a base too soon,
or that the previous batter
batted out of turn.
Not only does it simplify the process for addressing a rule violation
(you never have to rewind more than one play),
it also reduces the amount of state the umpires needs to carry
in their heads.
Pine Tar Incident
combines many of these little tidbits about baseball rules and umpiring.
When the illegal bat was identified, only Brett's most recent at-bat
The results of earlier at-bats with the illegal bat remained valid.
When the game was resumed a month later,
the umpires were armed with statements from the previous umpires
confirming that Brett had touched all the bases.
They didn't have to include statements about prior events
in the game, because the fact that the game continued put those
decisions beyond appeal.
I was reminded of this topic when I ws alerted to the book
As They See 'Em: A Fan's Travels in the Land of Umpires.
NPR book review
contains an excerpt in which the author Bruce Weber
discusses the amount of detail involved in the
seemingly casual action of removing one's mask.
You can also
listen to an interview with the author
the March 28, 2009 edition of Only a Game
the March 20, 2009 edition of The Leonard Lopate Show.
I attended a little league game which my friend was working as an umpire
with the intent of watching the umpires rather than the game.
It takes some effort to not watch the ball as it sails into
The WIN32_LEAN_AND_MEAN symbol was introduced
in the Windows 95 time frame as a way to exclude
a bunch of Windows header files when you include
You can take a look at your windows.h file to
see which ones they are.
The symbol was added as part of the transition from
16-bit Windows to 32-bit Windows.
The 16-bit windows.h header file
didn't include all of those header files,
and defining WIN32_LEAN_AND_MEAN
brought you back to the 16-bit Windows philosophy of
a minimal set of header files for writing a bare-bones
This appeased the programmers who liked to micro-manage
their header files,
and it was a big help because, at the time the symbol
precompiled header files were not in common use.
As I recall, on a 50MHz 80486 with 8MB of memory,
switching to WIN32_LEAN_AND_MEAN shaved
three seconds off the compile time of each C file.
When your project consists of 20 C files,
that's a whole minute saved right there.
Moore's Law and precompiled headers have conspired to
render the WIN32_LEAN_AND_MEAN symbol relative useless.
It doesn't really save you much any more.
But at one point, it did.
Commenter Boris mentions that
he uses NJ Transit to get rid of his excess pennies.
But what do you do if your area isn't served by NJ Transit?
I use the self-checkout line at the grocery store.
The machine has a slot for accepting coins, and you can drop
pennies in there until your arm falls off.
I don't do this when the grocery store is crowded,
since this holds up the line.
(Yes, banks also have change-counting machines,
but using the machine is overkill
when you have only thirty pennies to get rid of.)
Knowledge Base article 139071 has the technically correct but easily
OLE Automation BSTR caching will cause memory leak sources in Windows 2000.
The title is misleading because it makes you think that
Oh, this is a fix for a memory leak in OLE Automation,
but that's not what it is.
The BSTR is the string type used by OLE Automation,
and since strings are used a lot,
OLE Automation maintains a cache of recently-freed strings
which it can re-use when somebody allocates a new one.
Caches are nice
(though you need to make sure
you have a good replacement policy),
but they confuse memory leak detection tools,
because the memory leak detection tool will not be able to match up
the allocator with the deallocator.
What the memory leak detection tool sees is not the
creation and freeing of strings but rather the allocation and
deallocation of memory.
And if there is a string cache (say, of just one entry, for simplicity),
what the memory leak detection tool sees is only a part of the real
Your program sees only the lines marked Program:,
and the memory leak detection tool sees only the underlined part.
As a result, the memory leak detection tool sees a warped view
of the program's string usage:
Notice that the memory leak detection tool thinks that line 6
freed the memory allocated by line 1,
even though the two lines of the program are unrelated.
Line 6 is freeing string 2, and line 1 is
creating string 1!
Notice also that the memory leak detection tool will report a memory
leak, because it sees that you allocated two memory blocks but
deallocated only one of them.
The memory leak detection tool will say,
"Memory allocated at line 4 is never freed."
And you stare at line 4 of your program and insist that
the memory leak detection tool is on crack because there, you freed
it right at the very next line!
You chalk this up as
"Stupid memory leak detection tool, it has all these useless false positives."
Suppose somebody deletes line 6 of your program,
thereby introducing a genuine memory leak.
Now the memory leak detection tool will report two leaks:
You already marked the second report as bogus during your last
round of investigation.
Now you look at the first report, and decide that it too is bogus;
I mean look, we free the string right there at line 2!
A memory leak is introduced, the memory leak detection tool finds it,
but you discard it as another bug in the memory leak detection tool.
When you're doing memory leak detection, it helps to disable your caches.
the high-level object creation and destruction performed in your program
maps more directly to the low-level memory allocation and deallocation
functions tracked by the memory leak detection tool.
In our example, if there were no cache, then every Create string
would map directly to an Allocate memory call,
and every Free string would map directly to a
Deallocate memory call.
What KB article 139071 is trying to say is
OLE Automation BSTR cache cannot be disabled in Windows 2000.
Windows XP already contains support for the OANOCACHE
environment variable, which disables the BSTR cache
you can investigate those BSTR leaks more effectively.
The hotfix adds support for OANOCACHE to Windows 2000.
Why do we have BSTR anyway?
Why not just use null-terminated strings everywhere?
The BSTR data type was introduced by Visual Basic.
They couldn't use null-terminated strings because Basic
permits nulls to be embedded in strings.
Whereas Win32 is based on the K&R C  way of doing things,
OLE automation is based on the Basic way of doing things.
My older niece visited me at work one day,
and I got her a carton of chocolate milk,
which she very much enjoyed.
Some days later, she told me,
"I want to go to your work."
"Why?" I asked.
"I want to take all your chocolate milk."
Missing from the story is that upon returning home after that first visit,
she told everybody about her awesome visit with her uncle,
and that he even got her a chocolate milk from the refrigerator.
"And the chocolate milk is free, you can just take it!"
Her uncle (not me, a different uncle) told her,
"Then you should go there with a knapsack and take all the chocolate milk."
That uncle is clearly a troublemaker.
I'll have to keep an eye on him.
This story is inspired by an actual customer problem.
The program LitWare.exe is used for TPS management,
and when you want to create a new TPS report,
you have to pick a
The program shows you the cover sheets that have been defined,
which it loads from the C:\TPS Cover Sheets directory.
C:\TPS Cover Sheets
The customer found that on one of the machines,
the cover sheets weren't showing up,
even though the standard system setup copies a sample
cover sheet into the C:\TPS Cover Sheets directory.
The error message they got was
Cannot load cover sheets. The directory name is invalid.
The customer did some troubleshooting and determined that
"The cover sheet directory is missing,
and we have a file instead."
Volume in drive C is INITECH
Volume Serial Number is BAAD-F00D
Directory of C:\
09/18/2006 02:43 PM 24 autoexec.bat
09/18/2006 02:43 PM 10 config.sys
03/18/2009 10:30 AM <DIR> Program Files
11/21/2008 01:04 PM 1,677 TPS Cover Sheets
02/20/2008 10:39 AM <DIR> Users
05/29/2009 02:23 PM <DIR> Windows
2 File(s) 1,711 bytes
3 Dir(s) 229,031,751,680 bytes free
One of my colleagues employed psychic powers to determine that
at the time the customer tried to install the sample cover sheet
on the machine,
the C:\TPS Cover Sheets directory did not yet exist,
and that the batch file they used to set up a new computer
just does a
copy \\server\TPSConfig\Sample.tps "C:\TPS Cover Sheets",
which results in a file being created with the name
C:\TPS Cover Sheets.
copy \\server\TPSConfig\Sample.tps "C:\TPS Cover Sheets"
The customer was surprised by this conclusion.
"I would think that copy will fail if the
C:\TPS Cover Sheets directory doesn't exist,
but this might be our problem.
We'll look into it."
(I guess this customer never used the copy command to copy a file
to a new name.)
If the destination of a copy command exists and is a
directory, then the source files are copied into that directory.
If the destination of a copy command does not exists
or if it exists and is a file,
then the destination is treated as a file name for the destination.
(If there is more than one source file, then they are concatenated
as if they were text files.)
The customer went back and checked the scripts,
and the line they used was almost exactly what my colleague
copy "\\INITECH\Defaults\Sample cover sheet.tps" "C:\TPS Cover Sheets" /Y
If the C:\TPS Cover Sheets directory hasn't been created
yet, then that would explain the behavior they're seeing:
The copy command sees that the destination doesn't exist
and assumes you are doing a file-to-file copy
(as opposed to a file-to-directory copy).
In this case, the problem was that copying a sample cover sheet was
a step they added to their setup scripts, but they added it before
the step that creates the cover sheet directory.
Reordering the two steps fixed the problem.
While enjoying a meal with my nieces (at the time, ages 3 and 5),
I diluted my chocolate milk to cut the sweetness.
The nieces then demanded that I dilute their chocolate milk as well,
because as far as they could determine,
it was a magical way to create more chocolate milk.
Win32 doesn't expose a process's command line to other processes.
From Win32's point of view, the command line is just a
initialized parameter to the process's startup code,
some data copied from the launching process to the new process
We'll get back to the Win32 point of view a little later.
If you look around in WMI, you'll find a
Win32_Process object, and lo and behold,
it has a CommandLine property.
Let's check it out,
standard WMI application:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objItem in colItems
I fully anticipate that half of my readers will stop right there.
"Thanks for the script. Bye!"
And they won't bother reading the analysis.
"Because analysis is boring,
and it'll just tell me stuff I don't want to hear.
The analysis is going to tell me why this won't work,
or why it's a bad idea,
and that just cramps my style."
Remember that from Win32's point of view,
the command line is
just a string that is copied into the address space of the new process.
How the launching process and the new process interpret this string
not by rules but by convention.
What's more, since the string is merely a "preinitialized variable",
a process could in principle (and many do in practice,
although usually inadvertently) write to the memory that holds the
command line, in which case, if you go snooping around for it,
you'll see the modified command line.
There is no secret hiding place where the kernel keeps
the "real original command line,"
any more than there is a secret hiding place where the C compiler
keeps the "real original parameters to a function."
This is just another manifestation of the principle of
not keeping track of information you don't need.
What does this mean for people who disregard this principle and
go after the command line of another process?
You have to understand what you are getting is non-authoritative
In fact, it's worse.
It's information the application itself may have changed
in order to try to fool you,
so don't use it to make important decisions.
My colleague who
dabbled in economics when deciding how many lunch vouchers to buy
had a number of other money-related quirks.
One of the ones that I remember is that when paying for a purchase,
my colleague would double the balance and give the cashier that much
For example, if the total was $5.20,
my colleague would hand over $10.40.
Just to see if the cashier reacted when pressing the Enter
code appeared to have no effect.
Total is $5.20.
Cash tendered is $10.40.
Change is $5.20.
Most of the time, the cashier wouldn't pay any attention.
Heck, the cashier wouldn't even question why my colleague handed
over such a strange amount of money.
Sometimes my colleague would mix it up and instead add $6.66 to the
For example, if the total was $5.20,
my colleague would hand over $11.86,
just to see the cashier's reaction when the cash register indicated
that the change due was $6.66.
And then one day, magic happened:
The total was $6.66.
Without skipping a beat, my colleague handed over $13.32.
Today we're going to take a little trip in the wayback machine
with the help of my colleague Seth Manheim, who was there when this happened.
Set the date to November 22, 1989, twenty years ago and one day.
Bill Gates is being taken on a guided tour
of the product support department's new office building,
and during his visit, he asks one of the
people manning the phones,
"Mind if I take this call?"
Bill puts on a headset, sits down, and answers the phone.
"Hello, this is Microsoft Product Support, William speaking.
How can I help you?"
Bill talks with the customer,
collects the details of the problem,
searches in the product support Knowledge Base,
sifts through the search results,
finds the solution,
and patiently walks the customer through fixing the problem.
The customer is thrilled that William was able to fix the problem
so quickly, and with such a pleasant attitude.
Bill wraps up the call.
"And thank you for using Microsoft products."
At no point did Bill identify himself as anything other than William.
The customer had no idea that the product support engineer
who took the call was none other than Bill Gates.
But the story doesn't end there.
Even though this story took place while most of the support staff
were on their lunch break,
news travels quickly, and soon everybody in the department
knows about The time Bill took a product support call.
Some time later, the same customer calls back
with a follow-up question.
— Hi, I called you folks with a problem with XYZ,
and I talked with a nice man named William who straightened it all out.
But I have another question. Can I speak with William?
"Okay, let me see if William is available."
The product support engineer brings up the customer's service record
and looks at the name of the support engineer
who handled the earlier call:
"Yeah, um, I'm sorry, but William is not available right now.
His friends call him Bill, by the way.
The person who helped you last time?
That was Bill Gates."
— Oh my God.
While I'm tinkering with the wayback machine,
I may as well point you to
a story from a few years ago with a similar (but less dramatic) punch line.