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.

5
  • I'm surprised none of the answers mentioned Actor.
    – user8678
    May 14, 2018 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. May 15, 2018 at 5:33
  • I originally said "necessary to buy" instead of "necessary to use" -- it seems the SDK was not free (groups.google.com/d/msg/comp.windows.ms.programmer/DN0cWWErlPA/…), so perhaps that makes no difference
    – rakslice
    May 15, 2018 at 6:57
  • Also, a DOS compiler probably can't setup a winmain function correctly... May 15, 2018 at 16:18
  • 1
    Since this old question had some activity today... virtuallyfun.com/wordpress/2020/05/22/… "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" May 26, 2020 at 17:00

5 Answers 5

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.

22
  • 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. May 14, 2018 at 9:29
  • 5
    @tofro doesn’t the Windows loader load non-NE executables as DOS programs, in the VDM or real-mode DOS environment? May 14, 2018 at 9: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, 2018 at 9: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). May 14, 2018 at 9:38
  • 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. May 14, 2018 at 11:43
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.

6
  • “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). May 14, 2018 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, 2018 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.
    – user722
    May 14, 2018 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, 2018 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.
    – user722
    May 15, 2018 at 0:02
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 :))

4
  • 1
    Strictly all that was needed was a hex editor... May 15, 2018 at 15:47
  • @R.. DEBUG FTW!
    – Raffzahn
    May 15, 2018 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, 2018 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 8 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.!

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .