OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <windows.h> | 5 #include <windows.h> |
6 #include <msi.h> | 6 #include <msi.h> |
7 #include <shellapi.h> | 7 #include <shellapi.h> |
8 #include <shlobj.h> | 8 #include <shlobj.h> |
9 | 9 |
10 #include "base/at_exit.h" | 10 #include "base/at_exit.h" |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 // Delete an elevation policy associated with the old version, should one | 210 // Delete an elevation policy associated with the old version, should one |
211 // exist. | 211 // exist. |
212 if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) { | 212 if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) { |
213 installer::AddDeleteOldIELowRightsPolicyWorkItems(*installer_state, | 213 installer::AddDeleteOldIELowRightsPolicyWorkItems(*installer_state, |
214 install_list.get()); | 214 install_list.get()); |
215 } | 215 } |
216 // old_chrome.exe is still in use in most cases, so ignore failures here. | 216 // old_chrome.exe is still in use in most cases, so ignore failures here. |
217 install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path()) | 217 install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path()) |
218 ->set_ignore_failure(true); | 218 ->set_ignore_failure(true); |
219 | 219 |
220 // Collect the set of distributions we need to update, which is the | 220 // Add work items to delete the "opv", "cpv", and "cmd" values from all |
221 // multi-install binaries (if this is a multi-install operation) and all | 221 // products we're operating on (which including the multi-install binaries). |
222 // products we're operating on. | |
223 BrowserDistribution* dists[BrowserDistribution::NUM_TYPES]; | |
224 int num_dists = 0; | |
225 // First, add the multi-install binaries, if relevant. | |
226 if (installer_state->is_multi_install()) | |
227 dists[num_dists++] = installer_state->multi_package_binaries_distribution(); | |
228 // Next, add all products we're operating on. std::transform can handily do | |
229 // this for us, but this is discouraged as being too tricky. | |
230 const Products& products = installer_state->products(); | 222 const Products& products = installer_state->products(); |
231 for (Products::size_type i = 0; i < products.size(); ++i) { | |
232 dists[num_dists++] = products[i]->distribution(); | |
233 } | |
234 | |
235 // Add work items to delete the "opv", "cpv", and "cmd" values from all | |
236 // distributions. | |
237 HKEY reg_root = installer_state->root_key(); | 223 HKEY reg_root = installer_state->root_key(); |
238 string16 version_key; | 224 string16 version_key; |
239 for (int i = 0; i < num_dists; ++i) { | 225 for (size_t i = 0; i < products.size(); ++i) { |
240 version_key = dists[i]->GetVersionKey(); | 226 version_key = products[i]->distribution()->GetVersionKey(); |
241 install_list->AddDeleteRegValueWorkItem( | 227 install_list->AddDeleteRegValueWorkItem( |
242 reg_root, version_key, google_update::kRegOldVersionField); | 228 reg_root, version_key, google_update::kRegOldVersionField); |
243 install_list->AddDeleteRegValueWorkItem( | 229 install_list->AddDeleteRegValueWorkItem( |
244 reg_root, version_key, google_update::kRegCriticalVersionField); | 230 reg_root, version_key, google_update::kRegCriticalVersionField); |
245 install_list->AddDeleteRegValueWorkItem( | 231 install_list->AddDeleteRegValueWorkItem( |
246 reg_root, version_key, google_update::kRegRenameCmdField); | 232 reg_root, version_key, google_update::kRegRenameCmdField); |
247 } | 233 } |
248 installer::InstallStatus ret = installer::RENAME_SUCCESSFUL; | 234 installer::InstallStatus ret = installer::RENAME_SUCCESSFUL; |
249 if (!install_list->Do()) { | 235 if (!install_list->Do()) { |
250 LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; | 236 LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 if (!binaries) { | 362 if (!binaries) { |
377 if (app_host && !chrome && !chrome_frame && !cf_state && !chrome_state) { | 363 if (app_host && !chrome && !chrome_frame && !cf_state && !chrome_state) { |
378 DCHECK(!system_level); | 364 DCHECK(!system_level); |
379 // App Host may use Chrome/Chrome binaries at system-level. | 365 // App Host may use Chrome/Chrome binaries at system-level. |
380 if (original_state.GetProductState( | 366 if (original_state.GetProductState( |
381 true, // system | 367 true, // system |
382 BrowserDistribution::CHROME_BROWSER) || | 368 BrowserDistribution::CHROME_BROWSER) || |
383 original_state.GetProductState( | 369 original_state.GetProductState( |
384 true, // system | 370 true, // system |
385 BrowserDistribution::CHROME_BINARIES)) { | 371 BrowserDistribution::CHROME_BINARIES)) { |
| 372 VLOG(1) << "Installing/updating Application Host without binaries."; |
386 return true; | 373 return true; |
387 } else { | 374 } else { |
| 375 // Somehow the binaries were present when the quick-enable app host |
| 376 // command was run, but now they appear to be missing. |
| 377 // TODO(erikwright): should the binaries be implicitly added? |
| 378 LOG(ERROR) << "Cannot install Application Host without binaries."; |
| 379 *status = installer::APP_HOST_REQUIRES_BINARIES; |
| 380 installer_state->WriteInstallerResult(*status, 0, NULL); |
388 return false; | 381 return false; |
389 } | 382 } |
390 } else { | 383 } else { |
391 // Every other scenario requires the binaries to be installed/updated | 384 // Every other scenario requires the binaries to be installed/updated |
392 // simultaneous to the main product. | 385 // along with the main product. This will only be hit if |
393 return false; | 386 // --multi-install is given with no products. See |
| 387 // CheckPreInstallConditions for handling of this case. |
| 388 return true; |
394 } | 389 } |
395 } | 390 } |
396 | 391 |
397 if (chrome) { | 392 if (chrome) { |
398 if (chrome_frame && | 393 if (chrome_frame && |
399 chrome_frame->HasOption(installer::kOptionReadyMode)) { | 394 chrome_frame->HasOption(installer::kOptionReadyMode)) { |
400 // We're being asked to install Chrome with Chrome Frame in ready-mode. | 395 // We're being asked to install Chrome with Chrome Frame in ready-mode. |
401 // This is an optimistic operation: if a SxS install of Chrome Frame | 396 // This is an optimistic operation: if a SxS install of Chrome Frame |
402 // is already present, don't touch it; if a multi-install of Chrome | 397 // is already present, don't touch it; if a multi-install of Chrome |
403 // Frame is present, preserve its settings (ready-mode). | 398 // Frame is present, preserve its settings (ready-mode). |
404 if (cf_state != NULL) { | 399 if (cf_state != NULL) { |
405 installer_state->RemoveProduct(chrome_frame); | 400 installer_state->RemoveProduct(chrome_frame); |
406 chrome_frame = NULL; | 401 chrome_frame = NULL; |
407 if (cf_state->is_multi_install()) { | 402 if (cf_state->is_multi_install()) { |
408 chrome_frame = installer_state->AddProductFromState( | 403 chrome_frame = installer_state->AddProductFromState( |
409 BrowserDistribution::CHROME_FRAME, *cf_state); | 404 BrowserDistribution::CHROME_FRAME, *cf_state); |
410 VLOG(1) << "Upgrading existing multi-install Chrome Frame rather " | 405 VLOG(1) << "Upgrading existing multi-install Chrome Frame rather " |
411 "than installing in ready-mode."; | 406 "than installing in ready-mode."; |
412 } else { | 407 } else { |
413 VLOG(1) << "Skipping upgrade of single-install Chrome Frame rather " | 408 VLOG(1) << "Skipping upgrade of single-install Chrome Frame rather " |
414 "than installing in ready-mode."; | 409 "than installing in ready-mode."; |
415 } | 410 } |
416 } else { | 411 } else { |
417 VLOG(1) << "Performing initial install of Chrome Frame ready-mode."; | 412 VLOG(1) << "Performing initial install of Chrome Frame ready-mode."; |
418 } | 413 } |
419 } | 414 } |
420 } else if (chrome_state != NULL) { | 415 } else if (chrome_state) { |
421 // Chrome Frame is being installed in multi-install mode, and Chrome is | 416 // A product other than Chrome is being installed in multi-install mode, |
422 // already present. Add Chrome to the set of products (making it | 417 // and Chrome is already present. Add Chrome to the set of products |
423 // multi-install in the process) so that it is updated, too. | 418 // (making it multi-install in the process) so that it is updated, too. |
424 scoped_ptr<Product> multi_chrome(new Product( | 419 scoped_ptr<Product> multi_chrome(new Product( |
425 BrowserDistribution::GetSpecificDistribution( | 420 BrowserDistribution::GetSpecificDistribution( |
426 BrowserDistribution::CHROME_BROWSER))); | 421 BrowserDistribution::CHROME_BROWSER))); |
427 multi_chrome->SetOption(installer::kOptionMultiInstall, true); | 422 multi_chrome->SetOption(installer::kOptionMultiInstall, true); |
428 chrome = installer_state->AddProduct(&multi_chrome); | 423 chrome = installer_state->AddProduct(&multi_chrome); |
429 VLOG(1) << "Upgrading existing Chrome browser in multi-install mode."; | 424 VLOG(1) << "Upgrading existing Chrome browser in multi-install mode."; |
430 } else if (chrome_frame && | 425 } else if (chrome_frame && |
431 chrome_frame->HasOption(installer::kOptionReadyMode)) { | 426 chrome_frame->HasOption(installer::kOptionReadyMode)) { |
432 // Chrome Frame with ready-mode is to be installed, yet Chrome is | 427 // Chrome Frame with ready-mode is to be installed, yet Chrome is |
433 // neither installed nor being installed. Fail. | 428 // neither installed nor being installed. Fail. |
434 LOG(ERROR) << "Cannot install Chrome Frame in ready mode without Chrome."; | 429 LOG(ERROR) << "Cannot install Chrome Frame in ready mode without Chrome."; |
435 *status = installer::READY_MODE_REQUIRES_CHROME; | 430 *status = installer::READY_MODE_REQUIRES_CHROME; |
436 installer_state->WriteInstallerResult( | 431 installer_state->WriteInstallerResult( |
437 *status, IDS_INSTALL_READY_MODE_REQUIRES_CHROME_BASE, NULL); | 432 *status, IDS_INSTALL_READY_MODE_REQUIRES_CHROME_BASE, NULL); |
438 return false; | 433 return false; |
439 } | 434 } |
440 | 435 |
441 // Fail if we're installing Chrome Frame when a single-install of it is | 436 // Fail if we're installing Chrome Frame when a single-install of it is |
442 // already installed. | 437 // already installed. |
443 // TODO(grt): Add support for migration of Chrome Frame from single- to | |
444 // multi-install. | |
445 if (chrome_frame && cf_state && !cf_state->is_multi_install()) { | 438 if (chrome_frame && cf_state && !cf_state->is_multi_install()) { |
446 LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to " | 439 LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to " |
447 << "multi-install."; | 440 << "multi-install."; |
448 *status = installer::NON_MULTI_INSTALLATION_EXISTS; | 441 *status = installer::NON_MULTI_INSTALLATION_EXISTS; |
449 installer_state->WriteInstallerResult(*status, | 442 installer_state->WriteInstallerResult(*status, |
450 IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL); | 443 IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL); |
451 return false; | 444 return false; |
452 } | 445 } |
453 } else { | 446 } else { |
454 // This is a non-multi installation. | 447 // This is a non-multi installation. |
455 | 448 |
456 // It isn't possible to stuff two products into a single-install | |
457 // InstallerState. Abort the process here in debug builds just in case | |
458 // someone finds a way. | |
459 DCHECK_EQ(1U, products.size()); | |
460 if (products.size() != 1) | |
461 return false; | |
462 | |
463 // Check for an existing installation of the product. | 449 // Check for an existing installation of the product. |
464 const ProductState* product_state = original_state.GetProductState( | 450 const ProductState* product_state = original_state.GetProductState( |
465 system_level, products[0]->distribution()->GetType()); | 451 system_level, products[0]->distribution()->GetType()); |
466 if (product_state != NULL) { | 452 if (product_state != NULL) { |
467 // Block downgrades from multi-install to single-install. | 453 // Block downgrades from multi-install to single-install. |
468 if (product_state->is_multi_install()) { | 454 if (product_state->is_multi_install()) { |
469 LOG(ERROR) << "Multi-install " | 455 LOG(ERROR) << "Multi-install " |
470 << products[0]->distribution()->GetAppShortCutName() | 456 << products[0]->distribution()->GetAppShortCutName() |
471 << " exists; aborting single install."; | 457 << " exists; aborting single install."; |
472 *status = installer::MULTI_INSTALLATION_EXISTS; | 458 *status = installer::MULTI_INSTALLATION_EXISTS; |
473 installer_state->WriteInstallerResult(*status, | 459 installer_state->WriteInstallerResult(*status, |
474 IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL); | 460 IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL); |
475 return false; | 461 return false; |
476 } | 462 } |
477 } | 463 } |
| 464 } |
| 465 |
| 466 return true; |
| 467 } |
| 468 |
| 469 // Checks app host pre-install conditions, specifically that this is a |
| 470 // user-level multi-install. When the pre-install conditions are not |
| 471 // satisfied, the result is written to the registry (via WriteInstallerResult), |
| 472 // |status| is set appropriately, and false is returned. |
| 473 bool CheckAppHostPreconditions(const InstallationState& original_state, |
| 474 InstallerState* installer_state, |
| 475 installer::InstallStatus* status) { |
| 476 if (installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST)) { |
| 477 |
| 478 if (!installer_state->is_multi_install()) { |
| 479 LOG(DFATAL) << "Application Host requires multi install"; |
| 480 *status = installer::APP_HOST_REQUIRES_MULTI_INSTALL; |
| 481 // No message string since there is nothing a user can do. |
| 482 installer_state->WriteInstallerResult(*status, 0, NULL); |
| 483 return false; |
| 484 } |
| 485 |
| 486 if (installer_state->system_install()) { |
| 487 LOG(DFATAL) << "Application Host may only be installed at user-level."; |
| 488 *status = installer::APP_HOST_REQUIRES_USER_LEVEL; |
| 489 // No message string since there is nothing a user can do. |
| 490 installer_state->WriteInstallerResult(*status, 0, NULL); |
| 491 return false; |
| 492 } |
478 | 493 |
479 } | 494 } |
480 | 495 |
481 return true; | 496 return true; |
482 } | |
483 | |
484 bool CheckAppHostPreconditions(const InstallationState& original_state, | |
485 InstallerState* installer_state) { | |
486 if (!installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST)) | |
487 return true; | |
488 | |
489 if (!installer_state->is_multi_install()) { | |
490 VLOG(1) << "Application Host may only be installed in multi-install mode."; | |
491 return false; | |
492 } | |
493 | |
494 if (installer_state->system_install()) { | |
495 VLOG(1) << "Application Host may only be installed at user-level."; | |
496 return false; | |
497 } | |
498 | |
499 return true; | |
500 } | 497 } |
501 | 498 |
502 // Checks for compatibility between the current state of the system and the | 499 // Checks for compatibility between the current state of the system and the |
503 // desired operation. Also applies policy that mutates the desired operation; | 500 // desired operation. Also applies policy that mutates the desired operation; |
504 // specifically, the |installer_state| object. | 501 // specifically, the |installer_state| object. |
505 // Also blocks simultaneous user-level and system-level installs. In the case | 502 // Also blocks simultaneous user-level and system-level installs. In the case |
506 // of trying to install user-level Chrome when system-level exists, the | 503 // of trying to install user-level Chrome when system-level exists, the |
507 // existing system-level Chrome is launched. | 504 // existing system-level Chrome is launched. |
508 // When the pre-install conditions are not satisfied, the result is written to | 505 // When the pre-install conditions are not satisfied, the result is written to |
509 // the registry (via WriteInstallerResult), |status| is set appropriately, and | 506 // the registry (via WriteInstallerResult), |status| is set appropriately, and |
510 // false is returned. | 507 // false is returned. |
511 bool CheckPreInstallConditions(const InstallationState& original_state, | 508 bool CheckPreInstallConditions(const InstallationState& original_state, |
512 InstallerState* installer_state, | 509 InstallerState* installer_state, |
513 installer::InstallStatus* status) { | 510 installer::InstallStatus* status) { |
514 if (!CheckAppHostPreconditions(original_state, installer_state)) | 511 if (!CheckAppHostPreconditions(original_state, installer_state, status)) { |
| 512 DCHECK_NE(*status, installer::UNKNOWN_STATUS); |
515 return false; | 513 return false; |
| 514 } |
516 | 515 |
517 if (!CheckMultiInstallConditions(original_state, installer_state, status)) | 516 // See what products are already installed in multi mode. When we do multi |
| 517 // installs, we must upgrade all installations since they share the binaries. |
| 518 AddExistingMultiInstalls(original_state, installer_state); |
| 519 |
| 520 if (!CheckMultiInstallConditions(original_state, installer_state, status)) { |
| 521 DCHECK_NE(*status, installer::UNKNOWN_STATUS); |
518 return false; | 522 return false; |
| 523 } |
519 | 524 |
520 const Products& products = installer_state->products(); | 525 const Products& products = installer_state->products(); |
521 if (products.empty()) { | 526 if (products.empty()) { |
522 // We haven't been given any products on which to operate. | 527 // We haven't been given any products on which to operate. |
523 LOG(ERROR) | 528 LOG(ERROR) |
524 << "Not given any products to install and no products found to update."; | 529 << "Not given any products to install and no products found to update."; |
525 *status = installer::CHROME_NOT_INSTALLED; | 530 *status = installer::CHROME_NOT_INSTALLED; |
526 installer_state->WriteInstallerResult(*status, | 531 installer_state->WriteInstallerResult(*status, |
527 IDS_INSTALL_NO_PRODUCTS_TO_UPDATE_BASE, NULL); | 532 IDS_INSTALL_NO_PRODUCTS_TO_UPDATE_BASE, NULL); |
528 return false; | 533 return false; |
529 } | 534 } |
530 | 535 |
531 // See what products are already installed in multi mode. When we do multi | |
532 // installs, we must upgrade all installations since they share the binaries. | |
533 AddExistingMultiInstalls(original_state, installer_state); | |
534 | |
535 if (!installer_state->system_install()) { | 536 if (!installer_state->system_install()) { |
536 // This is a user-level installation. Make sure that we are not installing | 537 // This is a user-level installation. Make sure that we are not installing |
537 // on top of an existing system-level installation. | 538 // on top of an existing system-level installation. |
538 for (size_t i = 0; i < products.size(); ++i) { | 539 for (size_t i = 0; i < products.size(); ++i) { |
539 const Product* product = products[i]; | 540 const Product* product = products[i]; |
540 BrowserDistribution* browser_dist = product->distribution(); | 541 BrowserDistribution* browser_dist = product->distribution(); |
| 542 |
| 543 // Skip over the binaries, as it's okay for them to be at both levels |
| 544 // for different products. |
| 545 if (browser_dist->GetType() == BrowserDistribution::CHROME_BINARIES) |
| 546 continue; |
| 547 |
541 const ProductState* user_level_product_state = | 548 const ProductState* user_level_product_state = |
542 original_state.GetProductState(false, browser_dist->GetType()); | 549 original_state.GetProductState(false, browser_dist->GetType()); |
543 const ProductState* system_level_product_state = | 550 const ProductState* system_level_product_state = |
544 original_state.GetProductState(true, browser_dist->GetType()); | 551 original_state.GetProductState(true, browser_dist->GetType()); |
545 | 552 |
546 // Allow upgrades to proceed so that out-of-date versions are not left | 553 // Allow upgrades to proceed so that out-of-date versions are not left |
547 // around. | 554 // around. |
548 if (user_level_product_state) | 555 if (user_level_product_state) |
549 continue; | 556 continue; |
550 | 557 |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
866 installer_state->UpdateStage(installer::PRECONDITIONS); | 873 installer_state->UpdateStage(installer::PRECONDITIONS); |
867 // The stage provides more fine-grained information than -multifail, so remove | 874 // The stage provides more fine-grained information than -multifail, so remove |
868 // the -multifail suffix from the Google Update "ap" value. | 875 // the -multifail suffix from the Google Update "ap" value. |
869 BrowserDistribution::GetSpecificDistribution(installer_state->state_type()) | 876 BrowserDistribution::GetSpecificDistribution(installer_state->state_type()) |
870 ->UpdateInstallStatus(system_install, archive_type, install_status); | 877 ->UpdateInstallStatus(system_install, archive_type, install_status); |
871 if (CheckPreInstallConditions(original_state, installer_state, | 878 if (CheckPreInstallConditions(original_state, installer_state, |
872 &install_status)) { | 879 &install_status)) { |
873 VLOG(1) << "Installing to " << installer_state->target_path().value(); | 880 VLOG(1) << "Installing to " << installer_state->target_path().value(); |
874 install_status = InstallProductsHelper( | 881 install_status = InstallProductsHelper( |
875 original_state, cmd_line, prefs, *installer_state, &archive_type); | 882 original_state, cmd_line, prefs, *installer_state, &archive_type); |
| 883 } else { |
| 884 // CheckPreInstallConditions must set the status on failure. |
| 885 DCHECK_NE(install_status, installer::UNKNOWN_STATUS); |
876 } | 886 } |
877 | 887 |
878 const Products& products = installer_state->products(); | 888 const Products& products = installer_state->products(); |
879 | 889 |
880 for (size_t i = 0; i < products.size(); ++i) { | 890 for (size_t i = 0; i < products.size(); ++i) { |
881 const Product* product = products[i]; | 891 const Product* product = products[i]; |
882 product->distribution()->UpdateInstallStatus( | 892 product->distribution()->UpdateInstallStatus( |
883 system_install, archive_type, install_status); | 893 system_install, archive_type, install_status); |
884 } | 894 } |
885 if (installer_state->is_multi_install()) { | |
886 installer_state->multi_package_binaries_distribution()->UpdateInstallStatus( | |
887 system_install, archive_type, install_status); | |
888 } | |
889 | 895 |
890 installer_state->UpdateStage(installer::NO_STAGE); | 896 installer_state->UpdateStage(installer::NO_STAGE); |
891 return install_status; | 897 return install_status; |
892 } | 898 } |
893 | 899 |
894 installer::InstallStatus UninstallProduct( | 900 installer::InstallStatus UninstallProduct( |
895 const InstallationState& original_state, | 901 const InstallationState& original_state, |
896 const InstallerState& installer_state, | 902 const InstallerState& installer_state, |
897 const CommandLine& cmd_line, | 903 const CommandLine& cmd_line, |
898 bool remove_all, | 904 bool remove_all, |
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1457 const Product* cf_install = | 1463 const Product* cf_install = |
1458 installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); | 1464 installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); |
1459 | 1465 |
1460 if (cf_install && | 1466 if (cf_install && |
1461 !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { | 1467 !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { |
1462 if (install_status == installer::UNINSTALL_REQUIRES_REBOOT) { | 1468 if (install_status == installer::UNINSTALL_REQUIRES_REBOOT) { |
1463 ShowRebootDialog(); | 1469 ShowRebootDialog(); |
1464 } else if (is_uninstall) { | 1470 } else if (is_uninstall) { |
1465 // Only show the message box if Chrome Frame was the only product being | 1471 // Only show the message box if Chrome Frame was the only product being |
1466 // uninstalled. | 1472 // uninstalled. |
1467 if (installer_state.products().size() == 1U) { | 1473 const Products& products = installer_state.products(); |
| 1474 int num_products = 0; |
| 1475 for (size_t i = 0; i < products.size(); ++i) { |
| 1476 if (!products[i]->is_chrome_binaries()) |
| 1477 ++num_products; |
| 1478 } |
| 1479 if (num_products == 1U) { |
1468 ::MessageBoxW(NULL, | 1480 ::MessageBoxW(NULL, |
1469 installer::GetLocalizedString( | 1481 installer::GetLocalizedString( |
1470 IDS_UNINSTALL_COMPLETE_BASE).c_str(), | 1482 IDS_UNINSTALL_COMPLETE_BASE).c_str(), |
1471 cf_install->distribution()->GetAppShortCutName().c_str(), | 1483 cf_install->distribution()->GetAppShortCutName().c_str(), |
1472 MB_OK); | 1484 MB_OK); |
1473 } | 1485 } |
1474 } | 1486 } |
1475 } | 1487 } |
1476 | 1488 |
1477 int return_code = 0; | 1489 int return_code = 0; |
1478 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will | 1490 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will |
1479 // rollback the action. If we're uninstalling we want to avoid this, so always | 1491 // rollback the action. If we're uninstalling we want to avoid this, so always |
1480 // report success, squashing any more informative return codes. | 1492 // report success, squashing any more informative return codes. |
1481 if (!(installer_state.is_msi() && is_uninstall)) | 1493 if (!(installer_state.is_msi() && is_uninstall)) |
1482 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 1494 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT |
1483 // to pass through, since this is only returned on uninstall which is | 1495 // to pass through, since this is only returned on uninstall which is |
1484 // never invoked directly by Google Update. | 1496 // never invoked directly by Google Update. |
1485 return_code = InstallUtil::GetInstallReturnCode(install_status); | 1497 return_code = InstallUtil::GetInstallReturnCode(install_status); |
1486 | 1498 |
1487 VLOG(1) << "Installation complete, returning: " << return_code; | 1499 VLOG(1) << "Installation complete, returning: " << return_code; |
1488 | 1500 |
1489 return return_code; | 1501 return return_code; |
1490 } | 1502 } |
OLD | NEW |