If our program isn't installed and users double-click our document,
they get sent to a Web site that presents a list of programs,
but we want to send the user directly to our download site.
How do we claim a file extension for our application?

Um, you don't.

You cannot pre-emptively reserve a file extension.
If your program uses the extension .ABC and somebody
off in another country working out of a garage also uses the extension
.ABC, then that's fine.
Of course, things get exciting when a user installs both your program
and the garage program, but that's a conflict for the user to resolve.
It is not your position to declare unilaterally that you are more
important than that person in a garage.

That it's not a global setting is not readily apparent most of the time
since only Windows Terminal Server is set up to support multiple
simultaneous interactive sessions.
On Windows Terminal Server, you specify the properties of the virtual
monitor you wish to connect with, including resolution,
and the server accommodates your wishes.
Well, up to a point.
I mean if you ask for a 1,000,000×1,000,000 pixel screen,
the server is probably going to say "As if!"
(The Remote Desktop Connection feature found in, for example,
Windows Vista Ultimate is basically the same thing,
but on a smaller scale.)

You can have ten different people logged on, each using a different
video configuration.
Some users might be running at lowly 640×480, others at 800×600
and still others at 1024×768.
Some of them are running in 16-color mode, others 8-bit color,
and some really adventuresome people with a lot of network bandwidth
running at 24-bit color.
You can even have the same user logged on more than once,
with each session running at a different screen resolution.

If the resolution settings really were per-user, you'd have some
conflict resolution to deal with.
If a user logs on and specifies a resolution different from the one
stored in the user profile, does the new resolution overwrite
the existing one? Or is the new resolution just a temporary resolution
and the original one should stay?
If a user tries to log on a second time with a conflicting resolution,
is the second resolution ignored? Does the second resolution force
the first session to change its resolution?
Do you just get two sessions running with different resolutions?
Which one gets saved as the user's preferred resolution?

You also have to come up with a way to customize the resolution of
the screen when nobody is logged on, a way to reconcile the effect
of roaming profiles, what happens if you do a Run As on a user whose
screen resolution conflicts with the user who opened the session.

I'm not saying that these problems can't be solved.
They probably can, given enough thought, but not all of
the solutions will please everybody all the time,
because no matter what you do,
somebody will tell you that you're an idiot.
And think of all the time and effort necessary to
design how the feature should work,
nail all the boundary conditions
("What happens if
your per-user setting conflicts with an administrative policy?"),
then code it up, write automated tests for it,
run it through usability exercises
("Does the behavior match what users intuitively expect?" The answers
may surprise you.) write up the documentation and help text,
and continue maintaining the code, tests, and documentation for the
feature's anticipated lifetime (which in this case is probably forever).
Could all those resources have been spent on something that would
have a greater total benefit to the customer base?
(The answer to that is always "Yes"—everybody and her sister-in-law
can find a way to finish the sentence, "I can't believe they wasted
all that time on this stupid feature instead of fixing...")

As we saw a while ago,
MS-DOS acted as the 16-bit legacy device driver layer
for Windows 95.
Even though the operation was handled by the 32-bit file system,
all I/O calls were routed through 16-bit code (if only briefly)
so that 16-bit drivers, TSR, and the like would see what appeared
to be "normal 16-bit behavior" and continue operating in the manner
to which they had become accustomed.

In the old 16-bit days, disk formatting was done via software
interrupt 13h,
and many programs took advantage of this by hooking the interrupt
so they would know whenever a floppy disk was being formatted.
Some TSRs did this, as did backup programs
(including backup programs designed for Windows 3.0 which
included 32-bit Windows 3.x drivers—VxDs they were
called—to monitor the floppy drive).
But that doesn't explain everything.
After all, Windows 95
sent all disk I/O through the 16-bit vectors,
not just floppy disk formatting.
Why does floppy disk formatting take such a toll on the system?

As I noted in the linked article,
the 32-bit file system did a lot of fakery to make 16-bit code
believe that MS-DOS was in charge, even though it wasn't.
Anybody who's done TSR programming
(wow, the phrase anybody who's done TSR programming
used to cover a lot of people but nowadays describes a few dozen geezers,
most of whom are trying very hard to forget those days)
knows all about the INDOS flag.
This was a flag that MS-DOS set when an MS-DOS I/O call was
active.
Since MS-DOS was not re-entrant, TSRs had to pay close attention
to that flag to know whether it was safe to issue MS-DOS calls or not.
This INDOS flag was the 16-bit manifestation of what the 32-bit
kernel called simply The Critical Section,
with the definite article,
because the 32-bit kernel kept the two critical sections
(the 32-bit one and the 16-bit one) in sync so that
MS-DOS drivers and TSRs wouldn't themselves get re-entered.
If one virtual machine claimed the critical section,
another virtual machine that tried to claim it would wait
until the first one released it.
In that manner, the driver or TSR would not get re-entered.

As I already noted,
back in the 16-bit days, the actual work of formatting was done
by the ROM BIOS,
and for compatibility reasons,
floppy disk formatting was still sent through software interrupt 13h
on the 16-bit side so any TSRs or drivers could see what was going on.
There are a lot of crazy ROM BIOSes out there,
and when a floppy disk format request was issued, the 32-bit kernel
would do a bunch of extra work to ensure that the ROM BIOS got
the execution environment it wanted.
For example, the hardware timer ports were temporarily
unvirtualized so as not to mess up the sensitive timing loops
that ROM BIOSes used for floppy disk formatting.

Okay, let's add up the damage.
When a floppy disk is formatting,
the timer is unvirtualized so that the ROM BIOS timing loops will
run accurately.
Only the virtual machine that is formatting the floppy drive
receives timer ticks;
the others have to wait.
No timer ticks means the scheduler doesn't get told when it's time
to let another thread run.
What's more, the critical section is held across this operation,
which means that no other thread can issue I/O operations either.
And on top of that, the floppy disk is a slow medium, so any
operations that wait on the floppy disk will have to sit and wait for
several seconds.

Well, at least floppy disks are formatted a track at a time,
so the system doesn't get locked out for the entire duration of
the format operation.
The ROM BIOS would be told to format a track,
and when it was done,
the timers would be returned to normal
(allowing the scheduler to do a little bit of scheduling),
the critical section would be released
(so that any pent-up I/O gets a chance to run),
but then the FORMAT.COM program would turn around
and format the next track, and the system would go back into
hang on, let's not disturb the ROM BIOS while it does its thing
mode for another track.

Now, as with the 32-bit file system, there was a 32-bit floppy driver
that tried to catch the format operations on the back end,
and if successful, it would take over the job of formatting one track
from the ROM BIOS.
It was a valiant effort,
but it doesn't matter how high-performance your driver is;
the speed of formatting a track is pretty much constrained by the
mechanics of the floppy disk drive itself.
(The person responsible for Windows 95's 32-bit floppy driver
was no slouch. I'll try to remember to tell some more stories later.)

Sure, if Windows 95 didn't have to be compatible with 16-bit device
drivers, TSRs, and squirly ROM BIOSes,
it could have gone straight to the 32-bit floppy driver to do the
formatting without having to do all this timer and critical section
nonsense.
But it turns out we already had a product that said good-bye to
compatibility with 16-bit device drivers,
TSRs,
16-bit Windows programs that talked to custom
32-bit Windows 3.x drivers,
and squirly ROM BIOSes.
It was called Windows NT.

If you double-click a file for which there is no registered handler,
Windows will offer to visit the Web service on
shell.windows.com to locate a program that can open it.
But where does this information come from,
and how can you add your program to the database?

I'm
at a Thai restaurant
with my sister-in-law, who is Thai.
She's talking with the waitress in Thai,
and she discovers that the restaurant's cook is someone she knows.
And since she's from Thailand, she assumes the task of ordering the food,
since she knows what's good and what isn't.

During their conversation
(entirely in Thai, so I don't understand a word of it),
she turns to me and asks,
"So, is spicy food okay?"

I say, "Yeah, I like spicy food."

Classic rookie mistake.

I think that by the end of the meal, I had just started to regain
the ability to taste the food.

Happy birthday, P—!
And you'll be relieved to know that I can taste food again.

When
the file association Web service
was first being developed,
the programmer responsible for implementing the feature just scrounged
around and found an old unused computer
and set it up as a
simple Web server under his desk,
so there would be something to test the code against.
That server happily churned away serving out file extension information,
and when people asked for their program to be added, he would
manually add it to the server.
The server worked just fine, and like most things which work just fine,
it was forgotten.

And then remembered once things no longer worked just fine.

I think it was during one of the beta cycles, or maybe it was
RC1,
when the quiet neglected computer went offline.
I forget why, so let's pretend that the programmer
unplugged it
as part of an office redecoration project.
Suddenly, the shell.windows.com service went down.

What?
The file association Web service went down?

Everybody had forgotten that shell.windows.com
was still running on a computer under that programmer's desk.
It had done such a good job up until now that nobody gave
it a second though.

He plugged the computer back in and watched the server
bang out requests like nobody's business.

Wheels were quickly set into motion to transfer the file
association Web service
to a machine with a little bit more professional attention
and maintenance.

Well, part of it is that most people suck at technical writing.
The technical part, maybe, but the writing almost definitely not.
Writing is hard (as I've learned firsthand),
and technical writing is a special genre of writing that requires
a comparatively rare skill set,
combining technical background with strong writing skills.
Because it doesn't matter how much technical information you know
if you are unable to convey this information to anyone else clearly.

Also, there are lots of tools available for identifying potential
security problems.
PREfast, for example, can alert you to potential
buffer overruns, and other scripts can hunt down uses of
deprecated functions and similar potential security problems.
On the other hand, how do you write a script that locates bad documentation?

What's more, technical people tend to write documentation for other
technical people, on the assumption that the reader
is already familiar with the material.
Even knowing how to recognize that something "obvious" may not be obvious to
everyone is a skill that takes time to develop.
And as I have learned over and over again,
it's a skill that I myself do not possess.
Consider, for example, my posting that merely
restates what I thought was obvious from the documentation.

There's another problem with taking everybody on the team off their
normal tasks and focusing them on documentation:
How do you explain the one month delay in the product?
Even the one-month delay for the so-called security push
had its skeptics.
Imagine if you told everybody that the product was late
because we pulled the development team off of fixing bugs
and told them to write documentation.

Not all skill sets are interchangeable.
That's why we have concepts like division of labor
and specialization.
But it appears that not everybody understands this.

I was reminded of this topic when I read the reactions to
the Microsoft Exchange Team
announcing that
they had added Xbox and Zune themes to OWA.
Many people were shocked,
such as
Loren,
who was furious that "development time" was wasted on something
frivolous like new themes when there are so many bugs that need
to be fixed.
Loren appears to believe that the people who do graphic design and the
people who are up to their elbows in the code base fixing bugs and
adding features are one and the same,
that any time spent building a new visual style is time not spent
fixing bugs.

Generally speaking, programmers don't do the visual design.
I mean, these are people who are lucky if they are wearing
matching socks when they come to work,
if they even remember to wear socks at all.
And you want them to design a color scheme?
Visual design is done by people trained in the visual arts,
people who know about color wheels and lighting effects,
people who can argue for days about whether the spacing between
two visual elements should be one point or two,
about whether a serif or sans-serif font should be used for
a particular screen element.
What the programmers do is create the infrastructure for skins
and themes,
but the actual building of the skin or theme is left to
the designers.
Once the infrastructure is built,
the programmers' work is pretty much done,
and they can go back to fixing bugs and adding other features,
stuff that keeps Loren happy.
Of course, the infrastructure for themes and skins needs to be
maintained, but the amount of work
spent on maintenance is largely
independent of how many themes the designers have come up with.

Mind you, the new skins do create additional work for the testers,
who need to write tests to verify that
that the new skins don't have bugs like
"In the Zune skin, you can't read the subject lines."
But presumably they already have a template for testing skins—after
all, they have to test all the other skins—so plugging the new
skin's parameters into the template is a comparatively low
incremental cost.

So go ahead and enjoy those new themes,
comforted in knowing that the effort spent in making those new
themes was not at the cost of bug fixing.

Next time, a story about what happens when a tester needs to test
the skinning infrastructure when there are no skins.

A friend of mine told me a story of a project from over ten years ago.
Part of the product design was that it would include a bunch of
skins (visual styles).
The development team had written up the skinning infrastructure,
but the company which was hired to create the actual skins
hadn't delivered anything.
My friend's assignment was to test the skin-switching interface,
but since there were no skins,
there was nothing to test.

My friend was responsible for testing a bunch of other product
features, so it's not like the days were spent thumb-twiddling.
But eventually, it got to the point where
the automated testing for most of the other features
was nearly complete, and at the weekly status meetings,
my friend would ask the representative from the company that was hired to
deliver the skins when they might send over the first
two or three.
"I don't need all twenty skins, just two or three so I can test
the skin-switcher."

At the meetings, the company representative always answered,
"Yes, we know you're waiting for it,
but designing these skins is really complicated stuff,
and it's pretty slow going."

My friend wondered, "How hard is this, really?"
A visit to the development team quickly produced the same
tools and documents that the skin design company was given,
and in a few hours on a Saturday, my friend produced a brand new skin.
Since my friend was a big
Star Trek fan at the time,
the homegrown skin was naturally based on the science fiction series,
created by surfing the Internet and downloading pictures and
sound effects.
There was obviously
no way the company could include this skin with their product,
but at least it was something to test with.
The skin-switcher finally had something to switch between:
You could have the standard look or the Star Trek skin.

At the next meeting, my friend once again asked the representative
from the design company when they might deliver a skin or two
and received the same runaround as usual.
"It's a lot harder than we anticipated, but we're getting close,
so who knows, you might have something in a few weeks."

Except this time, my friend had a response for them.
"Oh, maybe I can help you guys out.
I threw together this skin in just a few hours.
Here, let me show you."
And then followed a demonstration of the Star Trek theme.
It had a lot of rough edges
(for example, the sound volumes weren't leveled),
but it certainly did the job as a demo.

As if by magic,
just a few days later,
the company that had been contracted to produce the skins
managed to overcome all the obstacles that had been
plaguing them up until now,
and a steady stream of new skins started arriving.

I find it surprising how often this happens.
A customer liaison will send a question to a mailing list like
this:

From: XTo: Gizmo Discussion

Hi, everybody.

My customer is using the Gizmo Toolkit and
wants to frob a gizmo without first registering
as a frobber.
They created the gizmo with CreateGizmo,
passing all the default flags,
and then they call AttachGizmo to attach
the gizmo to a sprocket.
When the sprocket detects that its host is decycling,
it tries to frob the gizmo by calling FrobGizmo,
but the call fails.
They can't register the sprocket as a frobber because
the sprocket doesn't have the right frob context.
They tried setting the DefaultFrobContext registry
key to Any but that didn't help.
How can they frob the gizmo?

Somebody from the Gizmo team will reply,
"Sorry, but you have to register as a frobber before you
can frob a gizmo. The DefaultFrobContext registry
key doesn't help you here; it's for cogs, not sprockets.
There is no analogous registry key for sprockets, sorry."

That seems to be the end of it; there is no further response.
Then about two weeks later, some other person will
ask a suspiciously similar question.

From: YTo: Gizmo Discussion

Hello.
I hope somebody can help us with this.

My customer is using the Gizmo Toolkit and
wants to frob a gizmo without first registering
as a frobber.
They created the gizmo with CreateGizmo,
passing all the default flags,
and then they call AttachGizmo to attach
the gizmo to a sprocket.
When the sprocket detects that its host is decycling,
it tries to frob the gizmo by calling FrobGizmo,
but the call fails.
They can't register the sprocket as a frobber because
the sprocket doesn't have the right frob context.
They tried setting the DefaultFrobContext registry
key to Any but that didn't help.
How can they frob the gizmo?

Okay,
maybe the customer was not happy with the answer and instead of
elaborating on their situation (so somebody might be able to spot
an alternate design that avoided this problem),
they just reopened the case and got a different liaison
the second time.
Maybe person Y was simply duped into asking the same question.

And then this happens.

From: YTo: Windows Programming Discussion

Greetings.

My customer is using the Gizmo Toolkit and
wants to frob a gizmo without first registering
as a frobber.
They created the gizmo with CreateGizmo,
passing all the default flags,
and then they call AttachGizmo to attach
the gizmo to a sprocket.
When the sprocket detects that its host is decycling,
it tries to frob the gizmo by calling FrobGizmo,
but the call fails.
They can't register the sprocket as a frobber because
the sprocket doesn't have the right frob context.
They tried setting the DefaultFrobContext registry
key to Any but that didn't help.
How can they frob the gizmo?

Okay, so much for the theory that person Y was a victim.
Person Y is clearly fishing around,
hoping that if you ask the right person,
you'll get an answer you like.
It's sort of like the teenager who asks his father,
"Can I borrow your car?"
When Dad says, "No,"
the teenager goes to his mother and asks,
"Can I borrow Dad's car?"
in the hopes that maybe Mom will give a more favorable answer
than Dad.