It crippled DOS quite half-heartedly.
As for why, Microsoft has apparently been intending to deprecate DOS (and Win16) in favour of Windows NT for quite some time0, for both technical and business reasons: I estimate it was since at least the inception of Windows 95, and possibly even earlier. They couldn’t afford to drop support for DOS software right away, though; after all, most of the value proposition of DOS (and any operating system ever) came from the programs written for it. If they ceased supporting them, Digital Research for example (or actually Novell at this point, if I remember correctly) would be more than eager to fill the void. So Microsoft painstakingly maintained backwards compatibility with DOS programs, while simultaneously incentivising application vendors to write new software against new, NT-compatible APIs that, of course, only Microsoft provided. They ported the Win32 API, created for Windows NT 3.1, first to DOS-based Windows 3.x (as Win32s) and then to Windows 95. They unified NT and 9x driver architecture with the Windows Driver Model; it’s telling that on the 9x side, the driver providing WDM support was named NTKERN.VXD
. The clearly wanted to move away from DOS to NT, but needed to do so gradually.
Maintaining compatibility with DOS meant that Microsoft had to keep the basic architecture that began with Windows 386 Enhanced Mode unchanged: a hypervisor (the Virtual Machine Manager), initially launched in a DOS environment, that takes over the responsibility of managing hardware from DOS drivers, loads its own virtual device drivers (VxDs) and then oversees a number of virtual machines that mimic the DOS ABI and physical hardware just well enough to allow most DOS programs to run unmodified. Any change to this basic design would risk introducing incompatibilities, which Microsoft wanted to avoid. When DOS and the VMM were integrated into a single product, Windows 95 (the VMM being launched automatically at boot time), a number of backwards compatibility features were introduced to keep supporting software that couldn’t run under the supervision of the VMM: single-application mode, an option to boot to a command prompt without launching Windows, and even an option to boot to a previously-installed version of MS-DOS.
Millenium in particular was a pretty rushed release; I remember reading somewhere that Microsoft wanted to switch the ‘consumer’ line of Windows to the NT codebase already back then, but apparently they felt they weren’t quite ready yet, so they came up with yet another DOS-based release to fill the gap until the switch was realised with Windows XP. They still could not afford to change the architecture too much; any radical change would risk breaking compatibility with existing software, which this time meant VxDs. So to continue with their deprecation plan, Microsoft simply removed single-application mode and the ability of the DOS component to do anything else but launch the VMM.
To restore DOS mode support, it suffices to replace the DOS component of Windows with a more functional version, and remove some other behaviour interfering with it. This requires patching three files: IO.SYS, COMMAND.COM and REGENV32.EXE.
IO.SYS
IO.SYS is the file containing the DOS kernel; it is the first file loaded and executed, straight from the boot sector. Unlike Windows 95 and 98 which use the same IO.SYS file in all situations, in Windows Me this file comes in multiple versions, of which I am going to highlight three:
The usual ‘crippled’ version, used to boot from hard disks.
This version ignores CONFIG.SYS and AUTOEXEC.BAT completely, won’t boot to a real mode command prompt and will always launch the VMM (i.e. execute %winbootdir%\SYSTEM\VMM32.VXD
instead of %winbootdir%\COMMAND.COM
). Otherwise though, it contains a fully-functional DOS kernel capable of running any DOS program. If one were to replace VMM32.VXD with some other executable, IO.SYS will happily load that instead. (Although it can’t just be the original COMMAND.COM: see below for that.)
The ‘Emergency Boot Disk’ version, used to boot from floppies.
This version can only boot to a command line and cannot be used to boot off a hard disk. It fully supports booting into real mode MS-DOS (including processing CONFIG.SYS and AUTOEXEC.BAT files), as that is its sole purpose: the boot menu (accessible via the F8 or Ctrl key) includes only a single item, ‘Normal’, which behaves just like ‘Command prompt only’ did in earlier versions. To actually start Windows from this version, one has to invoke WIN.COM, either manually or from inside AUTOEXEC.BAT. It is likewise a mostly fully-functional DOS, albeit it lacks serial and parallel port drivers that are present in the hard-disk version; the AUX
, PRN
, COMn
and LPTn
file names are still reserved, but the drivers are vestigial and always return failure.
In 32-bit Windows XP and later versions, diskcopy.dll
contains a copy of this version, altered only to remove the Windows Millenium branding in error messages. The un-branding was pretty half-hearted, though: the boot splash logo, for example, is still there, and the VER
command of COMMAND.COM still reports the version as ‘Windows Millenium’.
The version used to boot from the Windows Me installation CD.
This version is similar to the previous one: it also prevents booting off a hard disk, but is otherwise the most similar to IO.SYS of earlier Windows versions. It includes the full boot menu and can actually boot Windows by itself (without having COMMAND.COM do it). The serial and parallel port drivers are still non-functional, though.
The patch, applied to either of the latter two versions, simply disables the boot device check and allows hard disk boot to go through. Since Ross Ridge’s answer contains a detailed disassembly already, I’m not going to repeat it here; this answer is long enough as it is.
There are even reports of the Windows Me installation CD containing, stashed away in CAB files, a number of alternative versions of this file (and of COMMAND.COM) that don’t require any patching. (They have fully-functional port drivers, too.)
COMMAND.COM
As for COMMAND.COM, the file is identical on the hard disk and the EBD. The problem with this file is that if it detects that DOS has booted from a hard disk, it will refuse to run, unless in it also detects it’s running inside a DOS box. The patch modifies COMMAND.COM so that the result of this check is ignored.
The patched code is as follows:
seg000:2223 mov bx, 1
seg000:2226 mov ax, 1683h
seg000:2229 int 2Fh
seg000:222B cmp bx, 1
seg000:222E jnz short ?ok
seg000:2230 mov ax, 160Eh
seg000:2233 mov dl, 0
seg000:2235 mov bl, 6
seg000:2237 int 2Fh
seg000:2239 or ax, ax
seg000:223B jnz short ?ok
seg000:223D cmp dl, 3
seg000:2240 jnz short ?ok ; ← the patched byte
seg000:2242 mov ax, 160Eh
seg000:2245 mov bl, 3
seg000:2247 int 2Fh
seg000:2249 mov dx, ds:?msg_please_reboot
seg000:224D call ?print_msg
seg000:2250
seg000:2250 ?hang:
seg000:2250 jmp short ?hang
seg000:2252
seg000:2252 ?ok:
First, COMMAND.COM checks if it is running inside a Windows DOS box; it does this by calling interrupt 0x2f service 0x1683 that returns the virtual machine ID in the BX register. If Windows is not running, the register is unmodified and keeps the value 1 set up before the call; inside a DOS box, the returned value is greater than 1. (The call may also return 1 if COMMAND.COM is running in the system VM; this may happen if %winbootdir%\SYSTEM\KRNL386.EXE
is replaced with a copy of COMMAND.COM, like described in Andrew Schulman’s Unauthorized Windows 95.) If the value in the register is different from 1, the rest of the code is skipped and COMMAND.COM starts normally. Next, COMMAND.COM uses an undocumented interrupt 0x2f service 0x160e subfunction 6 to determine what drive the system was booted from. If the call is unsupported or returns something other than 3 (drive C), the rest of this code is again skipped. Otherwise, COMMAND.COM uses subfunction 3 to disable the boot splash screen, then it displays a message "Please press CTRL+ALT+DEL to restart your computer" and hangs the system.
(Amusingly enough though, COMMAND.COM still contains code that will invoke WIN.COM after processing AUTOEXEC.BAT if instructed so by IO.SYS.)
The patch makes it so that the result of the last of these checks is ignored, and the code that hangs the system is skipped always.
Another way to avoid problems with this file is to use an entirely different command interpreter (for example, FreeCOM) by putting a SHELL=
statement in CONFIG.SYS. The ‘hidden CAB file’ version of COMMAND.COM on the installation CD also doesn’t contain this code, so it may be used instead.
REGENV32.EXE
Modifying IO.SYS and COMMAND.COM is enough to obtain a functional DOS mode for Windows Me. To make it actually suitable for daily use, however, another file needs to be modified.
While the hard-disk version of IO.SYS will ignore AUTOEXEC.BAT and CONFIG.SYS, the VMM does not quite ignore them. On bootup, both files are scanned for commands that set environment variables and replaced with dummy versions (CONFIG.SYS is emptied, while AUTOEXEC.BAT is modified to contain only SET
commands). This means that all device drivers and TSRs are going to be removed from CONFIG.SYS and AUTOEXEC.BAT if Windows boots even once. To have an MS-DOS mode suitable for daily use, this mechanism has to be disabled.
This task is performed by a program named REGENV32.EXE. The simplest way to disable it is to replace the file names it looks for, so that the actual AUTOEXEC.BAT and CONFIG.SYS files are left untouched. This method is rather crude, but perfectly viable.
0 Look for example how Raymond Chen refers to DOS support in Windows 95 as a mere backwards-compatibility feature. This was written in 2007, so obviously there may be some hindsight bias there: perhaps there is a better source for this.