While I was poking around the web, looking for information on the most liberally licensed way to put together some utilities for the copies of MS-DOS 6.22 and Windows 3.11 for Workgroups on my retro-gaming PC, I ran across a thread on Computing.Net titled win3.x compatable compilers.
Now, given that it was opened in 2007 and the most recent post was as new as April of 2016, I though I might as well help to fill in the gaps in their knowledge but, much to my dismay, after creating a post (in Leafpad) and creating an account, it seems it’s been locked for being too old. (I can only assume the threshold is something more than 9 years and less than 10.)
…so I decided to post what I put together here instead, so it won’t go to waste.
Tip 1: Current versions of Open Watcom C/C++ can definitely be used to target Windows 3.x.
Not only have I successfully used it to cross-compile basic test binaries on Linux and then run them in Windows 3.11 for Workgroups under DOSBox, I found a Building Win16 GUI Applications in C tutorial which includes an OpenWatcom project file in its example code archive.
Beyond that, it also includes a “windows extender” called Win386, which is essentially a DPMI extender for Windows 3.x applications, providing both a 32-bit flat address space and API thunks to make it more comfortable to call the Win16 API from 32-bit code.
From a deployment standpoint, Win386 has the advantage that it gets bundled into your executable rather than being installed separately like Win32s, so users need never know it even exists. (In fact, for that exact reason, there’s not much information on the web about it today outside the Watcom .)
Tip 1.5: A Single OpenWatcom Install Can Compile To All Targets
build.sh script I put together for generating test files in one of my projects, I generate
.com, 16-bit DOS EXE, DOS/4GW EXE, OS/2 1.x, OS/2 2.x, Win16, Win386, Windows 95, and Windows NT binaries all from the same
hello.c file using the same OpenWatcom install.
(Also note that the linked script cross-compiles using other compilers as well, such as DJGPP, and includes instruction on how to get prebuilt Linux cross-compile binaries for them.)
Tip 2: Open Watcom C/C++ is the same compiler used by many classic games.
Watcom C/C++ was used in quite a few applications back in the day, because they offered the best value for your money if you wanted to do 32-bit protected-mode development. (The compiler was competitively priced, it was known for producing the tightest code, and it came with royalty-free licenses for both a DPMI extender and a precursor to Win32s at no extra charge.)
I’ll go into more detail on all of that…
When DOS games like DOOM say “DOS/4GW Protected Mode Runtime” on startup (or don’t, but include a copy of
DOS4GW.EXE), that means they were compiled using Watcom C/C++ because DOS/4GW is the special Watcom bundle edition of DOS/4G. (It’s even still included in OpenWatcom, though more advanced, less nostalgic extenders like PMODE/W, DOS/32A and Causeway are also now included.)
Win32s came out relatively late in Windows 3.1’s lifetime, so Watcom included a product called Win386 which did basically the same thing. (Providing a a 32-bit protected-mode environment with thunking wrappers to call back into Win16 code.)
Unlike with DOS/4GW, there’s no optional-but-on-by-default splash screen to tell you when Win386 is in use, but things like the Windows version of the Sierra SCI runtime use it.
(That’s actually why some Win16 programs crash on startup on modern CPUs. There’s a bug in older versions of Win386 that gets triggered on encountering CPUs faster than about 300MHz which can be fixed in any application by the “international” version of the KB240982 patch for Microsoft FoxPro 2.6.)
Information sourced from http://www.os2museum.com/wp/watcom-win386/
Performance of Resulting Binaries
According to Paul Hsieh’s WATCOM C/C++ Programmer’s FAQ, PC Magazine benchmarks indicated that “WATCOM C/C++ version 9.5 had the tightest and
fastest code among such compilers as Visual C++, Borland C/C++, Metaware Hi
C, Zortech and Symantec (by a wide margin)”.
According to that same FAQ, Borland’s strength was always their IDE and compile speed and, better code generators or not, Watcom’s approach to supporting embedding bits of assembly language is superior.
Tip 3: Free Pascal Can Apparently Produce Win32s-Compatible Applications
Free Pascal is currently incapable of developing Win16 applications because support for producing real-mode applications was only just added in version 3.0.0 (the most recent version at the moment), but they’re not ruling it out in the future.
Specifically, the docs say that “When the large memory model of the i8086 code generator matures, Win16 support can also be implemented”.
That said, the user “watler” on the aforementioned Computing.Net thread claims to have confirmed that Free Pascal 1.9.6 could produce Win32s binaries. However, I haven’t yet found any further information on the DOs and DON’Ts of doing so.
Since I’m doing this as a standalone blog post, I might as well throw in a few other related bits of knowledge I’ve had kicking around:
- Custom DOS Stub: The Windows executable format must begin with a DOS executable. Normally, it just displays that message about it not being a DOS program, but both the Watcom and Microsoft linkers allow you to specify a
STUB=filename.exeoption to provide a custom DOS EXE file. QEMM 97 uses this facility to put its DOS and Windows installers inside the same
.EXEfile rather than having separate
- Other Libre DOS C Compilers: I’ve already written a StackOverflow answer listing all of the ones I know, but DJGPP is the only one I’d consider worthwhile. (While not as native/storied/historic as Watcom and only capable of protected-mode DOS output, this GCC port has a big ecosystem.)
- Supplemental Libraries: Here are some which look promising:
- Argument Parsing: Argtable 3.x seems to place a pretty big emphasis on portability and argtable 2.x explicitly lists DJGPP and Open Watcom as known to build it successfully.
- zlib/libzip: Archlinux’s AUR contains patches to build zlib and libzip for OpenWatcom’s DOS targets. (As well as one for zlib on win16, though I don’t see why there would be a difference unless it’s for static libraries vs. an LE-format DLL.)
- Extended standard library: iMatix’s legacy repositories on GitHub provide a Standard Function Library (online docs) which offers useful stuff for C such as various string- and filesystem-related functions now standard in modern languages and INI and XML reading/writing. The docs list Watcom and DJGPP among the supported compilers for targeting DOS.
- TUI (ie. text-mode GUI) Development: There are ports of Turbo Vision for DJGPP (instructions) and Free Pascal.
- DOS Game Development: Allegro provides API abstractions and a library of ready-made, optimized utility routines to allow easy writing of portable games. Version 4.2 is the last release which supports targeting DOS.
- Pattern Matching: Ozan Yigit’s website has single-file public domain implementations of a robust glob matcher and 4.3 BSD regex syntax.
- Executable Compression: UPX can pack pretty much any kind of executable you’re likely to want to pack except Win16 or .NET.
- Useful Misc.: You can find lots of useful bits in the Wayback Machine on Troels K. and Japheth‘s sites, such as Win16-compatible CEditView / CRichEditView implementations and the HX DOS extender (which provides limited support for Win32 applications in DOS), but be sure to double-check for license compatibility since I think at least one component on the list is an improvement on an EPL-licensed component and the EPL is GPL-incompatible.
- BASIC: If QBasic/QuickBASIC was more your thing, FreeBASIC supports targeting 32-bit protected-mode DOS and offers a
- Python: It’s ancient, protected-mode, and I’ve heard people use the phrase “buggy old …” to describe it, but a port of Python 2.4.2 for DOS does exist.
I also have a bunch of useful links for building things with Pascal and DOS batch files, but this is already getting really long, so I’ll leave that for another day.