blob: 3965c1d05fca931402693217a6a3f46c9e2c48bc [file] [log] [blame]
[email protected]9e790bd2011-01-10 23:48:541// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5c9587c2008-12-09 21:20:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]e6b5bc22011-09-08 22:01:565#include "chrome/browser/chrome_browser_main_win.h"
[email protected]5c9587c2008-12-09 21:20:166
[email protected]71b73f02011-04-06 15:57:297#include <windows.h>
[email protected]e0785902011-05-19 23:34:178#include <shellapi.h>
[email protected]4a0765a2009-05-08 23:12:259
[email protected]c83dd912010-04-06 18:50:5110#include <algorithm>
11
[email protected]5c9587c2008-12-09 21:20:1612#include "base/command_line.h"
[email protected]ae0f0772010-08-13 04:54:1013#include "base/environment.h"
[email protected]7cf1b6ce2010-03-20 06:37:0114#include "base/i18n/rtl.h"
[email protected]3b63f8f42011-03-28 01:54:1515#include "base/memory/scoped_ptr.h"
[email protected]5c9587c2008-12-09 21:20:1616#include "base/path_service.h"
[email protected]e0785902011-05-19 23:34:1717#include "base/scoped_native_library.h"
[email protected]c7480942011-11-08 19:18:2718#include "base/string_number_conversions.h"
[email protected]be1ce6a72010-08-03 14:35:2219#include "base/utf_string_conversions.h"
[email protected]935aa542010-10-15 01:59:1520#include "base/win/windows_version.h"
[email protected]ecb924c2011-03-17 00:34:0921#include "base/win/wrapped_window_proc.h"
[email protected]a3abd5572011-04-15 02:09:3322#include "chrome/browser/browser_util_win.h"
[email protected]820735792010-07-29 23:40:0123#include "chrome/browser/first_run/first_run.h"
[email protected]cd1adc22009-01-16 01:29:2224#include "chrome/browser/metrics/metrics_service.h"
[email protected]f8b2ca32011-11-22 14:58:2325#include "chrome/browser/profiles/profile_info_cache.h"
26#include "chrome/browser/profiles/profile_shortcut_manager_win.h"
[email protected]71b73f02011-04-06 15:57:2927#include "chrome/browser/ui/browser_list.h"
[email protected]9e790bd2011-01-10 23:48:5428#include "chrome/browser/ui/views/uninstall_view.h"
[email protected]ecb924c2011-03-17 00:34:0929#include "chrome/common/chrome_constants.h"
[email protected]1fcfb202011-07-19 19:53:1430#include "chrome/common/chrome_result_codes.h"
[email protected]5c9587c2008-12-09 21:20:1631#include "chrome/common/chrome_switches.h"
32#include "chrome/common/env_vars.h"
[email protected]bf6117c7e2010-12-01 06:00:2533#include "chrome/installer/util/browser_distribution.h"
[email protected]5c9587c2008-12-09 21:20:1634#include "chrome/installer/util/helper.h"
35#include "chrome/installer/util/install_util.h"
36#include "chrome/installer/util/shell_util.h"
[email protected]4573fbd2011-10-31 20:25:1837#include "content/public/common/main_function_params.h"
[email protected]c7480942011-11-08 19:18:2738#include "grit/app_locale_settings.h"
[email protected]34ac8f32009-02-22 23:03:2739#include "grit/chromium_strings.h"
40#include "grit/generated_resources.h"
[email protected]c051a1b2011-01-21 23:30:1741#include "ui/base/l10n/l10n_util.h"
[email protected]c7480942011-11-08 19:18:2742#include "ui/base/l10n/l10n_util_win.h"
[email protected]75b68052011-02-03 06:01:1643#include "ui/base/message_box_win.h"
[email protected]c7480942011-11-08 19:18:2744#include "ui/gfx/platform_font_win.h"
[email protected]477ae052011-11-18 23:53:5745#include "ui/views/focus/accelerator_handler.h"
[email protected]c13be0d2011-11-22 02:09:5846#include "ui/views/widget/widget.h"
[email protected]5c9587c2008-12-09 21:20:1647
[email protected]0fd23af2011-02-20 06:33:0448namespace {
[email protected]ecb924c2011-03-17 00:34:0949
[email protected]a08ba822011-02-20 07:45:4750typedef HRESULT (STDAPICALLTYPE* RegisterApplicationRestartProc)(
[email protected]0fd23af2011-02-20 06:33:0451 const wchar_t* command_line,
52 DWORD flags);
[email protected]ecb924c2011-03-17 00:34:0953
54void InitializeWindowProcExceptions() {
55 // Get the breakpad pointer from chrome.exe
56 base::win::WinProcExceptionFilter exception_filter =
57 reinterpret_cast<base::win::WinProcExceptionFilter>(
58 ::GetProcAddress(::GetModuleHandle(
59 chrome::kBrowserProcessExecutableName),
60 "CrashForException"));
61 exception_filter = base::win::SetWinProcExceptionFilter(exception_filter);
62 DCHECK(!exception_filter);
63}
[email protected]c7480942011-11-08 19:18:2764
65// gfx::Font callbacks
66void AdjustUIFont(LOGFONT* logfont) {
67 l10n_util::AdjustUIFont(logfont);
68}
69
70int GetMinimumFontSize() {
71 int min_font_size;
72 base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE),
73 &min_font_size);
74 return min_font_size;
75}
76
[email protected]0fd23af2011-02-20 06:33:0477} // namespace
78
[email protected]1152b7e2009-09-14 03:26:0379void RecordBreakpadStatusUMA(MetricsService* metrics) {
[email protected]c83dd912010-04-06 18:50:5180 DWORD len = ::GetEnvironmentVariableW(
81 ASCIIToWide(env_vars::kNoOOBreakpad).c_str() , NULL, 0);
[email protected]1152b7e2009-09-14 03:26:0382 metrics->RecordBreakpadRegistration((len == 0));
83 metrics->RecordBreakpadHasDebugger(TRUE == ::IsDebuggerPresent());
84}
85
[email protected]34f73fb2010-03-24 20:50:3486void WarnAboutMinimumSystemRequirements() {
[email protected]935aa542010-10-15 01:59:1587 if (base::win::GetVersion() < base::win::VERSION_XP) {
[email protected]34f73fb2010-03-24 20:50:3488 // Display a warning message if the user is running chrome on Windows 2000.
[email protected]0f26d7b2011-01-05 19:10:4489 const string16 text =
90 l10n_util::GetStringUTF16(IDS_UNSUPPORTED_OS_PRE_WIN_XP);
91 const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
[email protected]75b68052011-02-03 06:01:1692 ui::MessageBox(NULL, text, caption, MB_OK | MB_ICONWARNING | MB_TOPMOST);
[email protected]5c9587c2008-12-09 21:20:1693 }
[email protected]5c9587c2008-12-09 21:20:1694}
95
[email protected]45d72762011-04-15 18:58:2096void RecordBrowserStartupTime() {
97 // Calculate the time that has elapsed from our own process creation.
98 FILETIME creation_time = {};
99 FILETIME ignore = {};
100 ::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore, &ignore,
101 &ignore);
102
[email protected]28f576f2011-08-26 20:46:55103 RecordPreReadExperimentTime("Startup.BrowserMessageLoopStartTime",
104 base::Time::Now() - base::Time::FromFileTime(creation_time));
[email protected]45d72762011-04-15 18:58:20105}
106
[email protected]4df8786f2009-04-17 13:24:57107int AskForUninstallConfirmation() {
[email protected]1fcfb202011-07-19 19:53:14108 int ret = content::RESULT_CODE_NORMAL_EXIT;
[email protected]956b3d32011-09-28 09:38:48109 views::Widget::CreateWindow(new UninstallView(&ret))->Show();
[email protected]047f6222009-07-29 23:34:56110 views::AcceleratorHandler accelerator_handler;
[email protected]4d6285312011-10-24 07:19:51111 MessageLoopForUI::current()->RunWithDispatcher(&accelerator_handler);
[email protected]4df8786f2009-04-17 13:24:57112 return ret;
[email protected]5c9587c2008-12-09 21:20:16113}
114
[email protected]53c38d232009-02-13 20:52:18115void ShowCloseBrowserFirstMessageBox() {
[email protected]0f26d7b2011-01-05 19:10:44116 const string16 text = l10n_util::GetStringUTF16(IDS_UNINSTALL_CLOSE_APP);
117 const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
[email protected]53c38d232009-02-13 20:52:18118 const UINT flags = MB_OK | MB_ICONWARNING | MB_TOPMOST;
[email protected]75b68052011-02-03 06:01:16119 ui::MessageBox(NULL, text, caption, flags);
[email protected]53c38d232009-02-13 20:52:18120}
121
122int DoUninstallTasks(bool chrome_still_running) {
[email protected]a173cc92009-08-20 23:26:37123 // We want to show a warning to user (and exit) if Chrome is already running
124 // *before* we show the uninstall confirmation dialog box. But while the
125 // uninstall confirmation dialog is up, user might start Chrome, so we
126 // check once again after user acknowledges Uninstall dialog.
[email protected]53c38d232009-02-13 20:52:18127 if (chrome_still_running) {
128 ShowCloseBrowserFirstMessageBox();
[email protected]1fcfb202011-07-19 19:53:14129 return chrome::RESULT_CODE_UNINSTALL_CHROME_ALIVE;
[email protected]53c38d232009-02-13 20:52:18130 }
[email protected]4df8786f2009-04-17 13:24:57131 int ret = AskForUninstallConfirmation();
[email protected]a3abd5572011-04-15 02:09:33132 if (browser_util::IsBrowserAlreadyRunning()) {
[email protected]a173cc92009-08-20 23:26:37133 ShowCloseBrowserFirstMessageBox();
[email protected]1fcfb202011-07-19 19:53:14134 return chrome::RESULT_CODE_UNINSTALL_CHROME_ALIVE;
[email protected]a173cc92009-08-20 23:26:37135 }
136
[email protected]1fcfb202011-07-19 19:53:14137 if (ret != chrome::RESULT_CODE_UNINSTALL_USER_CANCEL) {
[email protected]4df8786f2009-04-17 13:24:57138 // The following actions are just best effort.
[email protected]8e96e502010-10-21 20:57:12139 VLOG(1) << "Executing uninstall actions";
[email protected]4df8786f2009-04-17 13:24:57140 if (!FirstRun::RemoveSentinel())
[email protected]8e96e502010-10-21 20:57:12141 VLOG(1) << "Failed to delete sentinel file.";
[email protected]4df8786f2009-04-17 13:24:57142 // We want to remove user level shortcuts and we only care about the ones
143 // created by us and not by the installer so |alternate| is false.
[email protected]bf6117c7e2010-12-01 06:00:25144 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
145 if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
[email protected]f8b2ca32011-11-22 14:58:23146 false)) {
[email protected]8e96e502010-10-21 20:57:12147 VLOG(1) << "Failed to delete desktop shortcut.";
[email protected]f8b2ca32011-11-22 14:58:23148 }
149 if (!ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames(
150 ProfileShortcutManagerWin::GenerateShortcutsFromProfiles(
151 ProfileInfoCache::GetProfileNames()))) {
152 VLOG(1) << "Failed to delete desktop profiles shortcuts.";
153 }
[email protected]bf6117c7e2010-12-01 06:00:25154 if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
[email protected]f8b2ca32011-11-22 14:58:23155 ShellUtil::CURRENT_USER)) {
[email protected]8e96e502010-10-21 20:57:12156 VLOG(1) << "Failed to delete quick launch shortcut.";
[email protected]f8b2ca32011-11-22 14:58:23157 }
[email protected]4df8786f2009-04-17 13:24:57158 }
[email protected]5c9587c2008-12-09 21:20:16159 return ret;
160}
161
[email protected]b48c9182011-10-26 18:03:30162// ChromeBrowserMainPartsWin ---------------------------------------------------
163
164ChromeBrowserMainPartsWin::ChromeBrowserMainPartsWin(
[email protected]4573fbd2011-10-31 20:25:18165 const content::MainFunctionParams& parameters)
[email protected]b48c9182011-10-26 18:03:30166 : ChromeBrowserMainParts(parameters) {
167}
168
[email protected]c7480942011-11-08 19:18:27169void ChromeBrowserMainPartsWin::ToolkitInitialized() {
170 ChromeBrowserMainParts::ToolkitInitialized();
171 gfx::PlatformFontWin::adjust_font_callback = &AdjustUIFont;
172 gfx::PlatformFontWin::get_minimum_font_size_callback = &GetMinimumFontSize;
173}
174
[email protected]b48c9182011-10-26 18:03:30175void ChromeBrowserMainPartsWin::PreMainMessageLoopStart() {
[email protected]c7480942011-11-08 19:18:27176 ChromeBrowserMainParts::PreMainMessageLoopStart();
[email protected]b48c9182011-10-26 18:03:30177 if (!parameters().ui_task) {
178 // Make sure that we know how to handle exceptions from the message loop.
179 InitializeWindowProcExceptions();
180 }
181}
182
183// static
184void ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment(
185 const CommandLine& parsed_command_line) {
[email protected]5c9587c2008-12-09 21:20:16186 // Clear this var so child processes don't show the dialog by default.
[email protected]ae0f0772010-08-13 04:54:10187 scoped_ptr<base::Environment> env(base::Environment::Create());
188 env->UnSetVar(env_vars::kShowRestart);
[email protected]5c9587c2008-12-09 21:20:16189
190 // For non-interactive tests we don't restart on crash.
[email protected]ae0f0772010-08-13 04:54:10191 if (env->HasVar(env_vars::kHeadless))
[email protected]5c9587c2008-12-09 21:20:16192 return;
193
194 // If the known command-line test options are used we don't create the
195 // environment block which means we don't get the restart dialog.
196 if (parsed_command_line.HasSwitch(switches::kBrowserCrashTest) ||
197 parsed_command_line.HasSwitch(switches::kBrowserAssertTest) ||
198 parsed_command_line.HasSwitch(switches::kNoErrorDialogs))
199 return;
200
201 // The encoding we use for the info is "title|context|direction" where
202 // direction is either env_vars::kRtlLocale or env_vars::kLtrLocale depending
203 // on the current locale.
[email protected]6baca1a2010-08-14 00:17:05204 string16 dlg_strings(l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_TITLE));
205 dlg_strings.push_back('|');
[email protected]1c53ffde12010-08-17 22:40:31206 string16 adjusted_string(
207 l10n_util::GetStringUTF16(IDS_CRASH_RECOVERY_CONTENT));
[email protected]c32d31e2010-11-24 07:27:42208 base::i18n::AdjustStringForLocaleDirection(&adjusted_string);
[email protected]6baca1a2010-08-14 00:17:05209 dlg_strings.append(adjusted_string);
210 dlg_strings.push_back('|');
211 dlg_strings.append(ASCIIToUTF16(
212 base::i18n::IsRTL() ? env_vars::kRtlLocale : env_vars::kLtrLocale));
[email protected]5c9587c2008-12-09 21:20:16213
[email protected]6baca1a2010-08-14 00:17:05214 env->SetVar(env_vars::kRestartInfo, UTF16ToUTF8(dlg_strings));
[email protected]5c9587c2008-12-09 21:20:16215}
216
[email protected]b48c9182011-10-26 18:03:30217// static
218void ChromeBrowserMainPartsWin::RegisterApplicationRestart(
219 const CommandLine& parsed_command_line) {
[email protected]0fd23af2011-02-20 06:33:04220 DCHECK(base::win::GetVersion() >= base::win::VERSION_VISTA);
221 base::ScopedNativeLibrary library(FilePath(L"kernel32.dll"));
222 // Get the function pointer for RegisterApplicationRestart.
[email protected]a08ba822011-02-20 07:45:47223 RegisterApplicationRestartProc register_application_restart =
224 static_cast<RegisterApplicationRestartProc>(
225 library.GetFunctionPointer("RegisterApplicationRestart"));
[email protected]7b672752011-07-07 06:39:15226 if (!register_application_restart) {
227 LOG(WARNING) << "Cannot find RegisterApplicationRestart in kernel32.dll";
228 return;
229 }
[email protected]0fd23af2011-02-20 06:33:04230 // The Windows Restart Manager expects a string of command line flags only,
231 // without the program.
232 CommandLine command_line(CommandLine::NO_PROGRAM);
[email protected]a40ca4302011-05-14 01:10:24233 command_line.AppendArguments(parsed_command_line, false);
[email protected]0fd23af2011-02-20 06:33:04234 if (!command_line.HasSwitch(switches::kRestoreLastSession))
235 command_line.AppendSwitch(switches::kRestoreLastSession);
[email protected]61a4c6f2011-07-20 04:54:52236 if (command_line.GetCommandLineString().length() > RESTART_MAX_CMD_LINE) {
[email protected]7b672752011-07-07 06:39:15237 LOG(WARNING) << "Command line too long for RegisterApplicationRestart";
238 return;
239 }
[email protected]0fd23af2011-02-20 06:33:04240
241 // Restart Chrome if the computer is restarted as the result of an update.
242 // This could be extended to handle crashes, hangs, and patches.
[email protected]9dc12406b2011-03-03 15:50:30243 HRESULT hr = register_application_restart(
[email protected]61a4c6f2011-07-20 04:54:52244 command_line.GetCommandLineString().c_str(),
[email protected]0fd23af2011-02-20 06:33:04245 RESTART_NO_CRASH | RESTART_NO_HANG | RESTART_NO_PATCH);
246 DCHECK(SUCCEEDED(hr)) << "RegisterApplicationRestart failed.";
[email protected]0fd23af2011-02-20 06:33:04247}
248
[email protected]b48c9182011-10-26 18:03:30249void ChromeBrowserMainPartsWin::ShowMissingLocaleMessageBox() {
250 ui::MessageBox(NULL, ASCIIToUTF16(chrome_browser::kMissingLocaleDataMessage),
251 ASCIIToUTF16(chrome_browser::kMissingLocaleDataTitle),
252 MB_OK | MB_ICONERROR | MB_TOPMOST);
253}
254
255// static
256int ChromeBrowserMainPartsWin::HandleIconsCommands(
257 const CommandLine& parsed_command_line) {
[email protected]5c9587c2008-12-09 21:20:16258 if (parsed_command_line.HasSwitch(switches::kHideIcons)) {
[email protected]0f26d7b2011-01-05 19:10:44259 string16 cp_applet;
[email protected]935aa542010-10-15 01:59:15260 base::win::Version version = base::win::GetVersion();
261 if (version >= base::win::VERSION_VISTA) {
[email protected]5c9587c2008-12-09 21:20:16262 cp_applet.assign(L"Programs and Features"); // Windows Vista and later.
[email protected]935aa542010-10-15 01:59:15263 } else if (version >= base::win::VERSION_XP) {
[email protected]5c9587c2008-12-09 21:20:16264 cp_applet.assign(L"Add/Remove Programs"); // Windows XP.
265 } else {
[email protected]1fcfb202011-07-19 19:53:14266 return chrome::RESULT_CODE_UNSUPPORTED_PARAM; // Not supported
[email protected]5c9587c2008-12-09 21:20:16267 }
268
[email protected]0f26d7b2011-01-05 19:10:44269 const string16 msg =
270 l10n_util::GetStringFUTF16(IDS_HIDE_ICONS_NOT_SUPPORTED, cp_applet);
271 const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
[email protected]5c9587c2008-12-09 21:20:16272 const UINT flags = MB_OKCANCEL | MB_ICONWARNING | MB_TOPMOST;
[email protected]75b68052011-02-03 06:01:16273 if (IDOK == ui::MessageBox(NULL, msg, caption, flags))
[email protected]5c9587c2008-12-09 21:20:16274 ShellExecute(NULL, NULL, L"appwiz.cpl", NULL, NULL, SW_SHOWNORMAL);
[email protected]1fcfb202011-07-19 19:53:14275
276 // Exit as we are not launching the browser.
277 return content::RESULT_CODE_NORMAL_EXIT;
[email protected]5c9587c2008-12-09 21:20:16278 }
279 // We don't hide icons so we shouldn't do anything special to show them
[email protected]1fcfb202011-07-19 19:53:14280 return chrome::RESULT_CODE_UNSUPPORTED_PARAM;
[email protected]5c9587c2008-12-09 21:20:16281}
282
[email protected]b48c9182011-10-26 18:03:30283// static
284bool ChromeBrowserMainPartsWin::CheckMachineLevelInstall() {
[email protected]bf6117c7e2010-12-01 06:00:25285 // TODO(tommi): Check if using the default distribution is always the right
286 // thing to do.
287 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
[email protected]1db1b492010-12-16 19:03:37288 scoped_ptr<Version> version(InstallUtil::GetChromeVersion(dist, true));
[email protected]5c9587c2008-12-09 21:20:16289 if (version.get()) {
[email protected]b9696482010-11-30 23:56:18290 FilePath exe_path;
291 PathService::Get(base::DIR_EXE, &exe_path);
292 std::wstring exe = exe_path.value();
[email protected]bf6117c7e2010-12-01 06:00:25293 FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
294 if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
[email protected]0f26d7b2011-01-05 19:10:44295 const string16 text =
296 l10n_util::GetStringUTF16(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
297 const string16 caption = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
[email protected]5c9587c2008-12-09 21:20:16298 const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
[email protected]75b68052011-02-03 06:01:16299 ui::MessageBox(NULL, text, caption, flags);
[email protected]e5fbd4962011-02-11 16:30:43300 CommandLine uninstall_cmd(
301 InstallUtil::GetChromeUninstallCmd(false, dist->GetType()));
302 if (!uninstall_cmd.GetProgram().empty()) {
[email protected]74ca0442010-12-15 14:44:50303 uninstall_cmd.AppendSwitch(installer::switches::kForceUninstall);
[email protected]e6124ad52010-11-15 04:17:52304 uninstall_cmd.AppendSwitch(
[email protected]74ca0442010-12-15 14:44:50305 installer::switches::kDoNotRemoveSharedItems);
[email protected]e5992182011-07-15 16:47:02306 base::LaunchProcess(uninstall_cmd, base::LaunchOptions(), NULL);
[email protected]5c9587c2008-12-09 21:20:16307 }
308 return true;
309 }
310 }
311 return false;
312}