Why didn’t they use the Space Shuttle to rescue the Apollo 13 astronauts?


Many decisions make sense only in the context of history.

Much like the moviegoers who were puzzled why NASA didn't just use the Space Shuttle to rescue the Apollo 13 astronauts, computer users of today, when looking back on historical decisions, often make assumptions based on technology that didn't exist.

Consider, for example, pointing out that the absence of a console subsystem in Windows 3.1 was no excuse for not porting the ipconfig program as a character-mode application. "Sure maybe you didn't have a console subsystem, but why not just use the DOS box?"

The MS-DOS prompt is a virtual machine running a copy of MS-DOS. Since it's a virtual machine, as far as the MS-DOS prompt is concerned, it's just running all by its happy self on a dedicated computer running MS-DOS. In reality, of course, it's running inside a simulator being controlled by Windows, but the point of the simulation is so that old applications can continue to run even though they think they're running under MS-DOS.

"There wasn't any security in place with Win 3.1, so any program run from a DOS box should have been able to affect anything on the system."

Since the MS-DOS prompt ran in a virtual machine, everything it did was under the supervision of the virtual machine manager. If it tried to access memory it didn't have permission to access, an exception would be raised and handled by the virtual machine manager. If it tried to execute a privileged instruction, an exception would be raised, and the virtual machine manager would step in with a "Nope, I'm not going to let you do that" and terminate the virtual machine. In a sense, programs running in the MS-DOS prompt actually ran with more protection and isolation than Windows applications running on the desktop, because Windows created a whole separate universe for each MS-DOS prompt.

One of the consequences of virtualization is that programs running in the MS-DOS prompt are plain old MS-DOS applications, not Windows applications. There is no Windows API in MS-DOS, so there is no Windows API in the MS-DOS prompt either. (It's like running Windows inside a virtual machine on your Linux box and wondering why your Windows program can't call XCreateWindow. It can't call XCreateWindow because that's a function on the host system, not in the virtual machine.)

Okay, but let's suppose, just for the sake of argument, that somebody poked a hole in the virtual machine and provided a way for MS-DOS programs to call WinSock APIs.

You still wouldn't want ipconfig to be an MS-DOS program.

Recall that Windows 3.1 ran in one of two modes, either standard mode or enhanced mode. Standard mode is the version designed for the 80286 processor. It didn't have virtual memory or support for virtual machines. When you ran an MS-DOS prompt, standard mode Windows would freeze all your Windows programs and effectively put itself into suspended animation. It then ran your MS-DOS program (full-screen since there was no Windows around to put it in a window), and when your MS-DOS program exited, Windows would rouse itself from its slumber and bring things back to the way they were before you opened that MS-DOS prompt.

It would kind of suck if getting your computer's IP address meant stopping all your work, shutting down Windows (effectively), and switching the video adapter into character mode, just so it could print 16 characters to the screen.

"Well, who cares about standard mode Windows any more? Let's say that it only works in enhanced mode. Enhanced mode can multi-task MS-DOS prompts and run them in a window."

Recall that the minimum memory requirements for Windows 3.1 in enhanced mode was 1664KB of memory. Given that each MS-DOS box took up about 1MB of memory, you're saying that displaying 16 characters of information is going to consume over half of your computer's memory?

"Okay, helpdesk wants to know my IP address so they can troubleshoot my computer. In order to do that, I have to run this program, but first I need to save all my work and exit all my programs in order to free up enough memory to run the program they want me to run."

Better to just write a simple Windows application.

Bonus commentary: 640k asks, "Why wasn't winipcfg called ipconfig?"

Right. "Let's have two completely different and incompatible programs with the same name." See how far you get with that.

Comments (44)
  1. Dan Bugglin says:

    IIRC the net command in Windows for Workgroups did not allow you to run it under the MS-DOS Prompt, you needed to exit Windows first.  Now I know why.

  2. Mark says:

    In case you haven't already seen it, http://apollo13.spacelog.org/

  3. Chad Chisholm says:

    The space shuttle can't get anywhere near the moon.

  4. Gabe says:

    Perhaps a better question is why winipcfg wasn't ported to NT. The ipconfig program requires you to start a command prompt and then run ipconfig, sometimes multiple times (/release,/renew). Heaven forbid that your console window's buffer is smaller than the command's outpu. And you can't just tell somebody "Click Start, click Run, enter ipconfig" because it will immediately close the console window! Determining somebody's IP address over the phone is far more complicated than it was in the olden days.

  5. GWO says:

    Which still leaves the question "Why didn't Windows 3.1 have a console subsytem, distinct from the DOS Box, when such a system had proved its worth a million times over in NT"?

    [Why didn't they use the Space Shuttle to rescue the Apollo 13 astronauts? -Raymond]
  6. alexcohn says:

    @Gabe: why what could prevent you from copy wincfg.exe to your NT?

  7. John Topley says:

    @GWO Perhaps because Windows 3.1 predated Windows NT?

  8. Joshua says:

    @GWO: doesn't Windows 3.1 predate NT?

    Personally I'd have poked a tiny hole in the VM where a certain invalid instruction would have been an API call, but that's just me.

    BTW, the Windows application can call XCreateWindow if it knows its address (the VM we use has more holes than the DOS Box VM, and XCreateWindow is somewhere in kernel address space).

  9. GWO says:

    @GWO: doesn't Windows 3.1 predate NT?

    Developmentally, they are contemporaries, but point taken — though VMS, which heavily influenced NT's design had a console subsystem — and almost every successful multi-user operating system in the entire history of the world did too — proving its worth about a zillion times over, from the early 1970s. Now .. why didn't Windows 95 have a console subsystem?

  10. yuhong2 says:

    Actually there was INT 2F AX=1685 which allowed you to call between virtual machines. It would be pretty useless for this purpose however, since it does the call at interrupt time and requires that you already have an known address to call.

  11. Mathieu Garstecki says:

    GWO: because AFAIK, Windows 3.1 didn't even have the notion of subsystems. Win95 and 98 neither, they emulated the DOS console if I remember well. Subsystems are a core feature of the NT architecture, and were probably too hard to port back tn the "old", DOS-based architecture.

  12. Sunil Joshi says:

    @Joshua

    They did that already – they used ARPL I believe.

    It was certainly possible (in Win 3.1 and Windows 9x) to write a VxD which provided an interface to DOS clients running in a VM. This could have provided the information for a ipconfig-like client. But it seems like an awful lot of work to go through compared to the choosen solution.

  13. Skyborne says:

    @Joshua re calling XCreateWindow: in the systems I am familiar with, this is part of Xlib or perhaps XCB in these modern times; both are libraries running in userspace that's linked into your app.  Calling XCreateWindow is nowhere near issuing a syscall (into either the guest's or host's kernel), and in the end, the X server that handles the request… also runs in userspace.

    I would further claim that, even if you swap XCreateWindow for an actual syscall, if your virtual machine manager lets guest userspace call host kernel code with a single CALL instruction, it's failing at being a virtual machine.

  14. Maurits says:

    Easiest way to rescue the astronauts: keep them on the ground in the first place.

  15. rupert says:

    IP-Addresses are only 15 chars long, not 16.

    [Don't make me bring back the nitpicker's corner. -Raymond]
  16. Dan Bugglin says:

    IP Addresses are 4 bytes long.  They are typically represented as a string of dot-delimited decimal numbers but they can be stored in a 32-bit integer easily enough.  Of course I think official APIs all take strings anyway (possibly to accept other forms of addresses like IPv6 or hostnames?).

  17. Bob says:

    @rupert:  I expect that he was counting the n at the end.

  18. AsmGuru62 says:

    @rupert: that depends how to look at it. For example: char buf[15] will NOT BE ABLE to hold some of IP-addresses. char buf[16] on the other hand WILL hold all of them.

  19. ErikF says:

    PC Magazine experimented with DPMI and a Windows helper app to allow a DOS program to call into Windows. It worked for simple cases, but the conclusion was that while DPMI was an adequate memory manager, it left a lot to be desired for any serious use. ISTR that the best solution to the "I need a console program for Windows 3.1" was to use the fake consoles that were provided by the compilers at the time (QuickWin from Microsoft and Easy Win from Borland.)

  20. Joshua says:

    @Skybourne, I believe Raymond blogged about a similar condition.

    A pure VM would have been a bad solution. We wanted to interact with the host filesystem and desktop. Oh, and our VM doesn't actually emulate memory protection, just memory mapping, so the userspace code can execute a jmp to kernel.

  21. Skyborne says:

    @Joshua: the core definition of VM as I understand it is that it hides the host environment from the guest one.  If you can call host code directly from the guest, then you don't have a VM, because you're interacting with the un-virtualized machine.  Like a process.

    Also, if your system isn't running unmodified Windows as a guest, then it doesn't meet the conditions Raymond established in the comparison to begin with, regardless of how you define VM.

  22. James Schend says:

    @GWO: From a different perspective, because Windows 95 wasn't a multi-user operating system, and the most successful single-user OS at that point was Macintosh, which had no command line environment at all. So using your same logic, but applying it to single-user OSes, Windows 95 should have had no CLI.

    @Raymond: Maybe you should start a "totally missed the point" box and feature Chad Chisholm.

  23. ebyrob says:

    So um… this is probably totally off-topic and all that but I'm unable to find another place to post…

    I hit "Contact Me" and it goes to "Suggestion Box 4" link is – blogs.msdn.com/…/10040074.aspx

    Unfortunately that article is apparently sealed to comments…

    I wouldn't ordinarily care but I'd really like to comment on a snippet of code in "Cleaner, more elegant, and harder to recognize" which of course is closed since it's really old.

    My question is, what's wrong with the first version of the C# example?

    NotifyIcon CreateNotifyIcon()

    {

    NotifyIcon icon = new NotifyIcon();

    icon.Text = "Blah blah blah";

    icon.Visible = true;

    icon.Icon = new Icon(GetType(), "cool.ico");

    return icon;

    }

    I mean, I'm running it in a debugger (console C# app) and it seems to work just fine.  If an exception is thrown nothing appears on the screen and my test app goes on it's merry way.  Is there some memory getting allocated here that isn't properly cleaned up that isn't immediately obvious?  (it is interesting to Note that when the application exits the icon doesn't go away, but that only occurs when there's no exception)

    As to the other case of adding an item to a collection BEFORE properly initializing it…  That's a multi-thread problem as well as an exception problem.  (Purposely storing partially initialized data is wrong in any language, especially a managed language!!)

    But really, I'm very very confused by this example.  What's wrong with the original 'bad' CS code?!?!?!  

  24. Anonymous Coward says:

    People complain that Winipcfg is not a console program, but a nice little window? Man.

    Nowadays as far as I can tell, the information it shows is available in the dialogues in the network connections folder in the control panel.

    Still, I think that a determined idiot might have been able to establish a Windows <-> DOS box communication channel via a file.

    @ebyrob: the link you posted doesn't appear to lead to anything relevant to your question.

  25. JJJ says:

    @ebyrob:  You didn't get the hint from the closed suggestion box?

  26. Me says:

    @ebyrob: The bad example shows the notification icon before setting the .Icon property.  If new Icon() throws an exception, you'll end up with an blank icon on the task bar.  In other words, it's fairly obvious when you're not checking error conditions from error-code-based code, and not so obvious when you're using exception-based-code.

  27. Teo says:

    I don't remember the exact details, but I have a vague idea that the dosbox inside Windows had quite many holes. For sure, it could use int 31h to talk to the DPMI server (which essentially was the Windows VMM, right?). It also could use extended int 21h functions to query Windows version. And I think that the whole (or substantial) part of Win API was accessible through int 2fh, but I am not sure if that was in win 3.1 or win 95. Raymond, I'd be very happy if sometime in the future you write a cool article about what windows functionality was accessible to dos programs back in the good old days.

  28. AP² says:

    "I wonder how well DOOM would have worked if it restricted itself to stdin/stdout."

    Not that bad, actually: doom.wikia.com/…/Text_Mode_Doom

  29. yuhong2 says:

    [And in fact reading stdin/stout was what Windows 2.0 did. The problem is that very few DOS apps actually restrict themselves to stdin/stdout. Most of them use the BIOS or access video memory directly. (I wonder how well DOOM would have worked if it restricted itself to stdin/stdout.) -Raymond]

    Which killed the non-IBM PC compatible MS-DOS machines. Trivia: DOS was originally developed on a S-100 8086 machine by SCP, probably before the IBM PC project even existed. And was painful for Digital Research who had the multi-tasking MP/M.

  30. yuhong2 says:

    [And in fact reading stdin/stout was what Windows 2.0 did. The problem is that very few DOS apps actually restrict themselves to stdin/stdout. Most of them use the BIOS or access video memory directly. (I wonder how well DOOM would have worked if it restricted itself to stdin/stdout.) -Raymond]

    And BTW, how did Windows 2.x multitask DOS apps?

    [Coöperatively. You have enough information in this very comment to fill in the rest. -Raymond]
  31. Cheong says:

    I'm kind of confused regarding the context of discussion…

    Is there even TCP/IP exist in the days of Win3.1? I think all we have is IPX/SPX, AppleTalk, etc…

    Actually there seems to be a limited version of ipconfig in DOS LAN Manager v2.2+ (not supporting any of the switches).

    Also, if that's what Microsoft want, they can expose Windows features in VM as interrupt extensions.

    But yes, it would be bad if I have to exit all other programs to free enough memory to run the program to find my ip address (or whatever basic information.

  32. Crescens2k says:

    Cheong:

    Windows 3.x supported TCP/IP by means of vendor supplied stacks. This means that it was available but not as a built in part of Windows itself. It wasn't until around 1994 that Microsoft themselves provided a supported TCP/IP stack for Windows 3.x, and full support was added to Windows 95.

  33. Gabe says:

    GWO: Windows 3.1 didn't have a console subsystem probably for the same reason that the X Window System doesn't. They are both just programs that you already run from a console. The idea being, if you wanted to run a "console app", you wouldn't write it as a windowed application! But what if you want to run an app that doesn't know how to make a window from within the windowing environment? Just write a windowed app that sends keystrokes to the console apps' stdin and displays stdout in a window. In Unix you would call this windowed app "xterm". So why didn't Windows include an xterm-equivalent? The whole point of Windows was to *elminate* obscure command lines, not encourage them!

    [And in fact reading stdin/stout was what Windows 2.0 did. The problem is that very few DOS apps actually restrict themselves to stdin/stdout. Most of them use the BIOS or access video memory directly. (I wonder how well DOOM would have worked if it restricted itself to stdin/stdout.) -Raymond]
  34. keithmo says:

    "…and provided a way for MS-DOS programs to call WinSock APIs."

    I did exactly this way back in 1994 during the Wolverine Project (TCP/IP-32 for WFW). It began as an experiment to see if I could write an MS-DOS app that communicated with the WinSock VXD. It was surprisingly easy to create the plumbing necessary to connect a real-mode library to the VXD entry points. I even had ipconfig working.

    Ultimately, the changes were never committed to the source tree. There was no interest in a technology enabling one to create real-mode MS-DOS apps that could only run in Windows enhanced mode.

  35. yuhong2 says:

    keithmo: Not to mention that the support for Win32 console applications that had full access to most of the Win32 APIs made it obsolete.

  36. ender says:

    There was no interest in a technology enabling one to create real-mode MS-DOS apps that could only run in Windows enhanced mode.

    Wasn't this exactly what Microsoft TCP/IP for Windows 3.1 did? I know it has both ping.exe and ipconfig.exe, which are MS-DOS executables, but will not work unless you start them from a DOS box.

  37. Nick J says:

    As usual; great article; great sense of humor,… ;-)

    And I finally bought your book, after following the blog for a couple of years now I thought it was time to get more juicy details!

    Thanks for the great articles Raymond!

  38. Mike Dimmick says:

    @ebyboy: the icon hangs around after you close the application because icon cleanup is handled by NotifyIcon's Dispose method, which is never called. Explorer doesn't test that icons are valid until the user interacts with them, i.e. it has to send messages to the window that owns them. If it discovers that the window no longer exists it removes the icon.

    Because it's derived from System.ComponentModel.Component, it inherits that class's finalizer. The finalizer will call Dispose(false), which merely does internal cleanup, rather than notifying Explorer to remove the icon. The window that 'owns' the icon, and handles the messages from Explorer, is in fact controlled by the NotifyIcon object, and is destroyed by the call to Dispose(false).

    While the app is still running, the icon will behave unpredictably. After the first GC, the object will still be around because it's been moved to the freachable queue, so the icon will still work. As the finalizer thread processes the queue, to run the finalizers, it will eventually reach the NotifyIcon object's finalizer, run it, and the icon will stop working – but won't disappear until the user interacts with it.

    If you had subscribed to any of the NotifyIcon's events, the object would have a back-link to the object implementing the event handlers, and then the GC behaviour would depend on the lifetime of that other object.

    For proper behaviour, decide which window the icon represents, and add it to that Form's 'components' collection (assuming you're coding with Visual Studio, whose designer will have created a 'components' field of type System.ComponentModel.Container). The Container class calls IDisposable.Dispose on all of the objects that have been added to it, when it is itself disposed. VS generates code to Dispose the 'components' object in the form's (or UserControl's) implementation of Dispose. When you drop a non-visual component implementing IDisposable onto the form surface, it generates code to add the component to the 'components' collection. If you're coding by hand, you can choose to do this, or you can add a member variable to the form (or other component that should own it) and dispose it yourself when the form is disposed.

  39. David Walker says:

    @Alexcohn: licensing issues might prevent you from copying parts of one Windows operating system to another computer.  Wincfg is licensed for the computer on which it was originally installed.  If wincfg was from a retail version, you could maybe uninstall the entire operating system from the computer that wincfg was on, and then copy wincfg to NT.  If it was from an OEM version, you're not allowed to do that (legally).

  40. Maurits says:

    Coöperatively

    <3

  41. 640k says:

    Why wasn't ipconfig called ifconfig?

  42. Gabe says:

    640k: "Why wasn't ipconfig called ifconfig?"

    Right. "Let's have two completely different and incompatible programs with the same name." See how far you get with that.

  43. ebyrob says:

    @Me:

    > …you'll end up with an blank icon on the task bar…

    Ya, OK.  Except it doesn't behave that way.  You get nothing in the task-bar when setting .Visible until .Icon is set.  (.Net 2.0.50727 sp2, I tested two code-paths, valid icon and non-existent icon is there another code-path with a more interesting failure?)  Note: If .Visible caused an empty icon to display before .Icon were set you'd actually have a timing glitch.

    @JJJ – What so the author doesn't ever want to be reached?

    @Mike Dimmick –

    > …While the app is still running, the icon will behave unpredictably…

    Well, so NotifyIcon is disposable, that actually makes all the CS examples really obviously incorrect.  Except the 'broken' CS example is actually pretty darn functionally correct since dispose isn't needed until .Icon property is set and that's the very last thing that happens before return.  Moving .Visible below .Icon is probably more risky since it's clearly got some logic behind it.

    Hmm…  What if all .Net System.ComponentModel.Component objects were guaranteed not to require .Dispose() till after they were added to a live window?

    The note about the icon not going away was really just a jab at the OS bug surrounding task-bar icons… (file handles, by contrast, *do* get cleaned up on process exit.)

    > …and the icon will stop working…

    Mine keeps displaying "blah blah blah" on hover after I force-run the garbage collector…  (Although I always wonder which versions of .Net will implement GC calls like this {})

  44. 640k says:

    Shouldn't be more confusing than "System32".

Comments are closed.