Chapter 3: Component Sharing

Summary of Component Sharing Requirements

Rationale

Windows-based applications can share code, as well as application and component state in the registry, application specific data in the file system, and Windows APIs which expose global namespaces. Sharing allows for the efficient leverage of limited hardware resources and reduces the exposed front that Quality Assurance groups must test.

However, there are costs to sharing. Sharing causes applications to become interdependent upon one other, which introduces an element of fragility. In the extreme, applications that once worked will mysteriously start functioning oddly, or even fail. Typically, an application is dependent on a particular version or implementation of a shared component. If that shared component is upgraded (or downgraded) as a result of installing another application, the former application may break. This condition is often referred to as "DLL Hell."

Successful global sharing requires that any shared component behave exactly like previous versions of that component to avoid this problem. In practice, however, 100% backward compatibility is difficult, if not impossible, to achieve because:

Windows 2000 and Windows 98 Second Edition enable a new form of sharing called side-by-side sharing which minimizes this application fragility. Side-by-side sharing enables multiple versions of the same COM or Win32 component to run at the same time in memory. This means applications can use the specific components that they were designed for and tested with, even if another application requires a different version of the same component. This allows developers to build more reliable applications because developers can choose the version of the component they will use for their application, independent of the other applications on the system.

Side-by-side sharing requires the use of side-by-side components, which are ordinary COM or Win32 components, except that they:

Side-by-side components are isolated to a specific application and are not globally shared across all applications:

The following chart compares the traditional "global sharing" method with side-by-side sharing:

Global Sharing Side-by-Side Sharing
Requires consistency of interface and behavior over time. Backward compatibility needs to be tested. Interface and behavior can change over time.
All versions can/must share the same state (registry, etc). Requires isolation of state by component version and optionally, by application using the component.
Applications all use the "latest version" of a component. Applications choose which version of a component they use.
Installs into a globally shared location, for example the system directory. Installs into the application's directory.
System supports activation by absolute name (file name in system directory or GUID to an absolute file name). Activation is by relative name based on the application being run.
Upgrading / bug fixing the component simply requires replacing the single globally shared component. Upgrading and bug fixing a component is the responsibility of the application developer.

Customer Benefits

Requirements

3.1  On Windows 2000 do not attempt to replace files that are protected by Windows File Protection

3.2  Component producers: Build side-by-side components

3.3  Application developers: Consume and install side-by-side components

3.4  Install any non side-by-side shared files to the correct locations

References

How to Comply with Component Sharing Requirements

3.1  On Windows 2000 do not attempt to replace files that are protected by Windows File Protection

Your application must not attempt to replace any Windows 2000 files that are protected by Windows File Protection (WFP). To ensure that you do not invoke WFP, call SfcIsFileProtected when installing any file you did not create. The Windows Installer service version 1.1 automatically does this for you.

Protected files include the following files that ship on the Windows 2000 CD:

Note   Some redistributable files, such as specific versions of Microsoft Foundation Classes (MFC) DLLs, are installed by Windows 2000 and are protected by WFP.

Protected files form the core of the operating system and it is essential for system stability that the proper versions be maintained. These files can only be updated via Service Packs, operating system upgrades, QFE hotfixes, and Windows Update. Applications cannot replace them, and attempting to replace these files by means other than those listed above will result in the files being restored by the Windows File Protection feature.

Important   If your application requires newer versions of these components, your application must update these components using an approved Microsoft Service Pack that installs the required versions.

About Windows File Protection

Windows File Protection is a feature of Windows 2000 which prevents the replacement of essential system files. WFP runs as a background process on Windows 2000 and monitors the files listed in the preceding section. When WFP detects that a protected file has been changed, it restores the original.

The following code shows how to check if a file (in this case "ntdll.dll") is protected by WFP. Note that SfcIsFileProtected is Unicode-only and requires a fully qualified path.

SHGetFolderPath(NULL,CSIDL_SYSTEM, NULL, 0, szSystemDir);
PathAppend(szSystemDir,"ntdll.dll");
MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wzFileName, 265);

if ( SfcIsFileProtected(wzFileName) )
   MessageBox(hWnd,szProtected,szSystemDir,MB_OK);
else
   MessageBox(hWnd,szNotProtected,szSystemDir,MB_OK);

3.2  Component producers: Build side-by-side components

Authors writing new redistributable components must use side-by-side sharing techniques so their components can be installed into the application directory.

"Side-by-side" means version 1 of the component runs in one process while version 2 runs in another process. This requires each version to isolate its state so that it doesn't conflict with other versions. The rules below will help ensure your components can run in a side-by-side scenario. Most ordinary components will need only minor modifications to meet these requirements.

To build a side-side component:





Side-by-side sharing is supported in Windows 2000 and Windows 98 Second Edition. For previous Windows operating systems, side-by-side activation is not supported. However, a side-by-side DLL can be written so that it installs on down-level platforms into the system directory, and functions in a global-sharing (backward compatible) fashion. Side-by-side DLLs must be installed to the system directory on these platforms, and in the application directory on Windows 2000 and Windows 98 Second Edition. Applications must dynamically check the operating system version to determine which sharing technique to use. The following code checks if side-by-side sharing is supported:

BOOL bPlatformSupportsSideBySide(void)
{
    OSVERSIONINFOEX osviex ;

    osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    // If platform does not support OSVERSIONINFOEX structure, it does not 
    // have side-by-side support
    //
    if (!GetVersionEx((OSVERSIONINFO *)&osviex))
    {
        return FALSE ; // no DLL re-direction
    }

    // However, for NT, then NT4 SP4 had support for OSVERSIONINFOEX 
    // support but it did not support DLL re-direction. 
    // If DLL re-direction appears in a future NT4 SP,  this code will have 
    // to be updated.
    //
    if ( (osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osviex.dwMajorVersion < 5) )
    {
        return FALSE ;
    }

    // For the other platform Ids, assume has side by side support
    return TRUE ;
}

3.3  Application developers: Consume and install side-by-side components

For Windows 2000 and Windows 98 Second Edition, any side-by-side DLLs that your application depends on must be installed into your application directory:

%ProgramFiles%\<company name>\<App Name>

Be sure to follow the install and uninstall instructions provided by the component developer.

On down-level operating systems, install side-by-side components into the system directory. Installers must dynamically check the operating system version to determine which sharing technique to use.

3.4  Install any non side-by-side shared files to the correct locations

The proper location for shared components depends on whether these components are shared across companies or by a single company.

Note   The system directory is not locked down when the user is a power user or administrator, so legacy components or globally shared components can still be placed there. However, Windows File Protection prevents the replacement of protected operating system files. See Requirement 3.1.

How to Pretest Applications for Component Sharing Requirements

To Pretest Installation

After installing your component, make sure there are no instances of fully qualified names to your component stored in the registry.

To Pretest Uninstall

Test uninstall with one instance of your component installed (only one application uses your component). Make sure all GUIDs and other information to your component have been removed.

Test uninstall with two instances of your component installed (i.e., two apps uses your component). Make sure the other application still runs after uninstalling the first application which uses your component.

To Pretest Co-existence

Install your component in two different applications. Run both applications at the same time and make sure your component continues to function properly. Ideally, you will test using two different versions of your component.