browser_main_win.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/browser_main.h"
6#include "chrome/browser/browser_main_win.h"
7
8#include <windows.h>
9#include <shellapi.h>
10
11#include <algorithm>
12
13#include "base/command_line.h"
14#include "base/environment.h"
15#include "base/i18n/rtl.h"
16#include "base/nss_util.h"
17#include "base/path_service.h"
18#include "base/scoped_ptr.h"
19#include "base/utf_string_conversions.h"
20#include "base/win/windows_version.h"
21#include "chrome/browser/browser_list.h"
22#include "chrome/browser/first_run/first_run.h"
23#include "chrome/browser/metrics/metrics_service.h"
24#include "chrome/browser/ui/views/uninstall_view.h"
25#include "chrome/common/chrome_switches.h"
26#include "chrome/common/env_vars.h"
27#include "chrome/common/main_function_params.h"
28#include "chrome/common/result_codes.h"
29#include "chrome/installer/util/browser_distribution.h"
30#include "chrome/installer/util/helper.h"
31#include "chrome/installer/util/install_util.h"
32#include "chrome/installer/util/shell_util.h"
33#include "grit/chromium_strings.h"
34#include "grit/generated_resources.h"
35#include "net/base/winsock_init.h"
36#include "net/socket/ssl_client_socket_nss_factory.h"
37#include "ui/base/l10n/l10n_util.h"
38#include "ui/base/l10n/l10n_util_win.h"
39#include "ui/base/message_box_win.h"
40#include "views/focus/accelerator_handler.h"
41#include "views/window/window.h"
42
43void DidEndMainMessageLoop() {
44  OleUninitialize();
45}
46
47void RecordBreakpadStatusUMA(MetricsService* metrics) {
48  DWORD len = ::GetEnvironmentVariableW(
49      ASCIIToWide(env_vars::kNoOOBreakpad).c_str() , NULL, 0);
50  metrics->RecordBreakpadRegistration((len == 0));
51  metrics->RecordBreakpadHasDebugger(TRUE == ::IsDebuggerPresent());
52}
53
54void WarnAboutMinimumSystemRequirements() {
55  if (base::win::GetVersion() < base::win::VERSION_XP) {
56    // Display a warning message if the user is running chrome on Windows 2000.
57    const string16 text =
58        l10n_util::GetStringUTF16(IDS_UNSUPPORTED_OS_PRE_WIN_XP);
59    const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
60    ui::MessageBox(NULL, text, caption, MB_OK | MB_ICONWARNING | MB_TOPMOST);
61  }
62}
63
64int AskForUninstallConfirmation() {
65  int ret = ResultCodes::NORMAL_EXIT;
66  views::Window::CreateChromeWindow(NULL, gfx::Rect(),
67                                    new UninstallView(ret))->Show();
68  views::AcceleratorHandler accelerator_handler;
69  MessageLoopForUI::current()->Run(&accelerator_handler);
70  return ret;
71}
72
73void ShowCloseBrowserFirstMessageBox() {
74  const string16 text = l10n_util::GetStringUTF16(IDS_UNINSTALL_CLOSE_APP);
75  const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
76  const UINT flags = MB_OK | MB_ICONWARNING | MB_TOPMOST;
77  ui::MessageBox(NULL, text, caption, flags);
78}
79
80int DoUninstallTasks(bool chrome_still_running) {
81  // We want to show a warning to user (and exit) if Chrome is already running
82  // *before* we show the uninstall confirmation dialog box. But while the
83  // uninstall confirmation dialog is up, user might start Chrome, so we
84  // check once again after user acknowledges Uninstall dialog.
85  if (chrome_still_running) {
86    ShowCloseBrowserFirstMessageBox();
87    return ResultCodes::UNINSTALL_CHROME_ALIVE;
88  }
89  int ret = AskForUninstallConfirmation();
90  if (Upgrade::IsBrowserAlreadyRunning()) {
91    ShowCloseBrowserFirstMessageBox();
92    return ResultCodes::UNINSTALL_CHROME_ALIVE;
93  }
94
95  if (ret != ResultCodes::UNINSTALL_USER_CANCEL) {
96    // The following actions are just best effort.
97    VLOG(1) << "Executing uninstall actions";
98    if (!FirstRun::RemoveSentinel())
99      VLOG(1) << "Failed to delete sentinel file.";
100    // We want to remove user level shortcuts and we only care about the ones
101    // created by us and not by the installer so |alternate| is false.
102    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
103    if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
104                                                false))
105      VLOG(1) << "Failed to delete desktop shortcut.";
106    if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
107                                                    ShellUtil::CURRENT_USER))
108      VLOG(1) << "Failed to delete quick launch shortcut.";
109  }
110  return ret;
111}
112
113// Prepares the localized strings that are going to be displayed to
114// the user if the browser process dies. These strings are stored in the
115// environment block so they are accessible in the early stages of the
116// chrome executable's lifetime.
117void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
118  // Clear this var so child processes don't show the dialog by default.
119  scoped_ptr<base::Environment> env(base::Environment::Create());
120  env->UnSetVar(env_vars::kShowRestart);
121
122  // For non-interactive tests we don't restart on crash.
123  if (env->HasVar(env_vars::kHeadless))
124    return;
125
126  // If the known command-line test options are used we don't create the
127  // environment block which means we don't get the restart dialog.
128  if (parsed_command_line.HasSwitch(switches::kBrowserCrashTest) ||
129      parsed_command_line.HasSwitch(switches::kBrowserAssertTest) ||
130      parsed_command_line.HasSwitch(switches::kNoErrorDialogs))
131    return;
132
133  // The encoding we use for the info is "title|context|direction" where
134  // direction is either env_vars::kRtlLocale or env_vars::kLtrLocale depending
135  // on the current locale.
136  string16 dlg_strings(l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
137  dlg_strings.push_back('|');
138  string16 adjusted_string(
139      l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_CONTENT));
140  base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
141  dlg_strings.append(adjusted_string);
142  dlg_strings.push_back('|');
143  dlg_strings.append(ASCIIToUTF16(
144      base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));
145
146  env->SetVar(env_vars::kRestartInfo, UTF16ToUTF8(dlg_strings));
147}
148
149// This method handles the --hide-icons and --show-icons command line options
150// for chrome that get triggered by Windows from registry entries
151// HideIconsCommand & ShowIconsCommand. Chrome doesn't support hide icons
152// functionality so we just ask the users if they want to uninstall Chrome.
153int HandleIconsCommands(const CommandLine &parsed_command_line) {
154  if (parsed_command_line.HasSwitch(switches::kHideIcons)) {
155    string16 cp_applet;
156    base::win::Version version = base::win::GetVersion();
157    if (version >= base::win::VERSION_VISTA) {
158      cp_applet.assign(L"Programs and Features");  // Windows Vista and later.
159    } else if (version >= base::win::VERSION_XP) {
160      cp_applet.assign(L"Add/Remove Programs");  // Windows XP.
161    } else {
162      return ResultCodes::UNSUPPORTED_PARAM;  // Not supported
163    }
164
165    const string16 msg =
166        l10n_util::GetStringFUTF16(IDS_HIDE_ICONS_NOT_SUPPORTED, cp_applet);
167    const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
168    const UINT flags = MB_OKCANCEL | MB_ICONWARNING | MB_TOPMOST;
169    if (IDOK == ui::MessageBox(NULL, msg, caption, flags))
170      ShellExecute(NULL, NULL, L"appwiz.cpl", NULL, NULL, SW_SHOWNORMAL);
171    return ResultCodes::NORMAL_EXIT;  // Exit as we are not launching browser.
172  }
173  // We don't hide icons so we shouldn't do anything special to show them
174  return ResultCodes::UNSUPPORTED_PARAM;
175}
176
177// Check if there is any machine level Chrome installed on the current
178// machine. If yes and the current Chrome process is user level, we do not
179// allow the user level Chrome to run. So we notify the user and uninstall
180// user level Chrome.
181bool CheckMachineLevelInstall() {
182  // TODO(tommi): Check if using the default distribution is always the right
183  // thing to do.
184  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
185  scoped_ptr<Version> version(InstallUtil::GetChromeVersion(dist, true));
186  if (version.get()) {
187    FilePath exe_path;
188    PathService::Get(base::DIR_EXE, &exe_path);
189    std::wstring exe = exe_path.value();
190    FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
191    if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
192      const string16 text =
193          l10n_util::GetStringUTF16(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
194      const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
195      const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
196      ui::MessageBox(NULL, text, caption, flags);
197      CommandLine uninstall_cmd(
198          InstallUtil::GetChromeUninstallCmd(false, dist->GetType()));
199      if (!uninstall_cmd.GetProgram().empty()) {
200        uninstall_cmd.AppendSwitch(installer::switches::kForceUninstall);
201        uninstall_cmd.AppendSwitch(
202            installer::switches::kDoNotRemoveSharedItems);
203        base::LaunchApp(uninstall_cmd, false, false, NULL);
204      }
205      return true;
206    }
207  }
208  return false;
209}
210
211// BrowserMainPartsWin ---------------------------------------------------------
212
213class BrowserMainPartsWin : public BrowserMainParts {
214 public:
215  explicit BrowserMainPartsWin(const MainFunctionParams& parameters)
216      : BrowserMainParts(parameters) {}
217
218 protected:
219  virtual void PreEarlyInitialization() {
220    // Initialize Winsock.
221    net::EnsureWinsockInit();
222  }
223
224  virtual void PreMainMessageLoopStart() {
225    OleInitialize(NULL);
226
227    // If we're running tests (ui_task is non-null), then the ResourceBundle
228    // has already been initialized.
229    if (!parameters().ui_task) {
230      // Override the configured locale with the user's preferred UI language.
231      l10n_util::OverrideLocaleWithUILanguageList();
232    }
233  }
234
235 private:
236  virtual void InitializeSSL() {
237    // Use NSS for SSL by default.
238    // Because of a build system issue (http://crbug.com/43461), the default
239    // client socket factory uses SChannel (the system SSL library) for SSL by
240    // default on Windows.
241    if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
242      net::ClientSocketFactory::SetSSLClientSocketFactory(
243          net::SSLClientSocketNSSFactory);
244      // We want to be sure to init NSPR on the main thread.
245      base::EnsureNSPRInit();
246    }
247  }
248};
249
250// static
251BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
252    const MainFunctionParams& parameters) {
253  return new BrowserMainPartsWin(parameters);
254}
255