If you look at the
you'll find a horrific mishmash.
a null-terminated string,
even a Pascal-style string.
What's going on here?
Each of those members comes from a different era in time. The oldest member is the Pascal-style command line, which dates back to CP/M. On CP/M, command lines were stored at a fixed location, namely 0080h through 00FFh, in the form of a Pascal string. The byte at 0080h specified the length of the command line, and the bytes at 0081h through 00FFh contained the command line itself.
MS-DOS based much of its initial interface on CP/M in order to make porting to the new operating system easier, and part of what got carried over was the way command lines were passed from one program to another. The MS-DOS function to load a program took two parameters, a pointer to a null-terminated string (specifying the module to load) and a pointer to a parameter block which took the following form:
LOADPARMS struc loadp_environ dw ? ; environment of new process loadp_cmdline dd ? ; command line of new process loadp_fcb1 dd ? ; first FCB loadp_fcb2 dd ? ; second FCB LOADPARMS ends
To ease the transition,
Windows 1.0 used the same MS-DOS interface for launching
You loaded up the registers and issued an
int 21h instruction.
All the parameters had the same meaning.
Generally speaking, 16-bit Windows used the old MS-DOS interface
for a lot of functionality, especially disk access.
Want to write to a file?
Put the file handle in the
the number of bytes in the
a pointer to the buffer in the
40h in the
and issue an
just like in MS-DOS.
Why do this?
Well, it saved the Windows team from having to invent a whole
boatload of functions that duplicated what MS-DOS already did,
and it meant that existing MS-DOS programs
didn't need to change a thing in their file I/O code.
If they used a runtime library designed for MS-DOS (C or otherwise),
that library would still write to files by setting registers
and issuing an
If you want people to switch to your new platform, you need to make it easy,
and "you don't have to change anything; it all just works" is pretty easy.
(One minor change was that the first FCB was repurposed to contain
nCmdShow; the magic value of "2" in the first word of
the FCB signals that it's not really an FCB.)
As a minor convenience, the
LoadModule function provided a C-callable version of
int 21h, but you still had to provide
the parameters in the form of the MS-DOS exec structure.
It wasn't until later versions of Windows that the
WinExec function was added,
thereby providing a much more convenient interface to starting a new
No longer did you have to mess with the crazy MS-DOS exec structure
and its strange way of passing the command line and
The people who were designing Win32 created their own function
CreateProcess to launch a new process,
but for backward compatiblity, they retained the
and even older
The pointers in the crazy 16-bit exec block got converted to 32-bit,
but the craziness of what they pointed to was retained to make
porting old code easier.
int 21h interface no longer exists, of course.
The craziness is just a leftover from the old MS-DOS days.
are now just stub functions that convert their parameters and
CreateProcess function to do the real work.