Holy cow, I wrote a book!
When you call GetSaveFileName,
the common file save dialog will ask the user to choose a file name,
and just before it returns it does a little create/delete dance
where it creates the file the user entered, and then deletes it.
What's up with that?
This is a leftover from the ancient days of 16-bit Windows 3.1,
back when file systems were real file systems and didn't have this
namby-pamby "long file name" or "security" nonsense.
(Insert sound effect of muscle flexing and gutteral grunting.)
Back in those days, the file system interface was MS-DOS,
and MS-DOS didn't have a way to query security attributes
because, well, the file systems of the day didn't have security
attributes to query in the first place.
But network servers did.
If you mapped a network drive from a server running one of those
fancy new file systems,
then you were in this case where your computer didn't
know anything about file system security,
but the server did.
The only way to find out whether you had permission to create
a file in a directory was to try it and see whether it worked
or whether it failed with the error
(or, as it was called back in the MS-DOS days, "5"),
Another reason why a server might reject a file name was
that it contained a character that, while legal in Windows,
was not legal on the server.
At the time, the most common reason for this was that you used
a so-called "extended character" (in other words,
a character outside the ASCII range like an accented lowercase e)
which was part of your local code page but not on the server's.
Yet another possibility was that the file name you chose would exceed
the server's path name limit.
suppose the server is running Windows for Workgroups
(which has a 64-character maximum path name limit),
and it shared out
If you mapped M: to \\server\share,
then the maximum path name on M: was only about 30 characters
used up half of your 64-character limit.
The only way to tell whether the file could be created, then,
was to try to create it and see what happens.
After creating the test file (to see if it could),
the common file save dialog immediately deleted it
in order to cover its tracks.
(This could lead to some weird behavior if users picked a directory
where they had permission to create files but no permission to delete
files that they created!)
This "test to see if I can create the file by creating it"
behavior has been carried forward ever since,
but you can suppress it by passing the
There is an oft-abused program named
Why does its name end in 32?
Why not just call it
(I will for the moment ignore the rude behavior of calling people stupid
under the guise of asking a question.)
Because there needed to be a way to distinguish the 16-bit version
from the 32-bit version.
Windows 95 had
(the 16-bit version)
(the 32-bit version).
Of course, with the gradual death of support for 16-bit Windows,
the 16-bit rundll.exe is now just a footnote in history,
leaving just the 32-bit version.
But why did the two have to have different names?
Why not just use the same name (rundll.exe) for both,
putting the 16-bit version in the 16-bit system directory
and the 32-bit version in the
32-bit system directory?
Because Windows 95 didn't have separate
16-bit and 32-bit system directories.
There was just one system directory called SYSTEM
and everything hung out there,
both 16-bit and 32-bit, like one big happy family.
Well, maybe not a happy family.
At any rate,
when 64-bit Windows was introduced,
the plan was not to do things the crazy mishmash way
and instead separate the 32-bit files into one directory
and the 64-bit files into a different directory.
That way, no files needed to be renamed,
and your batch file that ran
rundll32.exe with some goofy command line
still worked, even on 64-bit Windows.
During the discussion of
how real-mode Windows handled return addresses into discarded segments,
"What happens when
somebody does a longjmp into a discardable segment?"
I'm going to assume that everybody knows how longjmp
traditionally works so I can go straight to the analysis.
The reason longjmp is tricky is that it has to
jump to a return address that isn't on the stack.
(The return address was captured in the jmp_buf.)
If that segment got relocated or discarded, then the jump target
is no longer valid.
It would have gotten patched to a return thunk if it were on the
stack, but since it's in a jmp_buf,
the stack walker didn't see it, and the result is a return address
that is no longer valid.
(There is a similar problem if the data segment or stack segment
Exercise: Why don't you have to worry about the data segment
or stack segment being discarded?)
Recall that when a segment got discarded, all return addresses
which pointed into that segment were replaced with
I didn't mention it explicitly in the original discussion,
but there are three properties of return thunks
which will help us here:
The first property
(idempotence of the return thunk) is no accident.
It's required behavior in order for return thunks to work
After all, if the segment was loaded (say by a
direct call or some other return thunk),
then the return thunk needs to say,
"Well, I guess that was easy," and simply skip
the "load the target segment" step.
(It still needs to do the rest of the work,
The second property (abandonment) is also no
An application might decide to exit without returning
all the way to WinMain
(the equivalent of calling ExitProcess
instead of returning from WinMain).
This would abandon all the stack frames between
the exit point and the WinMain.
The third property (reuse) is a happy accident.
(Well, it was probably designed in for the purpose
we're about to put it to right here.)
Okay, now let's look at the jump buffer again.
If you've been following along so far,
you may have guessed the solution:
Pre-patch the return address as if it had already been
If it turns out that the segment was discarded,
then the return thunk will restore it.
If the segment is present (either because it was
never discarded, or because it was discarded and
reloaded, possibly at a new address),
the return thunk will figure out where the code
is and jump to it.
Actually, since the state is being recorded in a
jmp_buf, the tight space constraints
of stack patching do not apply here.
If it turns out you need 20 bytes of memory to
record this information, then go ahead and
make your jmp_buf 20 bytes.
You don't have to try to make it all fit
inside an existing stack frame.
The jmp_buf therefore
doesn't have to try to play the crazy
air-squeezing games that stack patching did.
It can record the return thunk,
the handles to the data and stack segments,
and the return IP without any encoding at all.
And in fact, the longjmp
function doesn't need to invoke the return
It can just extract the segment number
after the initial INT 3Fh and
pass that directly to the segment loader.
(There is a little hitch if the address
being returned to is fixed; in that case,
there is no return thunk.
But that just makes things easier:
The lack of a return thunk means that the
return address cannot be relocated,
so there is no patching needed at all!)
This magic with return thunks and segment
reloading is internal to the operating system,
so the core setjmp and
was provided by the kernel rather than the
C runtime library in a pair of functions
called Catch and Throw.
The C runtime's setjmp
and longjmp functions
merely forwarded to the kernel versions.
Today is New Year's Eve,
another opportunity for to mark that an approximately-integral number
of revolutions of the earth have occurred since some point in time
that wasn't even calculated correctly in the first place.
(We retain it for backward compatibility.)
December 31, 1999 was a particularly anxious day in the technology sector.
Microsoft's Director of Y2K Readiness
and vice president of Product Support Services
described some of the steps that were being taken
to prepare for any timekeeping-related issues that would arise
as the calendar ticked over to 2000.
We've analyzed phone capacity,
IT systems backup for both data and power,
and additional lab environments for enhanced product support capabilities.
We have redundant power systems, including back-up generators,
at key locations in the unlikely event we lose power.
I got to see one of those key locations,
or at least I saw it from a distance.
Parked outside Building 26,
the home of the Core Operating Systems Division,
filled with computers and back-up generators,
ready to spring into action in case of
a disaster of biblical proportions
and somebody needed to develop a hotfix to Windows on the spot
as civilized society collapsed into anarchy all around.
(Personally, I would think that if civilization were collapsing,
you would have more important things to worry about than patching
an operating system.)
At least to make things more pleasant for the people who had
to remain at work that night,
"a New Year's Eve party with a disc jockey,
dinner, and a champagne toast at midnight.
Our employees can bring their spouses and children,
and we'll even host a separate children's party."
Actually, it sounds like they had more fun than I did that night.
I think I stayed at home and watched television.
It turns out that civilization did not collapse into anarchy.
There were minor glitches, but
"No problems were seen in Angola, Uganda and Kenya,
where the telephone system was said to be functioning
as erratically as usual.
Italy, one of the worst-prepared countries in the West,
also appeared to cross into the new century without any major trouble."
Nice to know you can be snarky in a newspaper article.
(Nitpicker's corner: January 1, 2000 was not the first day of a new
Depending on how you look at it,
Y2K was either an overhyped event created to generate revenue
for the technology industry,
or was a demonstration of how people can solve a major problem if they
just worked hard and coöperated.
Reality is probably a mix of the two.
Happy new year, everybody.
See you on the other side.
On the Windows 8 Start screen,
you can pan left and right,
and if you are using touch, you can whip the entire screen left and right
and send all your tiles flying past.
One of the effects we saw when you panned quickly around the Start screen
was something we called
but which formally goes by the much more mundane name
When you pan quickly through the Start screen,
the items are moving so fast that the human eye can't register any of the
It's just a bunch of colored boxes whizzing past.
But video displays are not continuous.
They refresh at a particular frequency,
so it's as if there's a strobe light flashing on your Start screen.
Therefore, what you perceive is not a bunch of boxes whizzing past,
but rather a bunch of boxes moving around in strange patterns.
When the panning hits a magic speed,
each frame's tiles happen to land in nearly the same spot
as the previous frame's tiles,
but since they are different tiles, the colors are all different.
At that critical speed,
you don't get the effect that the tiles are whizzing past.
Instead, it looks like they are blinking different colors,
like disco lights.
Photosensitive epilepsy warning:
Do not view the disco lights simulation
if you have or may have photosensitive epilepsy.
click the colored box to see the disco lights.
I created two versions of the simulation,
a more realistic one
and one with an exaggerated disco effect to show you what
inspired the name.
The fix was to turn off the colors and just show plain tiles.
That way you still felt the motion but you didn't get the disco effect.
(It also mean that the Start page was less likely to
induce photosensitive epilepsy.)
This is an interesting example of the sorts of design problems that
show up when you start implementing a feature.
In the original design for the Start screen,
it seemed obvious that the Start screen should show what the user
is scrolling through at full speed.
But when you actually did it, the hidden stroboscopic effect
showed that doing a better job actually looks worse.
Tomorrow marks the 36th anniversary of the disco dance movie
Saturday Night Fever.
Sorry we couldn't keep the lights on for you.
Some people suggest that one thing Microsoft Research could do
with that time machine they're working on
is to go back in time and
change the name of the Program Files directory to simply Programs.
No, it really should be Program Files.
Program Files are not the same as Programs.
Programs are things like Calc, Notepad, Excel, Photoshop.
They are things you run.
Program Files are things like
They are files that make programs run.
If the directory were named Programs,
then people who wanted to run a program would start
digging into that directory
and seeing a page full of weird DLL names
and wonder "What the heck kind of programs are these?"
And eventually they might figure out that if they want to run
PowerPoint, they need to double-click on the icon named
"Computers are so hard to use."
If you want to find your programs,
go to the Start menu.
The Program Files directory is like the pantry of a restaurant.
You aren't expected to go in there and nibble on things that look
You're expected to order things from the menu.
When you wrote code for 16-bit Windows,
one of the things you spent time doing
as part of performance tuning was
deciding which functions should be grouped together in which segments.
Code in 16-bit Windows executed out of code segments,
each of which could be up to
When a code segment was loaded from disk,
the entire segment was loaded,
and when it was discarded, the entire segment was discarded.
This meant that you could affect your application's performance
in significant ways by choosing which functions go in which segments.
For example, it was to your advantage to keep functions that
are called at the same time in the same segment,
so that they would be loaded as a unit (saving I/O time).
If you chose poorly and put unrelated functions in the same segment,
then calling any function in the segment caused all the functions
to be loaded,
which was a waste of I/O since you loaded a bunch of functions
you didn't need.
Even if the functions were called at the same time,
you also had to keep an eye on their popularity.
If you have one function that is called frequently
and another that is called infrequently (but always
preceded by a call to the first function),
the less popular function will ride the coattails of his
roommate and remain loaded in memory.
This creates unnecessary memory pressure that could cause
a function which is moderately-frequently-called
to be discarded to make room.
Creating lots of small segments allowed your memory usage
to be managed with finer granularity,
but it also costs you in general overhead as well as I/O,
because each segment load was a new round trip to the disk.
You therefore had to balance memory cost against I/O cost.
The process of optimizing the grouping of functions
was known as segment tuning.
During the development of Windows 3.0,
it was customary to have regular meetings with Bill Gates
to brief him on the status of the project.
At one of the reviews,
the topic was performance, and Bill complained,
"You guys are spending all this time with your segment
I could teach a twelve-year-old to segment-tune.
I want to see some real optimization,
not this segment tuning nonsense.
on an airplane, for heaven's sake."
(I can't believe I had to write this:
This is a dramatization, not a courtroom transcript.)
This "I wrote FAT on an airplane"
line was apparently one Bill used
when he wanted to complain that what other people was doing
wasn't Real Programming.
But this time, the development manager decided she'd had enough.
We'll set you up with a machine fully enlisted in the Windows
and you can help us out with some of your programming magic,
why don't you."
This shut him up.
Some time ago, I briefly ran down
how 16-bit Windows managed memory for resources.
But there's a detail that I neglected to mention:
As we saw,
a resource handle HRSRC was really
a pointer to the resource directory entry of the resource
from the corresponding module.
This could be done with a 16-bit pointer because the segment
portion of the pointer could be inferred from the module
the resource belonged to.
In fact, since modules could be relocated
in memory at run time due to compaction,
you had better not try to remember the segment portion of the
pointer since it could change!
The FindResource function located the
resource directory entry.
The LoadResource function allocated memory
for the resource and loaded it from disk.
The LockResource function locked the memory
so you could access it.
If two people tried to load the same resource,
the memory for the resource was re-used so there was only
one copy in memory,
and if both people free the resource,
the resource is cached in case somebody asks for it again soon.
Now things get interesting:
When does the resource get removed from the cache?
What actually controls the lifetime of the resource?
Answer: The resource lifetime is tied to the module it came from.
When the module is unloaded, all its resources are
unloaded along with it.
(Note that even if a resource is cached,
its contents can get
discarded if it is tagged as DISCARDABLE.)
In Win32, modules are directly mapped into memory,
and along with it, the resources.
Therefore, accessing the resources of a module
is a simple matter of figuring out where they got mapped
(FindResource and friends will tell you),
and then reading the memory directly.
So despite the radical change to resources work,
the basic rules haven't changed:
The resources are good as long as the module is still in memory.
But there are resources and then there are resources.
So far, we've been talking about resources in the sense of
FindResource, which I will call
module resources for lack of a better term.
But people often work with objects like icons and bitmaps
which are not literally
resources but which are derived from resources.
we'll look at the relationship between module resources
and resource-derived objects in 16-bit Windows.
The feature now known as Aero Peek wasn't born that way.
It went through several iterations before becoming what eventually
shipped in Windows 7.
At the MIX09 conference,
showed some of the precursors to Aero Peek.
Here are the highlights, and the corresponding time codes
if you want to jump straight to the demos.
Thumbnails in the taskbar
(time code 30:20)
How it worked:
Instead of labeled icons, the taskbar showed miniatures
of the windows themselves.
How it got its name:
Um, it was just named after what it was.
Why it failed:
When shrunk to taskbar size,
most windows looked the same:
white with unreadably tiny text.
Aladdin (time code 42:34)
How it worked:
To bring another window into view temporarily,
shake the mouse over that window.
The longer you shake, the longer the window stays visible.
How it got its name:
From the folk tale in which the hero
summons a genie by rubbing a magic lamp.
Why it failed:
It was too tiresome having to keep
shaking the mouse while you read a document.
Bat Signal (time code 31:10)
How it worked:
When you hover over a taskbar button,
the screen darkens, and a spotlight shines on the
How it got its name:
After the distress signal used in the Batman series.
Why it failed:
People liked the way it helped them find their windows,
but it was too easy to trigger accidentally.
Also, people tried to "ride the light beam", which inadvertently
canceled the bat signal.
Squeegee (time code 33:10)
How it worked:
When you hover over the pop-up thumbnail,
the corresponding window comes to the front, and
all the other windows turn into glass sheets.
How it got its name:
It makes your screen look like somebody took a squeegee
to all the other windows and washed all the pixels off them,
leaving clean sheets of glass.
Squeegee won the day,
and it was given the official name Aero Peek.
Wikipedia entry for Batman clocks in at
the entry for
Bat-Signal is only 857 milliGinsburgs.
Hey, Wikipedians, you're falling down on the job!
In the early 1980's,
Microsoft moved its headquarters from downtown Bellevue
to Northup Way in Bellevue,
a building which later served as a training center
and is now the North Campus of Bellevue Community College.
This is the building in which the infamous
Bill Gates Tiger Beat-style photo
and the one I told a story about
some years ago.
At the time, the company was still very small,
and the task of managing the relocation was shared among all the employees.
After everybody settled in at the new building,
it became apparent that the mail volume was barely a trickle.
checks were not coming in,
which is kind of an important part of running a business.
In the excitement of moving,
nobody remembered to file a Change of Address form with the Post Office.
A visit to the old Bellevue offices
revealed a huge mound of mail at the old location.
A Change of Address was quickly filed,
but in the meantime,
Steve Ballmer became the company mailman.
Every day, he would drive to the old offices,
pick up the mail that had accumulated,
dump it in the trunk of his car,
then deliver it to the Northup offices.
(Today's story is in recognition of the 238th birthday of the
United States Postal Service.)