DOS and Windows support in a single EXE
The excellent Digital Mars C/C++ compiler made my quest for a single EXE file to support both 16 bit DOS and 32 bit Windows at once surprisingly easy: just three build steps.
Just as Windows was originally built on top of MS-DOS, the 32 bit Windows executable format was built as an extension to the 16 bit format used in DOS. Typically, the 16 bit code would just display an error message such as “This program cannot be run in DOS mode” – but it is nonetheless a fully-fledged 16 bit DOS application, which can do much more if you wish.
First, build your C source with the -ms switch, producing a plain old MZ executable which should work on anything back to an 8088, with code and data together in a single 64k segment. (Other memory options are available if you need more memory.)
Next, I rename the MZ version to avoid name conflicts; I chose stub.exe.
Finally, compile the 32 bit Windows version. Being the default, this needs no switches – just add /L/stub:stub.exe to instruct the linker to insert the DOS version of the code instead of the standard routine which generates an error message about requiring Windows.
On platforms such as OS X you can take this much further, generating a single file which contains code for four or more architectures: typically PowerPC and x86 in both 32 and 64 bit variants.
Sadly, on Windows this appears limited to just 16 bit and either 32 or 64 bit, since any given PE file can only indicate support for a single processor architecture; to combine 32 and 64 bit code, as I do in TFind and Mark Russinovich does in many of his Sysinternals tools, you need to embed a whole 64 bit EXE file inside a 32 bit version, unpacking the former to execute when needed. (CPU-independent .Net executables, referred to as AnyCPU builds, are possible – the file format marks them as being x86-only, then additional .Net-specific operating system code overrides that.)blog comments powered by Disqus