Install and uninstall issues are some of the most common sources of application interoperability problems. These requirements help to ensure that the user has successful installation and uninstallation experiences, and that the application co-exists in a friendly way with other applications.
Note It is highly recommended that you use the Windows Installer service for the installation of your application. The Windows Installer service is an operating system component that centrally manages application installation configuration, as well as application uninstall. Using the Windows Installer service allows the operating system to manage application setup and configuration, which enables the following:
The Windows Installer service enables all of this functionality using packages that describe application configurations. The Windows Installer ships in Windows 2000 and is also available for redistribution on Windows NT 4.0, Windows 98, and Windows 95.
For more information, see the Windows Installer Programmer's reference in the Microsoft Platform SDK.
Note If your application uses the Windows Installer, the install/uninstall requirements from Chapter 2 of the Desktop Application Specification supercede Requirements 2.2 through 2.8 in this chapter, with the exception that Desktop Requirement 2.6 (Support Advertising) is not required for server applications.
Your application must not attempt to replace 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 (see below).
Note 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 that 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);
Your application's install must properly version-check to ensure the latest file versions are installed. Installing an application must never regress any files that you do not produce or that are shared by applications you don't produce.
The VerInstall or GetFileVersionInfo APIs are recommended for performing the version check. VerInstall is easiest because it uses GetFileVersionInfo internally and simplifies the process. Below is a simplified example for how to use VerInstall:
TCHAR szOldDir[MAX_PATH], szTempDir[MAX_PATH];
UINT cchTemp = MAX_PATH;
DWORD dwResult = VerInstallFile(0, TEXT("file.dll"), TEXT("file.dll"), g_tszSetupDirectory, g_tszInstallDirectory, szOldDir, szTempDir, &cchTemp);
if (dwResult != 0) {
Error(dwResult);
}
By default, your application must install non-shared components into an appropriate subdirectory where the user's program files are stored (e.g., Program Files). This folder is represented by CSIDL_PROGRAM_FILES. On English systems, this folder is often "C:\Program Files." However, do not hardcode that path, as it is not universal.
The recommended way to locate this folder by using SHGetFolderPath (CSIDL_PROGRAM_FILES,…). If you are using the Windows Installer, this folder is represented by the ProgramFilesFolder
property in the Windows Installer-based package.
Exceptions Note the following exceptions:
In some cases, shared components may need to be placed in locations other than the application directory. See next requirement.
The proper location for shared components depends on whether these components are shared across companies or by a single company.
common files directory\<company name>
%ProgramFiles%\<company name>\Shared Files
The common files directory can be accessed by passing
CSIDL_PROGRAM_FILES_COMMON to the SHGetFolderPath API.
Note You must document in your Vendor Questionnaire any cases where your software application writes to the system directory.
HKLM\software\microsoft\windows\CurrentVersion\control panel\cpls
HKCU\software\microsoft\windows\CurrentVersion\control panel\cpls
Example of a name / value pair under this key:
MyCpl = "%ProgramFiles%\MyCorp\MyApp\MyCpl.cpl"
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 2.
If your application does not use the Windows Installer, the application installer must refcount all shared components. This must be done under the following registry key:
[HKEY_LOCAL_MACHINE]\SOFTWARE\Microsoft\Windows\Current Version\SharedDLLs
If your installer finds a shared component already on the system that is not registered, the SharedDLL count should be incremented by one plus the number of components in your application that consume this component. For example, if your application installs three components that use a shared file and the shared file is already registered, your installer will bump the SharedDLL count by three. However, if the shared file was already on the system but no SharedDLL exists for it (that is, a previous installer did not create the refcount), then set the SharedDLL count to four. That way, when your application is uninstalled, it leaves the shared file on the system with a refcount of one.
Components that are shared with applications that don't use Windows Installer service need to properly implement the DLLRegisterServer and DLLUnregisterServer entry points if they need to do any registration at install time. (DLLs that use the Windows Installer should use the registration services provided by the Windows Installer.)
Your application must supply all the information in the following table so that Add/Remove Programs in the Control Panel can obtain information about the application as needed. You can write this information directly to the registry during install, or if you are using the Windows Installer service, you can set these values using properties in the Windows Installer-based package.
The registry values should be written under the following key:
HKEY_LOCAL_MACHINE
\Software
\Microsoft
\Windows
\CurrentVersion
\Uninstall
\{ProductCode}
Registry Value |
Type | Corresponding Windows Installer Property |
Contains |
DisplayName | REG_SZ | ProductName | Display name of application |
UninstallPath | REG_EXPAND_SZ | N/A | Full path to the application's uninstall program |
InstallLocation | REG_EXPAND_SZ | ARPINSTALLLOCATION | Full path where application is located (folder or .exe) |
Publisher | REG_SZ | Manufacturer | Publisher/Developer of application |
VersionMajor | DWORD | ProductVersion | Major version number of application |
VersionMinor | DWORD | ProductVersion | Minor version of application |
Note Property names are case-sensitive.
You can also provide additional properties to present in Add/Remove Programs, if you like, such as product ID, online support information, etc. See the platform SDK for full details.
The uninstaller must accurately decrement the count on all the components your application uses that are installed as shared components. Delete them when the refcount reaches zero.
Your application must provide an automated uninstaller that removes the application. The uninstaller must be properly registered as specified in the Requirement 2.7, and it must remove the following:
The following should remain on the hard disk:
You must explain in the Vendor Questionnaire everything you leave behind.
Tip If your application creates temporary files that should be removed during uninstallation, create a zero-length (0) file with the same name at installation time. Examples of such files would be .gid files created by Help.
Note If your application uses the Windows Installer service, follows componentization rules, and uses only native Windows Installer actions to modify the computer, uninstall capability is provided automatically.
The VeriTest-Rational Install Analyzer for Windows 2000, available at http://www.veritest.com/mslogos/windows2000/, can help you do this.
To ensure that your application interoperates well with other applications (that do not use the Windows Installer) that share some of the same components that your application uses, you should test and verify each of the following scenarios:
Scenario 1 | Scenario 2 | Scenario 3 | Scenario 4 | |
Step 1 | Install your app | Install your app | Install "other" app | Install "other" app |
Step 2 | Install "other" app | Install "other" app | Install your app | Install your app |
Step 3 | Uninstall your app | Uninstall "other" app | Uninstall "other" app | Uninstall your app |
Step 4 | Verify "other" app still works | Verify your app still works | Verify your app still works | Verify "other" app still works |
Step 5 | Uninstall "other" app | Uninstall your app | Uninstall your app | Uninstall "other" app |
Step 6 | Verify that shared components are deleted | Verify that shared components are deleted | Verify that shared components are deleted | Verify that shared components are deleted |