Holy cow, I wrote a book!
matushorvath was curious about the WINA20.386 file that came with some versions of MS-DOS.
The WINA20.386 file predates my involvement, but I was able to find some information on the Internet that explained what it was for. And it's right there in KB article Q68655: Windows 3.0 Enhanced Mode Requires WINA20.386:
Windows 3.0 Enhanced Mode Requires WINA20.386 Windows 3.0 enhanced mode uses a modular architecture based on what are called virtual device drivers, or VxDs. VxDs allow pieces of Windows to be replaced to add additional functionality. WINA20.386 is such a VxD. (VxDs could be called "structured" patches for Windows.) Windows 3.0 enhanced mode considers the state of the A20 line to be the same in all MS-DOS virtual machines (VMs). When MS-DOS is loaded in the high memory area (HMA), this can cause the machine to stop responding (hang) because of MS-DOS controlling the A20 line. If one VM is running inside the MS-DOS kernel (in the HMA) and Windows task switches to another VM in which MS-DOS turns off A20, the machine hangs when switching back to the VM that is currently attempting to execute code in the HMA. WINA20.386 changes the way Windows 3.0 enhanced mode handles the A20 line so that Windows treats the A20 status as local to each VM, instead of global to all VMs. This corrects the problem.
Windows 3.0 Enhanced Mode Requires WINA20.386
Windows 3.0 enhanced mode uses a modular architecture based on what are called virtual device drivers, or VxDs. VxDs allow pieces of Windows to be replaced to add additional functionality. WINA20.386 is such a VxD. (VxDs could be called "structured" patches for Windows.)
Windows 3.0 enhanced mode considers the state of the A20 line to be the same in all MS-DOS virtual machines (VMs). When MS-DOS is loaded in the high memory area (HMA), this can cause the machine to stop responding (hang) because of MS-DOS controlling the A20 line. If one VM is running inside the MS-DOS kernel (in the HMA) and Windows task switches to another VM in which MS-DOS turns off A20, the machine hangs when switching back to the VM that is currently attempting to execute code in the HMA.
WINA20.386 changes the way Windows 3.0 enhanced mode handles the A20 line so that Windows treats the A20 status as local to each VM, instead of global to all VMs. This corrects the problem.
(At the time I wrote this, a certain popular Web search engine kicks up as the top hit for the exact phrase "Windows 3.0 Enhanced Mode Requires WINA20.386" a spam site that copies KB articles in order to drive traffic. Meanwhile, the actual KB article doesn't show up in the search results. Fortunately, Bing got it right.)
That explanation is clearly written for a technical audience with deep knowledge of MS-DOS, Windows, and the High Memory Area. matushorvath suggested that "a more detailed explanation could be interesting." I don't know if it's interesting; to me, it's actually quite boring. But here goes.
The A20 line is a signal on the address bus that specifies the contents of bit 20 of the linear address of memory being accessed. If you aren't familiar with the significance of the A20 line, this Wikipedia article provides the necessary background.
The High Memory Area is a 64KB-sized block of memory (really, 64KB minus 16 bytes) that becomes accessible when the CPU is in 8086 mode but the A20 line is enabled. To free up conventional memory, large portions of MS-DOS relocate themselves into the HMA. When a program calls into MS-DOS, it really calls into a stub which enables the A20 line, calls the real function in the HMA, and then disables the A20 line before returning to the program. (The value of the HMA was discovered by my colleague who also discovered the fastest way to get out of virtual-8086 mode.)
The issue is that by default, Windows treats all MS-DOS device drivers and MS-DOS itself as global. A change in one virtual machine affects all virtual machines. This is done for compatibility reasons; after all, those old 16-bit device drivers assume that they are running on a single-tasking operating system. If you were to run a separate copy of each driver in each virtual machine, each copy would try to talk to the same physical device, and bad things would happen because each copy assumed it was the only code that communicated with that device.
Suppose MS-DOS device drivers were treated as local to each virtual machine. Suppose you had a device driver that controlled a traffic signal, and as we all know, one of the cardinal rules of traffic signals is that you never show green in both directions. The device driver has two variables: NorthSouthColor and EastWestColor, and initially both are set to Red. The copy of the device driver running in the first virtual machine decides to let traffic flow in the north/south direction, and it executes code like this:
if (EastWestColor != Red) { SetEastWestColor(Red); } SetNorthSouthColor(Green);
Since both variables are initially set to Red, this code sets the north/south lights to green.
Meanwhile, the copy of the device driver in the second virtual machine wants to let traffic flow in the east/west direction:
if (NorthSouthColor != Red) { SetNorthSouthColor(Red); } SetEastWestColor(Green);
Since we have a separate copy of the device driver in each virtual machine, the changes made in the first virtual machine do not affect the values in the second virtual machine. The second virtual machine sees that both variables are set to Red, so it merely sets the east/west color to green.
On the other hand, both of these device drivers are unwittingly controlling the same physical traffic light, and it just got told to set the lights in both directions to Green.
Oops.
Okay, so Windows defaults drivers to global. That way, you don't run into the double-bookkeeping problem. But this causes problems for the code which manages the A20 line:
Consider a system with two virtual machines. The first one calls into MS-DOS. The MS-DOS dispatcher enables the A20 line and calls the real function, but before the function returns, the virtual machine gets pre-empted. The second virtual machine now runs, and it too calls into MS-DOS. The MS-DOS dispatcher in the second virtual machine enables the A20 line and calls into the real function, and after the function returns, the second virtual machine disables the A20 line and returns to its caller. The second virtual machine now gets pre-empted, and the first virtual machine resumes execution. Oops: It tries to resume execution in the HMA, but the HMA is no longer there because the second virtual machine disabled the A20 line!
The WINA20.386 driver teaches Windows that the state of the A20 should be treated as a per-virtual-machine state rather than a global state. With this new information, the above scenario does not run into a problem because the changes to the A20 line made by one virtual machine have no effect on the A20 line in another virtual machine.
matushorvath goes on to add, "I would be very interested in how Windows 3.0 found and loaded this file. It seems to me there must have been some magic happening, e.g. DOS somehow forcing the driver to be loaded by Windows."
Yup, that's what happened, and there's nothing secret about it. When Windows starts up, it broadcasts an interrupt. TSRs and device drivers can listen for this interrupt and respond by specifying that Windows should load a custom driver or request that certain ranges of data should be treated as per-virtual-machine state rather than global state (known to the Windows virtual machine manager as instance data). MS-DOS itself listens for this interrupt, and when Windows sends out the "Does anybody have any special requests?" broadcast, MS-DOS responds, "Yeah, please load this WINA20.386 driver."
So there you have it, the story of WINA20.386. Interesting or boring?
You may have noticed a minor inconsistency between pinning a program to the Start menu and pinning a destination to a program's Jump List. Although pinned items appear at the top of the respective lists, and both the Start menu and Jump List let you right-click an item and select Pin/Unpin, the Jump List also lets you pin and unpin an item by clicking on the pushpin. Why doesn't the Start menu have a pushpin in addition to the right-click menu?
For a time, items on the Start menu did have a pushpin, just like items on Jump Lists. The design had a few problems, however. Start menu items can also have a triangle indicating the presence of a flyout menu, and the presence of two indicators next to an item made the interface look awkward and too busy. And what do you do if an item has only one indicator? Do you right-justify all the indicators? Or do you place the indicators in columns and reserve blank space for the missing ones?
Both look ugly for different reasons. The right-justify-everything version looks ugly because the pushpin appears to keep moving around. The blank-space-if-no-flyout version looks ugly because you have a pushpin hovering in the middle of nowhere. (Imagine trying to click on one of these things: You just have to "know" that the magic click spot for pinning an item is 20 pixels to the left of the far right edge.)
But the real death blow to showing a pushpin for pinning items to the Start menu was the usability testing. Users had trouble figuring out where to click to pin an item or to open the Jump List and frequently got the opposite of what they wanted. Since opening the Jump List is by far the more common operation, it won the battle of the prominent UI affordance, and the option for pinning and unpinning was left to a context menu.
Which, as it happens, is where the pin/unpin option started in the first place.
Chris asked for some stories about what Explorer was like in the early days.
Well, one thing is that the original name of Explorer was Cabinet, continuing the folder/document metaphor by taking all your folders and documents and putting them inside a virtual filing cabinet. (Cabinet was viewed as an update to the Windows 3.1 File Manager program, whose icon as we all know was a filing cabinet.) Some remnants of this old name can be found in places like the CABINETSTATE structure. (Note that this old sense of Cabinet is unrelated to the CAB file format, which is also called Cabinet.)
CABINETSTATE
In the early versions of Cabinet, shortcuts were indicated not by a little arrow overlay but by appending >> to the end of the name. For example, you might see an icon on the desktop called My Computer>>.
The first icon in each folder was a special icon that consisted of an upward-pointing arrow with the name Up One Folder. This was really just a leaky abstraction, exposing the .. directory entry as if it were a real directory.
..
We saw what the original Start menu and taskbar looked like some time ago, back before it was a taskbar, and also saw the precursor to the Start menu.
Carlos wonders why the Windows 95 shell was prototyped as 16-bit code running on the still-under-development 32-bit kernel, USER, and GDI as opposed to being prototyped as fully 32-bit code on Windows NT.
There were a number of reasons, some good, some bad.
One reason was that the Windows 95 shell was being developed by the Windows 95 team, which was an outgrowth of the Windows 3.1 team. That meant that they had Windows 3.1-class hardware. And the hardware requirements of Windows NT were significantly higher than the hardware requirements of Windows 3.1. Here's a table for comparison:
The Windows 3.1 team adhered to the principle that the team members' machines, as a general rule, were as powerful as the recommended hardware requirements. If you asked really nicely, you were permitted to exceed that, but not by too much, with one notable exception. Think of it as performance dogfood. If Windows was unusable on the stated recommended hardware requirements, the entire team felt it because that's what they were running. (When Windows 95 shipped, my primary machine was a 486/DX50 with 8MB of RAM. My test machine was a 386 with 4MB of RAM. The combined computing power and storage capacity of all the machines in my office is now exceeded by your cell phone.)
Okay, so you just finished Windows 3.1, and all of the team members currently have 4MB machines, with a few lucky people that have a whopping 8MB of RAM. If you decided to do your prototype work on Windows NT, that would mean tripling the amount of memory in most of the computers just to meet the minimum requirements for Windows NT. And you can't say that "Well, you would have had to pay for all that RAM anyway," because look at that chart: Windows 95's final hardware requirements were still lower than Windows NT's minimum!
Spending all that money to upgrade the computers for something that was just a temporary situation anyway seemed like a bad way of spending your hardware budget.
From the software development side, prototyping the new shell on Windows NT was not practical because Windows 95 introduced a whole bunch of new features to Win32, features which didn't exist in Windows NT. Part of the goal of the prototype was to exercise these new features, things we take for granted nowadays like RegisterClassEx and WM_MOVING and the Close button in the upper right corner. Those features didn't exist in Windows NT; if you wanted to develop the prototype on Windows NT, somebody would have had to port them and build a special "throwaway" version of Windows NT for the Windows 95 team to use. That means devoting some people to learning a whole new code base and development environment (and buying lots more hardware) to add features that they had no intention of shipping.
RegisterClassEx
WM_MOVING
It was much more cost-effective to do the prototyping of the Windows 95 shell on Windows 95. You could see if a design led to poor performance and deal with it before things went too far in the wrong direction. You could use those fancy new functions in kernel, USER, and GDI, which is great because that meant that you would start finding bugs in those fancy new functions, you would start finding design flaws in those fancy new functions. If the shell team needed a new feature from the window manager or the kernel, they could just ask for it, and then they could start using it and file bugs when it didn't work the way they wanted. All the effort was for real. Nothing was being thrown away except for the stuff inside #ifdef WIN16 blocks, which was kept to a minimum.
#ifdef WIN16
All through the shell prototyping effort, the code was compiled both with and without #define WIN16, and as the kernel team worked on supporting 32-bit processes, they had this program sitting there waiting to go that they could try out. And not some dorky Hello world program but a real program that does interesting things. (They couldn't use any of the Windows NT built-in programs because those were Unicode-based, and Windows 95 didn't support Unicode.)
#define WIN16
Maybe those were bad reasons, but that was the thinking.
One of the continuing compatibility problems that plagued Direct3D was the way it reported texture formats. Historically, the way an application checked which texture formats were available was by calling EnumZBufferFormats and passing a callback function which is called once for each supported format. The application's callback made some sort of decision based on the information it received. The problem was that any time a new format was added, a bunch of programs ended up not working. Either the new format confused them, or the change in the order of the formats violated some assumption. For example, they may have assumed that if a video card supports R8G8B8 format, then it will always be the first one in the list.
EnumZBufferFormats
For a time, the compatibility strategy was to try to detect what flavor of Direct3D the application was designed for and manipulating the list of supported formats in a way to keep that application happy, say by ordering the formats in a particular way or suppressing some formats from the list.
In Direct3D 8, a new direction was taken: Ask, don't tell.
Instead of the application being told what formats are available, the application asks, "Do you support format X?" and Direct3D answers "Yes" or "No." This solves both types of problems: Applications never saw a format they didn't expect, because if they didn't expect it, they would never ask for it in the first place. And applications always saw the supported formats in the order they requested, because the application chose what order they asked for them.
The main casualties of the new design were diagnostic programs which listed technical details of your video card. They no longer were able to get a list of all supported formats; instead, they had to have a table of all the formats and ask for them one at a time.
There was one company that objected to this new design because they wanted their program to support all texture formats, even the ones that didn't exist at the time the program was written. This is just another variation of Sure, we do that. "Oh look, this video card supports pixel format 826. I'm going to use it! Just one question, though. What's pixel format 826?"
They broke their problem into two parts and were asking for help with the first part, unaware that even if the managed to solve that part, they were stuck with the impossible second part!
Commenter Ivo wants to know if the RegisterClipboardFormat function returns a UINT, why is the CLIPFORMAT data type defined to be a WORD? Since a WORD is smaller than a UINT, you have to stick in a cast every time you assign the result of RegisterClipboardFormat to a CLIPFORMAT.
RegisterClipboardFormat
UINT
CLIPFORMAT
WORD
Rewind to 16-bit Windows. Back in those days, a UINT and a WORD were the same size, namely, 16 bits. As a result, people got lazy about the distinction. Six of one, a half dozen of the other. (People are lazy about this sort of distinction even today, assuming for example that UINT and DWORD are the same size, and in turn forcing UINT to remain a 32-bit integer type even on 64-bit Windows.) The RegisterClipboardFormat function came first, and when the OLE folks wanted to define a friendly name for the data type to hold a clipboard format, they said, "Well, a clipboard format is a 16-bit integer, so let me use a 16-bit integer." A WORD is a 16-bit integer, so there you go.
DWORD
This mismatch had no effect in 16-bit code, but once Win32 showed up, you had a problem since 32-bit Windows expanded the UINT type to 32 bits. Not only does keeping a CLIPFORMAT in a WORD create the need for all this casting, it also leaves two bytes of padding in the FORMATETC structure. Strike two.
FORMATETC
Yeah, basically, it sucks.
Commenter Vilx- wondered why animated GIFs weren't used as the animation format for the shell animation common control. After all, "they are even more lightweight than AVIs."
Animated GIFs are certainly more lightweight than general AVIs, since AVI is just a container format, so decoding a general AVI means decoding any encoding format invented now or in the future. On the other hand, the shell common control imposed enough limits on the type of AVIs it could handle to the point where what was left was extremely lightweight, certainly much more lightweight than an animated GIF.
Think about it: To use an animated GIF, you need a GIF decoder. And a GIF decoder is already significantly larger (both in terms of code and memory) than the RLE-8 decoder. Also significantly more complicated, and therefore significantly more likely to have bugs. Whereas RLE-8 is so simple there isn't much that can go wrong, and the RLE-8 decoder had been around since Windows 3.0, so it was already a known quantity. All you have to do to invoke the RLE-8 decoder is call SetDIBitsToDevice. One line of code is hard to beat.
SetDIBitsToDevice
Windows 95 did not come with a GIF decoder. Remember, Internet Explorer 1.0 did not come with Windows 95; it was part of the Plus! pack. As I recall, at the time Windows 95 released to manufacturing, the Plus! pack was still under development. (And at the time the animation common control was being designed, Internet Explorer didn't exist. Heck, Mosaic didn't exist!) Plus the fact that the common controls were available in both 16-bit and 32-bit versions—in fact it was the 16-bit versions that were written first since Windows 95 didn't have good Win32 support at the start of the project. More accurately, Windows 95 didn't have any Win32 support at the start of the project.
So I'm kind of amused by the description of GIF as a lightweight animation encoding algorithm. Compared to RLE, the GIF format weighs a ton!
Commenters Mick and Nick (you guys ever considered teaming up and forming a morning radio show?) are interested in the life story of the SwitchToThisWindow function.
SwitchToThisWindow
The SwitchToThisWindow was originally added in enhanced mode Windows 3.0 in order to support switching out of fullscreen MS-DOS sessions. Recall that enhanced mode Windows 3.0 was actually three operating systems in one: There was a 32-bit virtual machine manager, and inside one virtual machine ran a copy of standard-mode Windows,¹ and inside all the others ran a copy of MS-DOS. This mean that when you pressed a key when in an MS-DOS session, the keyboard interrupt went to the MS-DOS program and not to Windows.
When you pressed Alt+Tab, some crazy magic had to happen. The virtual machine manager had to "un-press" the Alt key in the MS-DOS program, then synchronize the shift states of the Windows virtual machine to match the one from the MS-DOS virtual machine. (For example, if you had the shift key down in the MS-DOS virtual machine, it had to simulate pressing the shift key in the Windows virtual machine so they two shift states were back in sync.) And then it could simulate pressing the Tab key, at which point the Windows virtual machine would see the Alt+Tab sequence and put up the Alt+Tab interface.
That's how things worked if you were running in a windowed MS-DOS session. But if you were in a fullscreen MS-DOS session, things worked differently. Switching back to Windows would mean a display mode reset (which can take a second or longer), and then all the applications on your desktop had to redraw themselves (and probably paging quite a bit in order to do so). This definitely failed to meet the responsiveness people expected from Alt+Tab, so the virtual machine manager pulled a trick: If you pressed Alt+Tab while in a fullscreen MS-DOS session, then instead of switching back to the Windows virtual machine, the virtual machine manager displayed a text-mode version of the Alt+Tab interface.
I will stop to let the craziness of that sink in: The virtual machine manager had its own Alt+Tab interface built out of text mode.
Anyway, when you finally released the Alt key and completed the Alt+Tab sequence, the virtual machine manager needed to tell Windows, "Hey, like, pretend that an Alt+Tab thingie just happened, okay?"
That is what the SwitchToThisWindow function was for. It was the function the virtual machine manager called to tell Windows to switch to a window as if the user had selected it via Alt+Tab (because that is, in fact, what the user did, just via the text-mode interface rather than the graphical one).
A similar thing happened if you pressed Alt+Esc (or Alt+Shift+Esc in a fullscreen MS-DOS session. That's why there's a second parameter to indicate whether the switch should be done "in the style of Alt+Tab" or "in the style of Alt+Esc."
The function was undocumented because it existed only for the virtual machine manager to call in order to coordinate its actions with Windows user interface so that you had one big happy Alt+Tab family.
The text-mode Alt+Tab interface disappeared in Windows 95, but the SwitchToThisWindow function hung around because it wasn't causing anybody any harm, and there was at the time no formal process in place to deprecate and eventually remove an API, not even an internal undocumented one.
In the Windows XP SP1 timeframe, a bunch of lawyers decided that some functions in Windows needed to be documented. The precise rules for determining which functions needed to be documented and which didn't need to be documented were rather complicated. (Some people applied an algorithm different from the ones those lawyers used and came up with a list of functions that are "missing", when all that they really came up with is a list of functions different from the list those lawyers came up with.)²
Anyway, the SwitchToThisWindow function got caught in the dragnet, so it got documented. Mind you, like it says right at the top of the documentation, there is no guarantee that the function will continue to exist; it can vanish at any time. Although there is documentation, it has the logical status of an internal function, and internal functions have a tendency to change or vanish entirely. Perhaps someday a new chapter will be added to the life story of SwitchToThisWindow: "The SwitchToThisWindow was removed in Windows Q" for some value of Q.
Footnotes
¹ Not true, but true enough. Don't make me bring back the Nitpicker's Corner.
² I will delete any comments on the subject of the algorithm by which those lawyers determined which functions needed to be documented, or on the documentation itself.
Bonus chatter: As far as I can determine, SwitchToThisWindow just does a SetForegroundWindow on the window you're switching to, possibly posting it a WM_SYSCOMMAND/SC_RESTORE message, and moving the previous foreground window to the bottom of the Z-order if switched via Alt+Esc. It doesn't provide any special secret sauce for bypassing the normal foreground activation rules. The process that calls SwitchToThisWindow still requires foreground-change permission.
SetForegroundWindow
WM_SYSCOMMAND
SC_RESTORE
When you pin items to the Jump List, they go to the top of the menu that appears when you right-click the Taskbar item. Why not put the pinned items at the bottom? After all, over 98% of users leave the taskbar at the bottom of the screen, so putting the pinned items at the bottom of the list maintains a consistent position relative to the Taskbar icon, permitting the development of muscle memory.
The Taskbar folks tried out all sorts of ideas for ordering the Pinned items, the Frequent/Recent items, the Tasks, and the system commands on that one pop-up menu. And these ideas were put to the test: With real users.
Usability tests are one of those things that every developer should go through. You think you've designed a system that is intuitive and easy to use, and then you are shocked back into reality as you watch user after user struggle with your masterpiece.
In this case, the usability tests revealed that most people look for the important items at the top of the list. When they went looking for their pinned items, they started at the top. And often, if it wasn't there, they simply gave up.
The resulting order of items (Pinned, Frequent/Recent, Tasks, system) reflects the results of these studies. Since Pinned items go at the top, that leaves the opportunity to put the system commands at the bottom so that they have a consistent location. For example, Close is always the last item. That's where your muscle memory can develop. The Tasks go next to the system commands since they act like application-specific extensions of the system commands. Tasks also do not change, so that permits muscle memory to extend further into the menu.
Once the other three items are placed, the decision of where to put the Frequent or Recent items is forced: It goes beneath the Pinned items and above the Tasks.
There you have it: The order of the items in the right-click pop-up menu for Taskbar icons. There's a method to its madness. And it was decided by you, the users.
Pre-emptive hate: Yes we know that you think messing with the taskbar button right-click menu was the stupidest idea on the planet.
Some time in the early part of this century, somebody sent a message to the Windows NT Development Announcements mailing list at Microsoft. It went something like, "My car was parked in «location X» and somebody ran into it and didn't leave a note. Does anybody have any information about this?"
Now, one thing you need to know is that the Windows NT Development Announcements mailing list has the entire Windows division as members. We're talking thousands of people. And the sort of announcements sent to the alias are not the "somebody dinged my car" type of announcements. They are announcements like "We will be reformatting the scratch server on Tuesday." Important stuff that everybody on the team needs to know. And it's most certainly not for discussions.
Anyway, somebody replied to the message saying something like "Yeah, my car was parked in the same area and it got damaged, too." And then somebody else decided to be silly and wrote, "I parked my car in Germany once and it got damaged. I wonder if that's related."
Before things could spiral out of control, Jim Allchin, vice president of Windows, stepped in and sent a message to everybody. "Stop replying to this thread."
That shut the thread down really quickly. Nothing like your vice president telling you to shut up to get you to shut up.
There was one reply that came through, though. It was a reply to Jim's message saying to stop replying. The person wrote, "Yes sir, captain sir. Saluting as I type, sir."
I have no confirmation that anybody ever saw that person alive again.
Bonus history: Today is the 14th anniversary of the infamous Bedlam Incident.