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.

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:

  1. 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.
  2. Extraction: Explorer invokes IShellLink::GetArguments to retrieve the argument string from the file's data block.
  3. 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 argc and argv[] 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 .pif files. Arguments defined in the PIF or shortcut were passed to the Virtual DOS Machine (NTVDM equivalent in Windows 9x, managed via WINOLDAP.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 offset 80h. 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.