Updated 2023-03-14: Added link to guide for writing control panel applets in Delphi.
See Also: Resources for Reverse-Engineering 16-bit Applications for DOS and Win16 debuggers and the rest of the Retrocomputing category for other useful resources like installer builders and unit test frameworks.
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 documentation.)
Tip 1.5: A Single OpenWatcom Install Can Compile To All Targets
In the 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…
DOS/4GW
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. In fact, it’s creator was planning to dig out and provide the source for a more recent version for Open Watcom 2.0 but, sadly, he passed away in 2018.)
I forget which, but at least some of them can be merged into the binary to remove the need for a separate DPMI EXE file.
Win386
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: Older Versions of Free Pascal Can Produce Win32s-Compatible Applications and Win16 Support is Being Worked On
Release versions of Free Pascal are currently (v3.0.4) incapable of developing Win16 applications, but real-mode DOS support has been released and Win16 support is being developed in FPC trunk.
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, aside from these pages saying to use -WR
with Free Pascal 1.0.10 and avoid console functions in order to target Win32s, I haven’t yet found any further information on the DOs and DON’Ts.
According to this thread, Lazarus 1.6.x and Free Pascal 2.6.4 are the last versions to support Windows 9x with Free Pascal 2.4.x being the last to support it officially, so that’s where you’d want to start looking if you need to develop a Win32s application right now.
Tip 4: Open-Source Installer Creators for Old OSes
This section has been moved to its own post.
Tip 5: WINFILE.EXE is MIT-licensed
Remember how Microsoft included tools like Program Manager in 32-bit Windows up until Windows XP SP1 in order to allow companies to delay retraining?
Well, in early 2018, they MIT-licensed and GitHub’d the version of the Windows 3.1 File Manager that had been included in Windows NT 4 with the original_plus
branch containing only minimal changes to allow it to build as a native 64-bit application using Visual Studio 2015 and 2017.
To quote the README…
The most significant changes are:
- converted to Visual Studio solution; works on VS 2015 and 2017
- compiles and runs on 64-bit Windows (e.g., GetWindowLong -> GetWindowLongPtr, LONG -> LPARAM)
- added a few header files which were stored elsewhere in the NT source tree (e.g., wfext.h)
- deleted some unused files (e.g., winfile.def)
- converted 64-bit arithmetic from internal libraries to C
- converted internal shell APIs to public APIs (the primary reason the old version would not run)
That means it shouldn’t be too difficult to port things back if you want to borrow things now considered standard (like the Tree View widget) for your own projects or if you just want to read the code comments and examine the architectural decisions made by official Microsoft programmers.
UPDATE: In fact, efforts are being made to backport it at least far enough to get a Windows 3.11-compatible Win32s build.
As for those “internal shell APIs”, that’s why we have used/library copies of books like Undocumented Windows and Windows Internals by Schulman, Maxey, and Pietrek. (If you came here trying to figure out how to write a shell extension of the Windows Explorer variety, see this article.)
Other Tips
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:
-
-
- Awesome DOS is another list of resources like this. When I can find the time, I want to go through my list and contribute anything that’s missing.
- While not specifically for DOS, this list of single-file public-domain/open source libraries with minimal dependencies should probably be a good place to look for stuff that either works with Open Watcom C/C++ or isn’t hard to port.
- Jeff Parsons has worked hard to scrape together an archive of the Microsoft KnowledgeBase articles that Microsoft no longer cares to preserve.
- 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.exe
option to provide a custom DOS EXE file. For example, you could follow QEMM 97‘s lead in having a singleINSTALL.EXE
which launches either a DOS or a Windows installer depending on what you run it under, rather than having separateINSTALL.EXE
(DOS) andSETUP.EXE
(Windows) files. - Other Libre DOS C Compilers: I’ve already written a StackOverflow answer listing all of the ones I know, but DJGPP and GCC IA16 are the only one I’d consider worthwhile.
While not as native/storied/historic as Watcom and only capable of protected-mode DOS output, DJGPP is a GCC port has a big ecosystem and, according to this comp.os.msdos.programmer post, produces DPMI executables which require no extender under NTVDM or dosemu, unlike OpenWatcom.
On the other hand, GCC IA16 is quite young, but, if it’s implemented what you need, its optimizers are going to be more advanced than Open Watcom’s. (eg. It’ll have better dead code elimination.) - Bundling the DPMI stub: Moved to its own post.
- 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 and there is also Al Stevens’s D-Flat.
- 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.For Win16, you can use either PKLite 2.01 (Archive Team) which is under “you must pay to install this in a corporate or government environment” shareware terms but appears allow individual/hobbyist developers to sell what they pack with the shareware version, or PackWin which, as far as I can tell from its documentation, is under “We’d really like you to register, but there are no legal limitations on what the free version can be used for” shareware terms that don’t preclude full commercial use.
- JSON Parsing: While it doesn’t explicitly list compatibility with compilers like Open Watcom, microjson is a likely candidate, being a very compact, low-footprint, malloc-free parser for a subset of JSON intended for resource-constrained environments.
- 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.
- More Useful Misc.: Also, check out x2ftp and Sunsite mirrors for useful libraries and tutorials. (eg. the watcom folder on x2ftp)
- BASIC: If QBasic/QuickBASIC was more your thing, FreeBASIC supports targeting 32-bit protected-mode DOS and offers a
qb
dialect mode. - 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.
- Embedded Scripting: While I haven’t tested any of them yet, the most likely candidates for embedded scripting in a DOS/Win16 environment seem to be running either Lua or the V7 or tiny-js JavaScript runtimes under one of DPMI, Win386, or Win32s. (For more home-grown scripting handling, microjson may be useful as an example of how to write a resource-constrained parser.) …or Microsoft has open-sourced GW-BASIC under the MIT license if you know enough assembly to make it embeddable.
- Control Panels in Delphi: If you have Borland Delphi 1.x and want to write a control panel applet for Windows 3.1, there’s a FAQ entry that covers it in The Wayback Machine. (More specifically, it covers writing something that’ll build for 16-bit or 32-bit versions of Delphi using
{$IFDEF WIN32}
, unlike the one which doesn’t require the Wayback Machine, which is for Delphi 3 and has noIFDEF
s.)
-
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.
Changelog
- 2017-12-29: Add a mention of the installer for Open Watcom C/C++, which is in the same source repository and can be built to run as a DOS or Win32 (possibly more) application using a single codebase and
setup.inf
. - 2017-12-27: Merry slightly overdue Christmas. I tracked down the installer builder from the Windows 3.1 SDK, discovered that it’s effectively freeware, and added it to the table. (see
LEGAL.TXT
inside the self-extracting archive.) - 2017-12-19: Added mentions of x2ftp and sunsite mirrors as good places to look for old programming resources.
- 2017-12-17: Added instructions for generating retro-styled Windows 9x installers using either an InnoSetup release or NSIS plugins. (And completed the table up to the present day for the heck of it. Speaking of which, for Linux, use Flatpak. It’s good enough for software pirates!)
- 2017-12-10: Updated information on Free Pascal’s real-mode support and added instructions for embedding the DPMI stub used by DJGPP and Free Pascal.
- 2017-12-08: Added “Tip 4: Open-Source Installer Creators for Old OSes” and a link to microjson.
- 2018-02-16: Moved list of installer creators to its own post and moved changelog to the bottom of the post.
- 2018-12-12: Added mention of WinFile being open-source.
- 2019-01-11: Added link to tutorial and documentation for Watcom’s
wmake
makefile dialect. - 2019-04-10: Added mention of efforts to backport the open-sourced
WINFILE.EXE
code and a little more info on how to target Win32s with Free Pascal. - 2020-05-21: Added mention of GW-BASIC being released under the MIT license and added a link to The Complete Idiot’s Guide To Writing Shell Extensions for lack of a better place.
- 2020-10-31: Moved the CWSDPMI bundling instructions to an appendix on the post about bundling Open Watcom DPMI extenders.
- 2021-01-25: Added link to Jeff Parsons’s Microsoft KnowledgeBase Archive.
- 2021-04-07: Added links to a couple of Watcom-compatible Win16 executable packers.
- 2023-02-27: Added link to my Internet Archive upload of various versions of D-Flat to the TUI library section.
- 2023-03-14: Added link to guide for writing control panel applets in Delphi.
Useful Info On Win16-Targeting Compilers… And a List of DOS/Win16 Resources by Stephan Sokolow is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
The Free Pascal wiki page for the i8086-msdos compiler was a little outdated, so I updated it:
1) the latest stable release for i8086-msdos is 3.0.4, not 3.0.0
2) the large memory model support has matured and win16 support has already been started in fpc trunk. I’ve created a new wiki page for it:
http://wiki.freepascal.org/Win16
It still doesn’t contain much information, but it will gradually be updated.
Thanks. I’ve updated the post accordingly.
(Now all I need to do is get off my lazy butt and start making real-mode ports of RTL and FCL components I’d want to use in a real-mode application, like INI read/write, JSON parsing, and unzipping.)
Can’t wait to see it happen 😉
Btw, I just added information on what units are currently available for win16 in the wiki page:
http://wiki.freepascal.org/Win16#Status
Later, I will probably also add a screenshot of fpctris working under Windows for Workgroups 3.11 🙂
Nice! I should really look into what it would take to automate the generation of that kind of information for display on the website.
That said, whatever I decide to work on, It’ll be a while before I contribute anything.
I spent so much of my life never bringing hobby projects to v1.0 (either due to perfectionist burn-out or because something new caught my attention) that my mantra these days is “make it work, then make it perfect”… and I can build v1.0 of my first Pascal project using the units available for GO32v2.
Specifically, I want to write libre installer toolkits for DOS and Win16 (starting with DOS, since there isn’t even an InnoSetup 1.2.16 analogue for it) with selectable “themes” that allow hobbyist developers to easily replicate the look and feel of nostalgic installers from companies like iD Software, Microsoft, Sierra, Wise, etc.
I just spent yesterday going through about a quarter of my collection of old CD-ROMs (so far), screenshotting the installers in DOSBox so I can have reference material to work from while I wait for the book I’ve ordered on Turbo Vision.
UPDATE 2020-10-31: Aside from issues in my life that ground my hobby projects to a crawl for a while, I also decided to switch from Free Pascal to Open Watcom C/C++ for the installer project, since I found that I was needing to rewrite all my dependencies for the installer runtime anyway to get them as small as I wanted.
Free Pascal is still an excellent “Java or C# for DOS retro-computing”, given the ecosystem of ready-made libraries, but the most important part of my installer project (the part that shouldn’t crowd actual content off a floppy disk) has binary size requirements that have me micro-optimizing my C for size using
wdis
to inspect the generated assembly and replacing standard library functions with hand-rolled versions… sometimes using inline assembly.Another tip which I don’t yet consider high-enough quality to include in the main post:
In theory, it should be possible to use Duncan Murdoch’s freely-redistributable glue.exe tool (originally here) to replace the DOS stubs in NE-format (Windows 3.x) EXE files if the compiler is something like Free Pascal which doesn’t support a
/STUB
option in the linker.Unfortunately, it dies with “Runtime error 200” for me in both DOSBox and DOSEmu and none of the patchers I tried would fix it.
Great stuff!
Just want to add that Digital Mars C++ is another relatively new compiler that targets DOS/Win16. It is not free though. DJGPP also has been updated 2015, after being dormant for a while. wxWidgets also supported win16 upto a certain version.
Thanks.
I hadn’t realized wxWidgets (or wxWindows, as it no doubt would still have been called at the time) supported Win16 but, looking at the date of its initial release, that makes perfect sense.
I’ll have to look into what the last Win16-supporting version was that when I can find a moment.
UPDATE: I couldn’t wait… and bah!
According to this FAQ, while wxWindows 2.x does still support Windows 3.1 up to at least version 2.4.2 (the release associated with the FAQ), it only supports 16-bit compilation with Microsoft and Borland compilers.