How Windows 98 Processed Shortcut Arguments
In Microsoft Windows 98, passing command-line arguments through
shortcuts involved reading binary shortcut files (.lnk),
extracting stored string payloads via the Windows Shell, and passing
those parameters directly to application launch APIs. This article
details the underlying architecture, from the binary structure of
Windows 98 shell links and the role of the IShellLink
interface to the distinct execution paths used for 32-bit Windows
applications and legacy MS-DOS programs.
The Shell Link Binary Structure
Windows 98 shortcuts are stored as binary files with a
.lnk extension, defined by Microsoft's Shell Link binary
file format. Inside the file, a series of fixed-size headers and
optional data blocks define the target file, working directory, icon
location, and any specified command-line parameters.
When an argument is entered into the "Target" field of a shortcut
properties window (or set programmatically), Windows stores it in an
optional structure known as the COMMANDLINE_ARGUMENTS
string block. In Windows 98, this string was stored as standard
single-byte ANSI characters (CP_ACP), reflecting the
operating system's reliance on the Win32 ANSI subsystem rather than full
native Unicode.
Shell Resolution and Extraction
When a user double-clicks a shortcut or invokes it via the shell,
Windows Explorer (explorer.exe) parses the file. Windows
uses the Component Object Model (COM) interface IShellLinkA
to resolve the target and its properties:
- Resolution: The Shell checks whether the target file still exists at the recorded path. If moved, Windows 98 runs a heuristic resolution process using file metadata to locate the target.
- Extraction: Explorer invokes
IShellLink::GetArgumentsto retrieve the argument string from the file's data block. - Environment Expansion: If the path or arguments contain environment variables, the shell expands them before proceeding with the execution phase.
Execution via Win32
(CreateProcessA)
Once the target path and arguments are extracted, the shell invokes
ShellExecuteExA or directly calls
CreateProcessA in KERNEL32.DLL.
In Windows 98, CreateProcessA accepts the application
name and a command-line string. Windows combines the executable path and
the shortcut's arguments into a single string:
"C:\Program Files\App\program.exe" /arg1 /arg2
The operating system allocates a process environment block for the new task and loads the combined string into memory. The target Win32 application then accesses these arguments using one of two methods:
- Direct API Call: The application calls
GetCommandLineA()to retrieve the raw string buffer, handling parsing manually. - C Runtime (CRT) Initialization: The application's
runtime startup code automatically parses the raw string buffer into the
standard
argcandargv[]array by splitting tokens separated by whitespace, unless enclosed in quotation marks.
Legacy MS-DOS and 16-Bit Processing
Windows 98 maintained heavy backward compatibility with 16-bit Windows and MS-DOS applications. If a shortcut targeted a legacy application, the handling differed:
- Program Information Files (PIF): Shortcuts to DOS
programs often relied on
.piffiles. Arguments defined in the PIF or shortcut were passed to the Virtual DOS Machine (NTVDMequivalent in Windows 9x, managed viaWINOLDAP.MOD). - The PSP Command Tail: MS-DOS programs could not use
Win32 APIs like
GetCommandLineA(). Instead, Windows 98 constructed an MS-DOS Program Segment Prefix (PSP) for the process. The arguments were copied into the PSP command tail buffer located at offset80h. Due to real-mode architecture limits, this buffer was capped at 126 characters, preceded by a length byte and terminated with a carriage return (0Dh). Any arguments exceeding this limit were truncated.