For those of you who are fans of my channel, you all may know that I have an interest in
software preservation and history.
Well, as of late, I’ve been interested in digging into a program nearly everyone has
used as one point or another: Microsoft Word.
While people may have differing opinions about Word, it’s hard to argue that it has had
a tremendous impact not only in just computing, but the digital office space as a whole.
Unlike many of the titans of the early 90s such as WordPerfect, the source code to an
early version of Word is legally available.
In 2014, Microsoft donated the source code of Word for Windows 1.1a, or Winword to the
Computer History Museum.
The Museum, in turn, has made it available for download from their website.
This version of Word was originally released in 1989 for Windows 2.1, and 3.0, and thus
provides an interesting insight into the early days of Microsoft.
That being said, although seemingly simple on the surface, the Word source archives contained
more than a few surprises as I dug into it.
It also has the distinction of being the few examples of a Microsoft product from an era
when OS/2 was considered to be the future of computing!
Yes, there was in fact an era where even Microsoft didn’t think Windows had a future!
Strap yourself in folks, because this is going to be one heck of a journey back to 1989.
As always, this is your host NCommander, and today, I’m going to suffer in pain as we
attempt to compile Word for Windows from OS/2!
… Ok, that probably sounds more epic in my head but let’s get into it!
At this point, I’m guessing most of you have one of two questions: What is OS/2, or
Why OS/2?
Let’s what with the what first: OS/2 was the intended replacement for DOS as product
of the ultimately ill fated venture between IBM and Microsoft.
Originally announced in 1987, OS/2 promised to bring multitasking to the masses, and usher
in an era of graphical applications with its Presentation Manager replacing the clunky
command line.
While graphical user interfaces or GUIs already existed at this point, for the most part,
they were still fairly niche.
OS/2 promised to bring the GUI mainstream to IBM compatible machines.
For the later half of the 80s and early 90s, OS/2 was seen as the “future of computing”.
For a variety of reasons, this future didn’t come to pass.
In truth, the reasons for this are so long I could dedicate a series of videos talking
about the flaws and failures of OS/2 from both a technical and marketing standpoint.
That being said, OS/2 does have real improvements over both DOS, and early versions of Windows.
While it wasn’t a true market success, OS/2 did find a niche as a host platform for software development.
This is a good moment to explain why developing on top DOS can be somewhat painful.
Due to the fact that DOS runs in real mode, it is subject to several limitations, such
as the infamous 640 kilobyte barrier.
This can be best seen if I simply try to build WinWord from DOS.
As shipped from Microsoft, the DOS build tools require the 386MAX memory manager, and on
system start-up, we can see that we have 8 megabytes of memory available.
However, I attempt to build WinWord without a very specific setup, then the build will
fail running out of conventional memory.
This is, in part, due to the inert limitations of real mode applications.
While these problem can be kludged around through the use of DOS extenders, the long
and short of it is that it’s easier to use a more capable environment.
This brings us to the “Why OS/2?” part of the equation.
For this time period, it is likely that most development was done on top of OS/2, and I
wanted to get an idea of what a Microsoft engineer might have experienced.
While I would love to say I had no issues in getting this to work, my first attempt
at booting off the INSTALL disk immediately crashed with a TRAP error.
While it’s not uncommon for older operating systems to go belly up on newer hardware,
the 16-bit versions of OS/2 are notoriously bad about this.
In practical terms, any system faster than a 386 will cause the system to crash on boot.
While there are unofficial patches to fix this, I decided, for the sake of authenticity,
to simply emulate a 33Mhz 386 processor with 8 megabytes of RAM; a truly monstrous
system for the time period.
I would also come to regret that decision.
With an emulated 386 in hand, I successfully made it to the boot splash screen.
Overall, installation is fairly straightforward, although one thing to note is OS/2’s very
small selection of drivers.
Due to this, I was stuck in a low resolution 16-color mode throughout this video.
After a few basic questions, the installation grinded away for a while, and then prompted
me to reboot.
After the system came back up, we’re greeted with what can be only described as the blandest
desktop known to mankind.
It won’t surprise me at all to learn if there was a committee at IBM to keep things
as bland as possible.
Aside from some system utilities, the only application of note is the system text editor,
known as E. There are no games or other applets to be found here.This is compounded by the
distinct lack of native OS/2 software, especially for these early versions.
In addition, for those familiar with early Windows, you might also notice a striking resemblance
to the then upcoming Windows 3.0 in both look and feel, one of the last vestiges of the
IBM-Microsoft partnership.
Besides the rather bland desktop, a single icon exists in the corner labeled DOS
This is icon is OS/2 1.2's feeble attempt at supporting DOS applications.
Until OS/2 2.0, released in 1992, the system was only capable of running one application
at a time in full screen mode.
Furthermore, this was compounded by poor performance, and a lack of sandboxing.
This meant a misbehaving DOS application could hang the entire system.
Of course, we’re here to compile Word from scratch, and not just gork at old operating
systems.
The next question is how we’re going to load the Winword source code into OS/2.
While there are numerous ways to solve this issue, such as making a multipart ZIP archive,
I decided to go with what could be described as the “lazy” option.
Due to the virtual nature of our OS/2 machine: we can simply mount the hard drive under Linux,
and copy the files over.
A few commands later, and we’re ready to restart OS/2.
With the files copied over, we can start examining the download from the Computer History Museum.
The first thing, unfortunately, I need to talk about is the license.
The source code for Word for Windows is under a very restrictive license that essentially
limits the context in which I can talk about it.
Primarily, I can’t show or publish anything beyond short excerpts of code, nor can I publish binaries.
So instead of the usual “here’s a GitHub” link with all my work, for this one, you’ll
have to follow along at home, and take my word for it.
Secondly, the license also requires that any projects, such as this video, be non-commercial in nature.
To comply with that requirement, I pledge not to monetize this video.
With the legal mumbo-jumbo out of the way, let's get down to it
Most of the code to Word is located in the “Opus” folder, which was the codename
for Word for Windows.
As previously alluded to, a full set of tools and compiler binaries are included for use
on both DOS and OS/2.
Interestingly, many of the Opus tools are what are known as family mode binaries.
As the name suggests, family mode binaries, also known as fat binaries are intended to
work both on OS/2 and DOS, similar to how WIndows binaries can also include an optional
DOS component.
We can easily see this by using the DOS window to run makeopus - notice that it runs the
same in either environment!
A closer examination of the tools begins to show unexpected results.
Microsoft’s primary toolchain at the time was Microsoft C and C++ which eventually evolved
to become the modern day Visual C++.
However, the toolchain included within Word for Windows is NOT Microsoft C. Instead, it’s
a custom tool called CSL.
After a close examination, it’s clear that CSL, and many of the tools in the Opus directly
were entirely internal to Microsoft.
What’s truly unique here is that this is not a normal C compiler.
Instead, it’s what’s known as a p-code compiler.
Instead of compiling to native code, it compiles to a special type of bytecode that Microsoft
calls “the embedded language”, or EL.
Instead of running Word directly, the “winword” executable loads a special interpreter which
reads the bytecode and converts it to machine code at runtime.
In modern terms, Word 1.1a could be seen as an early predecessor to Microsoft’s later
.NET, or Sun’s Java Runtime Environment which would come years later.
According to the comments, EL was also used in early versions of Excel, and some research
suggests it was also used in Multiplan.
There is relatively little information about Microsoft’s use of p-code, but I have my
suspiouses on why they used it.
Before we get into that though, it would behoove to actually attempt to compile Word for Windows.
I hinted at it earlier, but compilation is handled by the makeopus tool, which has a
large mydird of options and settings.
The built-in help of makeopus, combined with some loose notes I found on the Internet gave
me the general idea of what I needed to do.
To make a long story short, makeopus needs a special configuration file to define the
build environment.
Helpfully, Microsoft included two example config files; one for release builds and another
for a debug builds.
I started with the release settings file, and edited it to machine our setup.
Beyond that, I also found out I had found that I needed the TOOLS directories added
to the PATH.
I also needed to setup a TEMP directory.
On OS/2, environmental variables are set in CONFIG.SYS.
This is different from DOS, which instead uses AUTOEXEC.BAT for this purpose.
In many ways, using OS/2, especially from a programming perspective is like a bizarro
version of DOS or Windows with many things being similar and yet different at the same
time.
Before I get a bit too philosophical though, we’re ready to try this after a reboot.
Unfortunately, it didn’t take long for errors to go screaming by.
Fortunately, the error is obvious by reading the backscroll: makeopus is trying to load
the DOS versions of the tools.
This turned out to be easy to fix.
In makeopus’s help, it has a full list of options.
The relevant one here is called “MAKEOS2” which tells makeopus to use the OS/2 versions
of the tools.
I’m not entirely sure why this needs to option exists: one would think that makeopus
would simply load the correct tools based on its environment.
Regardless, with MAKEOS2 added, we can see that the build is finally starting.
Of course, it would be *far* too easy if that’s all it took to build Word.
After only a few minutes, a new string of build errors crops up, this time relating
to an application called DE.
From the context, DE appears to be a tool to compile UI elements.
In this case, we’re getting an OS/2 SYS error.
Information and system errors under OS/2 always start with SYS followed by a number.
This is especially true on OS/2, which comes with an extensive built in help mechanism.
By running HELP SYS0197, we get both the cause and fix to this the exact failure.
In this case, DE needs an option called IOPL set to true in CONFIG.SYS.
The IOPL option (short for I/O Privilege Level) controls the use of what are known as IOPL
segments, and the ability to run code in a special processor mode known as Ring 2.
I’m not entirely sure why a compiler needs this, but after a reboot, the “de” utility
is now working.
So the question is, will it build yet?
The answer, sadly, is no.
With DE fixed, its only a matter of time before we get yet another failure, with a different error message.
In this case, it’s a rather unclear message that simply states the program could not be run.
HELP says we’re trying to run a “wrong mode” application.
In other words, makeopus is trying to use a DOS utility under OS/2 mode.
Unfortunately, we don’t have a clear cause of failure due to masked compilation messages.
By examining the makeopus tool, and the build directory, I eventually worked out that makeopus
writes out a script called mo2.cmd.
This script lists every command that will be run to complete the build.
Through a process of trial and error, I eventually managed to isolate the problem: the egrep command.
For those familiar with Linux or almost any Unix-like operating system, egrep might be familiar.
It’s a utility to search the contents of files via regular expressions.
Egrep isn’t provided by OS/2, instead it’s one of the tools included in the WinWord source.
More ergeriously, it’s closely related cousins, grep, and fgrep work just fine.
Switching back to our Linux host system, running the file command reveals the reason why: egrep
is not a family mode executable; only a DOS version is provided.
True enough, if we use the DOS window, we can also get egrep to work.
This however presents a problem.
On OS/2, DOS and OS/2 binaries can only be used within their respective environments.
Without an OS/2 version of egrep, I was stuck, although I wasn’t necessarily out of luck.
Egrep is a fairly standardized utility.
Looking at the grep and fgrep commands I had, Microsoft likely had ported egrep from their
Xenix operating system to DOS and OS/2.
Since there were free and open source implementations of egrep available, there was a good chance
I could find or compile a replacement.
It was at this point, where a member of the Virtually Fun Discord group pointed me at
the GNUish Project.
The GNUish project had ported several GNU utilities to DOS and early OS/2, including
a copy of egrep which I confirmed worked properly under OS/2 1.2.
Further testing showed that it worked identically to the DOS version of the command!
In short, after renaming a few files, we were back in business!
So, the question now is, would it build?
As it turned out, the compilation dragged on, primarily due to the underlying 33Mhz
386 emulation.
It took several hours before I got my answer, but in this case, preserve is a blessing,
and I was finally greeted with the magical line of “Make Complete!”
A quick look in the BUILD directory shows that I indeed have a copy of WINWORD.EXE waiting
for me?
The question now is, does it work?
As I stated previously, the official retail release of Word for Windows 1.1 required Windows
2.1 or later, although Windows 3.0 was recommended.
For eagle eyed viewers, you may have noticed that the WinWord binary was MARKed, as we
saw in Hello World for Windows 1.0 to prevent compatibility warnings.
We’re going to test this binary in a moment, but I do want to address the implied elephant in the room.
Now, for those familiar with OS/2, and especially the later versions, you may be wondering why
I haven’t shown Win-OS/2 up to this point.
For those of you less familiar with OS/2, you might be wondering “isn’t having to
develop on OS/2 and test on Windows kinda a pain?”.
Well, let’s answer those one at a time.
Later versions of OS/2 was rather famously marketed as “a better DOS than DOS and better
Windows than Windows”, and versions 2.0 and later can run 16-bit Windows applications without issue.
However, this is OS/2 1.2, and there’s no Windows support built into this version.
That isn’t to say you can’t add it.
As it turns out, you can simply install a normal copy of Windows 3.0 directly into the DOS box
This is infact something supported by Microsoft, and is even mentioned in the README.
After installation, simply type WIN, and boom, welcome to Windows 3.0 running under OS/2.
In truth, this is more of a novelty than anything actually useful due to the fact that Windows
is stuck running in Real Mode meaning most Windows 3.0 and 3.1 applications simply won’t work.
Furthermore, trying to open a command line or DOS application simply says this feature
isn’t available under OS/2.
However, we can run our compiled version of Word without issue!
At this point, I can safely say: mission accomplished!
However, there’s more to talk about here than just compiling Word.
Through the course of this project, I found myself with quite a few more questions than answers.
For example, let’s take a brief look at the native OS/2 version of Word 1.1.
At a glance, it looks identical to the Windows version we just compiled.
Is it the same code base, or is something else going on here?
As I dug deeper, I began finding more and more questions as I dug.
For instance, why is Word compiled to bytecode, and just what other mysteries did I find in
this codebase?
What is the relationship between Word for Windows, and the myriad of other versions
that existed at that time.
And finally, the question you’re probably all wondering?
Does it work on Windows 10?
Unfortunately, those questions, and more will have to wait until next time because we’re
out of time on this video.
Next time, we’re going to be digging into the lineage of Word, and the secrets I found
hidden in this codebase.
If you’d like to see that video when it becomes available, please subscribe and leave
a like, it really does make a huge difference for the channel.
Beyond that, as usual, I can be found on Twitter, and Discord if you want to follow my adventures
in real time.
Until the next time, this is NCommander, signing off!