Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

903 lines
21 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
uninst.c
Abstract:
Implements the code to launch the uninstall.
Author:
Jim Schmidt (jimschm) 28-Nov-2000
Revision History:
--*/
#include "pch.h"
#include "undop.h"
#include "resource.h"
//
// Types
//
typedef enum {
BACKUP_DOESNT_EXIST,
BACKUP_IN_PROGRESS,
BACKUP_SKIPPED_BY_USER,
BACKUP_COMPLETE
} JOURNALSTATUS;
//
// Global Variables
//
DRIVELETTERS g_DriveLetters;
TCHAR g_BootDrv = UNKNOWN_DRIVE;
#define WMX_STOP (WM_APP+96)
//
// Code
//
VOID
pAddSifEntry (
IN HINF Inf,
IN PINFSECTION Section,
IN PCTSTR Key,
IN PCTSTR Data
)
{
PTSTR quotedData;
quotedData = AllocText (CharCount (Data) + 2);
wsprintf (quotedData, TEXT("\"%s\""), Data);
AddInfLineToTable (Inf, Section, Key, quotedData, 0);
FreeText (quotedData);
}
BOOL
pEnablePrivilege(
IN PTSTR PrivilegeName,
IN BOOL Enable
)
{
HANDLE Token;
BOOL b;
TOKEN_PRIVILEGES NewPrivileges;
LUID Luid;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
return(FALSE);
}
if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
CloseHandle(Token);
return(FALSE);
}
NewPrivileges.PrivilegeCount = 1;
NewPrivileges.Privileges[0].Luid = Luid;
NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
b = AdjustTokenPrivileges(
Token,
FALSE,
&NewPrivileges,
0,
NULL,
NULL
);
CloseHandle(Token);
return(b);
}
VOID
pWriteDrvLtrFiles (
VOID
)
{
BOOL rf = TRUE;
DWORD index;
HANDLE signatureFile;
TCHAR signatureFilePath[MAX_PATH * 2];
DWORD signatureFilePathLength;
DWORD bytesWritten;
InitializeDriveLetterStructure (&g_DriveLetters);
//
// Hard drive information is actually written to a special signature file
// on the root directory of each fixed hard drive. The information is
// nothing special -- just the drive number (0 = A, etc.)
//
lstrcpy (signatureFilePath,TEXT("*:\\$DRVLTR$.~_~"));
signatureFilePathLength = lstrlen(signatureFilePath);
for (index = 0; index < NUMDRIVELETTERS; index++) {
if (g_DriveLetters.ExistsOnSystem[index] &&
g_DriveLetters.Type[index] == DRIVE_FIXED) {
*signatureFilePath = (TCHAR) index + TEXT('A');
signatureFile = CreateFile(
signatureFilePath,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_HIDDEN,
NULL
);
if (signatureFile != INVALID_HANDLE_VALUE) {
WriteFile (signatureFile, &index, sizeof(DWORD), &bytesWritten, NULL);
CloseHandle (signatureFile);
}
}
}
}
VOID
pAppendSystemRestore (
IN HANDLE FileHandle,
IN PCWSTR SystemGuid
)
{
INT index;
WCHAR outputStr[MAX_PATH];
DWORD dontCare;
DEBUGMSG ((DBG_VERBOSE, "Enumerating sr drives"));
for (index = 0; index < NUMDRIVELETTERS; index++) {
if (g_DriveLetters.ExistsOnSystem[index] &&
g_DriveLetters.Type[index] == DRIVE_FIXED
) {
wsprintfW (
outputStr,
L"%c:\\System Volume Information\\_restore%s\r\n",
(WCHAR) index + L'A',
SystemGuid
);
DEBUGMSGW ((DBG_VERBOSE, "Adding %s to deldirs.txt file", outputStr));
SetFilePointer (FileHandle, 0, NULL, FILE_END);
WriteFile (FileHandle, outputStr, ByteCountW (outputStr), &dontCare, NULL);
}
}
}
VOID
pAppendSystemRestoreToDelDirs (
IN PCTSTR DelDirsTxtPath
)
{
HANDLE delDirsFile = INVALID_HANDLE_VALUE;
HKEY key = NULL;
PCWSTR data = NULL;
__try {
key = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Services\\sr\\Parameters"));
if (!key) {
DEBUGMSG ((DBG_ERROR, "Can't open SR Parameters key"));
__leave;
}
data = GetRegValueStringW (key, L"MachineGuid");
if (!data) {
DEBUGMSG ((DBG_ERROR, "Can't get SR MachineGuid"));
__leave;
}
delDirsFile = CreateFile (
DelDirsTxtPath,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (delDirsFile == INVALID_HANDLE_VALUE) {
DEBUGMSG ((DBG_ERROR, "Can't open %s for writing", DelDirsTxtPath));
__leave;
}
pAppendSystemRestore (delDirsFile, data);
}
__finally {
if (delDirsFile != INVALID_HANDLE_VALUE) {
CloseHandle (delDirsFile);
}
if (data) {
FreeMem (data);
}
if (key) {
CloseRegKey (key);
}
}
}
BOOL
WINAPI
pCabNotificationSeekForDrive(
IN PCTSTR FileName
)
{
if(!FileName){
MYASSERT(FALSE);
return FALSE;
}
MYASSERT(UNKNOWN_DRIVE == g_BootDrv);
g_BootDrv = (TCHAR)FileName[0];
return -1;
}
BOOL
GetBootDrive(
IN PCTSTR BackUpPath,
IN PCTSTR Path
)
{
OCABHANDLE cabHandle;
if(UNKNOWN_DRIVE != g_BootDrv){
return TRUE;
}
cabHandle = CabOpenCabinet (Path);
if (cabHandle) {
SetCurrentDirectory (BackUpPath);
CabExtractAllFilesEx (
cabHandle,
NULL,
(PCABNOTIFICATIONW)pCabNotificationSeekForDrive);
CabCloseCabinet (cabHandle);
MYASSERT(UNKNOWN_DRIVE != g_BootDrv);
} else {
return FALSE;
}
return TRUE;
}
DWORD
WINAPI
pLongOperationUi (
PVOID DontCare
)
{
HWND h;
RECT parentRect;
MSG msg;
TCHAR textBuf[256];
HKEY key;
LONG rc;
DWORD size;
HFONT font;
HDC hdc;
LOGFONT lf;
SIZE textSize;
RECT rect;
HWND parent;
TCHAR title[128];
//
// Get dialog title
//
if (!LoadString (g_hInst, IDS_TITLE, title, ARRAYSIZE(title))) {
return 0;
}
//
// Get display text
//
key = OpenRegKeyStr (S_WIN9XUPG_KEY);
if (!key) {
return 0;
}
size = sizeof (textBuf);
rc = RegQueryValueEx (key, S_UNINSTALL_DISP_STR, NULL, NULL, (PBYTE) textBuf, &size);
CloseRegKey (key);
if (rc != ERROR_SUCCESS) {
return 0;
}
//
// Create font object and compute width/height
//
hdc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
ZeroMemory (&lf, sizeof (lf));
lf.lfHeight = -MulDiv (9, GetDeviceCaps (hdc, LOGPIXELSY), 72);
StringCopy (lf.lfFaceName, TEXT("MS Shell Dlg"));
font = CreateFontIndirect (&lf);
SelectObject (hdc, font);
GetTextExtentPoint32 (hdc, textBuf, TcharCount (textBuf), &textSize);
DeleteDC (hdc);
//
// Compute window position
//
GetWindowRect (GetDesktopWindow(), &parentRect);
rect.left = (parentRect.right - parentRect.left) / 2;
rect.right = rect.left;
rect.left -= textSize.cx * 2;
rect.right += textSize.cx * 2;
rect.top = (parentRect.bottom - parentRect.top) / 2;
rect.bottom = rect.top;
rect.top -= textSize.cy * 4;
rect.bottom += textSize.cy * 4;
parent = CreateWindow (
TEXT("STATIC"),
title,
WS_OVERLAPPED|WS_BORDER|WS_CAPTION|SS_WHITERECT,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
g_hInst,
NULL
);
//
// Create static control
//
GetClientRect (parent, &rect);
//
// Create window & let it run until verify is done
//
h = CreateWindow (
TEXT("STATIC"),
textBuf,
WS_CHILD|SS_CENTER|SS_CENTERIMAGE,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
parent,
NULL,
g_hInst,
NULL
);
SendMessage (h, WM_SETFONT, (WPARAM) font, 0);
ShowWindow (parent, SW_SHOW);
ShowWindow (h, SW_SHOW);
UpdateWindow (parent);
while (GetMessage (&msg, NULL, 0, 0)) {
if (msg.message == WMX_STOP) {
DestroyWindow (parent);
break;
}
TranslateMessage (&msg);
DispatchMessage (&msg);
}
DeleteObject (font);
return 0;
}
DWORD
pStartLongOperationUi (
VOID
)
{
HANDLE h;
DWORD threadId;
h = CreateThread (
NULL,
0,
pLongOperationUi,
NULL,
0,
&threadId
);
if (!h) {
return 0;
}
CloseHandle (h);
return threadId;
}
VOID
pKillLongOperationUi (
IN DWORD ThreadId
)
{
if (ThreadId) {
PostThreadMessage (ThreadId, WMX_STOP, 0, 0);
}
}
BOOL
CheckCabForAllFilesAvailability(
IN PCTSTR CabPath
)
{
OCABHANDLE cabHandle;
BOOL result = FALSE;
DWORD threadId;
threadId = pStartLongOperationUi();
cabHandle = CabOpenCabinet (CabPath);
if (cabHandle) {
result = CabVerifyCabinet (cabHandle);
CabCloseCabinet (cabHandle);
}
pKillLongOperationUi (threadId);
return result;
}
BOOL
DoUninstall (
VOID
)
{
HINF inf = INVALID_HANDLE_VALUE;
PINFSECTION section;
PCTSTR path = NULL;
PCTSTR path2 = NULL;
PCTSTR sifPath = NULL;
TCHAR bootPath[4] = TEXT("?:\\");
BOOL error = TRUE;
OCABHANDLE cabHandle;
PINFLINE infLine;
DWORD attribs;
PCTSTR backUpPath;
PTSTR updatedData;
BOOL cantSave;
TCHAR textModeBootIniEntry[] = TEXT("?:\\$win_nt$.~bt\\bootsect.dat");
TCHAR bootDirPath[MAX_PATH] = TEXT("");
HANDLE fileHandle;
DWORD bytesWritten;
JOURNALSTATUS journalStatus;
BOOL result;
__try {
backUpPath = GetUndoDirPath();
SetCursor (LoadCursor (NULL, IDC_WAIT));
//
// Retrieve directory path of backup directory
//
if(!backUpPath) {
LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to retrieve directory path"));
__leave;
}
//
// Recreate "backup.$$$" with correct content, if file was not in place.
//
path = JoinPaths (backUpPath, TEXT("backup.$$$"));
if(0xffffffff == GetFileAttributes(path)){
MYASSERT(ERROR_FILE_NOT_FOUND == GetLastError());
fileHandle = CreateFile(path,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(INVALID_HANDLE_VALUE != fileHandle){
journalStatus = BACKUP_COMPLETE;
result = WriteFile(fileHandle,
&journalStatus,
sizeof(journalStatus),
&bytesWritten,
NULL);
CloseHandle(fileHandle);
if(!result){
LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to write to backup.$$$"));
__leave;
}
}
else {
LOG ((LOG_WARNING, "Uninstall Cleanup: Failed to create file backup.$$$"));
__leave;
}
}
FreePathString (path);
//
// Write a drive signature file to each drive
//
pWriteDrvLtrFiles();
//
// Prepare boot path, clean out existing $win_nt$.~bt
// directory
//
path = JoinPaths (backUpPath, TEXT("boot.cab"));
if(GetBootDrive(backUpPath, path)){
bootPath[0] = g_BootDrv;
textModeBootIniEntry[0] = g_BootDrv;
}
else{
LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path));
__leave;
}
FreePathString (path);
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt"));
RemoveCompleteDirectory (path);
StringCopy(bootDirPath, path);
FreePathString (path);
path = NULL;
//
// Extract the boot files from the boot.cab
//
path = JoinPaths (backUpPath, TEXT("boot.cab"));
cabHandle = CabOpenCabinet (path);
if (cabHandle) {
SetCurrentDirectory (backUpPath);
CabExtractAllFiles (cabHandle, NULL);
CabCloseCabinet (cabHandle);
} else {
LOG ((LOG_WARNING, "Uninstall Cleanup: Unable to open %s", path));
__leave;
}
//
// Verify the CAB expanded properly
//
FreePathString (path);
path = NULL;
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt"));
if (!DoesFileExist (path)) {
LOG ((LOG_ERROR, "Files did not expand properly or boot.cab is damaged"));
__leave;
}
FreePathString (path);
path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT);
if (!DoesFileExist (path)) {
LOG ((LOG_ERROR, "delfiles.txt not found"));
__leave;
}
FreePathString (path);
path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT);
if (!DoesFileExist (path)) {
LOG ((LOG_ERROR, "deldirs.txt not found"));
__leave;
}
FreePathString (path);
path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT);
if (!DoesFileExist (path)) {
LOG ((LOG_ERROR, "mkdirs.txt not found"));
__leave;
}
FreePathString (path);
path = NULL;
path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT);
if (!DoesFileExist (path)) {
LOG ((LOG_ERROR, "moved.txt not found"));
__leave;
}
FreePathString (path);
path = NULL;
//
// Modify winnt.sif so that text mode knows what to do
//
sifPath = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\winnt.sif"));
inf = OpenInfFile (sifPath);
if (inf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "Can't open %s", sifPath));
__leave;
}
section = FindInfSectionInTable (inf, TEXT("data"));
if (section) {
//
// Write keys to winnt.sif...
//
if (!FindLineInInfSection (inf, section, TEXT("Rollback"))) {
pAddSifEntry (inf, section, TEXT("Rollback"), TEXT("1"));
}
//
// ...change %windir%\setup\uninstall\*.txt to %backuppath%\*.txt
//
// moved.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_MOVE);
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
path = JoinPaths (backUpPath, S_ROLLBACK_MOVED_TXT);
pAddSifEntry (inf, section, WINNT_D_ROLLBACK_MOVE, path);
FreePathString (path);
path = NULL;
// delfiles.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE);
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
path = JoinPaths (backUpPath, S_ROLLBACK_DELFILES_TXT);
pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE, path);
FreePathString (path);
path = NULL;
// deldirs.txt
infLine = FindLineInInfSection (inf, section, WINNT_D_ROLLBACK_DELETE_DIR);
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
path = JoinPaths (backUpPath, S_ROLLBACK_DELDIRS_TXT);
pAddSifEntry (inf, section, WINNT_D_ROLLBACK_DELETE_DIR, path);
//
// append System Restore directories to deldirs.txt
//
DEBUGMSG ((DBG_VERBOSE, "Appending SR dirs to %s", path));
pAppendSystemRestoreToDelDirs (path);
FreePathString (path);
path = NULL;
// mkdirs.txt
infLine = FindLineInInfSection (inf, section, S_ROLLBACK_MK_DIRS);
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
path = JoinPaths (backUpPath, S_ROLLBACK_MKDIRS_TXT);
pAddSifEntry (inf, section, S_ROLLBACK_MK_DIRS, path);
FreePathString (path);
path = NULL;
//
// ...write changed winnt.sif file
//
if (!SaveInfFile (inf, sifPath)) {
LOG ((LOG_ERROR, "Unable to update winnt.sif"));
__leave;
}
//
// clone txtsetup.sif
//
path = JoinPaths (bootPath, TEXT("$win_nt$.~bt\\txtsetup.sif"));
path2 = JoinPaths (bootPath, TEXT("txtsetup.sif"));
SetFileAttributes (path2, FILE_ATTRIBUTE_NORMAL);
if (!CopyFile (path, path2, FALSE)) {
LOG ((LOG_ERROR, "Can't copy %s to %s", path, path2));
__leave;
}
FreePathString (path);
path = NULL;
FreePathString (path2);
path2 = NULL;
} else {
LOG ((LOG_ERROR, "[data] not found in winnt.sif"));
}
CloseInfFile (inf);
FreePathString (sifPath);
sifPath = NULL;
//
// Edit the current boot.ini
//
sifPath = JoinPaths (bootPath, TEXT("boot.ini"));
inf = OpenInfFile (sifPath);
if (inf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "Can't open %s", sifPath));
__leave;
}
section = FindInfSectionInTable (inf, TEXT("Operating Systems"));
if (!section) {
LOG ((LOG_ERROR, "[Operating Systems] not found in boot.ini"));
__leave;
}
//
// Add /rollback to textmode entry
//
infLine = FindLineInInfSection (inf, section, textModeBootIniEntry);
if (infLine) {
if(!_tcsistr (infLine->Data, TEXT("/rollback"))){
updatedData = AllocText (TcharCount (infLine->Data) + 10);
StringCopy (updatedData, infLine->Data);
StringCat (updatedData, TEXT(" /rollback"));
AddInfLineToTable (inf, section, infLine->Key, updatedData, infLine->LineFlags);
DeleteLineInInfSection (inf, infLine);
FreeText (updatedData);
}
} else {
updatedData = AllocText (256 + sizeof (TEXT("\" /rollback\"")) / sizeof (TCHAR));
StringCopy (updatedData, TEXT("\""));
if (!LoadString (g_hInst, IDS_TITLE, GetEndOfString (updatedData), 256)) {
DEBUGMSG ((DBG_ERROR, "Can't load boot.ini text"));
__leave;
}
StringCat (updatedData, TEXT("\" /rollback"));
AddInfLineToTable (inf, section, textModeBootIniEntry, updatedData, 0);
FreeText (updatedData);
}
//
// Set timeout to zero and set default
//
section = FindInfSectionInTable (inf, TEXT("boot loader"));
if (!section) {
LOG ((LOG_ERROR, "[Boot Loader] not found in boot.ini"));
__leave;
}
infLine = FindLineInInfSection (inf, section, TEXT("timeout"));
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
AddInfLineToTable (inf, section, TEXT("timeout"), TEXT("0"), 0);
infLine = FindLineInInfSection (inf, section, TEXT("default"));
if (infLine) {
DeleteLineInInfSection (inf, infLine);
}
AddInfLineToTable (inf, section, TEXT("default"), textModeBootIniEntry, 0);
//
// Save changes
//
attribs = GetFileAttributes (sifPath);
SetFileAttributes (sifPath, FILE_ATTRIBUTE_NORMAL);
cantSave = (SaveInfFile (inf, sifPath) == FALSE);
if (attribs != INVALID_ATTRIBUTES) {
SetFileAttributes (sifPath, attribs);
}
if (cantSave) {
LOG ((LOG_ERROR, "Unable to update boot.ini"));
__leave;
}
//
// Rollback environment is ready to go
//
error = FALSE;
}
__finally {
FreePathString (path);
FreePathString (path2);
FreePathString (sifPath);
if (backUpPath) {
MemFree (g_hHeap, 0, backUpPath);
}
if (inf != INVALID_HANDLE_VALUE) {
CloseInfFile (inf);
}
}
//
// Shutdown on success
//
if (!error) {
pEnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
ExitWindowsEx (EWX_REBOOT, 0);
} else {
RemoveCompleteDirectory (bootDirPath);
return FALSE;
}
return TRUE;
}