Windows 98 Visual C++ Runtime DLL Dependency Management

In Microsoft Windows 98, application dependencies on Visual C++ runtime dynamic-link libraries (DLLs) were managed primarily through shared system directories, standard dynamic link resolution orders, and installer-level version checks. Lacking the isolated, side-by-side assembly architecture introduced in later operating systems like Windows XP, Windows 98 relied on global deployment models that often led to version conflicts, commonly referred to as "DLL Hell." This article examines the mechanisms Windows 98 used to resolve, install, and execute Visual C++ runtime libraries like MSVCRT.DLL and version-specific libraries such as MSVCRT40.DLL.

The DLL Search Order

When an application compiled with Microsoft Visual C++ launched on Windows 98, the operating system resolved its imported DLL dependencies using a predetermined search order. The loader searched for required libraries in the following sequence:

  1. The directory from which the application binary was executed.
  2. The current working directory.
  3. The 32-bit Windows system directory (typically C:\WINDOWS\SYSTEM).
  4. The main Windows directory (typically C:\WINDOWS).
  5. Directories listed in the system's PATH environment variable.

If an application developer placed runtime libraries directly in the application’s root directory, the program would load those local files. However, most software of the era relied on the runtime being accessible globally via the system directory to conserve memory and disk space.

Shared Deployment in the System Directory

The standard practice for deploying Visual C++ runtimes—such as MSVCRT.DLL (Visual C++ 4.2 through 6.0) or MSVCP60.DLL (the C++ Standard Library)—was placing them into C:\WINDOWS\SYSTEM. Because Windows 98 treated this directory as a central repository for shared components, multiple independent applications depended on the exact same DLL files stored in this single location.

Once a DLL was loaded into memory by any running process, the operating system's memory manager mapped the executable code pages to other processes requesting the same library, provided the file paths and base addresses aligned.

Installer Responsibility and Version Checking

Windows 98 lacked an operating system-enforced package manager to protect runtime libraries. Responsibility for managing dependencies fell almost entirely on application setup programs, such as InstallShield or Wise Installation System.

Installers used the Windows File Installation API (functions like VerInstallFile) to inspect the version stamps inside the existing DLLs in C:\WINDOWS\SYSTEM. Under standard installation rules:

  • If the file did not exist, the installer copied the runtime DLL.
  • If a file with the same name existed, the installer compared the file versions (VS_FIXEDFILEINFO).
  • The installer was supposed to overwrite the file only if the incoming DLL had a higher version number.

Despite these guidelines, poorly designed installers frequently overwrote newer versions of MSVCRT.DLL with older ones, breaking other software installed on the system.

The Role of MSVCRT.DLL as an OS Component

During the Windows 98 release cycle, MSVCRT.DLL transitioned from being merely a compiler-provided runtime library to an integrated operating system component. Windows 98 shipped with MSVCRT.DLL pre-installed to support native shell components and Internet Explorer 4.01.

Because Windows components actively depended on this file, modifying or replacing it carried a high risk of system instability. Later maintenance updates and the Windows 98 Second Edition (SE) release bundled updated versions of the runtime to maintain backward compatibility with software built using Visual C++ 5.0 and 6.0 while stabilizing OS-level operations.