Holy cow, I wrote a book!
As a follow-up to
the difference between My Documents and Application Data,
I'd like to rant about all the subdirectories of My Documents
that programs create because they think they're so cool.
I'm sure there are more.
Everything in the My Documents folder
the user should be able to point to and say,
"I remember creating that file on such-and-such date when I did a 'Save'
from Program Q."
If it doesn't pass that test, then don't put it into My Documents.
Use Application Data.
And don't create subdirectories off of My Documents.
If the user wants to organize their documents into subdirectories,
that's their business.
You just ask them where they want their documents and let it go at that.
(Yes, I'm not a fan of My Music, My Videos, and My Pictures, either.)
Omar Shahine points out that
Apple has similar guidelines for the Macintosh.
I wonder how well people follow them.
Back in 2003, I wrote that
I'm doing this instead of writing a book.
That was true then, but last year I decided to give this book thing
another go, only to find that publishers generally aren't interested
in this stuff any more.
"Does the world really need another book on Win32?
Nobody buys Win32 books any more, that dinosaur!"
"A conversational style book?
People want books with step-by-step how-to's and comprehensive treatments,
not water cooler anecdotes!"
"Just 200 pages?
There isn't enough of an audience for a book that small!"
Luckily, I found a sympathetic ear from the folks at
who were willing to take a chance on my unorthodox proposal.
But I caved on the length, bringing it up to 500 pages.
Actually, I came up with more like 700 pages of stuff,
and they cut it back to 500,
because 700 pages would take the book into the next price tier, and
"There isn't enough of an audience for a book that big!"
Eighteen months later, we have
The Old New Thing:
Practical Development Throughout the Evolution of Windows,
following in what appears to be the current fad of giving your
book a title of the form
Catchy Phrase: Longer Explanation of What the Catchy Phrase Means.
It's a selection of entries from this blog,
and with new material sprinkled in.
There are also new chapters that go in depth into parts of Win32
you use every day but may not fully understand
(the dialog manager, window messages), plus a chapter dedicated
(For some reason, the Table of Contents on the book web site is incomplete.)
Oh, and those 200 pages that got cut?
They'll be made available for download as "bonus chapters".
(The bonus chapters aren't up yet, so don't all rush over there
looking for them.)
The nominal release date for the book is January 2007,
which is roughly in agreement with the book web site
which proclaims availability on December 29th.
Just in time for Christmas your favorite geek,
if your favorite geek can't read a calendar.
Now I get to see
how many people were lying
when they said, "If you wrote a book based on this blog, I'd buy it."
The bonus chapters are now available.)
Now available in Japanese!
Now available in Chinese!
All the students at a local school
were asked to composed an in-class essay on the following topic:
"Your science teacher has invented a time machine.
You have been selected to take the first trip.
Explain in a multi-paragraph letter to your teacher
where you will go and why."
(Students were given two hours, plus one additional hour upon request.
In practice, many students were finished early and
almost nobody requested the third hour.)
(Aside: Sometimes I think my readers believe in time machines.
For example, one of them wondered
why OLE/COM uses HRESULTs instead of Win32 error codes.
Um, when OLE was invented, Win32 didn't exist.)
The students really enjoyed this topic.
Too much so, however,
for more than a few of them turned their essays into a narrative
rather than sticking to the assignment.
One student was so excited that the essay consisted of a single
Well, technically it was two paragraphs,
thereby meeting the letter (if not the spirit)
of the "multi-paragraph" requirement.
About halfway down page three was this sentence:
"The essay continues in the next paragraph."
Roughly two thirds of the students opted to go into the past;
one third chose to go into the future.
One student didn't travel in time at all (!),
choosing instead to visit Europe in the present day
"to see castles and ruins".
Psst, you've got a time machine.
Why not go and see the ruins before they are ruined?
(Actually, some friends pointed out to me that travelling to the present
day is still handy.
You can use your time machine as a teleporter.
And you can even set the time machine to zip you backward, say,
That way, when you travel from Seattle to Europe,
you arrive without any jet lag!)
Boys were more likely to want to travel back in time to get rich,
although their plans for doing so were not necessarily fully thought-out.
(Good luck getting anybody in the past to accept today's money.)
Girls were more likely to travel in time to meet themselves or
A few students confused a time machine with regressive therapy,
choosing to go back in time to re-live a cherished moment from
a year or two ago.
Psst, if you use a time machine to go into the past to visit
yourself on that awesome vacation to Hawaii,
you won't re-live the vacation.
You'll be watching the other copy of yourself enjoy the vacation.
assuming that the other copy of yourself doesn't see you and freak out.)
Several students wanted to change world history.
Many students wanted to go back in time to observe and experience
a historical period.
One student wanted to ask Jesus to teach him how to walk on water.
(Step one: Be the son of God.)
Coming up in Part 2,
selected sentences from student essays.
Where would you go if you could take one trip in a time machine?
"I bet somebody is looking to get a really nice bonus for that feature."
A customer was having trouble with one of their features that
scans for resources that their program can use,
and, well, the details aren't important.
What's important is that their feature ran in the Startup group,
and as soon as it found a suitable resource,
it displayed a balloon tip:
"Resource XYZ has been found.
Click here to add it to your resource portfolio."
We interrupted them right there.
— Why are you doing this?
"Oh, it's a great feature.
That way, when users run our program, they don't have to go
looking for the resources they want to operate with.
We already found the resources for them."
— But why are you doing it even when your program isn't running?
The user is busy editing a document or working on a spreadsheet
or playing a game.
The message you're displaying is out of context:
You're telling users about a program they aren't even using.
"Yeah, but this feature is really important to us.
It's crucial in order to remain competitive in our market."
— The message is not urgent.
It's a disruption.
Why don't you wait until
they launch your program
to tell them about the resources you found?
That way, the information appears in context:
They're using your program, and the program tells them about these
"We can't do that! That would be annoying!"
Here's a question that floated past my view:
How do I set the ACLs on a file so users can read it
but can't copy it?
I can't find a "Copy" access mask that I can deny.
If I can't deny copying, I'd at least like to audit it,
so I can tell who made a copy of the file.
There is no "Copy" access mask because copying is not
a fundamental file operation.
Copying a file is just reading it into memory and then
writing it out.
Once the bytes come off the disk, the file system has no
control any more over what the user does with them.
Last time, I introduced
a friend I called "Bob" for the purposes
of this story.
At a party earlier this year, I learned second-hand
what Bob had been up to more recently.
The team Bob worked for immediately prior to his retirement gave
him a call.
We're trying to ship version N+1 of Product X,
and we really need your help.
I know you're all retired and stuff,
and you don't live in the area any more,
but you're the only guy who can save us.
Could you come out of retirement just for a few months?"
Bob said, "Okay.
This is a favor to you guys since I like you so much."
When he sat down to sign the paperwork,
he took the contract and crossed out the amount of money he
would be paid and wrote in its place, "One dollar".
Because he wasn't taking this job to get rich.
He was doing it as a favor to his old team.
He then signed it and returned the contract to the agency.
The contracting agency was flabbergasted.
"You can't do this for just one dollar!
That's completely unheard of!"
The real reason the agency was so upset is probably
that their fee was a percentage of whatever Bob made,
and if Bob made only one dollar, they would effectively
be doing all the paperwork and getting paid a stick of chewing gum.
Bob said, "Okay, then, if you want me to get paid 'for real',
send me a contract with 'real money'."
The agency sent him the original contract (before he changed
it to "one dollar"), and Bob sent it back, indignant.
"I said 'real money'. This amount is an insult."
You already know how to do this,
you just don't realize it.
How do you find files with an "x" in their name?
That's right, you use dir *x*.
Now you just have to change that x to a space.
And since spaces are command line delimiters, you need to quote
the sequence so it gets treated as a single parameter
rather than two "*" parameters:
dir "* *"
Stick in a /s if you want to search recursively.
Jesse Kaplan, one of the CLR program managers,
why you shouldn't write in-process shell extensions in managed code.
The short version is that doing so introduces a CLR version dependency
which may conflict with the CLR version expected by the host process.
Remember that shell extensions are injected into all processes that
use the shell namespace, either explicitly by calling
SHGetDesktopFolder or implicitly by calling
a function like SHBrowseForFolder,
ShellExecute, or even
Since only one version of the CLR can be loaded per process,
it becomes a race to see who gets to load the CLR first and
establish the version that the process runs,
and everybody else who wanted some other version loses.
Now that version 4 of the .NET Framework
supports in-process side-by-side runtimes,
is it now okay to write shell extensions in managed code?
The answer is still no.
If you pay close attention, you'll notice that most user
interface actions tend to occur on the release,
not on the press.
When you click on a button, the action occurs when the mouse button
When you press the Windows key, the Start menu pops up when you
When you tap the Alt key, the menu becomes active when you release it.
(There are exceptions to this general principle, of course,
typing being the most notable one.)
Why do most actions wait for the release?
For one thing, waiting for the completion of a mouse action means
that you create the opportunity for the user to cancel it.
For example, if you click the mouse while it is over a button
(a radio button, push button, or check box),
then drag the mouse off the control, the click is cancelled.
But a more important reason for waiting for the press is to ensure
that the press won't get confused with the action itself.
suppose you are in mode where objects disappear when the user
clicks on them.
For example, it might be a customization dialog, with two columns,
one showing available objects and another showing objects in use.
Clicking on an available object moves it to the list of in-use objects
and vice versa.
Now, suppose you acted on the click rather than the release.
When the mouse button goes down while the mouse is over
on an item, you remove it from the list
and add it to the opposite list.
This moves the items the user clicked on, so that the item
beneath the mouse is now some other item that moved into the original
And then the mouse button is released, and you get a
WM_LBUTTONUP message for the new item.
Now you have two problems:
First, the item the user clicked on got a WM_LBUTTONDOWN
and no corresponding WM_LBUTTONUP,
and second, the new item got a WM_LBUTTONUP
with no corresponding WM_LBUTTONDOWN.
You can also get into a similar situation with the keyboard,
though it takes more work.
For example, if you display a dialog box while the Alt key
is still pressed rather than waiting for the release,
the Alt key may autorepeat and end up delivered to the dialog box.
This prevents the dialog box from appearing
since it's stuck in menu mode that was initiated by the Alt key,
and it's is waiting for you to finish your menu operation
before it will display itself.
Now, this type of mismatch situation is not often a problem,
but when it does cause a problem, it's typically a pretty nasty one.
This is particularly true if you're using some sort of
framework that tries to associate mouse and keyboard events with
the corresponding windowless objects.
When the ups and downs get out of sync,
things can get mighty confusing.
(This entry was posted late because
a windstorm knocked out power to the entire Seattle area.
My house still doesn't have electricity.)
(Make sure you've read
Part 1 for background information.)
On the subject of where they would go in a time machine,
many students wrote well-thought-out essays,
These sentences below did not come from those essays.
I've categorized the snippets roughly by theme,
though I had to guess at some of them since the sentences are taken
out of context.
(In a futile attempt to assist non-native speakers,
I have glossed some of the trickier parts.
I've also added editorial comments in italics.)
Personal History: These are essays from students who would
travel to their own past.
The Middle Ages:
The students recently studied the Middle Ages,
which helps to explain why so many of them chose to go there.
United States(?) History
I'll stop here before I
runnun too much.
We'll learn more about seventh graders and time machines in
the next installment.