Useful Info On Win16-Targeting Compilers… And a List of DOS/Win16 Resources

Updated 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.

Updated 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.)

Updated 2017-12-19: Added mentions of x2ftp and sunsite mirrors as good places to look for old programming resources.

Updated 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!)

Updated 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.

Updated 2017-12-08: Added “Tip 4: Open-Source Installer Creators for Old OSes” and a link to microjson.

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/WDOS/32A and Causeway are also now included.)

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: Free Pascal Can Apparently Produce Win32s-Compatible Applications and Win16 support is pending

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, I haven’t yet found any further information on the DOs and DON’Ts of doing so.

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

  • InnoSetup 1.2.16 is the last release of InnoSetup which can target Windows 3.1.
  • InnoSetup 2.0.19 is the last release of InnoSetup which supports WizardStyle=classic.
  • InnoSetup 5.4.3 (non-unicode version) is the last release of InnoSetup which can target Windows 9x.
  • Different major versions of InnoSetup can be installed on the same machine without stepping on each others’ toes.
  • NSIS still supports Win32 targets all the way back to Windows 95 according to the features list and the changelog for the most recent minor version as of this writing (3.02).  It can also be used for cross-building via the nsis package on Debian-family Linux distros.
  • The v2.0 version of the setup builder included with the Windows 3.1 SDK is effectively freeware, with the only potentially unusual condition from the included LEGAL.TXT being that you’re only allowed to profit from it when you’ve combined it with another software product which adds substantial value. (I originally obtained it from the Windows 3.x Resources page on conradshome.com)
  • If neither InnoSetup nor NSIS works for your use case, HJ-Install is probably the next-best choice. It is also free for commercial use and its base overhead is only about twice theirs (138Kb).
  • If you don’t mind the “publish the source, even for private uses” license and the need to compile it yourself, the installer for Open Watcom C/C++ is just as open-source as the compiler, gives you both DOS and early- Win95-era-style Win32 installers from a single setup.inf and codebase, and supports bundling all of the files into a single downloadable EXE file. (They only distribute DPMI and Win32 builds, but the source repo suggests it was intended to also compile for real-mode DOS and their Win386 extender for Win16.)
  • FreeDOS’s installer is built using batch files and V8Power.
  • Info-ZIP and ARJ both offer fully open-source ways to produce self-extracting archives for DOS… though neither’s self-extractor stub has ready-made support for extracting to a temporary folder, running a command, and then cleaning up the temporary files.
    • According to Maximum Compression, ARJ loses out to a good Zip compressor and, from what I remember, the only significant advantage it held over Zip back in the day was that PKZip’s support for split archives was a mess.
    • Info-ZIP lets you build DOS self-extractors from other platforms. Just grab the UnZipSFX stub from a DOS copy of Info-ZIP, concatenate the Zip file onto the end of it, and then run zip -A using your native copy of InfoZip to fix up the offsets in the Zip file.
    • You don’t strictly need to fix up offsets to make the UnZipSFX stub work… it just keeps it from complaining and ensures that you retain compatibility with external extractors like PKUNZIP.EXE which aren’t smart enough to compensate for offsets rendered invalid by prepended garbage.
    • You can customize the second line and beyond of the UnZipSFX banner text by setting an archive comment. Info-ZIP supports editing archive comments while I couldn’t find a way to do so using p7zip.
    • Zip compression can be optimized by either generating the Zip file using 7-zip/p7zip or recompressing it using advzip from AdvanceCOMP. However, advzip will strip the comment if you set it before optimizing the compression.
    • The zipnote command for editing archive comments is very picky about its input data.
    • While some FreeDOS versions of 7-zip include a DOS self-extractor stub, you don’t want it because it requires an external DPMI host.

I haven’t been able to find a single freeware or open-source option which allows a self-extracting archive to run custom install scripting and then clean up its own temporary files. (While UnZipSFX does support being compiled into a mode which can run a post-extraction command, doing so disables the ability to extract to a location other than the current working directory.)

The Takeaway:

Target OS Desired Experience Installer to Use
Anything .msi WiX
Windows 2000+ 64-bit era InstallShield NSIS with ExperienceUI or UltraModernUI
Win2K/XP era NSIS with Modern UI [1]
InnoSetup
Windows 95+ Win2K/XP era NSIS with ModernUI [1]
Late Win9x era NSIS with InstallSpiderUI [2][3]
Early Win9x era InnoSetup 2.0.19 with WizardStyle=classic [4]
Borrow Open Watcom C/C++’s installer
Windows 3.1x Single EXE or split archive InnoSetup 1.2.16
Open Watcom C/C++’s installer may be usable like this. [5]
Can replace system files
MS Setup 2.0 [6]
DOS Only suits EXE Downloads Use Info-ZIP‘s self-extractor [7]
Good for EXE Download or CD Image Borrow Open Watcom C/C++’s installer
Wait until I have time to write my planned installer kit.
Only suits CD Images Write an INSTALL.BAT using V8Power [8][9]
Suitable for Floppy Images  Use Info-ZIP‘s self-extractor [7][10]

Footnotes:

  1. Included with NSIS
  2. CAUTION: I wouldn’t use InstallSpiderUI without first substituting replacement icons and wizard sidebars. The default sidebar art says “Powered by NSIS” at the bottom and I’m skeptical that the author created such a convincing knock-off of unInstallShield’s distinctive sidebar art rather than just yanking every bit of art he used from a copy of InstallShield.
  3. So far, I have only tested InstallSpiderUI on Windows 98 SE and am suggesting it for Win9x based on the fact that NSIS itself still supports Windows 95. Do your own testing!. Also, in my tests, SimpleBg silently refused to activate on a real Windows 98 SE machine, so this can’t be used to replicate early Win9x-era stuff.
  4. I haven’t found a way to achieve maximum authenticity by disabling the confirmation prompt InnoSetup displays before progressing to the screen-filling gradient background. If I find time, I may examine the source code to get a definitive answer.
  5. The source repository for Open Watcom C/C++ suggests that it should be possible to compile a version of the installer GUI for Watcom’s Win386 extender for Win16, but I haven’t tried it. That code may have bit-rotted.
  6. Microsoft’s “MS Setup” cannot bundle all of your files into a single archive, but explicitly supports installing off multi-floppy sets in resource-constrained contexts and, judging by the documentation, has much more comprehensive support than InnoSetup for performing installs which must restart Windows 3.1x to replace system components.
  7. Shareware distributors who were higher-end, but not rich enough to pay for an install wizard would use a self-extracting archive with custom banner text. The self-extractor stub from real-mode DOS versions of Info-ZIP can be added to a Zip file using a native build of Info-ZIP. Here’s how you’d build an un-split self-extractor on a POSIXy OS like Linux:
    #!/bin/bash
    NAME="testapp2"
    SFX_STUB="infozip/UNZIPSFX.EXE"
    FILES="testapp"
    ENDFILES="SETUP.EXE README.1ST"
    BANNER="Test Application v2.01
    By: Foobar Software
    
    Synopsis and/or company slogan here
    
    "
    
    # -- Configuration Ends --
    
    # Ensure relative paths are relative to this script
    cd "$(dirname "$(readlink -f "$0")")"
    
    ZIPNAME="$NAME".zip
    EXENAME="$NAME".exe
    
    # shellcheck disable=SC2086
    zip -rT9 "$ZIPNAME" $FILES $ENDFILES -z <<< "$BANNER"
    
    cat "$SFX_STUB" "$ZIPNAME" > "$EXENAME"
    zip -A "$EXENAME"
    rm "$ZIPNAME"

    Note that I’ve added two newlines to the end of the banner and taken advantage of the fact that files will be decompressed in the order they were added to the file to make SETUP.EXE and README.1ST the last two file names which the extractor will print to the screen before it exits. (At some point in the future, I might make a proper reader/writer abstraction for zipnote dumps so it’s possible to reliably combine custom banner text with advzip -z4)

  8. Without the need to worry about the awkwardness of manually unpacking, running the installer, and then deleting the unpacked temporary files, you’ve got a lot more freedom.Do as FreeDOS does. Put the pieces of V8Power which are relevant to your needs into a folder and call them from INSTALL.BAT or INSTALL.EXE to make a fancy, professional-looking install wizard. (Run the included demos and examples inside DOSBox to get an idea for which effects are portable and how to accomplish them.)
  9. If you still feel the need to compress the files to be installed, rather than distributing the whole ISO inside some more modern kind of compression like 7-zip, the UnZipSFX stub allows your frontend to specify a destination directory using the -d switch starting with version 5.5.
  10. Info-ZIP’s zipsplit tool doesn’t require you to swap floppies to make a multi-volume set the way PKZip did. The -r option will allow you to leave a specified amount of room on the first disk for your installer frontend. However, not having all the V8Power bits remain resident in memory means that you’ll either need to do all of your configuration prompting before you turn the job over to the Zip extractor or, alternatively, build your own GUI.

If I can find the time to finish it, I’ve started experimenting with using Free Pascal to write a DOS analogue to InnoSetup or NSIS which functions as a scriptable Zip self-extractor stub. (Though, unfortunately, it won’t be suitable for floppy sets (at least in v1.0) because of how much storage overhead I’m incurring from depending on DPMI, unzip code not intended to be an SFX stub, and Turbo Vision.)

Given that my goal is to use this sort of thing for nostalgic retrocomputing, I may even write one for Windows 3.1 as well in order to replicate the appearance of memorable installers which don’t resemble 16-bit InnoSetup… though I’ll probably wait and see if the Win16 efforts by the Free Pascal crew reach a point where I could patch InnoSetup 1.2.19 for theming without needing Delphi 1.x to compile it.

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:

      1. 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. QEMM 97 uses this facility to put its DOS and Windows installers inside the same .EXE file rather than having separate INSTALL.EXE (DOS) and SETUP.EXE (Windows) files.
      2. 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 and, according to this comp.os.msdos.programmer post, produces DPMI executables which require no extender under NTVDM or dosemu, unlike OpenWatcom.)
      3. Bundling the DPMI stub: If you’re using DJGPP or Free Pascal, then it’s possible to bundle the GO32v2 DPMI stub to produce a standalone EXE file by stripping the default one off using exe2coff (also included with DJGPP cross-compiler builds.) and then prepending cwsdstub.exe (included with DOS versions of DJGPP and Free Pascal) using the same technique shown above for cross-building self-extracting Zip files. Some of the DPMI extenders included with OpenWatcom can also be bundled in a similar manner. This comp.os.msdos.programmer post provides a good overview of how it all fits together and this other post lists noteworthy alternative DPMI hosts such as DPMIONE.
      4. Supplemental Libraries: Here are some which look promising:
        1. 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.
        2. 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.)
        3. 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.
        4. TUI (ie. text-mode GUI) Development: There are ports of Turbo Vision for DJGPP (instructions) and Free Pascal.
        5. 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.
        6. Pattern Matching: Ozan Yigit’s website has single-file public domain implementations of a robust glob matcher and 4.3 BSD regex syntax.
        7. Executable Compression: UPX can pack pretty much any kind of executable you’re likely to want to pack except Win16 or .NET.
        8. 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.
        9. 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.
        10. More Useful Misc.: Also, check out x2ftp and Sunsite mirrors for useful libraries and tutorials. (eg. the watcom folder on x2ftp)
      5. BASIC: If QBasic/QuickBASIC was more your thing, FreeBASIC supports targeting 32-bit protected-mode DOS and offers a qb dialect mode.
      6. 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.
      7. 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.)

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.

CC BY-SA 4.0 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.

This entry was posted in Geek Stuff. Bookmark the permalink.

5 Responses to Useful Info On Win16-Targeting Compilers… And a List of DOS/Win16 Resources

  1. Nikolay Nikolov says:

    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.)

      • Nikolay Nikolov says:

        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.

  2. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution under the same terms as the associated post.       Also, please be aware that non-constructive comments will have their URL field erased before being approved in order to combat SEO spam.