Holy cow, I wrote a book!
previous entry I discussed the story behind the functions with the funny names
BEAR, BUNNY and PIGLET. But what about the ones with goofier names like BOZOSLIVEHERE
For this, you need a deeper history lesson.
Back in the old days of real-mode Windows, all callback functions had to be exported.
This was necessary for complicated technical reasons I may bother to explain if anybody
really cared but I doubt anybody does any more. So the window procedures for all of
the standard window classes (edit controls, list boxes, check boxes, etc.) were exported
from USER. So too were various other callback functions like timer procedures. This
was in addition to the usual collection of internal functions so USER, KERNEL and
GDI could coordinate their efforts.
Some people reverse-engineered all these internal functions and printed books on how
they worked, and as a result there were a lot of programs that actually used them.
Which was quite a surprise to us because they were internal functions. And then when
we wanted to redesign these internal functions (for example, to add a parameter, or
if we decided that we didn't need it any more and tried to delete it), we found found
that the progams stopped working.
So we had to put the functions back, with their old behavior. The new features were
were contemplating had to be redesigned, redirected, or possibly even abandoned entirely.
(If we wanted to delete a function, then the work could continue, but the old function
had to stay around with its old behavior. It was basically dead code from the OS's
point of view, hanging around just because some random app or other decided to cheat
and bypass the documented way of doing things.) But to teach people a lesson, they
often got given goofy names.
For example, BOZOSLIVEHERE was originally the window procedure for the edit control,
with the rather nondescript name of EditWndProc. Then some people who wanted to use
the edit control window procedure decide that GetWindowLong(GWL_WNDPROC) was too much
typing, so they linked to EditWndProc directly. Then when Windows 2.0 (I think) removed
the need to export window procedures, we removed them all, only to find that programs
stopped working. So we had to put them back, but they got goofy names as a way of
scolding the programs that were doing these invalid things.
Things got even worse in Windows 95, when all our window procedures were converted
to 32-bit versions. The problem is that the old window procedures were only 16-bit.
So we couldn't even simply export the 32-bit window procedure under the name BOZOSLIVEHERE.
We had to write a conversion function that took an illegal 16-bit function call and
converted it to the corresponding illegal 32-bit function call.
Welcome Knowledge Base article 932955 readers!
Remember, the information on this Web site is not
official Microsoft documentation.
Daylight Savings Time ends this weekend in most of North America and Europe, so it
seems a good time to discuss the whole problem of Daylight Savings Time and timestamps.
A common complaint is that all the time zone conversion functions like FileTimeToLocalFileTime
apply the current Daylight Savings Time (DST) bias rather than the bias that
was in effect at the time in question.
For example, suppose you have a FILETIME structure that represents "1 January 2000
12:00AM". If you are in Redmond during the summertime, this converts to "31 December
1999 5:00PM", seven hours difference, even though the time difference between Redmond
and UTC was eight hours at that time. (I.e., when people in London were celebrating
the new year, it was 4pm in Redmond, not 5pm.)
The reason is that the time got converted from "1 January 2000 12:00AM UTC" to "31
December 1999 5:00PM PDT". So, technically, the conversion is correct. Of course,
nobody was using PDT on December 31, 1999 in Redmond; everybody was on PST.
Why don't the time zone conversion functions use the time zone appropriate for the
time of year?
One reason is that it means that FileTimeToLocalFileTime and LocalFileTimeToFileTime
would no longer be inverses of each other. If you had a local time during the "limbo
hour" during the cutover from standard time to daylight time, it would have no
corresponding UTC time because there was no such thing as 2:30am local time. (The
clock jumped from 2am to 3am.) Similarly, a local time of 2:30am during the cutover
from daylight time back to standard time would have two corresponding UTC times.
Another reason is that the laws regarding daylight savings time are in constant flux.
For example, if the year in the example above was 1977 instead of 2000, the conversion
would have been correct because the United States was running on year-round
Daylight Savings Time due to the energy crisis. Of course, this information isn't
encoded anywhere in the TIME_ZONE_INFORMATION structure. Similarly, during World War
2, the United States went on DST all year round. And between 1945 and 1966, the DST
rules varied from region to region.
DST rules are in flux even today. The DST cutover dates in Israel are decided on a
year-by-year basis by the Knesset. As a result, there is no deterministic formula
for the day, and therefore no way to know it ahead of time.
(Warning: .NET content ahead; two days in a row, what's gotten into me!?)
Compare the output of FileInfo.LastWriteTime.ToString("f") with what you see in the
property sheet for a file that was last written to on the other side of the DST transition.
For example, suppose the file was last modified on October 17, during DST but DST
is not currently in effect. Explorer's file properties reports Thursday, October 17,
2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, 2003, 9:45 AM.
En gang til for prins Knud: Win32 does not attempt to guess which time zone
rules were in effect at that other time. So Win32 says, "Thursday, October 17, 2002
8:45:38 AM PST". Note: Pacific Standard Time. Even though October
17 was during Pacific Daylight Time, Win32 displays the time as standard
time because that's what time it is now.
.NET says, "Well, if the rules in effect now were also in effect on October 17, 2003,
then that would be daylight time" so it displays "Thursday, October 17, 2003, 9:45
AM PDT" - daylight time.
So .NET gives a value which is more intuitively correct, but is also potentially incorrect,
and which is not invertible. Win32 gives a value which is intuitively incorrect, but
is strictly correct.
I suspect that the .NET behavior was for compatibility with Visual Basic, but I don't
know for sure.
Early beta versions of the taskbar clock did display seconds, and it even blinked
the colon like some clocks do. But we had to remove it.
Because that blinking colon and the constantly-updating time were killing our benchmark
On machines with only 4MB of memory (which was the minimum memory requirement for
Windows 95), saving even 4K of memory had a perceptible impact on benchmarks. By blinking
the clock every second, this prevented not only the codepaths related to text rendering
from ever being paged out, it also prevented the taskbar's window procedure from being
paged out, plus the memory for stacks and data, plus all the context structures related
to the Explorer process. Add up all the memory that was being forced continuously
present, and you had significantly more than 4K.
Some commenters mentioned that I should write a book.
It turns out that writing a book is hard.
A few years ago, MS Press actually approached me about
writing a book for them. But I declined because the
fashion for technical books is to take maybe
fifty pages of information and pad it to a 700-page
book, and I can't write that way. None of my
topics would ever make it to a 100-page chapter.
They're just little page-and-a-half vignettes.
And it's not like the world needs yet another book
on Win32 programming.
So I'll just continue to babble here. It's easier.
Blue means compressed; green means encrypted.
This is an example of one of those "come on, it's a tiny, simple feature" requests.
Yes, the code to do this isn't particularly complicated, but it adds another element
of "Ha ha, I'm going to do something in a way that you will never be able to figure
out unless somebody tells you."
We get a lot of these little requests. If we accepted them all, you'd have icons with
so many incomprehensible decorations you'd never be able to figure out what all the
colors and markers mean.
So the next time you say to yourself, "Windows should change the appearance of X if
simple condition Y," imagine what it would be like if we actually did even twenty
of those simple things.
What determines the order in which icons appear in the Alt+Tab list?
The icons appear in the same order as the window Z-order. When you switch to a window,
then it comes to the top of the Z-order. If you minimize a window, it goes to the
bottom of the Z-order. The Alt+Esc hotkey (gosh, does anybody still use Alt+Esc?)
takes the current top window and sends it to the bottom of the Z-order (and the window
next in line comes to the top). The Alt+Shift+Esc hotkey (I bet you didn't know that
hotkey even existed) takes the bottom-most window and brings it to the top, but does
not open the window if it is minimized.
The presence of "always on top" windows makes this a little more complicated. The
basic rule is that an "always on top" window always appears on top of a "not always
on top" window. So if the above rules indicate that a "not always on top" window comes
to the top, it really just goes as high as it can without getting on top of any "always
on top" windows.
You may have run across the term "fast task switching". This was the term used to
describe the precursor to the current Alt+Tab switching interface. The old way of
switching via Alt+Tab (Windows 3.0 and earlier) was just like Alt+Esc, except that
the window you switched to was automatically opened if it had been minimized. When
the new Alt+Tab was added to Windows 3.1, we were concerned that people might prefer
the old way, so there was a switch in the control panel to set it back to the slow
way. (There is also a setting SPI_SETFASTTASKSWITCH that lets you change it programmatically.)
It turns out nobody complained, so the old slow way of task switching was removed
entirely and the setting now has no effect.
This does highlight the effort we take to try to allow people who don't like the new
way of doing something to go back to the old way. It turns out that corporations with
10,000 employees don't like it when the user interface changes, because it forces
them to spend millions of dollars retraining all their employees. If you open up the
Group Policy Editor, you can see the zillions of deployment settings that IT administrators
can use to disable a variety of new Windows UI features.
Set the wayback machine to DOS 1.0.
DOS 1.0 didn't support subdirectories, lowercase, or filenames longer than 8.3.
When you ran the assembler (or compiler if you were really fancy) the conversation
went something like this:
A>asm foo the ".asm" extension on "foo" is implied
Assembler version blah blah blah
Source file: FOO.ASM
Listing file [FOO.LST]: just hit Enter to accept the default
Object file [FOO.OBJ]: just hit Enter to accept the
Assembler cranks away
Assembler version blah blah blah
Source file: FOO.ASM
Listing file [FOO.LST]:
Object file [FOO.OBJ]:
You only had to type the base name of the file; the ".LST" and ".OBJ" extensions were
appended automatically. In fact, I don't think you could disable the extensions; they
were always added.
But what if you didn't want a listing file? The assembler demanded a filename, and
if you didn't type any filename at all, it created one with the same basename as your
That's where the magic filenames come in. Suppose you wanted the listing file to go
straight to the printer. You didn't want to create a file on your floppy drive because
there might not be enough space to hold it, or just because you didn't want to waste
the time creating a file just to delete it anyway. So you typed "PRN" as the filename.
Now, the assembler doesn't know about these magic filenames. So the assembler will
try to create the file "PRN.LST" and then start writing to it. Little does the assembler
realize that the output is actually going to the printer.
If you wanted to discard the output entirely, you would type "NUL", of course. And
if you wanted it to go to the screen, you would type "CON".
Now, if you followed closely, you can see that the above story explains two things
Why are the magic filenames magical even if I add an extension?
Answer: If an extension removed the magic, then when the assembler added ".LST" to
the filename, it would no longer be recognized as magical, thereby defeating the purpose
of the magic.
Why do these magic files exist in every directory?
Answer: Because DOS 1.0 didn't have subdirectories. There was only one directory,
which today we would call the root directory, but back then, since there was no such
thing as a subdirectory, there was no need to talk about directories in the first
place, much less give the only one you have a name. It was just called "the files
on your disk". If magic files didn't work in subdirectories, then when you tried to,
for example, chdir into a subdirectory and then run the assembler, you wouldn't be
able to type "NUL" as the filename and get the magic.
But why do we carry these magic filenames forward even today?
Because everybody still relies on them. Just look at all the batch files that do things
like redirect to >NUL or test if a directory exists by asking "if exist directoryname\nul",
or all the documentation that says to create a file with "copy CON ...".
"Why would somebody ever want to do that?" you might ask. Well, this is a common appearance
for floating toolbars. (But aside from that case, I can't think of any other valid
reason to draw a window as active even though it isn't.)
Fortunately this is easy to do. Just add this line to the WndProc of
our scratch program:
case WM_NCACTIVATE: if (wParam == FALSE) wParam = TRUE; break;
This says, "If Windows asks me to paint my caption bar in the inactive state, turn
around and draw it in the active state."
I had mentioned in passing in a
comment on 10/10/2003 10:07PM that one of the reasons the clock on the taskbar
isn't analog is that some disturbingly high percentage of people (30%? 40%? I forget
exactly) do not know how to read an analog clock.
Yet there is is in the Longhorn sidebar. What gives?
Ah but if you look more closely, the digital time is printed immediately below it.
The first letter of the program is the accelerator and there's nothing you can do
about it. So if you have ten programs by Microsoft, they all use the accelerator "M".
(Yes I hate this too. The first thing I do after installing a Microsoft program is
go into the Start menu and delete the word "Microsoft" from the front.)
For Win32 menus, the ampersand character acts as the marker for the menu accelerator.
For example, you would set your menu text to "Save &As" to set Alt+A as the accelerator
for the menu item.