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.

660 lines
17 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. Duinst.cpp
  5. Abstract:
  6. Contains the entry point for the Dynamic
  7. Update package and the install and
  8. uninstall main functions.
  9. Notes:
  10. Unicode only.
  11. History:
  12. 03/02/2001 rparsons Created
  13. --*/
  14. #include "precomp.h"
  15. #include "systemrestore.h"
  16. SETUP_INFO g_si;
  17. /*++
  18. Routine Description:
  19. Application entry point
  20. Arguments:
  21. hInstance - App instance handle
  22. hPrevInstance - Always NULL
  23. lpCmdLine - Pointer to the command line
  24. nCmdShow - Window show flag
  25. Return Value:
  26. -1 on failure, 0 on success
  27. --*/
  28. int APIENTRY
  29. WinMain(
  30. IN HINSTANCE hInstance,
  31. IN HINSTANCE hPrevInstance,
  32. IN LPSTR lpCmdLine,
  33. IN int nCmdShow
  34. )
  35. {
  36. int nReturn = -1;
  37. BOOL fReturn = FALSE;
  38. Print(TRACE, L"[WinMain] Application is started\n");
  39. //
  40. // Ensure that two separate instances of the app
  41. // are not running
  42. //
  43. if (IsAnotherInstanceRunning(L"WUINST")) {
  44. return -1;
  45. }
  46. //
  47. // Parse the command line and save app-related
  48. // data away
  49. //
  50. if (!ParseCommandLine()) {
  51. Print(ERROR, L"[WinMain] Call to ParseCommandLine failed\n");
  52. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_PARSE_CMD_LINE, TRUE);
  53. goto eh;
  54. }
  55. g_si.hInstance = hInstance;
  56. //
  57. // Determine the action to take
  58. //
  59. if (g_si.fInstall) {
  60. //
  61. // Start system restore point
  62. //
  63. if (!SystemRestorePointStart(TRUE)) {
  64. Print(ERROR, L"[WinMain] Call to SystemRestorePointStart failed\n");
  65. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE);
  66. goto eh;
  67. }
  68. if (!WUInitialize()) {
  69. Print(ERROR, L"[WinMain] Call to WUInitialize failed\n");
  70. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE);
  71. goto eh;
  72. }
  73. fReturn = DoInstallation();
  74. } else if (!g_si.fInstall) {
  75. //
  76. // Start system restore point
  77. //
  78. if (!SystemRestorePointStart(FALSE)) {
  79. Print(ERROR, L"[WinMain] Call to SystemRestorePointStart failed\n");
  80. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE);
  81. goto eh;
  82. }
  83. if (!WUInitialize()) {
  84. Print(ERROR, L"[WinMain] Call to WUInitialize failed\n");
  85. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_INIT_FAILED, TRUE);
  86. goto eh;
  87. }
  88. fReturn = DoUninstallation();
  89. } else {
  90. goto eh;
  91. }
  92. nReturn = 0;
  93. eh:
  94. //
  95. // Perform cleanup
  96. //
  97. WUCleanup();
  98. if (nReturn == 0) {
  99. if (!SystemRestorePointEnd()) {
  100. Print(ERROR, L"[WinMain] Call to SystemRestorePointEnd failed\n");
  101. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE);
  102. }
  103. } else {
  104. if (!SystemRestorePointCancel()) {
  105. Print(ERROR, L"[WinMain] Call to SystemRestorePointCancel failed\n");
  106. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_SYSTEM_RESTORE_FAIL, TRUE);
  107. }
  108. }
  109. return nReturn;
  110. }
  111. /*++
  112. Routine Description:
  113. Performs the grunt work of the installation
  114. Arguments:
  115. None
  116. Return Value:
  117. TRUE on success, FALSE otherwise
  118. --*/
  119. BOOL
  120. DoInstallation()
  121. {
  122. int nReturn = 0;
  123. WCHAR wszError[1024] = L"";
  124. WCHAR wszTemp[MAX_PATH] = L"";
  125. WCHAR wszBegin[MAX_PATH] = L"";
  126. WCHAR wszDestFileName[MAX_PATH] = L"";
  127. WORD wNumStrings = 0;
  128. LPWSTR lpwMessageArray[2];
  129. Print(TRACE, L"[DoInstallation] Installation is starting\n");
  130. //
  131. // Display the prompt for installation if we're
  132. // not in quiet mode
  133. //
  134. if (!g_si.fQuiet) {
  135. LoadString(g_si.hInstance, IDS_INSTALL_PROMPT, wszTemp, MAX_PATH);
  136. wsprintf(wszBegin, wszTemp, g_si.lpwPrettyAppName);
  137. if (MessageBox(NULL,
  138. wszBegin,
  139. g_si.lpwMessageBoxTitle,
  140. MB_YESNO | MB_ICONQUESTION)!=IDYES)
  141. {
  142. return TRUE;
  143. }
  144. }
  145. //
  146. // Log an event that the install is starting
  147. //
  148. LogEventDisplayError(EVENTLOG_INFORMATION_TYPE,
  149. ID_INSTALL_START,
  150. FALSE,
  151. FALSE);
  152. //
  153. // If we're not forcing an installation, check the
  154. // version number
  155. //
  156. if (!g_si.fForceInstall) {
  157. nReturn = InstallCheckVersion();
  158. }
  159. if (0 == nReturn) {
  160. //
  161. // This indicates that a newer package is installed
  162. // on the user's PC. Warn them if we're not in quiet
  163. // mode
  164. //
  165. Print(TRACE,
  166. L"[DoInstallation] Newer package is installed\n");
  167. if (!g_si.fQuiet) {
  168. LoadString(g_si.hInstance, IDS_NEWER_VERSION, wszTemp, MAX_PATH);
  169. wsprintf(wszError,
  170. wszTemp,
  171. g_si.lpwPrettyAppName,
  172. g_si.lpwPrettyAppName);
  173. if (MessageBox(NULL,
  174. wszError,
  175. g_si.lpwMessageBoxTitle,
  176. MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2)!=IDYES)
  177. {
  178. return TRUE;
  179. }
  180. } else {
  181. //
  182. // If we're in quiet mode, log an event to the event log
  183. //
  184. LogEventDisplayError(EVENTLOG_INFORMATION_TYPE,
  185. ID_NO_ACTION_TAKEN,
  186. FALSE,
  187. FALSE);
  188. return TRUE;
  189. }
  190. }
  191. //
  192. // Attempt to verify if our target directory exists
  193. // If not, try to create it
  194. //
  195. if (GetFileAttributes(g_si.lpwInstallDirectory)== -1) {
  196. if (!CreateDirectory(g_si.lpwInstallDirectory, NULL)) {
  197. wNumStrings = 0;
  198. lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwPrettyAppName;
  199. lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwInstallDirectory;
  200. LogWUEvent(EVENTLOG_ERROR_TYPE,
  201. ID_NO_APPPATCH_DIR,
  202. 2,
  203. (LPCWSTR*) lpwMessageArray);
  204. if (!g_si.fQuiet) {
  205. DisplayErrMsg(GetDesktopWindow(),
  206. ID_NO_APPPATCH_DIR,
  207. (LPWSTR) lpwMessageArray);
  208. }
  209. Print(ERROR, L"[DoInstallation] Failed to create installation directory\n");
  210. return FALSE;
  211. }
  212. }
  213. //
  214. // If we need to adjust permissions on our target directory, do it
  215. //
  216. if (g_si.fNeedToAdjustACL) {
  217. if (!AdjustDirectoryPerms(g_si.lpwInstallDirectory)) {
  218. wNumStrings = 0;
  219. lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwPrettyAppName;
  220. lpwMessageArray[wNumStrings++] = (LPWSTR) g_si.lpwInstallDirectory;
  221. LogWUEvent(EVENTLOG_ERROR_TYPE,
  222. ID_ACL_APPPATCH_FAILED,
  223. 2,
  224. (LPCWSTR*) lpwMessageArray);
  225. if (!g_si.fQuiet) {
  226. DisplayErrMsg(GetDesktopWindow(),
  227. ID_ACL_APPPATCH_FAILED,
  228. (LPWSTR) lpwMessageArray);
  229. }
  230. Print(ERROR,
  231. L"[DoInstallation] Failed to apply ACL to installation directory\n");
  232. return FALSE;
  233. }
  234. }
  235. //
  236. // Get section names from the INF
  237. //
  238. if (!InstallGetSectionsFromINF()) {
  239. Print(ERROR, L"[DoInstallation] Failed to get section names from INF\n");
  240. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INF_SCAN_FAILED, TRUE, FALSE);
  241. return FALSE;
  242. }
  243. //
  244. // Install catalog files
  245. //
  246. if (!InstallCatalogFiles(g_si.hInf, g_si.lpwExtractPath)) {
  247. Print(ERROR, L"[DoInstallation] Failed to install catalog file\n");
  248. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_CATALOG_INSTALL_FAILED, TRUE, FALSE);
  249. return FALSE;
  250. }
  251. //
  252. // If we're allowing an uninstall, backup files listed in the INF
  253. //
  254. if (!g_si.fNoUninstall) {
  255. if (!InstallBackupFiles()) {
  256. Print(ERROR, L"[DoInstallation] Failed to backup files from INF\n");
  257. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_BACKUP_FAILED, TRUE, FALSE);
  258. g_si.fCanUninstall = FALSE;
  259. }
  260. }
  261. //
  262. // If we're allowing an uninstall and the backup of files worked,
  263. // backup registry keys listed in the INF
  264. //
  265. if (!g_si.fNoUninstall) {
  266. if (g_si.fCanUninstall) {
  267. if (!InstallBackupRegistryKeys()) {
  268. Print(ERROR, L"[DoInstallation] Failed to backup registry keys from INF\n");
  269. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_BACKUP_FAILED, TRUE, FALSE);
  270. g_si.fCanUninstall = FALSE;
  271. }
  272. }
  273. }
  274. //
  275. // Remove any registry keys specified in the INF
  276. //
  277. CommonDeleteRegistryKeys();
  278. //
  279. // Remove files from the installation directory
  280. //
  281. CommonRemoveDirectoryAndFiles(g_si.lpwInstallDirectory,
  282. (PVOID) TRUE,
  283. FALSE,
  284. FALSE);
  285. //
  286. // Copy files specified in the INF
  287. //
  288. if (!InstallCopyFiles()) {
  289. Print(ERROR, L"[DoInstallation] Failed to copy files from INF\n");
  290. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_COPY_FAILED, TRUE, FALSE);
  291. return FALSE;
  292. }
  293. //
  294. // Merge any registry data specified in the INF
  295. //
  296. if (!InstallRegistryData()) {
  297. Print(ERROR, L"[DoInstallation] Failed to install registry data from INF\n");
  298. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_MERGE_FAILED, TRUE, FALSE);
  299. return FALSE;
  300. }
  301. //
  302. // Perform any server registrations specified in the INF
  303. //
  304. if (!CommonRegisterServers(TRUE)) {
  305. Print(ERROR, L"[DoInstallation] Failed to register servers from INF\n");
  306. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REGSVR32_FAILED, TRUE, FALSE);
  307. }
  308. //
  309. // Run any processes specified in the INF
  310. //
  311. InstallRunINFProcesses();
  312. //
  313. // If the backup operations worked, write out the uninstall key
  314. // In addition, put our uninstall INF in the installation directory
  315. //
  316. if (g_si.fCanUninstall) {
  317. InstallWriteUninstallKey();
  318. wsprintf(wszDestFileName,
  319. L"%s\\%s",
  320. g_si.lpwInstallDirectory,
  321. UNINST_INF_FILE_NAMEW);
  322. ForceCopy(g_si.lpwUninstallINFPath, wszDestFileName);
  323. }
  324. //
  325. // Perform a reboot
  326. //
  327. if (!g_si.fQuiet && !g_si.fNoReboot) {
  328. LoadString(g_si.hInstance, IDS_REBOOT_NEEDED, wszTemp, MAX_PATH);
  329. nReturn = MessageBox(NULL,
  330. wszTemp,
  331. g_si.lpwMessageBoxTitle,
  332. MB_YESNO | MB_ICONQUESTION);
  333. if (nReturn == IDYES) {
  334. if (!ShutdownSystem(FALSE, TRUE)) {
  335. // The shutdown failed - prompt the user for a manual one
  336. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INS_REBOOT_FAILED, TRUE, FALSE);
  337. } else {
  338. // The shutdown was successful - write a message to the event log
  339. LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_INSTALL_SUCCESSFUL, FALSE, FALSE);
  340. }
  341. } else {
  342. // Interactive mode - the user said no to the reboot - write it to the event log
  343. // Don't display a message.
  344. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_INS_QREBOOT_NEEDED, FALSE, FALSE);
  345. }
  346. } else {
  347. // Quiet mode - A reboot is needed - write it to event log
  348. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_INS_QREBOOT_NEEDED, FALSE, FALSE);
  349. }
  350. Print(TRACE, L"[DoInstallation] Installation is complete\n");
  351. return TRUE;
  352. }
  353. /*++
  354. Routine Description:
  355. Performs the grunt work of the uninstall
  356. Arguments:
  357. None
  358. Return Value:
  359. TRUE on success, FALSE otherwise
  360. --*/
  361. BOOL
  362. DoUninstallation()
  363. {
  364. WCHAR wszTemp[MAX_PATH] = L"";
  365. WCHAR wszBegin[MAX_PATH] = L"";
  366. WCHAR wszBackupDir[MAX_PATH] = L"";
  367. char szGuid[80] = "";
  368. WCHAR wszGuid[80] = L"";
  369. BOOL fReturn = FALSE;
  370. int nReturn = 0;
  371. Print(TRACE, L"[DoUninstallation] Uninstall is starting\n");
  372. //
  373. // Display the prompt for installation if we're
  374. // not in quiet mode
  375. //
  376. if (!g_si.fQuiet) {
  377. LoadString(g_si.hInstance, IDS_UNINSTALL_PROMPT, wszTemp, MAX_PATH);
  378. wsprintf(wszBegin, wszTemp, g_si.lpwPrettyAppName);
  379. if (MessageBox(NULL,
  380. wszBegin,
  381. g_si.lpwMessageBoxTitle,
  382. MB_YESNO | MB_ICONQUESTION)!=IDYES)
  383. {
  384. return TRUE;
  385. }
  386. }
  387. //
  388. // Log an event that the uninstall is starting
  389. //
  390. LogEventDisplayError(EVENTLOG_INFORMATION_TYPE,
  391. ID_UNINSTALL_START,
  392. FALSE,
  393. FALSE);
  394. //
  395. // Get section names from the INF
  396. //
  397. if (!UninstallGetSectionsFromINF()) {
  398. Print(ERROR, L"[DoUninstallation] Failed to get section names from INF\n");
  399. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_INF_SCAN_FAILED, TRUE, FALSE);
  400. return FALSE;
  401. }
  402. //
  403. // Remove the Uninstall key
  404. // If we replaced it during install, it will be restored
  405. // below. If not, no package was installed previously
  406. //
  407. fReturn = SetupGetLineTextA(NULL,
  408. g_si.hInf,
  409. "Strings",
  410. "GUID",
  411. szGuid,
  412. sizeof(szGuid),
  413. NULL);
  414. if (!fReturn) {
  415. Print(ERROR, L"[DoUninstallation] Failed to get GUID from INF\n");
  416. LogEventDisplayError(NULL, EVENTLOG_ERROR_TYPE, ID_GET_INF_FAIL, TRUE);
  417. return FALSE;
  418. }
  419. pAnsiToUnicode(szGuid, wszGuid, 80);
  420. UninstallDeleteSubKey(REG_UNINSTALL, wszGuid);
  421. UninstallDeleteSubKey(REG_ACTIVE_SETUP, wszGuid);
  422. //
  423. // Delete any registry keys in prep for restore
  424. //
  425. if (!CommonDeleteRegistryKeys()) {
  426. Print(ERROR, L"[DoUninstallation] Failed to delete registry keys\n");
  427. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_DELETE_FAILED, TRUE, FALSE);
  428. return FALSE;
  429. }
  430. //
  431. // Restore registry keys we replaced
  432. //
  433. if (!UninstallRestoreRegistryKeys()) {
  434. Print(ERROR, L"[DoUninstallation] Failed to restore registry keys from INF\n");
  435. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_REG_RESTORE_FAILED, TRUE, FALSE);
  436. return FALSE;
  437. }
  438. //
  439. // The routine below does some custom things
  440. //
  441. UninstallCustomWorker();
  442. //
  443. // Remove files under the installation directory
  444. //
  445. UninstallRemoveFiles();
  446. //
  447. // Restore any files we replaced
  448. //
  449. if (!UninstallRestoreFiles()) {
  450. Print(ERROR, L"[DoUninstallation] Failed to restore files from INF\n");
  451. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_FILE_RESTORE_FAILED, TRUE, FALSE);
  452. return FALSE;
  453. }
  454. //
  455. // Remove the '$Uninstall$ directory and delete the uninstall INF file
  456. //
  457. wsprintf(wszBackupDir,
  458. L"%s\\%s",
  459. g_si.lpwInstallDirectory,
  460. g_si.lpwUninstallDirectory);
  461. Print(TRACE, L"[DoUninstallation] Path to Uninstall dir: %s\n", wszBackupDir);
  462. CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, TRUE, FALSE);
  463. SetupCloseInfFile(g_si.hInf);
  464. DeleteFile(g_si.lpwUninstallINFPath);
  465. //
  466. // Perform a reboot
  467. //
  468. if (!g_si.fQuiet) {
  469. LoadString(g_si.hInstance, IDS_REBOOT_NEEDED, wszTemp, MAX_PATH);
  470. // Prompt the user to reboot
  471. nReturn = MessageBox(NULL,
  472. wszTemp,
  473. g_si.lpwMessageBoxTitle,
  474. MB_YESNO | MB_ICONQUESTION);
  475. if (nReturn == IDYES) {
  476. if (!ShutdownSystem(FALSE, TRUE)) {
  477. // The shutdown failed - prompt the user for a manual one
  478. LogEventDisplayError(EVENTLOG_ERROR_TYPE, ID_UNINS_REBOOT_FAILED, TRUE, FALSE);
  479. } else {
  480. // The shutdown was successful - write a message to the event log
  481. LogEventDisplayError(EVENTLOG_INFORMATION_TYPE, ID_UNINSTALL_SUCCESSFUL, FALSE, FALSE);
  482. }
  483. } else {
  484. // Interactive mode - the user said no to the reboot - write it to the event log
  485. // Don't display a message.
  486. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_UNINS_QREBOOT_NEEDED, FALSE, FALSE);
  487. }
  488. } else {
  489. // Quiet mode - A reboot is needed - write it to event log
  490. LogEventDisplayError(EVENTLOG_WARNING_TYPE, ID_UNINS_QREBOOT_NEEDED, FALSE, FALSE);
  491. }
  492. return TRUE;
  493. }