Holy cow, I wrote a book!
This Web site is not for beginners.
I try to write for advanced programmers,
and if you're not an advanced programmer,
then you'll just have to accept that
there will be times you are baffled by what I write.
Often I dial the geek back a notch,
explaining some things which should be "obvious" to an advanced programmer,
such as why storing a constant pointer into a stack location from
dynamically-generated code is a clear indicator of a framework thunk.
But I will dial it back only so far,
and eventually you may just be forced to (horrors!)
do your own background research
to get yourself up to speed
or simply give up and see if you have better luck with the next entry.
There are some topics I have sitting in my ideas folder
which I will probably never actually post about because
they are so advanced that even
COM guru extraordinaire,
admitted in email to me that they're too advanced
his super-advanced book on COM.
At the PDC, talks used to be categorized as 100, 200, 300, or 400-level,
mimicking the categorization of classes at most U.S. universities,
with 100-level classes being introductory,
and 400-classes being college senior seminar type stuff.
COM weak QueryInterface would be somewhere at the graduate
Stuff so esoteric, nobody would actually need to know it.
To be honest, I don't think I've written anything truly advanced
in a long time.
It's all been fairly intermediate for the past few years.
People don't seem to mind too much, so I'll just keep it going.
One of my colleagues was overwhelmed by how many times
papers need to be signed when you buy a house.
A seemingly endless stack of papers.
Sign and date here, initial here, initial here,
now sign this, and this, and this, and sign and date here,
and sign here, and initial here...
By the time it's over, your arm is about to fall off.
Some years later, my colleague was about to buy a new house and
began to dread the signature-fest that would invariably ensue
at the closing.
Another ten-foot-tall stack of papers that needed to be
signed and initialed.
In preparation, my colleague actually did hand exercises
to build up stamina and strength.
I'm not sure what the exercises consisted of,
but they were probably a mix of strength-building wrist exercises and some
stints of extended longhand writing.
Finally closing day came.
My colleague walked into the agent's office,
sat down, and prepared for the worst,
only to be surprised when the stack of papers was only a dozen pages long.
What happened to the ten-foot-tall stack of papers that took hours to
sign and initial?
The difference is that my colleague paid cash for the new house
rather than taking out a loan.
That ten-foot-tall stack of papers?
Nearly all of them were related to the mortgage,
not to the actual sale of the house.
The paperwork associated with a house sale proper is comparatively light.
But all was not lost.
At least my colleague had pretty strong wrists now.
A thank-you to commenter
for pointing it out that the Seattle Symphony made changes
to their UBS Masterworks 13 series after the brochures were printed.
I compared my printed brochure against
the online one
the 2009/2010 Seattle Symphony subscription season at a glance
They deleted five concerts and added six, so the Masterworks 13 series
actually has 14 concerts.
They probably kept the name for backward compatibility.
Commenter c_e_pizano asks what the purpose of the HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\foo.exe\RunAsCommand registry value is.
Well, for starters, it isn't documented, so the official answer to that question is "Don't mess with it."
Kind of makes me wonder why you're asking about the registry value anyway, seeing as it's undocumented in the first place. Are you trying to reverse-engineer Windows?
To be honest, I don't know what its purpose is, but I do know what happens when you set it: Everything stops working.
This is one of those abandoned features like EM_SETHILITE. When it got abandoned, not all of the pieces got cleaned up, and there is still code that queries for the key, but the code path that gets executed when the query succeeds simply doesn't work (probably because some of the functionality it relied upon was deleted!) and consequently always returns an error. That's why, if you set the value, you get a weird error message.
The broken code was deleted in 2004, so Windows Vista doesn't even query for the value any more. It's now just a footnote to history.
Last week, I posed
a process shutdown puzzle
in honor of National Puzzle Day.
Let's see how we did.
Part One asked us to explain why
the ThreadFunction thread no longer exists.
One of the things that happen inside ExitProcess is
that all threads (other than the one calling ExitProcess)
are forcibly terminated in the nastiest way possible.
This happens before the DLL_PROCESS_DETACH notification
Therefore, the code in StopWorkerThread that waits for
the thread completion event waits forever because the
ThreadFunction is no longer running.
There is nobody around to
see the shutdown event and respond by setting the completion event.
Okay, that was the easy part.
Part Two asked us to criticize the replacement solution which
replaced the completion event with a call to
FreeLibraryAndExitThread and changed the
StopWorkerThread function to wait for the
thread handle to become signaled.
This solution is also flawed.
Consider the case that the DLL is receiving its
DLL_PROCESS_DETACH notification because the DLL is
being unloaded by
a call to FreeLibrary, rather than due to process
In that case, StopWorkerThread sets the shutdown
event, and the ThreadFunction proceeds to clean up
and call FreeLibraryAndExitThread.
But one of the steps in thread shutdown is sending
which will not happen until the DLL_PROCESS_DETACH
notifications are complete.
The WaitForSingleObject waits indefinitely
because it won't complete until the thread exits,
but the thread won't exit until StopWorkerThread returns.
Finally, Part Three asks us to explain why the code doesn't
cause a problem in practice even though the code is flawed.
The call to FreeLibraryAndExitThread implies that
the code follows the
"Worker thread retains its own reference on the DLL" model.
After all, that's why the last thing the thread does is
free the library.
But if that's the case, then a call to FreeLibrary
coming from the application won't actually unload the DLL,
because the DLL reference count is still nonzero:
There is one reference still being held by the worker thread.
the DLL will never actually unload outside of process termination.
All the flaws in the dynamic unload case are masked by the fact
that the code never executes.
Some of us mentioned that waiting on ThreadHandle
returned immediately because the handle to a thread is automatically
closed when the thread exits.
This is wrong.
Handles do not self-close.
You have to call CloseHandle to close them.
This is "obvious" if you apply the "imagine if the world
actually worked this way" rule:
Suppose thread handles were invalidated (and eligible for re-use)
when a thread exited.
Then how could you use a thread handle at all?
Any time you use a thread handle, there would be an unavoidable
race condition where the thread might have exited just before you
used the handle.
And it would be impossible to call
GetExitCodeThread at all!
(Since it only does anything interesting if you pass the handle
to a thread that has exited.)
A handle to a thread remains valid until you close it.
If the thread has exited, then a wait on the thread handle
completes, but the handle is still valid
because if it went invalid,
programming would become impossible.
Although you can tag your registry data with any of a variety
of types, such as REG_DWORD or
REG_BINARY or REG_EXPAND_SZ.
What do these mean, really?
Well, that depends on what you mean by mean,
specifically, who is doing the interpreting.
At the bottom, the data stored in the registry are opaque chunks of data.
The registry itself doesn't care if you lie and write two bytes
of data to something you tagged as REG_DWORD.
The type is just another user-defined piece of metadata.
The registry dutifully remembers the two bytes you stored, and when the next
person comes by asking for the data, those two bytes come out,
along with the type REG_DWORD.
Garbage in, garbage out.
The registry doesn't care that what you wrote doesn't many any sense
any more than the NTFS file system driver doesn't care
that you wrote an invalid XML document to the file config.xml.
Its job is just to remember
what you wrote and produce it later upon request.
There is one place where the registry does pay attention to the type,
and that's when you use one of the types that involve strings.
If you use the RegQueryValueA function to read data
which is tagged with one of the string types (such as REG_SZ),
then the registry code will read the raw data from its database,
and then call WideCharToMultiByte to convert
it to ANSI.
But that's the extent of its assistance.
Just as the registry doesn't care whether you really wrote four
bytes when you claimed to be writing a REG_DWORD,
is also doesn't care whether the various
string types actually are of the form they claim to be.
If you forget to include the null terminator in your byte count
when you write the data to the registry, then the null terminator
will not be stored to the registry, and the next person to read from
it will not read back a null terminator.
This simplicity in design pushes the responsibility onto the code
that uses the registry.
If you read a registry value and the data is tagged with the
then it's up to you to expand it if that's what you want to do.
The REG_EXPAND_SZ value is just part of the secret
handshake between the code that wrote the data and the code that is
a secret handshake which is well-understood by convention.
After all, if RegQueryValueEx automatically expanded
the value, then how could you read the original
Windows Vista added a new function
RegGetValue which tries to take care of most of the
cumbersome parts of reading registry values.
You can tell it what data types you are expecting (and it will fail
if the data is of an incompatible type),
and it coerces the data to match its putative type.
it auto-expands REG_EXPAND_SZ data, and
if a blob of registry data marked REG_SZ
is missing a null terminator,
RegGetValue will add one for you.
Better late than never.
I decided to begin searching for a replacement for
my current laptop computer
since it was by this point literally being held together with electrical tape,
and I decided to go against my more common computer replacement
policy of "Wait until it breaks, and then panic."
There was one model I had my eye on,
and it was on sale at a local big-box store as one of those
I didn't feel like waking up at 4am to stand in line for the
slim chance of actually snagging one, so I figured I would just
wait, and maybe it'll go on sale again after the shopping season.
(This is a strategy that isn't available when you use the
"Wait until it breaks, and then panic" model.)
A few weeks later, I happened to be in the shop for an unrelated
I naturally stopped by the laptop computer section and, as expected,
the model I had in mind was no longer on display.
It had presumably sold out.
On the other hand, on my way out the store, I saw that very model
sitting in the locked cage at the front of the store.
The locked cage
is one of those loss-prevention techniques, where high-value items
are not kept on the shelves.
Instead, only a token (such as claim ticket or an empty box)
is placed on the shelf,
and you bring the token to the customer service desk to exchange it
for the actual item.
If the laptop had sold out, why did they have one in the cage?
I asked an employee, who explained,
"Oh, yeah, we sold out of these almost immediately,
but a few days later, somebody returned one unopened,
so that's why we still have one unit up here."
Is it still for sale?
Not only was it still for sale, it was still for sale at the
There was a bit of confusion that followed, since they had to figure
out how to sell an item that was not on the shelves and for which
there was no token,
but everything got straightened out, and I walked out with my new laptop.
Hives, keys, values, types, and data.
As I noted some years ago,
the file that holds the registry data is called a hive.
A hive contains a tree of keys.
Keys contain a list of values.
Associated with each value is a type and
The terminology is weird and counter-intuitive
thanks to the history of the registry.
Back in the days before named values,
you queried the data associated with (the default value of)
a key by calling RegQueryValue,
which was a rather natural name since it matches the key/value pattern.
But the introduction of named values threw this pattern into
Perhaps a better name could have been chosen for what today are known
as values and data,
but what's done is done and that's the name we're stuck with.
"Raymond, you idiot" section:
"Sure, Raymond, that's the historical reason why the terminology is
messed up, but
why hasn't anybody fixed it in the meantime?"
Well, changing terminology at this point would probably create
even more confusion.
For example, suppose you decide that the terminology should be
changed as follows:
I agree with you that this terminology would probably be much
less confusing, but how do you get there from here?
When you update all the documentation to change the terminology,
how do you know that you covered everything?
Do you grep for the word key everywhere and then decide
on a case-by-case whether it should be changed to node?
That's probably some hundreds of thousands of hits just inside the
(Even worse with value, type, and data.)
And then there are all the comments in source code that are now wrong.
And all the magazine articles written prior to the change are now wrong;
who's going to go update them?
And the existing source code needs to change
HKEY to HNODE
and RegOpenKey to RegOpenNode.
Okay, so maybe you leave the old names around for compatibility,
but now you have the problem that
RegOpenKey returns a node, not a key,
and that you pass a key name to RegQueryValueEx,
and what the heck does RegDeleteKey do?
Does it delete an old-key or a new-key?
There's also this thing called a class.
I have no idea what it's for, so don't ask.
I put together a
little pocket guide to the
Seattle Symphony subscription season
for my symphony friends to help them decide which
ticket package they want.
As before, you might find it helpful, you might not, but either way,
you're going to have to suffer through it.
Here's the at-a-glance season guide for
Gerard Schwarz's 25th and
season as the orchestra's music director.
This chart doesn't include "one-off" concert series such
as the Visiting Orchestras or Distinguished Artists series.
The comments column very crudely categorizes the works
to assist my less-classically-aware friends.
This is, of course, a highly subjective rating system,
but I tried to view each piece from the ears of somebody new.
Thus, I rated downward pieces that I personally like
but which others might not and rated up pieces that I may not
find musically satisfying but which nevertheless tend to be
These predictions have, of course, proven wrong in the past.
my assessments of Bruckner have always been optimistic.
(And I haven't learned my lesson, because this year,
I'm rating the Bruckner Fourth Symphony as Good,
because this time I really think they will like it.)
Here's what the comments mean.
Note that they do not indicate whether the piece is significant in
a musicological sense; they're just my guess as to whether my friends
are going to like it.
In many cases, I am not familiar with the piece
and am basing my evaluation on what I know about the composer
(or am just guessing).
Seattle Symphony notes:
Principal Second Violin Elisa Barston had worked
under the shadow of heartthrob Joshua Roman,
Roman's departure last year,
she has inherited the mantle of taking the lead in
appealing to the "youth audience."
She's been given
increasingly visible solo performances
and even authored
an entry on the symphony's blog.
I for one am pleased by her more prominent profile.
She always seems to be
genuinely enjoying herself when I see her performing.
Update: Minor corrections as noted in comments.
* Update: Changes were made to the subscription schedule
for the UBS Masterworks 13 series after the brochures were printed.
for pointing it out.)
They have been updated in the chart above.
Note that five concerts were deleted but six were added,
so the Masterworks 13 concert series actually has 14 concerts.
§ Update: Many changes were made to the subscription schedule
in July 2009.
They have been updated in the chart above.
The concert for the week of October 30, 2009 has been cancelled;
ticket-holders will be given tickets for the concert on the week
of May 6, 2010.
I have only one citation, but the usage is so egregious to me
that one citation is all I need.
I'm looking for XYZ recommends.
My requirements are...
Why write recommendations
when you can shorten it to recommends
and sound buzzwordier at the same time!