/*++ Copyright (c) 2001 Microsoft Corporation Module Name: Duinst.cpp Abstract: Contains the entry point for the Dynamic Update package and the install and uninstall main functions. Notes: Unicode only. History: 03/02/2001 rparsons Created --*/ #include "precomp.h" #include "systemrestore.h" SETUP_INFO g_si; /*++ Routine Description: Application entry point Arguments: hInstance - App instance handle hPrevInstance - Always NULL lpCmdLine - Pointer to the command line nCmdShow - Window show flag Return Value: -1 on failure, 0 on success --*/ int APIENTRY WinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nCmdShow ) { int nReturn = -1; BOOL fReturn = FALSE; Print(TRACE, L"[WinMain] Application is started\n"); // // Ensure that two separate instances of the app // are not running // if (IsAnotherInstanceRunning(L"WUINST")) { return -1; } // // Parse the command line and save app-related // data away // if (!ParseCommandLine()) { Print(ERROR, L"[WinMain] Call to ParseCommandLine failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_PARSE_CMD_LINE, TRUE); goto eh; } g_si.hInstance = hInstance; // // Determine the action to take // if (g_si.fInstall) { // // Start system restore point // if (!SystemRestorePointStart(TRUE)) { Print(ERROR, L"[WinMain] Call to SystemRestorePointStart failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE); goto eh; } if (!WUInitialize()) { Print(ERROR, L"[WinMain] Call to WUInitialize failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE); goto eh; } fReturn = DoInstallation(); } else if (!g_si.fInstall) { // // Start system restore point // if (!SystemRestorePointStart(FALSE)) { Print(ERROR, L"[WinMain] Call to SystemRestorePointStart failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE); goto eh; } if (!WUInitialize()) { Print(ERROR, L"[WinMain] Call to WUInitialize failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE); goto eh; } fReturn = DoUninstallation(); } else { goto eh; } nReturn = 0; eh: // // Perform cleanup // WUCleanup(); if (nReturn == 0) { if (!SystemRestorePointEnd()) { Print(ERROR, L"[WinMain] Call to SystemRestorePointEnd failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE); } } else { if (!SystemRestorePointCancel()) { Print(ERROR, L"[WinMain] Call to SystemRestorePointCancel failed\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE); } } return nReturn; } /*++ Routine Description: Performs the grunt work of the installation Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL DoInstallation() { int nReturn = 0; WCHAR wszError[1024] = L""; WCHAR wszTemp[MAX_PATH] = L""; WCHAR wszBegin[MAX_PATH] = L""; WCHAR wszDestFileName[MAX_PATH] = L""; WORD wNumStrings = 0; LPWSTR lpwMessageArray[2]; Print(TRACE, L"[DoInstallation] Installation is starting\n"); // // Display the prompt for installation if we're // not in quiet mode // if (!g_si.fQuiet) { LoadString(g_si.hInstance, IDS_INSTALL_PROMPT, wszTemp, MAX_PATH); wsprintf(wszBegin, wszTemp, g_si.lpwPrettyAppName); if (MessageBox(NULL, wszBegin, g_si.lpwMessageBoxTitle, MB_YESNO | MB_ICONQUESTION)!=IDYES) { return TRUE; } } // // Log an event that the install is starting // LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_INSTALL_START, FALSE, FALSE); // // If we're not forcing an installation, check the // version number // if (!g_si.fForceInstall) { nReturn = InstallCheckVersion(); } if (0 == nReturn) { // // This indicates that a newer package is installed // on the user's PC. Warn them if we're not in quiet // mode // Print(TRACE, L"[DoInstallation] Newer package is installed\n"); if (!g_si.fQuiet) { LoadString(g_si.hInstance, IDS_NEWER_VERSION, wszTemp, MAX_PATH); wsprintf(wszError, wszTemp, g_si.lpwPrettyAppName, g_si.lpwPrettyAppName); if (MessageBox(NULL, wszError, g_si.lpwMessageBoxTitle, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2)!=IDYES) { return TRUE; } } else { // // If we're in quiet mode, log an event to the event log // LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_NO_ACTION_TAKEN, FALSE, FALSE); return TRUE; } } // // Attempt to verify if our target directory exists // If not, try to create it // if (GetFileAttributes(g_si.lpwInstallDirectory)== -1) { if (!CreateDirectory(g_si.lpwInstallDirectory, NULL)) { wNumStrings = 0; lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwPrettyAppName; lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwInstallDirectory; LogWUEvent(EVENTLOG_ERROR_TYPE, ID_NO_APPPATCH_DIR, 2, (LPCWSTR*) lpwMessageArray); if (!g_si.fQuiet) { DisplayErrMsg(GetDesktopWindow(), ID_NO_APPPATCH_DIR, (LPWSTR) lpwMessageArray); } Print(ERROR, L"[DoInstallation] Failed to create installation directory\n"); return FALSE; } } // // If we need to adjust permissions on our target directory, do it // if (g_si.fNeedToAdjustACL) { if (!AdjustDirectoryPerms(g_si.lpwInstallDirectory)) { wNumStrings = 0; lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwPrettyAppName; lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwInstallDirectory; LogWUEvent(EVENTLOG_ERROR_TYPE, ID_ACL_APPPATCH_FAILED, 2, (LPCWSTR*) lpwMessageArray); if (!g_si.fQuiet) { DisplayErrMsg(GetDesktopWindow(), ID_ACL_APPPATCH_FAILED, (LPWSTR) lpwMessageArray); } Print(ERROR, L"[DoInstallation] Failed to apply ACL to installation directory\n"); return FALSE; } } // // Get section names from the INF // if (!InstallGetSectionsFromINF()) { Print(ERROR, L"[DoInstallation] Failed to get section names from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INF_SCAN_FAILED, TRUE, FALSE); return FALSE; } // // Install catalog files // if (!InstallCatalogFiles(g_si.hInf, g_si.lpwExtractPath)) { Print(ERROR, L"[DoInstallation] Failed to install catalog file\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_CATALOG_INSTALL_FAILED, TRUE, FALSE); return FALSE; } // // If we're allowing an uninstall, backup files listed in the INF // if (!g_si.fNoUninstall) { if (!InstallBackupFiles()) { Print(ERROR, L"[DoInstallation] Failed to backup files from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_BACKUP_FAILED, TRUE, FALSE); g_si.fCanUninstall = FALSE; } } // // If we're allowing an uninstall and the backup of files worked, // backup registry keys listed in the INF // if (!g_si.fNoUninstall) { if (g_si.fCanUninstall) { if (!InstallBackupRegistryKeys()) { Print(ERROR, L"[DoInstallation] Failed to backup registry keys from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_BACKUP_FAILED, TRUE, FALSE); g_si.fCanUninstall = FALSE; } } } // // Remove any registry keys specified in the INF // CommonDeleteRegistryKeys(); // // Remove files from the installation directory // CommonRemoveDirectoryAndFiles(g_si.lpwInstallDirectory, (PVOID) TRUE, FALSE, FALSE); // // Copy files specified in the INF // if (!InstallCopyFiles()) { Print(ERROR, L"[DoInstallation] Failed to copy files from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_COPY_FAILED, TRUE, FALSE); return FALSE; } // // Merge any registry data specified in the INF // if (!InstallRegistryData()) { Print(ERROR, L"[DoInstallation] Failed to install registry data from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_MERGE_FAILED, TRUE, FALSE); return FALSE; } // // Perform any server registrations specified in the INF // if (!CommonRegisterServers(TRUE)) { Print(ERROR, L"[DoInstallation] Failed to register servers from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REGSVR32_FAILED, TRUE, FALSE); } // // Run any processes specified in the INF // InstallRunINFProcesses(); // // If the backup operations worked, write out the uninstall key // In addition, put our uninstall INF in the installation directory // if (g_si.fCanUninstall) { InstallWriteUninstallKey(); wsprintf(wszDestFileName, L"%s\\%s", g_si.lpwInstallDirectory, UNINST_INF_FILE_NAMEW); ForceCopy(g_si.lpwUninstallINFPath, wszDestFileName); } // // Perform a reboot // if (!g_si.fQuiet && !g_si.fNoReboot) { LoadString(g_si.hInstance, IDS_REBOOT_NEEDED, wszTemp, MAX_PATH); nReturn = MessageBox(NULL, wszTemp, g_si.lpwMessageBoxTitle, MB_YESNO | MB_ICONQUESTION); if (nReturn == IDYES) { if (!ShutdownSystem(FALSE, TRUE)) { // The shutdown failed - prompt the user for a manual one LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INS_REBOOT_FAILED, TRUE, FALSE); } else { // The shutdown was successful - write a message to the event log LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_INSTALL_SUCCESSFUL, FALSE, FALSE); } } else { // Interactive mode - the user said no to the reboot - write it to the event log // Don't display a message. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_INS_QREBOOT_NEEDED, FALSE, FALSE); } } else { // Quiet mode - A reboot is needed - write it to event log LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_INS_QREBOOT_NEEDED, FALSE, FALSE); } Print(TRACE, L"[DoInstallation] Installation is complete\n"); return TRUE; } /*++ Routine Description: Performs the grunt work of the uninstall Arguments: None Return Value: TRUE on success, FALSE otherwise --*/ BOOL DoUninstallation() { WCHAR wszTemp[MAX_PATH] = L""; WCHAR wszBegin[MAX_PATH] = L""; WCHAR wszBackupDir[MAX_PATH] = L""; char szGuid[80] = ""; WCHAR wszGuid[80] = L""; BOOL fReturn = FALSE; int nReturn = 0; Print(TRACE, L"[DoUninstallation] Uninstall is starting\n"); // // Display the prompt for installation if we're // not in quiet mode // if (!g_si.fQuiet) { LoadString(g_si.hInstance, IDS_UNINSTALL_PROMPT, wszTemp, MAX_PATH); wsprintf(wszBegin, wszTemp, g_si.lpwPrettyAppName); if (MessageBox(NULL, wszBegin, g_si.lpwMessageBoxTitle, MB_YESNO | MB_ICONQUESTION)!=IDYES) { return TRUE; } } // // Log an event that the uninstall is starting // LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_UNINSTALL_START, FALSE, FALSE); // // Get section names from the INF // if (!UninstallGetSectionsFromINF()) { Print(ERROR, L"[DoUninstallation] Failed to get section names from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INF_SCAN_FAILED, TRUE, FALSE); return FALSE; } // // Remove the Uninstall key // If we replaced it during install, it will be restored // below. If not, no package was installed previously // fReturn = SetupGetLineTextA(NULL, g_si.hInf, "Strings", "GUID", szGuid, sizeof(szGuid), NULL); if (!fReturn) { Print(ERROR, L"[DoUninstallation] Failed to get GUID from INF\n"); LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_GET_INF_FAIL, TRUE); return FALSE; } pAnsiToUnicode(szGuid, wszGuid, 80); UninstallDeleteSubKey(REG_UNINSTALL, wszGuid); UninstallDeleteSubKey(REG_ACTIVE_SETUP, wszGuid); // // Delete any registry keys in prep for restore // if (!CommonDeleteRegistryKeys()) { Print(ERROR, L"[DoUninstallation] Failed to delete registry keys\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_DELETE_FAILED, TRUE, FALSE); return FALSE; } // // Restore registry keys we replaced // if (!UninstallRestoreRegistryKeys()) { Print(ERROR, L"[DoUninstallation] Failed to restore registry keys from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_RESTORE_FAILED, TRUE, FALSE); return FALSE; } // // The routine below does some custom things // UninstallCustomWorker(); // // Remove files under the installation directory // UninstallRemoveFiles(); // // Restore any files we replaced // if (!UninstallRestoreFiles()) { Print(ERROR, L"[DoUninstallation] Failed to restore files from INF\n"); LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_RESTORE_FAILED, TRUE, FALSE); return FALSE; } // // Remove the '$Uninstall$ directory and delete the uninstall INF file // wsprintf(wszBackupDir, L"%s\\%s", g_si.lpwInstallDirectory, g_si.lpwUninstallDirectory); Print(TRACE, L"[DoUninstallation] Path to Uninstall dir: %s\n", wszBackupDir); CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, TRUE, FALSE); SetupCloseInfFile(g_si.hInf); DeleteFile(g_si.lpwUninstallINFPath); // // Perform a reboot // if (!g_si.fQuiet) { LoadString(g_si.hInstance, IDS_REBOOT_NEEDED, wszTemp, MAX_PATH); // Prompt the user to reboot nReturn = MessageBox(NULL, wszTemp, g_si.lpwMessageBoxTitle, MB_YESNO | MB_ICONQUESTION); if (nReturn == IDYES) { if (!ShutdownSystem(FALSE, TRUE)) { // The shutdown failed - prompt the user for a manual one LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_UNINS_REBOOT_FAILED, TRUE, FALSE); } else { // The shutdown was successful - write a message to the event log LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_UNINSTALL_SUCCESSFUL, FALSE, FALSE); } } else { // Interactive mode - the user said no to the reboot - write it to the event log // Don't display a message. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_UNINS_QREBOOT_NEEDED, FALSE, FALSE); } } else { // Quiet mode - A reboot is needed - write it to event log LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_UNINS_QREBOOT_NEEDED, FALSE, FALSE); } return TRUE; }