windows-nt/Source/XPSP1/NT/windows/appcompat/windowsupdate/installer/wuuninst.cpp
2020-09-26 16:20:57 +08:00

722 lines
20 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
Duuninst.cpp
Abstract:
Contains the main uninstallation code
used by the app.
Notes:
Unicode only.
History:
03/02/2001 rparsons Created
--*/
#include "precomp.h"
extern SETUP_INFO g_si;
/*++
Routine Description:
Removes the specified registry key
Assumes HKEY_LOCAL_MACHINE
Arguments:
lpwKey - Path of the key to open
lpwSubKey - Path of the subkey to delete
Return Value:
None
--*/
void
UninstallDeleteSubKey(
IN LPCWSTR lpwKey,
IN LPCWSTR lpwSubKey
)
{
CRegistry creg;
//
// Remove the key from the registry
//
creg.DeleteRegistryKey(HKEY_LOCAL_MACHINE,
lpwKey,
lpwSubKey,
TRUE,
TRUE);
return;
}
/*++
Routine Description:
Retrieves the section names from the uninstall
INF file. This dictates what operations will be
performed during uninstall
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
UninstallGetSectionsFromINF()
{
BOOL fReturn = FALSE;
DWORD dwType = 0;
char szSectionName[MAX_QUEUE_SIZE] = "";
char *pSectionName;
WCHAR wszDirective[MAX_PATH] = L"";
INFCONTEXT InfContext;
//
// Loop through all the lines in the Sections section(s),
//
fReturn = SetupFindFirstLineA(g_si.hInf, INF_MASTER_SECTIONS, NULL,
&InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szSectionName, MAX_QUEUE_SIZE, NULL);
while (fReturn) {
//
// Determine which section we're working with
//
if (strstr(szSectionName, INF_RESTORE_FILES)) {
dwType = dwRestoreFiles;
} else if (strstr(szSectionName, INF_DELETE_REGISTRY)) {
dwType = dwDeleteRegistry;
} else if (strstr(szSectionName, INF_RESTORE_REGISTRY)) {
dwType = dwRestoreRegistry;
} else if (strstr(szSectionName, INF_UNREGISTRATIONS)) {
dwType = dwUnRegistrations;
} else if (strstr(szSectionName, INF_EXCLUDE)) {
dwType = dwExclusionsUninstall;
} else {
Print(ERROR,
L"[UninstallGetSectionsFromINF] Illegal section name passed %s\n",
szSectionName);
return FALSE; // illegal section name
}
pSectionName = strtok(szSectionName, ",");
do {
pAnsiToUnicode(pSectionName, wszDirective, MAX_PATH);
//
// Loop through each section name and add it to the
// appropriate queue
//
switch (dwType) {
case dwRestoreFiles:
g_si.RestoreFileQueue.Enqueue(wszDirective);
break;
case dwDeleteRegistry:
g_si.DeleteRegistryQueue.Enqueue(wszDirective);
break;
case dwRestoreRegistry:
g_si.RestoreRegistryQueue.Enqueue(wszDirective);
break;
case dwUnRegistrations:
g_si.RegistrationQueue.Enqueue(wszDirective);
break;
case dwExclusionsUninstall:
g_si.ExclusionQueue.Enqueue(wszDirective);
break;
default:
return FALSE; // illegal section name
}
pSectionName = strtok(NULL, ",");
} while (NULL != pSectionName);
fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szSectionName, MAX_QUEUE_SIZE, NULL);
}
return TRUE;
}
/*++
Routine Description:
Restores registry keys that were saved
during the install
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
UninstallRestoreRegistryKeys()
{
BOOL fReturn = FALSE, fResult = FALSE;
HKEY hKeyRoot = NULL;
char szEntry[MAX_QUEUE_SIZE] = "";
WCHAR wszEntry[MAX_QUEUE_SIZE] = L"";
char szKeyPath[MAX_PATH*3] = "";
WCHAR wszKeyPath[MAX_PATH*3] = L"";
LPWSTR lpwSubKey = NULL, lpwFilePath = NULL, lpwKeyRoot = NULL;
UINT uCount = 0;
CRegistry creg;
INFCONTEXT InfContext;
//
// The entry in the uninstall INF will have the following format:
// HKxx,SubKeyPath,PathToBackupFile
//
//
// Step through each entry in the queue
//
while (g_si.RestoreRegistryQueue.GetSize()) {
g_si.RestoreRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
//
// Loop through all the lines in the restore registry section(s),
// and perform the restore
//
fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
&InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szKeyPath, MAX_PATH*3, NULL);
while (fReturn) {
pAnsiToUnicode(szKeyPath, wszKeyPath, MAX_PATH*3);
//
// Split the key path into three separate parts
//
lpwKeyRoot = GetNextToken(wszKeyPath, L",");
if (NULL == lpwKeyRoot) {
break;
}
Print(TRACE, L"[UninstallRestoreRegistryKeys] Key root: %s\n", lpwKeyRoot);
if (!_wcsicmp(lpwKeyRoot, L"HKLM")) {
hKeyRoot = HKEY_LOCAL_MACHINE;
} else if (!_wcsicmp(lpwKeyRoot, L"HKCR")) {
hKeyRoot = HKEY_CLASSES_ROOT;
} else if (!_wcsicmp(lpwKeyRoot, L"HKCU")) {
hKeyRoot = HKEY_CURRENT_USER;
} else if (!_wcsicmp(lpwKeyRoot, L"HKU")) {
hKeyRoot = HKEY_USERS;
} else {
break;
}
//
// Get the subkey path
//
lpwSubKey = GetNextToken(NULL, L",");
if (NULL == lpwSubKey) {
break;
}
Print(TRACE, L"[UninstallRestoreRegistryKeys] Subkey path: %s\n", lpwSubKey);
//
// Get the file name with full path
//
lpwFilePath = GetNextToken(NULL, L",");
if (NULL == lpwFilePath) {
break;
}
Print(TRACE, L"[UninstallRestoreRegistryKeys] File path: %s\n", lpwFilePath);
//
// Restore the key
//
fResult = creg.RestoreKey(hKeyRoot, lpwSubKey, lpwFilePath, TRUE);
if (!fResult) {
Print(ERROR,
L"[UninstallRestoreRegistryKeys] Failed to restore key\n");
return FALSE;
}
fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szKeyPath, MAX_PATH*3, NULL);
}
}
return TRUE;
}
/*++
Routine Description:
Removes files from the installation directory
Arguments:
None
Return Value:
None
--*/
BOOL
UninstallRemoveFiles()
{
CEnumDir ced;
//
// Remove files from the installation directory,
// but leave subdirectories alone
//
ced.EnumerateDirectoryTree(g_si.lpwInstallDirectory,
DeleteOneFile,
FALSE,
(PVOID) TRUE);
return TRUE;
}
/*++
Routine Description:
Restores files that were backed up during the install
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
UninstallRestoreFiles()
{
WCHAR wszBackupDir[MAX_PATH] = L"";
WCHAR wszDestFileName[MAX_PATH] = L"";
WCHAR wszSourceFileName[MAX_PATH] = L"";
char szEntry[MAX_PATH] = "";
WCHAR wszEntry[MAX_PATH] = L"";
char szFileName[MAX_PATH] = "";
WCHAR wszFileName[MAX_PATH] = L"";
BOOL fReturn = FALSE, fResult = FALSE;
LPWSTR lpwDestDir = NULL;
DWORDLONG dwlSourceVersion = 0, dwlDestVersion = 0;
INFCONTEXT InfContext;
//
// Step through each entry in the queue
//
while (g_si.RestoreFileQueue.GetSize()) {
g_si.RestoreFileQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
//
// Get the destination directory
//
GetNextToken(wszEntry, L".");
GetNextToken(NULL, L".");
lpwDestDir = GetNextToken(NULL, L".");
if (NULL == lpwDestDir) {
break;
}
//
// Loop through all the lines in the restore files section(s),
// and perform the copy
//
fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
&InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szFileName, MAX_PATH, NULL);
while (fReturn) {
pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
//
// Build the path to the destination file
//
wsprintf(wszDestFileName,
L"%s\\%s\\%s",
g_si.lpwWindowsDirectory,
lpwDestDir,
wszFileName);
//
// Build the path to the source file
//
wsprintf(wszSourceFileName,
L"%s\\%s\\%s",
g_si.lpwExtractPath,
g_si.lpwUninstallDirectory,
wszFileName);
//
// Ensure that this file is not under WFP
//
fResult = IsFileProtected(wszDestFileName);
//
// Copy the file - be sensitive to WFP
//
if (fResult) {
Print(TRACE,
L"[UninstallRestoreFiles] Preparing to restore WFP file from %s to %s\n",
wszSourceFileName, wszDestFileName);
fResult = CommonEnableProtectedRenames();
if (!fResult) {
Print(ERROR,
L"[UninstallRestoreFiles] Failed to enable protected renames\n");
return FALSE;
}
Print(TRACE,
L"[UninstallRestoreFiles] Preparing to install WFP file from %s to %s\n",
wszSourceFileName, wszDestFileName);
fResult = UninstallWFPFile(wszSourceFileName,
wszFileName,
wszDestFileName,
g_si.fUpdateDllCache);
if (!fResult) {
Print(ERROR,
L"[UninstallRestoreFiles] Failed to install WFP file %s\n",
wszFileName);
return FALSE;
}
} else {
Print(TRACE,
L"[UninstallRestoreFiles] Preparing to restore file from %s to %s\n",
wszSourceFileName, wszDestFileName);
fResult = ForceMove(wszSourceFileName, wszDestFileName);
if (!fResult) {
Print(ERROR,
L"[UninstallRestoreFiles] Failed to restore file from %s to %s. GLE = %d\n",
wszSourceFileName, wszDestFileName, GetLastError());
return FALSE;
}
}
fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
SetupGetLineTextA(&InfContext,
NULL, NULL, NULL,
szFileName, MAX_PATH, NULL);
}
}
return TRUE;
}
/*++
Routine Description:
Restores a file that is protected
by WFP
Arguments:
lpwSourceFileName - Path to the source file
lpwDestFileName - Name of the destination file
lpwDestFileNamePath Name & path to the destination file
fUpdateDllCache - A flag to indicate if the file
should be placed in the DllCache directory
Return Value:
TRUE on success, FALSE otherwise
--*/
BOOL
UninstallWFPFile(
IN LPCWSTR lpwSourceFileName,
IN LPCWSTR lpwDestFileName,
IN LPCWSTR lpwDestFileNamePath,
IN BOOL fUpdateDllCache
)
{
LPWSTR lpwCachePath = NULL;
LPWSTR lpwExpandedCachePath = NULL;
LPWSTR lpwTempFileName = NULL;
DWORD cbSize = 0;
WCHAR wszDllCachePath[MAX_PATH] = L"";
CRegistry creg;
if (g_si.fUpdateDllCache) {
Print(TRACE,
L"[UninstallWFPFile] Restoring %s to DllCache dir\n",
lpwSourceFileName);
//
// Try to get the dllcache directory path from
// the registry
//
lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE,
REG_WINFP_PATH,
L"SfcDllCacheDir",
TRUE);
if (lpwCachePath) {
if (cbSize = ExpandEnvironmentStrings(lpwCachePath,
lpwExpandedCachePath,
0)) {
lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR));
if (lpwExpandedCachePath) {
if (ExpandEnvironmentStrings(lpwCachePath,
lpwExpandedCachePath,
cbSize)) {
//
// Build a full path to \%windir%\system32\dllcache\filename.xxx
//
wsprintf(wszDllCachePath,
L"%s\\%s",
lpwExpandedCachePath,
lpwDestFileName);
}
}
}
}
//
// If we couldn't get it from that key, try another
//
if (NULL == lpwExpandedCachePath) {
lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE,
REG_WINLOGON_PATH,
L"SfcDllCacheDir",
TRUE);
if (lpwCachePath) {
if (cbSize = ExpandEnvironmentStrings(lpwCachePath,
lpwExpandedCachePath,
0)) {
lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR));
if (lpwExpandedCachePath) {
if (ExpandEnvironmentStrings(lpwCachePath,
lpwExpandedCachePath,
cbSize)) {
//
// Build a full path to \%windir%\system32\dllcache\filename.xxx
//
wsprintf(wszDllCachePath,
L"%s\\%s",
lpwExpandedCachePath,
lpwDestFileName);
}
}
}
}
}
//
// If neither key worked, build the path manually
//
if (NULL == lpwExpandedCachePath) {
wsprintf(wszDllCachePath,
L"%s\\DllCache\\%s",
g_si.lpwSystem32Directory,
lpwDestFileName);
}
//
// Replace the file in the DllCache directory
//
if (!CopyFile(lpwSourceFileName, wszDllCachePath, FALSE)) {
Print(ERROR,
L"[UninstallWFPFile] Failed to copy %s to %s\n",
lpwSourceFileName, wszDllCachePath);
goto cleanup;
return FALSE;
}
}
//
// This is semi-custom, but because some of the
// WFPs will be in use, we'll delay replace them
// and let the Session Manager rename them
//
lpwTempFileName = CopyTempFile(lpwSourceFileName,
g_si.lpwSystem32Directory);
if (NULL == lpwTempFileName) {
Print(ERROR, L"[UninstallWFPFile] Failed to get temp file\n");
goto cleanup;
return FALSE;
}
if (!MoveFileEx(lpwTempFileName,
lpwDestFileNamePath,
MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT)) {
Print(ERROR, L"[UninstallWFPFile] Failed to delay replace from %s to %s\n",
lpwTempFileName, lpwDestFileNamePath);
goto cleanup;
return FALSE;
}
cleanup:
if (lpwTempFileName) {
FREE(lpwTempFileName);
}
if (lpwExpandedCachePath) {
FREE(lpwExpandedCachePath);
}
return TRUE;
}
/*++
Routine Description:
Custom worker routine for uninstall
Arguments:
None
Return Value:
None
--*/
void
UninstallCustomWorker()
{
//
// This is where determine if we should remove
// any regsvr32s that we did during install.
// We also remove the $Sources$ directory,
// if necessary.
// Our method of detection is to see if our
// Guid is present under the Active Setup
// key. If not, it's safe to assume that
// no package is currently installed
//
BOOL fReturn = FALSE;
CRegistry creg;
char szActiveSetupKey[MAX_PATH] = "";
WCHAR wszActiveSetupKey[MAX_PATH] = L"";
WCHAR wszSourcesDir[MAX_PATH] = L"";
fReturn = SetupGetLineTextA(NULL,
g_si.hInf,
"Strings",
"ActiveSetupKey",
szActiveSetupKey,
sizeof(szActiveSetupKey),
NULL);
if (!fReturn) {
return;
}
pAnsiToUnicode(szActiveSetupKey, wszActiveSetupKey, MAX_PATH);
fReturn = creg.IsRegistryKeyPresent(HKEY_LOCAL_MACHINE,
wszActiveSetupKey);
if (!fReturn) {
wsprintf(wszSourcesDir, L"%s\\$Sources$", g_si.lpwInstallDirectory);
CommonRemoveDirectoryAndFiles(wszSourcesDir, (PVOID) FALSE, TRUE, FALSE);
CommonRegisterServers(FALSE);
}
return;
}