|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
Dufns.cpp
Abstract:
Functions used throughout the app.
Notes:
Unicode only.
History:
03/02/2001 rparsons Created --*/
#include "precomp.h"
extern SETUP_INFO g_si;
/*++
Routine Description:
Parses the command line and fills in our structure that contains app-related data
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ParseCommandLine() { int nArgc = 0; int nCount = 0; LPWSTR *lpwCommandLine = NULL;
//
// Initialize structure members to defaults
//
g_si.fQuiet = FALSE; g_si.fInstall = TRUE; g_si.fForceInstall = FALSE; g_si.nErrorLevel = ERROR; g_si.fNoReboot = FALSE; g_si.fNoUninstall = FALSE; g_si.fNeedToAdjustACL = FALSE; g_si.fOnWin2K = FALSE; g_si.fUpdateDllCache = TRUE; g_si.fCanUninstall = TRUE; g_si.nErrorLevel = ERROR; //
// Get the command line
//
lpwCommandLine = CommandLineToArgvW(GetCommandLine(), &nArgc);
if (NULL == lpwCommandLine) { return FALSE; }
for (nCount = 1; nCount < nArgc; nCount++) {
if ((lpwCommandLine[nCount][0] == L'-') || (lpwCommandLine[nCount][0] == L'/')) { switch (lpwCommandLine[nCount][1]) { case 'q': case 'Q': g_si.fQuiet = TRUE; break;
case 'i': case 'I': g_si.fInstall = TRUE; break;
case 'u': case 'U': g_si.fInstall = FALSE; break;
case 'f': case 'F': g_si.fForceInstall = TRUE; break;
case 'd': case 'D': g_si.nErrorLevel = TRACE; break;
case 'z': case 'Z': g_si.fNoReboot = TRUE; break;
case 'n': case 'N': g_si.fNoUninstall = TRUE; break; } } }
GlobalFree(lpwCommandLine); return TRUE; }
/*++
Routine Description:
Determines if another instance of the application is running
Arguments:
lpwInstanceName - Name of the instance to look for
Return Value:
TRUE if another instance is present, FALSE otherwise
--*/ BOOL IsAnotherInstanceRunning( IN LPCWSTR lpwInstanceName ) { HANDLE hMutex = NULL; DWORD dwLastError = 0;
//
// Attempt to create a mutex with the given name
//
hMutex = CreateMutex(NULL, FALSE, lpwInstanceName);
if (NULL != hMutex) {
//
// See if it was created by another instance
//
dwLastError = GetLastError();
if (ERROR_ALREADY_EXISTS == dwLastError) { CloseHandle(hMutex); return TRUE; } else {
CloseHandle(hMutex); return FALSE; } }
return FALSE; }
/*++
Routine Description:
Obtains the path that the EXE is currently running from. This memory is allocated with the MALLOC macro and should be released with the FREE macro Arguments:
None Return Value:
On success, a pointer to our current directory On failure, NULL The directory path will not contain a trailing backslash
--*/ LPWSTR GetCurWorkingDirectory() { WCHAR wszFullPath[MAX_PATH]; LPWSTR lpwEnd = NULL, lpwReturn = NULL; DWORD dwLen = 0;
//
// Retrieve the full path where we're running from
//
dwLen = GetModuleFileName(NULL, wszFullPath, MAX_PATH);
if (dwLen <= 0) { return NULL; }
//
// Allocate memory and store the path
//
lpwReturn = (LPWSTR) MALLOC((wcslen(wszFullPath)+1)*sizeof(WCHAR));
if (NULL == lpwReturn) { return NULL; }
wcscpy(lpwReturn, wszFullPath);
//
// Find the last backslash
//
lpwEnd = wcsrchr(lpwReturn, '\\');
if (NULL == lpwEnd) { return NULL; } //
// Trim off the EXE name
//
if (lpwEnd){ *lpwEnd = '\0'; }
return (lpwReturn); }
/*++
Routine Description:
Obtains a non-string value from the given INF file Arguments:
hInf - Handle to the INF lpSectionName - Name of the section lpKeyName - Name of the key pdwValue - Receives the value
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL GetInfValue( IN HINF hInf, IN LPCSTR lpSectionName, IN LPCSTR lpKeyName, OUT PDWORD pdwValue ) { BOOL fReturn = FALSE; char szBuffer[MAX_PATH] = "";
fReturn = SetupGetLineTextA(NULL, hInf, lpSectionName, lpKeyName, szBuffer, sizeof(szBuffer), NULL); *pdwValue = strtoul(szBuffer, NULL, 0);
return (fReturn); }
/*++
Routine Description:
Determines if the user is an administrator
Arguments:
None Return Value:
-1 on failure 1 if the user is an admin 0 if they are not
--*/ int IsUserAnAdministrator() { HANDLE hToken; DWORD dwStatus = 0, dwAccessMask = 0; DWORD dwAccessDesired = 0, dwACLSize = 0; DWORD dwStructureSize = sizeof(PRIVILEGE_SET); PACL pACL = NULL; PSID psidAdmin = NULL; BOOL fReturn = FALSE; int nReturn = -1; PRIVILEGE_SET ps; GENERIC_MAPPING GenericMapping; PSECURITY_DESCRIPTOR psdAdmin = NULL; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
__try { // AccessCheck() requires an impersonation token
if (!ImpersonateSelf(SecurityImpersonation)) { __leave; } // Attempt to access the token for the current thread
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) { if (GetLastError() != ERROR_NO_TOKEN) { __leave; } // If the thread does not have an access token, we'll
// examine the access token associated with the process.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) __leave; } // Build a SID for administrators group
if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) __leave; // Allocate memory for the security descriptor
psdAdmin = MALLOC(SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psdAdmin == NULL) { __leave; } // Initialize the new security descriptor
if (!InitializeSecurityDescriptor(psdAdmin, SECURITY_DESCRIPTOR_REVISION)) { __leave; } // Compute size needed for the ACL
dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD); // Allocate memory for ACL
pACL = (PACL) MALLOC(dwACLSize);
if (pACL == NULL) { __leave; } // Initialize the new ACL
if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) { __leave; } dwAccessMask = ACCESS_READ | ACCESS_WRITE; // Add the access-allowed ACE to the DACL
if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin)) { __leave; } // Set our DACL to the security descriptor
if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) { __leave; } // AccessCheck is sensitive about the format of the
// security descriptor; set the group & owner
SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); // Ensure that the SD is valid
if (!IsValidSecurityDescriptor(psdAdmin)) { __leave; } dwAccessDesired = ACCESS_READ; // Initialize GenericMapping structure even though we
// won't be using generic rights.
GenericMapping.GenericRead = ACCESS_READ; GenericMapping.GenericWrite = ACCESS_WRITE; GenericMapping.GenericExecute = 0; GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; // After all that work, it boils down to this call
if (!AccessCheck(psdAdmin, hToken, dwAccessDesired, &GenericMapping, &ps, &dwStructureSize, &dwStatus, &fReturn)) { __leave; } RevertToSelf();
// Everything was a success
nReturn = (int) fReturn;
} // try
__finally {
if (pACL) { FREE(pACL); } if (psdAdmin){ FREE(psdAdmin); } if (psidAdmin){ FreeSid(psidAdmin); } } // finally
return (nReturn); }
/*++
Routine Description:
Gets the amount of available disk space on the drive that contains the Windows system files (boot partition)
Arguments: None
Return Value:
A 64-bit value containing the free space available on success, 0 on failure
--*/ DWORDLONG GetDiskSpaceFreeOnNTDrive() { UINT nLen = 0; BOOL fUseHeap = FALSE, fReturn = FALSE; WCHAR wszSysDir[MAX_PATH] = L""; WCHAR wszDiskName[4] = {'x',':','\\','\0'}; LPWSTR lpwSysDir = NULL; DWORDLONG dwlReturn = 0; unsigned __int64 i64FreeBytesToCaller = 0, i64TotalBytes = 0, i64TotalFreeBytes = 0;
nLen = GetSystemDirectory(wszSysDir, MAX_PATH);
if (0 == nLen) { return 0; }
if (nLen > MAX_PATH) {
//
// Allocate a buffer that will hold the return
//
lpwSysDir = (LPWSTR) MALLOC(nLen*sizeof(WCHAR));
if (NULL == lpwSysDir) { return 0; }
GetSystemDirectory(lpwSysDir, nLen*sizeof(WCHAR));
fUseHeap = TRUE; }
if (!fUseHeap) { wszDiskName[0] = wszSysDir[0]; } else {
wszDiskName[0] = lpwSysDir[0]; }
fReturn = GetDiskFreeSpaceEx(wszDiskName, (PULARGE_INTEGER) &i64FreeBytesToCaller, (PULARGE_INTEGER) &i64TotalBytes, (PULARGE_INTEGER) &i64TotalFreeBytes);
if (FALSE == fReturn) { return 0; }
//
// Calculate free MBs on drive
//
dwlReturn = i64FreeBytesToCaller / 0x100000;
if (lpwSysDir) { FREE(lpwSysDir); }
return (dwlReturn); }
/*++
Routine Description:
Displays a formated error to the screen
Arguments:
hWnd - Handle to the parent window dwMessageId - Message identifier lpwMessageArray - An array of insertion strings Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL DisplayErrMsg( IN HWND hWnd, IN DWORD dwMessageId, IN LPWSTR lpwMessageArray ) { LPVOID lpMsgBuf = NULL; DWORD dwReturn = 0; int nReturn = 0; WCHAR wszError[MAX_PATH] = L"";
dwReturn = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, g_si.hInstance, dwMessageId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &lpMsgBuf, 0, (va_list*) lpwMessageArray);
if (0 == dwReturn) { //
// We can't let it go without displaying an error message
// to the user
//
nReturn = LoadString(g_si.hInstance, IDS_FORMAT_MESSAGE_FAILED, wszError, MAX_PATH);
if (0 == nReturn) {
//
// Major problems - can't pull a string from the EXE
//
MessageBox(hWnd, LOAD_STRING_FAILED, g_si.lpwMessageBoxTitle, MB_OK | MB_ICONERROR);
return FALSE; }
MessageBox(hWnd, wszError, g_si.lpwMessageBoxTitle, MB_OK | MB_ICONERROR);
return FALSE; }
//
// Display the intended message to the user
//
MessageBox(hWnd, (LPCWSTR) lpMsgBuf, g_si.lpwMessageBoxTitle, MB_OK | MB_ICONERROR);
LocalFree(lpMsgBuf); return TRUE; }
/*++
Routine Description:
Given a version string, convert it to a long DWORD. This string will be in the form of aa,bb,cc,dd
Arguments:
lpwVersionString - The string to convert lpVersionNumber - Receives the converted version
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL VersionStringToNumber( IN LPCWSTR lpwVersionString, IN OUT DWORDLONG *lpVersionNumber ) { DWORDLONG dwVersion = 0; DWORD dwSubVersion; int nIndex;
for (nIndex = 0; nIndex < 4; nIndex++) {
if (*lpwVersionString == '\0') { return FALSE; }
dwSubVersion = 0;
while ((*lpwVersionString >= '0') && (*lpwVersionString <= '9')) {
dwSubVersion *= 10; dwSubVersion += ( *lpwVersionString - '0' );
if (dwSubVersion > 0x0000FFFF) { return FALSE; }
lpwVersionString++; }
if (*lpwVersionString == ',') { lpwVersionString++; } else if (*lpwVersionString != '\0') { return FALSE; }
dwVersion <<= 16; dwVersion += dwSubVersion; }
if (lpVersionNumber != NULL) { *lpVersionNumber = dwVersion; }
return TRUE; }
/*++
Routine Description:
Converts a UNICODE string to an ANSI one
Arguments:
lpwUnicodeString - The UNICODE string lpAnsiString - Receives the ANSI string nLen - The size of the ANSI buffer
Return Value:
None
--*/ void pUnicodeToAnsi( IN LPCWSTR lpwUnicodeString, IN OUT LPSTR lpAnsiString, IN int nLen ) { WideCharToMultiByte(CP_ACP, 0, lpwUnicodeString, -1, lpAnsiString, nLen, NULL, NULL); return; }
/*++
Routine Description:
Converts an ANSI string to a UNICODE one
Arguments: lpAnsiString - The ANSI string lpwUnicodeString - Receives the UNICODE string nLen - The size of the UNICODE buffer
Return Value:
None
--*/ void pAnsiToUnicode( IN LPCSTR lpAnsiString, IN OUT LPWSTR lpwUnicodeString, IN int nLen ) {
MultiByteToWideChar(CP_ACP, 0, lpAnsiString, -1, lpwUnicodeString, nLen); return; }
/*++
Routine Description:
Initializes frequently used strings, paths, etc.
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL WUInitialize() { BOOL fReturn = FALSE; int nReturn = 0; LPWSTR lpwCurrentDirectory = NULL; char szTemp[MAX_PATH] = ""; WCHAR wszTemp[MAX_PATH] = L""; WCHAR wszInstInfFileName[MAX_PATH] = L""; char szInstInfFileName[MAX_PATH] = ""; WCHAR wszUninstInfFileName[MAX_PATH] = L""; char szUninstInfFileName[MAX_PATH] = ""; char szMessageBoxTitle[MAX_PATH] = ""; WCHAR wszMessageBoxTitle[MAX_PATH] = L""; char szComponentName[MAX_PATH] = ""; WCHAR wszComponentName[MAX_PATH] = L""; char szEventLogSourceName[MAX_PATH] = ""; WCHAR wszEventLogSourceName[MAX_PATH] = L""; char szDestDir[MAX_PATH] = ""; WCHAR wszDestDir[MAX_PATH] = L""; char szUninstallDir[MAX_PATH] = ""; WCHAR wszUninstallDir[MAX_PATH] = L""; WCHAR wszSysDir[MAX_PATH] = L""; WCHAR wszWinDir[MAX_PATH] = L""; UINT uDirLen = 0; DWORD dwNoReboot = 0, dwNoUninstall = 0, dwQuiet = 0; DWORD dwAdjustACL = 0, dwUpdateDllCache = 0; DWORDLONG dwlFreeSpace = 0; OSVERSIONINFOEX osviex; //
// Perform a version check - Windows 2000 or greater
//
ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX)); osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *) &osviex); if ((osviex.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osviex.dwMajorVersion == 5) && (osviex.dwMinorVersion == 0)) {
g_si.fOnWin2K = TRUE;
} else if ((osviex.dwPlatformId != VER_PLATFORM_WIN32_NT) && (osviex.dwMajorVersion < 5)) { return FALSE; }
//
// Determine where we're running from and save it
//
lpwCurrentDirectory = GetCurWorkingDirectory();
if (NULL == lpwCurrentDirectory) { return FALSE; }
g_si.lpwExtractPath = (LPWSTR) MALLOC((wcslen(lpwCurrentDirectory)+1)*sizeof(WCHAR));
if (NULL == g_si.lpwExtractPath) { return FALSE; }
wcscpy(g_si.lpwExtractPath, lpwCurrentDirectory);
//
// Set up the path to the install INF, make it ANSI, and save it
//
wsprintf(wszInstInfFileName, L"%s\\%s", lpwCurrentDirectory, INF_FILE_NAMEW); pUnicodeToAnsi(wszInstInfFileName, szInstInfFileName, MAX_PATH); g_si.lpwInstallINFPath = (LPWSTR) MALLOC((wcslen(wszInstInfFileName)+1)*sizeof(WCHAR));
if (NULL == g_si.lpwInstallINFPath) { return FALSE; }
wcscpy(g_si.lpwInstallINFPath, wszInstInfFileName);
//
// Set up the path to the uninstall INF, make it ANSI, and save it
//
wsprintf(wszUninstInfFileName, L"%s\\%s", lpwCurrentDirectory, UNINST_INF_FILE_NAMEW); pUnicodeToAnsi(wszUninstInfFileName, szUninstInfFileName, MAX_PATH); FREE(lpwCurrentDirectory);
g_si.lpwUninstallINFPath = (LPWSTR) MALLOC((wcslen(wszUninstInfFileName)+1)*sizeof(WCHAR));
if (NULL == g_si.lpwUninstallINFPath) { return FALSE; }
wcscpy(g_si.lpwUninstallINFPath, wszUninstInfFileName);
//
// We need to grab some strings from the INF
//
g_si.hInf = SetupOpenInfFileA(g_si.fInstall ? szInstInfFileName : szUninstInfFileName, NULL, INF_STYLE_WIN4, NULL);
if ((NULL == g_si.hInf) || (INVALID_HANDLE_VALUE == g_si.hInf)) { Print(ERROR, L"[WUInitialize] Failed to open INF\n"); return FALSE; }
fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "MessageBoxTitle", szMessageBoxTitle, sizeof(szMessageBoxTitle), NULL);
if (!fReturn) { return FALSE; }
fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "ComponentName", szComponentName, sizeof(szComponentName), NULL);
if (!fReturn) { return FALSE; }
fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "EventLogSourceName", szEventLogSourceName, sizeof(szEventLogSourceName), NULL);
if (!fReturn) { return FALSE; }
fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "DestDir", szTemp, sizeof(szTemp), NULL);
if (!fReturn) { return FALSE; }
fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "UninstallDirName", szUninstallDir, sizeof(szUninstallDir), NULL);
if (!fReturn) { return FALSE; }
if (g_si.fInstall) {
fReturn = GetInfValue(g_si.hInf, "Version", "RequiredFreeSpaceNoUninstall", &g_si.dwRequiredFreeSpaceNoUninstall);
if (!fReturn) { return FALSE; }
fReturn = GetInfValue(g_si.hInf, "Version", "RequiredFreeSpaceWithUninstall", &g_si.dwRequiredFreeSpaceWithUninstall);
if (!fReturn) { return FALSE; } GetInfValue(g_si.hInf, "Version", "NoReboot", &dwNoReboot); GetInfValue(g_si.hInf, "Version", "NoUninstall", &dwNoUninstall); GetInfValue(g_si.hInf, "Version", "AdjustACLOnTargetDir", &dwAdjustACL); GetInfValue(g_si.hInf, "Version", "UpdateDllCache", &dwUpdateDllCache); }
GetInfValue(g_si.hInf, "Version", "RunQuietly", &dwQuiet);
if (dwNoReboot) { g_si.fNoReboot = TRUE; }
if (dwNoUninstall) { g_si.fNoUninstall = TRUE; } if (dwQuiet) { g_si.fQuiet = TRUE; }
if (dwAdjustACL) { g_si.fNeedToAdjustACL = TRUE; }
if (!dwUpdateDllCache) { g_si.fUpdateDllCache = FALSE; }
//
// Expand the directory string
//
pAnsiToUnicode(szTemp, wszTemp, MAX_PATH); ExpandEnvironmentStrings(wszTemp, wszDestDir, MAX_PATH);
//
// Save the strings for later use
//
pAnsiToUnicode(szMessageBoxTitle, wszMessageBoxTitle, MAX_PATH); pAnsiToUnicode(szComponentName, wszComponentName, MAX_PATH); pAnsiToUnicode(szEventLogSourceName, wszEventLogSourceName, MAX_PATH); pAnsiToUnicode(szUninstallDir, wszUninstallDir, MAX_PATH);
uDirLen = GetSystemDirectory(wszSysDir, MAX_PATH);
if (0 == uDirLen) { return FALSE; }
uDirLen = GetWindowsDirectory(wszWinDir, MAX_PATH);
if (0 == uDirLen) { return FALSE; }
g_si.lpwMessageBoxTitle = (LPWSTR) MALLOC((wcslen(wszMessageBoxTitle)+1)*sizeof(WCHAR)); g_si.lpwPrettyAppName = (LPWSTR) MALLOC((wcslen(wszComponentName)+1)*sizeof(WCHAR)); g_si.lpwEventLogSourceName = (LPWSTR) MALLOC((wcslen(wszEventLogSourceName)+1)*sizeof(WCHAR)); g_si.lpwInstallDirectory = (LPWSTR) MALLOC((wcslen(wszDestDir)+1)*sizeof(WCHAR)); g_si.lpwUninstallDirectory = (LPWSTR) MALLOC((wcslen(wszUninstallDir)+1)*sizeof(WCHAR)); g_si.lpwSystem32Directory = (LPWSTR) MALLOC((wcslen(wszSysDir)+1)*sizeof(WCHAR)); g_si.lpwWindowsDirectory = (LPWSTR) MALLOC((wcslen(wszWinDir)+1)*sizeof(WCHAR));
if ((NULL == g_si.lpwMessageBoxTitle) || (NULL == g_si.lpwPrettyAppName) || (NULL == g_si.lpwEventLogSourceName) || (NULL == g_si.lpwInstallDirectory) || (NULL == g_si.lpwUninstallDirectory) || (NULL == g_si.lpwSystem32Directory) || (NULL == g_si.lpwWindowsDirectory)) { return FALSE; }
wcscpy(g_si.lpwMessageBoxTitle, wszMessageBoxTitle); wcscpy(g_si.lpwPrettyAppName, wszComponentName); wcscpy(g_si.lpwEventLogSourceName, wszEventLogSourceName); wcscpy(g_si.lpwInstallDirectory, wszDestDir); wcscpy(g_si.lpwUninstallDirectory, wszUninstallDir); wcscpy(g_si.lpwSystem32Directory, wszSysDir); wcscpy(g_si.lpwWindowsDirectory, wszWinDir);
//
// Ensure that the user has administrator rights
//
nReturn = IsUserAnAdministrator();
if (0 == nReturn) {
//
// The user is not an admin
//
LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_NOT_ADMIN, TRUE, FALSE);
return FALSE; } else if (-1 == nReturn) {
//
// The access check failed. Assume that problems occured
// during the check and continue. The worst thing that will
// happen is the user will see an error later on
//
LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_ADMIN_CHECK_FAILED, FALSE, FALSE);
return FALSE; } //
// Verify that we have enough disk space for the install
//
if (g_si.fInstall) { dwlFreeSpace = GetDiskSpaceFreeOnNTDrive();
if (dwlFreeSpace < g_si.dwRequiredFreeSpaceNoUninstall) {
//
// Not enough space available to complete
//
LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_NOT_ENOUGH_DISK_SPACE, TRUE, FALSE);
return FALSE; } }
return TRUE; }
/*++
Routine Description:
Releases any memory used throughout the app
Arguments:
None
Return Value:
None
--*/ void WUCleanup() { if (NULL != g_si.lpwEventLogSourceName) { FREE(g_si.lpwEventLogSourceName); }
if (NULL != g_si.lpwExtractPath) { FREE(g_si.lpwExtractPath); }
if (NULL != g_si.lpwInstallDirectory) { FREE(g_si.lpwInstallDirectory); }
if (NULL != g_si.lpwInstallINFPath) { FREE(g_si.lpwInstallINFPath); }
if (NULL != g_si.lpwUninstallINFPath) { FREE(g_si.lpwUninstallINFPath); }
if (NULL != g_si.lpwMessageBoxTitle) { FREE(g_si.lpwMessageBoxTitle); }
if (NULL != g_si.lpwPrettyAppName) { FREE(g_si.lpwPrettyAppName); }
if (NULL != g_si.lpwSystem32Directory) { FREE(g_si.lpwSystem32Directory); }
if (NULL != g_si.lpwUninstallDirectory) { FREE(g_si.lpwUninstallDirectory); }
if (NULL != g_si.lpwWindowsDirectory) { FREE(g_si.lpwWindowsDirectory); }
if (NULL != g_si.hInf) { SetupCloseInfFile(g_si.hInf); }
return; }
/*++
Routine Description:
Takes the DACL from a given directory and applies it to another directory
Arguments:
lpwSourceDir - The directory to get the DACL from lpwDestDir - The directory to apply the DACL to
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL MirrorDirectoryPerms( IN LPWSTR lpwSourceDir, IN LPWSTR lpwDestDir ) { DWORD dwResult = 0; BOOL fResult = FALSE; PACL pDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; PSID pOwnerSid;
__try {
//
// Get the DACL from the source directory
//
dwResult = GetNamedSecurityInfo(lpwSourceDir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, &pOwnerSid, NULL, &pDACL, NULL, &pSD); if (ERROR_SUCCESS != dwResult) { __leave; }
//
// Attach the DACL to the destination directory
//
dwResult = SetNamedSecurityInfo(lpwDestDir, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, pOwnerSid, NULL, pDACL, NULL); if (ERROR_SUCCESS != dwResult) { __leave; }
fResult = TRUE; } //try
__finally {
if (NULL != pSD) { LocalFree((HLOCAL) pSD); } } //finally
return (fResult); }
/*++
Routine Description:
Adjusts permissions on the given directory
Arguments:
lpwDirPath - Directory to modify
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL AdjustDirectoryPerms( IN LPWSTR lpwDirPath ) { DWORD dwResult = 0; PSID pSid = NULL; BOOL fReturn = FALSE, fResult = FALSE; PACL pOldDACL = NULL, pNewDACL = NULL; EXPLICIT_ACCESS ea; PSECURITY_DESCRIPTOR pSD = NULL; SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
__try {
//
// Get the DACL for the directory
//
dwResult = GetNamedSecurityInfo(lpwDirPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD); if (ERROR_SUCCESS != dwResult) { __leave; } //
// Build a SID to the local Users group
//
fReturn = AllocateAndInitializeSid(&sia, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &pSid);
if (!fReturn) { __leave; }
//
// Ensure that the SID is valid
//
fReturn = IsValidSid(pSid);
if (!fReturn) { __leave; } //
// Initialize an EXPLICIT_ACCESS structure for the new ACE
//
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE; ea.grfAccessMode = GRANT_ACCESS; ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; ea.Trustee.ptstrName = (LPTSTR) pSid; //
// Create a new ACL that merges the new ACE
// into the existing DACL
//
dwResult = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL); if (ERROR_SUCCESS != dwResult) { __leave; } //
// Attach the new ACL as the object's DACL
//
dwResult = SetNamedSecurityInfo(lpwDirPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL); if (ERROR_SUCCESS != dwResult) { __leave; }
// Everything was a success
fResult = TRUE; } // try
__finally {
if (NULL != pSD) { LocalFree((HLOCAL) pSD); }
if (NULL != pNewDACL) { LocalFree((HLOCAL) pNewDACL); }
if (NULL != pSid) { FreeSid(pSid); } } //finally
return (fResult); }
/*++
Routine Description:
Retrieves version information from a catalog file Arguments:
lpwCatName - The catalog file to check Return Value:
A DWORD which contains a version number for the catalog
--*/ DWORD GetCatVersion( IN LPWSTR lpwCatName ) { char szVersionString[MAX_PATH] = ""; HANDLE hCat = NULL; DWORD dwVer = 0; CRYPTCATATTRIBUTE *pSpCatAttr = NULL; NTSTATUS Status;
__try { hCat = CryptCATOpen(lpwCatName, 0, 0, 0, 0);
if (NULL == hCat) { __leave; } pSpCatAttr = CryptCATGetCatAttrInfo(hCat, L"SPAttr"); if ((pSpCatAttr == NULL) || (pSpCatAttr->pbValue == NULL)) { __leave; } pUnicodeToAnsi((LPWSTR)pSpCatAttr->pbValue, szVersionString, MAX_PATH); Status = RtlCharToInteger(szVersionString, 10, (PULONG)&dwVer); if (!NT_SUCCESS(Status)) { __leave; }
} // try
__finally {
if (hCat) { CryptCATClose(hCat); } } // finally
return (dwVer); }
/*++
Routine Description:
Wraps CreateProcess and WaitForSingleObject
Arguments:
lpwCommandLine - Command line to execute pdwReturnCode - Receives a return code from the process Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL LaunchProcessAndWait( IN LPCWSTR lpwCommandLine, OUT PDWORD pdwReturnCode ) { PROCESS_INFORMATION pi; STARTUPINFO si; BOOL fReturn = FALSE; LPWSTR lpwCmdLine = NULL;
//
// CreateProcess requires a non-const command line
//
lpwCmdLine = (LPWSTR) MALLOC((wcslen(lpwCommandLine)+1)*sizeof(WCHAR));
if (NULL == lpwCmdLine) { return FALSE; }
wcscpy(lpwCmdLine, lpwCommandLine);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
fReturn = CreateProcess(NULL, lpwCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (!fReturn) { return FALSE; }
WaitForSingleObject(pi.hProcess, INFINITE);
if (NULL != pdwReturnCode) { GetExitCodeProcess(pi.hProcess, pdwReturnCode); }
if (NULL != lpwCmdLine) { FREE(lpwCmdLine); }
CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
return TRUE; }
/*++
Routine Description:
Callback function for our directory enumeration routine
Arguments:
lpwPath - Path of the directory or filename pFindFileData - Pointer to WIN32_FIND_DATA struct containing information about lpwPath pEnumerateParameter - A 32-bit enumeration parameter
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL DeleteOneFile( IN LPCWSTR lpwPath, IN PWIN32_FIND_DATA pFindFileData, IN PVOID pEnumerateParameter ) { WCHAR wszTempPath[MAX_PATH] = L""; char szFileName[MAX_PATH] = ""; WCHAR wszFileName[MAX_PATH] = L""; char szEntry[MAX_QUEUE_SIZE] = ""; WCHAR wszEntry[MAX_QUEUE_SIZE] = L""; WCHAR wszTestPath[MAX_PATH] = L""; BOOL fCheckQueue = FALSE, fReturn = FALSE, fDelete = TRUE; LPWSTR lpwDestDir = NULL; int nLen = 0; LONG cLines = 0; INFCONTEXT InfContext;
if (pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { return TRUE; }
//
// Note: This may seem a little complex, but because there could
// multiple entries in a section, we have to run through them
// each time this function gets called.
//
//
// See if there's anything in the exclusion queue
//
fCheckQueue = (BOOL) pEnumerateParameter; if (fCheckQueue) {
nLen = g_si.ExclusionQueue.GetSize();
while (nLen != 0) {
//
// Walk through the queue and make sure
// we don't delete files we shouldn't
//
g_si.ExclusionQueue.Dequeue(wszEntry, MAX_QUEUE_SIZE - 1, TRUE);
pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
//
// Get the destination directory
//
GetNextToken(wszEntry, L"."); lpwDestDir = GetNextToken(NULL, L"."); if (NULL == lpwDestDir) { return FALSE; }
//
// Get the number of files in the section
//
cLines = SetupGetLineCountA(g_si.hInf, szEntry);
//
// Loop through all the lines in the exclusion section(s),
// and do a comparison
//
fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); while (fReturn) {
while (cLines != 0) { pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
//
// Put the path together
//
wsprintf(wszTestPath, L"%s\\%s", lpwDestDir, wszFileName); wcscpy(wszTempPath, lpwPath); CharLower(wszTestPath); CharLower(wszTempPath);
//
// See if the paths match
//
if (wcsstr(wszTempPath, wszTestPath)) { fDelete = FALSE; break; // paths match, move to the next file
}
SetupFindNextLine(&InfContext, &InfContext); SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL);
--cLines; }
if (fDelete) { ForceDelete(lpwPath); fDelete = TRUE; // reset the flag
} fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); }
nLen--; } } else {
//
// Don't worry about the queue, delete the file
//
ForceDelete(lpwPath); }
return TRUE; }
/*++
Routine Description:
Retrieves a token, given a separator. Basically a wrapper for strtok
Arguments:
lpwSourceString - The source string to parse lpwSeparator - The separator string that specifies the delimiter
Return Value:
A pointer to the return string
--*/ LPWSTR GetNextToken( IN LPWSTR lpwSourceString, IN LPCWSTR lpwSeparator ) { LPWSTR lpwReturn = NULL;
lpwReturn = wcstok(lpwSourceString, lpwSeparator);
return (lpwReturn); }
/*++
Routine Description:
Attempts to move a file. If it's in use, replace it on reboot
Arguments:
lpwSourceFileName - The source file name lpwDestFileName - The destination file name Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ForceMove( IN LPCWSTR lpwSourceFileName, IN LPCWSTR lpwDestFileName ) { WCHAR wszTempPath[MAX_PATH] = L""; WCHAR wszDelFileName[MAX_PATH] = L"";
if (!lpwSourceFileName || !lpwDestFileName) { return FALSE; }
if (!MoveFileEx(lpwSourceFileName, lpwDestFileName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
Print(TRACE, L"[ForceMove] First call to MoveFileEx failed. GLE = %d\n", GetLastError()); if (!GetTempPath(MAX_PATH, wszTempPath)) { return FALSE; } if (!GetTempFileName(wszTempPath, L"DEL", 0, wszDelFileName)) { return FALSE; }
if (!MoveFileEx(lpwDestFileName, wszDelFileName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
Print(ERROR, L"[ForceMove] Second call to MoveFileEx failed. GLE = %d\n", GetLastError()); return FALSE; } if (!MoveFileEx(wszDelFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) {
Print(ERROR, L"[ForceMove] Third call to MoveFileEx failed. GLE = %d\n", GetLastError()); return FALSE; }
if (!MoveFileEx(lpwSourceFileName, lpwDestFileName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) {
Print(ERROR, L"[ForceMove] Second call to MoveFileEx failed. GLE = %d\n", GetLastError()); return FALSE; } }
return TRUE; }
/*++
Routine Description:
Attempts to delete a file. If it's in use, delete it on reboot
Arguments:
lpwFileName - The file name to delete Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ForceDelete( IN LPCWSTR lpwFileName ) { WCHAR *pTempFile = NULL; WCHAR *pExt = NULL;
//
// Attempt to delete the specified file
//
SetFileAttributes(lpwFileName, FILE_ATTRIBUTE_NORMAL);
if (!DeleteFile(lpwFileName)) {
//
// The file is most likely in use
// Attempt to rename it
//
pTempFile = _wcsdup(lpwFileName);
pExt = PathFindExtension(pTempFile);
if (pExt) { wcscpy(pExt, L"._wu"); }
if (MoveFile(lpwFileName, pTempFile)) { //
// We renamed the target - delete it on reboot
//
MoveFileEx(pTempFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } else {
//
// Couldn't rename it - mark it for deletion on reboot
//
MoveFileEx(lpwFileName, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); }
free(pTempFile); }
return TRUE; }
/*++
Routine Description:
Attempts to copy a file If it's in use, move it and replace on reboot
Arguments:
lpwSourceFileName - The source file name lpwDestFileName - The destination file name Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ForceCopy( IN LPCWSTR lpwSourceFileName, IN LPCWSTR lpwDestFileName ) { WCHAR wszTempPath[MAX_PATH] = L""; WCHAR wszDelFileName[MAX_PATH] = L"";
if (!lpwSourceFileName || !lpwDestFileName) { return FALSE; }
if (!CopyFile(lpwSourceFileName, lpwDestFileName, FALSE)) { if (!GetTempPath(MAX_PATH, wszTempPath)) { return FALSE; } if (!GetTempFileName(wszTempPath, L"DEL", 0, wszDelFileName)) { return FALSE; } if (!MoveFileEx(lpwDestFileName, wszDelFileName, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) { return FALSE; } if (!MoveFileEx(wszDelFileName, NULL, MOVEFILE_COPY_ALLOWED | MOVEFILE_DELAY_UNTIL_REBOOT)) { return FALSE; } if (!CopyFile(lpwSourceFileName, lpwDestFileName, FALSE)) { return FALSE; } }
return TRUE; }
/*++
Routine Description:
Determines if a file is protected by WFP
Arguments:
lpwFileName - Name of the file
Return Value:
TRUE if the file is protected, FALSE otherwise
--*/ BOOL IsFileProtected( IN LPCWSTR lpwFileName ) { BOOL fReturn = FALSE;
if (lpwFileName == NULL) { return FALSE; }
return (SfcIsFileProtected(NULL, lpwFileName)); }
/*++
Routine Description:
Retrieve file version and language info from a file
The version is specified in the dwFileVersionMS and dwFileVersionLS fields of a VS_FIXEDFILEINFO, as filled in by the win32 version APIs. For the language we look at the translation table in the version resources and assume that the first langid/codepage pair specifies the language
If the file is not a coff image or does not have version resources, the function fails. The function does not fail if we are able to retrieve the version but not the language
Arguments:
lpwFileName - Supplies the full path of the file whose version data is desired
pdwVersion - Receives the version stamp of the file. If the file is not a coff image or does not contain the appropriate version resource data, the function fails
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL GetVersionInfoFromImage( IN LPCWSTR lpwFileName, OUT PDWORDLONG pdwVersion ) { DWORD nSize = 0L, dwIgnored = 0L; UINT nDataLength = 0; BOOL fResult = FALSE; PVOID pVersionBlock = NULL; VS_FIXEDFILEINFO *FixedVersionInfo;
//
// Get the size of version info block
//
nSize = GetFileVersionInfoSize((LPWSTR)lpwFileName, &dwIgnored);
if (nSize) { //
// Allocate memory block of sufficient size to hold version info block
//
pVersionBlock = MALLOC(nSize*sizeof(WCHAR)); if (pVersionBlock) {
//
// Get the version block from the file.
//
if (GetFileVersionInfo((LPWSTR)lpwFileName, 0, nSize*sizeof(WCHAR), pVersionBlock)) { //
// Get fixed version info
//
if (VerQueryValue(pVersionBlock, L"\\", (LPVOID*) &FixedVersionInfo, &nDataLength)) {
//
// Return version to caller
//
*pdwVersion = (((DWORDLONG)FixedVersionInfo->dwFileVersionMS) << 32) + FixedVersionInfo->dwFileVersionLS;
fResult = TRUE; } }
FREE(pVersionBlock); } }
return (fResult); }
/*++
Routine Description:
Copies the specified file giving it a temporary name
Arguments:
lpwFileName - The full path & name of the file Return Value:
A pointer to the full path & name of the file The caller is responsible for freeing the memory
--*/ LPWSTR CopyTempFile( IN LPCWSTR lpwSrcFileName, IN LPCWSTR lpwDestDir ) { LPWSTR lpwTempFileName = NULL;
lpwTempFileName = (LPWSTR) MALLOC(MAX_PATH * sizeof(WCHAR));
if (NULL == lpwTempFileName) { return NULL; }
if (!GetTempFileName(lpwDestDir, L"_wu", 0, lpwTempFileName)) { FREE(lpwTempFileName); return NULL; } else {
//
// Copy the source file down to the destination directory
// using the name we just got
//
if (!CopyFile(lpwSrcFileName, lpwTempFileName, FALSE)) { FREE(lpwTempFileName); return NULL; } }
return (lpwTempFileName); }
/*++
Routine Description:
Prints formatted debug strings
Arguments:
uLevel - A flag to indicate if the message should be displayed lpwFmt - A string to be displayed ... - A variable length argument list of insertion strings Return Value:
TRUE on success, FALSE otherwise
--*/ #if DBG
void Print( IN UINT uLevel, IN LPWSTR lpwFmt, IN ... ) { va_list arglist; if (g_si.nErrorLevel < uLevel) { return; }
va_start(arglist, lpwFmt);
_vsnwprintf(g_si.wszDebugOut, 2047, lpwFmt, arglist);
g_si.wszDebugOut[2047] = 0;
va_end(arglist);
OutputDebugString(g_si.wszDebugOut);
return; } #endif
/*++
Routine Description:
Reboots the system
Arguments:
fForceClose - A flag to indicate if apps should be forced to close fReboot - A flag to indicate if we should reboot after shutdown Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ShutdownSystem( IN BOOL fForceClose, IN BOOL fReboot ) { BOOL fResult = FALSE;
if (!ModifyTokenPrivilege(L"SeShutdownPrivilege", TRUE)) { return FALSE; }
fResult = InitiateSystemShutdown(NULL, // machinename
NULL, // shutdown message
0, // delay
fForceClose, // force apps close
fReboot // reboot after shutdown
);
ModifyTokenPrivilege(L"SeShutdownPrivilege", FALSE);
return (fResult); }
/*++
Routine Description:
Enables or disables a specified privilege
Arguments:
lpwPrivilege - The name of the privilege fEnable - A flag to indicate if the privilege should be enabled Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL ModifyTokenPrivilege( IN LPCWSTR lpwPrivilege, IN BOOL fEnable ) { HANDLE hToken = NULL; LUID luid; BOOL fResult = FALSE; TOKEN_PRIVILEGES tp;
if (NULL == lpwPrivilege) { return FALSE; }
__try { //
// Get a handle to the access token associated with the current process
//
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); if (NULL == hToken) { __leave; } //
// Obtain a LUID for the specified privilege
//
if (!LookupPrivilegeValue(NULL, lpwPrivilege, &luid)) { __leave; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; //
// Modify the access token
//
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { __leave; } fResult = TRUE; } // try
__finally {
if (hToken) { CloseHandle(hToken); } } // finally
return (fResult); }
/*++
Routine Description:
Saves the specified information to the file that will be used by the uninstaller
Arguments:
lpwSectionName - The name of the section where our entry will be saved lpwKeyName - A 1-based number in a string. It should be unique for each entry in the section lpwEntryName - The value or entry to save lpwFileName - The file to save our changes to Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL SaveEntryToINF( IN LPCWSTR lpwSectionName, IN LPCWSTR lpwKeyName, IN LPCWSTR lpwEntryName, IN LPCWSTR lpwFileName ) { BOOL fReturn = FALSE; //
// Write the entry to the INF
//
fReturn = WritePrivateProfileString(lpwSectionName, lpwKeyName, lpwEntryName, lpwFileName);
if (!fReturn) { Print(ERROR, L"[SaveEntryToINF] Failed to save entry: Section: %\nKey Name: %s\n Entry: %s\n File: %s\n"); }
return (fReturn ? TRUE : FALSE); }
/*++
Routine Description:
Deletes the specified registry keys during install
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL CommonDeleteRegistryKeys() { BOOL fReturn = FALSE, fResult = FALSE; HKEY hKeyRoot = NULL; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; char szKeyPath[MAX_PATH*3] = ""; WCHAR wszKeyPath[MAX_PATH*3] = L""; LPWSTR lpwKeyRoot = NULL, lpwSubKey = NULL; UINT uCount = 0; CRegistry creg; INFCONTEXT InfContext;
//
// Step through each entry in the queue
//
while (g_si.DeleteRegistryQueue.GetSize()) {
g_si.DeleteRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
//
// Loop through all the lines in the delete registry section(s),
// and perform the deletion
//
fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szKeyPath, MAX_PATH, NULL);
while (fReturn) {
pAnsiToUnicode(szKeyPath, wszKeyPath, MAX_PATH*3);
//
// Split the key path into two separate parts
//
lpwKeyRoot = GetNextToken(wszKeyPath, L","); if (NULL == lpwKeyRoot) { break; }
Print(TRACE, L"[CommonDeleteRegistryKeys] 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; }
lpwSubKey = GetNextToken(NULL, L",");
if (NULL == lpwSubKey) { break; }
Print(TRACE, L"[CommonDeleteRegistryKeys] Subkey path %s\n", lpwSubKey);
//
// Verify that the specified key exists
//
fResult = creg.IsRegistryKeyPresent(hKeyRoot, lpwSubKey);
if (fResult) {
//
// Do a recursive delete on the key
//
SHDeleteKey(hKeyRoot, lpwSubKey); }
fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szKeyPath, MAX_PATH, NULL); } }
return TRUE; }
/*++
Routine Description:
Based on the flag, performs a server registration or performs a server removal (unregistration)
Arguments:
fRegister - A flag to indicate if we should perform a register server Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL CommonRegisterServers( IN BOOL fRegister ) { int nLen = 0; char szFileName[MAX_PATH] = ""; WCHAR wszFileToRun[MAX_PATH] = L""; WCHAR wszFileName[MAX_PATH] = L""; char szEntry[MAX_PATH] = ""; WCHAR wszEntry[MAX_PATH] = L""; WCHAR wszEntryToSave[MAX_PATH*2] = L""; WCHAR wszKey[10] = L""; WCHAR wszSectionName[MAX_PATH] = L""; BOOL fReturn = FALSE; UINT uCount = 0; LPWSTR lpwDestDir = NULL; INFCONTEXT InfContext;
//
// Step through each entry in the queue
//
while (g_si.RegistrationQueue.GetSize()) {
g_si.RegistrationQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
//
// Get the destination directory
//
GetNextToken(wszEntry, L"."); lpwDestDir = GetNextToken(NULL, L".");
if (NULL == lpwDestDir) { return FALSE; }
//
// Loop through all the lines in the approriate section,
// spawning off each one
//
fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); while (fReturn) { pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
//
// Set up the path to the file to (un)register and run it
//
if (fRegister) { wsprintf(wszFileToRun, L"regsvr32.exe /s \"%s\\%s\\%s\"", g_si.lpwWindowsDirectory, lpwDestDir, wszFileName); } else { wsprintf(wszFileToRun, L"regsvr32.exe /s /u \"%s\"", wszFileName); }
Print(TRACE, L"[CommonRegisterServers] Preparing to launch %s\n", wszFileToRun); LaunchProcessAndWait(wszFileToRun, NULL);
if (fRegister) {
//
// Now save an entry to the queue
//
wsprintf(wszEntryToSave, L"%s\\%s\\%s", g_si.lpwWindowsDirectory, lpwDestDir, wszFileName); wsprintf(wszKey, L"%u", ++uCount);
wsprintf(wszSectionName, L"%s.%s", INF_UNREGISTRATIONSW, lpwDestDir); SaveEntryToINF(wszSectionName, wszKey, wszEntryToSave, g_si.lpwUninstallINFPath); } fReturn = SetupFindNextLine(&InfContext, &InfContext) && SetupGetLineTextA(&InfContext, NULL, NULL, NULL, szFileName, MAX_PATH, NULL); } } return TRUE; }
/*++
Routine Description:
Removes all files from the specified directory, then removes the directory
Arguments:
lpwDirectoryPath - Full path to the directory pEnumerateParameter - A parameter for misc storage fRemoveDirectory - A flag to indicate if we should remove the directory fRemoveSubDirs - A flag to indicate if we should remove subdirectories Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL CommonRemoveDirectoryAndFiles( IN LPCWSTR lpwDirectoryPath, IN PVOID pEnumerateParameter, IN BOOL fRemoveDirectory, IN BOOL fRemoveSubDirs ) { CEnumDir ced;
//
// Remove any files from the directory
//
ced.EnumerateDirectoryTree(lpwDirectoryPath, DeleteOneFile, fRemoveSubDirs, pEnumerateParameter);
//
// Now try to remove the directory itself
//
if (fRemoveDirectory) {
SetFileAttributes(lpwDirectoryPath, FILE_ATTRIBUTE_NORMAL); if (!RemoveDirectory(lpwDirectoryPath)) { Print(ERROR, L"[CommonRemoveDirectoryAndFiles] Failed to remove directory %s\n", lpwDirectoryPath); return FALSE; } }
return TRUE; }
/*++
Routine Description:
Enables protected renames in the registry
Arguments:
None
Return Value:
TRUE on success, FALSE otherwise
--*/ BOOL CommonEnableProtectedRenames() { CRegistry creg; BOOL fReturn = FALSE;
fReturn = creg.SetDword(HKEY_LOCAL_MACHINE, REG_SESSION_MANAGER, REG_PROT_RENAMES, (DWORD) 1, TRUE);
return (fReturn); }
/*++
Routine Description:
Installs a catalog file
Arguments:
lpwCatalogFullPath - Full path to the catalog file lpwNewBaseName - Name catalog should get when it's installed in the store Return Value:
NO_ERROR on success
--*/ #ifdef WIN2KSE
DWORD pInstallCatalogFile( IN LPCWSTR lpwCatalogFullPath, IN LPCWSTR lpwNewBaseName ) { DWORD dwError = 0;
dwError = VerifyCatalogFile(lpwCatalogFullPath); if (dwError == NO_ERROR) { dwError = InstallCatalog(lpwCatalogFullPath, lpwNewBaseName, NULL); } return (dwError); } #else
DWORD pInstallCatalogFile( IN LPCWSTR lpwCatalogFullPath, IN LPCWSTR lpwNewBaseName ) { DWORD dwError = 0;
dwError = pSetupVerifyCatalogFile(lpwCatalogFullPath); if (dwError == NO_ERROR) { dwError = pSetupInstallCatalog(lpwCatalogFullPath, lpwNewBaseName, NULL); } return (dwError); } #endif
|