22

It seems that right from the outset, the plan for Windows development was that it would be done with a separate set of compilers specifically equipped for that purpose.

The Windows SDK comes with 7 diskettes, with all the tools you need including a special version of the Microsoft C Compiler version 3.0,

(from Windows 1.0 and the Applications of Tomorrow, Petzhold, 2005)

Certainly, as a significant programming language implementation company, Microsoft had the capability to build the specialized tools and an interest in selling them.

But was it actually necessary to use Windows-specific tools?

The 16-bit Windows API was provided through dynamic link libraries, and the initial versions Windows used a single address space, which suggests that it would be theoretically possible to use it with any code that could make appropriate calls to the known fixed addresses.

However it is unclear to me if this would be a problem in practice either due to practical issues with using the API or other compatibility issues.

user3840170
  • 23,072
  • 4
  • 91
  • 150
rakslice
  • 918
  • 7
  • 13
  • I'm surprised none of the answers mentioned Actor. –  May 14 '18 at 18:23
  • I remember something along the lines that special start-up code was required for Windows executables and that Microsoft didn't publish this code for some time. So all toolmakers had to first disassemble a working Windows program in order to find this magic code. Thus a pre-existing DOS development tool certainly wouldn't have this code. – No'am Newman May 15 '18 at 05:33
  • I originally said "necessary to buy" instead of "necessary to use" -- it seems the SDK was not free (https://groups.google.com/d/msg/comp.windows.ms.programmer/DN0cWWErlPA/qEE-KKy84wYJ), so perhaps that makes no difference – rakslice May 15 '18 at 06:57
  • Also, a DOS compiler probably can't setup a winmain function correctly... – rackandboneman May 15 '18 at 16:18
  • 1
    Since this old question had some activity today... https://virtuallyfun.com/wordpress/2020/05/22/examining-windows-1-0-hello-c/ "More interestingly, all the above tools were compilers for DOS, and didn’t have any specific support for Windows. Instead, a replacement linker was shipped in the SDK that could create Windows 1.0 “NE” New Executables" – Kelvin Sherlock May 26 '20 at 17:00

5 Answers5

24

Windows executables are in NE format rather than the MZ format used by DOS, so a developer would need a toolchain capable of generating files in that format.

Windows functions are not accessed by calling known fixed addresses, but by a list of imported symbols which are populated when the program is loaded. So the tools used would also have to generate this list.

john_e
  • 7,263
  • 20
  • 44
  • Exactly — you need a NE-capable linker (and that’s all). The question remains as to whether a plain MZ executable could access the Windows entry-points — it certainly can’t in extended mode, since DOS and Windows run in separate VMs, probably can’t in standard mode either, but it probably could in real mode (unless Windows swapped itself out). – Stephen Kitt May 14 '18 at 09:28
  • 5
    It’s also impractical to develop any useful Windows software without the SDK, because of all the data structures and constants required; see Steve Gibson’s Small Is Beautiful example. – Stephen Kitt May 14 '18 at 09:29
  • I see no reason why you couldn't write a proper Windows executable in MZ format. It would be a bit pointless and rather tedious (like developing your own startup code, building all the stub libs,...), but possible. – tofro May 14 '18 at 09:30
  • 5
    @tofro doesn’t the Windows loader load non-NE executables as DOS programs, in the VDM or real-mode DOS environment? – Stephen Kitt May 14 '18 at 09:32
  • 1
    @StephenKitt Not really. There is no "pure NE" executable in Windows (or rather, all NE binaries are MZ binaries as well). NE is a superset of MZ. The standard MZ branch that is normally included in an NE program contains the stub that says "This program must be run in windows" - If you fiddle around with that stub, you could put a complete Windows application in there. – tofro May 14 '18 at 09:34
  • 1
    @tofro I know how the executables are structured; what I’m wondering is how the Windows executable loader works (I’m not 100% sure of my memories there). I think it looks for the NE header and loads anything without that as a DOS program (without the DLL imports and relocations etc.). I’ve seen full DOS programs replacing the MZ stub, likewise for combined DOS/OS/2 programs (ignoring the Family APIs), but I doubt you can have two Windows programs in one (one in the NE “branch“, one replacing the MZ stub). – Stephen Kitt May 14 '18 at 09:38
  • @StephenKitt The Windows Setup program (the installer) is known to be an example of a Windows program that has all of its code in the MZ branch. And I am pretty sure that is a regular Windows program (even if it doesn't use the GUI) – tofro May 14 '18 at 09:47
  • @tofro I spent my lunch time disassembling, and the first part of the Windows installer (SETUP.EXE) is a plain DOS program, no Windows anywhere; it copies a bunch of files, including WINSETUP.EXE, which is a pure Windows program with the “This program requires Microsoft Windows...” MZ stub, and a minimal Windows installation, then starts Windows to continue the installation (with the GUI). – Stephen Kitt May 14 '18 at 11:40
  • 1
    I also checked Windows Internals, and there is one “well-known” combined DOS/Windows program: KRNL386.EXE, which has a DOS part which switches to protected mode and sets various things up, including LoadModule (the NE loader), then loads its NE portion to continue booting. LoadModule assumes it’s loading a NE binary, and fails if no NE header is present; the extended INT 21/4Bh service in KRNL386 loads WINOLDAP instead if a non-NE executable is loaded (and LoadModule has a bunch of specific code for that case too). So I stand by what I wrote earlier. – Stephen Kitt May 14 '18 at 11:43
  • 1
    The MZ format lacks the right sorts of fixups. – JdeBP May 14 '18 at 14:00
  • IIRC the windows 9x installer runs as a win16 program if run from windows and a DOS program (which loads a minimal version of windows 3.x then runs the installer in it) if run from dos. Not sure about other versions. – Peter Green May 14 '18 at 18:12
  • @StephenKitt: Which it does. Windows occupies more than 1MB RAM but there' s only 1MB in real mode. – Joshua May 14 '18 at 18:19
  • @Joshua are you referring to it swapping itself out? Real mode Windows never needed 1 MiB of RAM, it could run in as little as 256 KiB (in version 1.0) and 3.0 would work with 512 KiB (for some value of “work” of course). – Stephen Kitt May 14 '18 at 19:43
  • @StephenKitt: Yeah. It swaps itself out. To do otherwise would have required more than the 1MB that real mode could address. – Joshua May 14 '18 at 19:45
  • @Joshua, good to know, thanks, which means there’s nothing left for a DOS program to talk to... – Stephen Kitt May 14 '18 at 20:42
  • @StephenKitt is definitely right here -- I did a load of work in real-mode Windows back in the early 90s and it definitely suspended itself entirely whenever a non-NE executable was loaded. You could put more stuff into the MZ stub than just a message (I recall at least one program that ran itself with a cut-down version of the Windows GUI when executed from DOS), but if you didn't have a working Windows entry point & headers, Windows just swapped itself out before executing your program. A linker that supported generating those headers was mandatory, and MS's standard LINK.EXE didn't. – Jules May 15 '18 at 04:35
  • @StephenKitt Perhaps this is not what @tofro meant, but I suppose %windir%\SETUP.EXE, the one which allows configuring the display/keyboard/mouse/network both from Windows and DOS, would be another "separate program in the MZ stub" example – rakslice May 15 '18 at 07:09
  • @rakslice that’s exactly the same binary as the installation binary on the floppies, and it’s not a Windows binary. When you run “Windows Setup” from the Program Manager, the executable is WINSETUP.EXE, not SETUP.EXE. – Stephen Kitt May 15 '18 at 07:15
  • @StephenKitt Maybe there are version differences. I'm looking at my Windows 3.1 install right now... %windir%\SETUP.EXE is the same as the one from the installation disk, but the Windows Setup item in Program Manager points to SETUP.EXE and there is no WINSETUP.EXE – rakslice May 15 '18 at 20:34
  • @StephenKitt I see WINSETUP.EXE in a Windows for Workgroups 3.11 install however and the situation there is as you described. – rakslice May 15 '18 at 20:38
  • 1
    @rakslice ah yes, Windows 3.1 has a SETUP.EXE which is a combined DOS (replacing the MZ stub) and Windows (with a proper NE header) program. So yes, that’s another example of a full DOS program in the “stub”, but it’s not a Windows program in the stub as tofro was claiming. – Stephen Kitt May 15 '18 at 20:47
  • The QEMM 97 installer is another example of a program with a non-trivial MZ stub. Run it under DOS and you get a TUI installer that installs QEMM for DOS only. Run it under Windows and you get a GUI installer which installs both the DOS and Windows stuff. (But I think the NE portion might just be the bootstrap stage for a normal InstallShield installer. It's been a while.) – ssokolow May 27 '20 at 18:20
15

After doing a bit of research (on Raymond Chen's blog) one of the better examples of things Windows compilers did on 16 bit Windows was to increment BP before pushing it on the stack in a far called function (and decrementing it afterwards) so the code that walked the stack knew the size of the return address.

https://devblogs.microsoft.com/oldnewthing/20110316-00/?p=11203/

Compilers did need to do some odd things to work with 16 bit Windows and I remember Microsoft at the time period (things got better during the OS/2 Windows 3.x era) being a bit of a pain to work with.

So unless you were writing assembler, probably not.

Stephen Kitt
  • 121,835
  • 17
  • 505
  • 462
PeterI
  • 5,297
  • 1
  • 16
  • 44
  • “being a bit of a pain to work with” — which is one of the reasons it took so long for Windows-capable compilers to be made available by anyone else (Zortech being the first IIRC). – Stephen Kitt May 14 '18 at 12:16
  • 3
    I was at Borland during the 86-87 period doing tech support for Turbo C & Turbo Basic. My memory is that getting information out of Microsoft at time was tricky. For example the format of a .LIB file wasn't documented (the Borland linker used concatenated .OBJ files IIRC) nor was the stuff required to make CodeView work. Symdeb was possible. I'd left by the time Windows 3.x arrived and I think by then MS were being a bit more open. Individuals at MS UK were great to work with we would do things like swap products with them so we didn't have to buy them. – PeterI May 14 '18 at 12:55
  • Incrementing BP wasn't required, as it wasn't necessary for anything to be able to walk the stack. It's just helpful if it's possible to do this while debugging. I don't think many release versions of Windows programs actually did this because it would only hurt performance and code size. –  May 14 '18 at 21:14
  • 2
    I'm going from the Raymond Chen description of the way memory management works (in the linked article) and reloading discarded code segments. Please read the linked article, while Raymond might be wrong occasionally I'm pretty sure he's right. – PeterI May 14 '18 at 23:18
  • 3
    Ah, it was required in 16-bit real-mode Windows code. In 16-bit protected mode Windows code (ie. almost all 16-bit Windows applications) it wasn't necessary. Note that BP wasn't incremented before far calls, instead "you must increment the bp register before you push it" in the prologue of functions that use RETF. –  May 15 '18 at 00:02
  • Ross, you're absolutely right. Fixed the text. – PeterI May 15 '18 at 10:20
6

But was it actually necessary to buy Windows-specific tools?

As usual it depends on the value of 'actually necessary' used.

Strictly all that was needed was a linker producing NE (Windows) binaries. Of course, when calling Windows functions (hard to avoid) its calling convention needs to be satisfied. So either some wrapper libraries where needed, or low level code had to be added to do do the calling, or just change your style to do so (as I did with Assembly (*1)).

If you programs were already nicely modularized (read: used external symbolic addresses for linking), then switching to programming for Windows wasn't a big deal.


*1 - Jup, my first Windows programs were written in Assembly - as most stuff I did :))

Raffzahn
  • 222,541
  • 22
  • 631
  • 918
  • 1
    Strictly all that was needed was a hex editor... – R.. GitHub STOP HELPING ICE May 15 '18 at 15:47
  • @R.. DEBUG FTW! – Raffzahn May 15 '18 at 18:37
  • @Raffzahn In a way, it's the self-hostedness of DOS 2+ with its little 16-bit assembler in DEBUG that made me wonder about the situation with early Windows – rakslice May 15 '18 at 21:39
  • @rakslice Also the early DOS versions (often) shipped with Microsoft's LINK.EXE; while you can uses .COM executables in DOS (and create and debug them with DEBUG), real program development needed a MZ linker. Which is the point made here. Windows never shipped with a linker, nor a debugger. – AntoineL May 08 '23 at 15:04
1

I did all my early windows development using Borland Turbo C. One had to exit to dos, build the program, and then re-run windows to test it.!

jr593
  • 111
  • 1
1

At a minimum, Borland quickly supported win3.xxx either at the same time or close to 1992 with their OOP release. I remember being able to make both Turbo C and Turbo Pascal programs with a module. Borland released a Win TPU Unit for their older Borland DOS releases.

In 1992 Borland released two versions named "Turbo Pascal for Windows" (TPW), for Windows 3.x: TPW 1.0, based on Turbo Pascal 6, and later TPW 1.5; they were succeeded by Borland Pascal 7, which had Windows support. The Windows compiler in Pascal 7 was titled 'Borland Pascal for Windows'.

Both versions built Windows-compatible programs, and featured a Windows-based IDE, as opposed to the DOS-based IDE in Turbo Pascal. The IDE and editor commands conformed to the Microsoft Windows user interface guidelines instead of the classic TP user interface.

Turbo Pascal was superseded for the Windows platform by Delphi; the Delphi compiler can produce console programs in addition to GUI applications, so that the use of Turbo and Borland Pascal became unnecessary.

jwzumwalt
  • 4,479
  • 6
  • 24
  • 47