blob: d3964617be89049e8fcd4474f535ed958ad255aa [file] [log] [blame]
[email protected]e3ce40a2012-01-31 03:03:031// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]fc14cef2009-01-27 22:17:292// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]7c47ae3e2009-02-18 00:34:215#include "chrome/browser/process_singleton.h"
[email protected]fc14cef2009-01-27 22:17:296
[email protected]b1d7844b2012-08-22 22:37:477#include <shellapi.h>
[email protected]6927f2e02012-09-18 00:13:498#include <shobjidl.h>
[email protected]b1d7844b2012-08-22 22:37:479
[email protected]fc14cef2009-01-27 22:17:2910#include "base/base_paths.h"
11#include "base/command_line.h"
[email protected]f805fe82010-08-03 22:47:1012#include "base/file_path.h"
[email protected]9e9b6e8e2009-12-02 08:45:0113#include "base/path_service.h"
[email protected]fc14cef2009-01-27 22:17:2914#include "base/process_util.h"
[email protected]f394bc62012-08-22 21:42:2915#include "base/stringprintf.h"
[email protected]0f26d7b2011-01-05 19:10:4416#include "base/utf_string_conversions.h"
[email protected]f394bc62012-08-22 21:42:2917#include "base/win/metro.h"
[email protected]b3d791c92012-10-05 19:01:2418#include "base/win/registry.h"
[email protected]6927f2e02012-09-18 00:13:4919#include "base/win/scoped_com_initializer.h"
20#include "base/win/scoped_comptr.h"
[email protected]b90d7e802011-01-09 16:32:2021#include "base/win/scoped_handle.h"
[email protected]b3d791c92012-10-05 19:01:2422#include "base/win/win_util.h"
[email protected]6927f2e02012-09-18 00:13:4923#include "base/win/windows_version.h"
[email protected]ecb924c2011-03-17 00:34:0924#include "base/win/wrapped_window_proc.h"
[email protected]b50892c5f2012-05-13 07:34:1425#include "chrome/browser/ui/simple_message_box.h"
[email protected]fc14cef2009-01-27 22:17:2926#include "chrome/common/chrome_constants.h"
[email protected]b3d791c92012-10-05 19:01:2427#include "chrome/common/chrome_paths.h"
28#include "chrome/common/chrome_paths_internal.h"
[email protected]6927f2e02012-09-18 00:13:4929#include "chrome/installer/util/browser_distribution.h"
[email protected]786799692012-09-26 14:16:4830#include "chrome/installer/util/install_util.h"
[email protected]6927f2e02012-09-18 00:13:4931#include "chrome/installer/util/shell_util.h"
[email protected]0a194552011-09-14 17:53:3532#include "chrome/installer/util/wmi.h"
[email protected]b39ef1cb2011-10-25 04:46:5533#include "content/public/common/result_codes.h"
[email protected]34ac8f32009-02-22 23:03:2734#include "grit/chromium_strings.h"
35#include "grit/generated_resources.h"
[email protected]f394bc62012-08-22 21:42:2936#include "net/base/escape.h"
[email protected]c051a1b2011-01-21 23:30:1737#include "ui/base/l10n/l10n_util.h"
[email protected]e7661062011-01-19 22:16:5338#include "ui/base/win/hwnd_util.h"
[email protected]fc14cef2009-01-27 22:17:2939
40namespace {
41
[email protected]2b7ff5b92012-07-17 22:45:1842const char kLockfile[] = "lockfile";
43
[email protected]f394bc62012-08-22 21:42:2944const char kSearchUrl[] =
45 "http://www.google.com/search?q=%s&sourceid=chrome&ie=UTF-8";
46
[email protected]b3d791c92012-10-05 19:01:2447const int kImmersiveChromeInitTimeout = 500;
48
[email protected]f891fb32009-04-08 00:20:3249// Checks the visibility of the enumerated window and signals once a visible
[email protected]fc14cef2009-01-27 22:17:2950// window has been found.
51BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
52 bool* result = reinterpret_cast<bool*>(param);
53 *result = IsWindowVisible(window) != 0;
54 // Stops enumeration if a visible window has been found.
55 return !*result;
56}
57
[email protected]e3ce40a2012-01-31 03:03:0358// This function thunks to the object's version of the windowproc, taking in
59// consideration that there are several messages being dispatched before
60// WM_NCCREATE which we let windows handle.
61LRESULT CALLBACK ThunkWndProc(HWND hwnd, UINT message,
62 WPARAM wparam, LPARAM lparam) {
63 ProcessSingleton* singleton =
64 reinterpret_cast<ProcessSingleton*>(ui::GetWindowUserData(hwnd));
65 if (message == WM_NCCREATE) {
66 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
67 singleton = reinterpret_cast<ProcessSingleton*>(cs->lpCreateParams);
68 CHECK(singleton);
69 ui::SetWindowUserData(hwnd, singleton);
70 } else if (!singleton) {
71 return ::DefWindowProc(hwnd, message, wparam, lparam);
72 }
73 return singleton->WndProc(hwnd, message, wparam, lparam);
74}
75
[email protected]edf04b512012-02-23 09:47:4376bool ParseCommandLine(const COPYDATASTRUCT* cds,
77 CommandLine* parsed_command_line,
78 FilePath* current_directory) {
79 // We should have enough room for the shortest command (min_message_size)
80 // and also be a multiple of wchar_t bytes. The shortest command
81 // possible is L"START\0\0" (empty current directory and command line).
82 static const int min_message_size = 7;
83 if (cds->cbData < min_message_size * sizeof(wchar_t) ||
84 cds->cbData % sizeof(wchar_t) != 0) {
85 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
86 return false;
87 }
88
89 // We split the string into 4 parts on NULLs.
90 DCHECK(cds->lpData);
91 const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
92 cds->cbData / sizeof(wchar_t));
93 const std::wstring::size_type first_null = msg.find_first_of(L'\0');
94 if (first_null == 0 || first_null == std::wstring::npos) {
95 // no NULL byte, don't know what to do
96 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
97 ", first null = " << first_null;
98 return false;
99 }
100
101 // Decode the command, which is everything until the first NULL.
102 if (msg.substr(0, first_null) == L"START") {
103 // Another instance is starting parse the command line & do what it would
104 // have done.
105 VLOG(1) << "Handling STARTUP request from another process";
106 const std::wstring::size_type second_null =
107 msg.find_first_of(L'\0', first_null + 1);
108 if (second_null == std::wstring::npos ||
109 first_null == msg.length() - 1 || second_null == msg.length()) {
110 LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
111 "parts separated by NULLs";
112 return false;
113 }
114
115 // Get current directory.
116 *current_directory = FilePath(msg.substr(first_null + 1,
117 second_null - first_null));
118
119 const std::wstring::size_type third_null =
120 msg.find_first_of(L'\0', second_null + 1);
121 if (third_null == std::wstring::npos ||
122 third_null == msg.length()) {
123 LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
124 "parts separated by NULLs";
125 }
126
127 // Get command line.
128 const std::wstring cmd_line =
129 msg.substr(second_null + 1, third_null - second_null);
130 *parsed_command_line = CommandLine::FromString(cmd_line);
131 return true;
132 }
133 return false;
134}
135
[email protected]6927f2e02012-09-18 00:13:49136bool ActivateMetroChrome() {
137 FilePath chrome_exe;
138 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
139 NOTREACHED() << "Failed to get chrome exe path";
140 return false;
141 }
142 string16 app_id = ShellUtil::GetBrowserModelId(
[email protected]786799692012-09-26 14:16:48143 BrowserDistribution::GetDistribution(),
144 InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()));
[email protected]6927f2e02012-09-18 00:13:49145 if (app_id.empty()) {
146 NOTREACHED() << "Failed to get chrome app user model id.";
147 return false;
148 }
149
150 base::win::ScopedComPtr<IApplicationActivationManager> activation_manager;
151 HRESULT hr = activation_manager.CreateInstance(
152 CLSID_ApplicationActivationManager);
153 if (!activation_manager) {
154 NOTREACHED() << "Failed to cocreate activation manager. Error: " << hr;
155 return false;
156 }
157
158 unsigned long pid = 0;
159 hr = activation_manager->ActivateApplication(app_id.c_str(),
160 L"open",
161 AO_NONE,
162 &pid);
163 if (FAILED(hr)) {
164 NOTREACHED() << "Failed to activate metro chrome. Error: " << hr;
165 return false;
166 }
167 return true;
168}
169
[email protected]b3d791c92012-10-05 19:01:24170// Returns true if Chrome needs to be relaunched into Windows 8 immersive mode.
171// Following conditions apply:-
172// 1. Windows 8 or greater.
173// 2. Not in Windows 8 immersive mode.
174// 3. Process integrity level is not high.
175// 4. The profile data directory is the default directory .
176// 5. Last used mode was immersive/machine is a tablet.
177// TODO(ananta)
178// Move this function to a common place as the Windows 8 delegate_execute
179// handler can possibly use this.
180bool ShouldLaunchInWindows8ImmersiveMode(const FilePath& user_data_dir) {
181#if defined(USE_AURA)
182 return false;
183#endif
184
185 if (base::win::GetVersion() < base::win::VERSION_WIN8)
186 return false;
187
188 if (base::win::IsProcessImmersive(base::GetCurrentProcessHandle()))
189 return false;
190
191 base::IntegrityLevel integrity_level = base::INTEGRITY_UNKNOWN;
192 base::GetProcessIntegrityLevel(base::GetCurrentProcessHandle(),
193 &integrity_level);
194 if (integrity_level == base::HIGH_INTEGRITY)
195 return false;
196
197 FilePath default_user_data_dir;
198 if (!chrome::GetDefaultUserDataDirectory(&default_user_data_dir))
199 return false;
200
201 if (default_user_data_dir != user_data_dir)
202 return false;
203
204 base::win::RegKey reg_key;
205 LONG key_result = reg_key.Create(HKEY_CURRENT_USER,
206 chrome::kMetroRegistryPath,
207 KEY_READ);
208 if (key_result == ERROR_SUCCESS) {
209 DWORD reg_value = 0;
210 reg_key.ReadValueDW(chrome::kLaunchModeValue,
211 &reg_value);
212 if (reg_value == 1)
213 return true;
214 }
215 return base::win::IsMachineATablet();
216}
217
[email protected]fc14cef2009-01-27 22:17:29218} // namespace
219
[email protected]0a194552011-09-14 17:53:35220// Microsoft's Softricity virtualization breaks the sandbox processes.
221// So, if we detect the Softricity DLL we use WMI Win32_Process.Create to
222// break out of the virtualization environment.
223// http://code.google.com/p/chromium/issues/detail?id=43650
224bool ProcessSingleton::EscapeVirtualization(const FilePath& user_data_dir) {
225 if (::GetModuleHandle(L"sftldr_wow64.dll") ||
226 ::GetModuleHandle(L"sftldr.dll")) {
227 int process_id;
228 if (!installer::WMIProcess::Launch(GetCommandLineW(), &process_id))
229 return false;
230 is_virtualized_ = true;
231 // The new window was spawned from WMI, and won't be in the foreground.
232 // So, first we sleep while the new chrome.exe instance starts (because
233 // WaitForInputIdle doesn't work here). Then we poll for up to two more
234 // seconds and make the window foreground if we find it (or we give up).
235 HWND hwnd = 0;
236 ::Sleep(90);
237 for (int tries = 200; tries; --tries) {
238 hwnd = FindWindowEx(HWND_MESSAGE, NULL, chrome::kMessageWindowClass,
239 user_data_dir.value().c_str());
240 if (hwnd) {
241 ::SetForegroundWindow(hwnd);
242 break;
243 }
244 ::Sleep(10);
245 }
246 return true;
247 }
248 return false;
249}
250
[email protected]f891fb32009-04-08 00:20:32251// Look for a Chrome instance that uses the same profile directory.
[email protected]9a182832012-02-10 18:45:58252// If there isn't one, create a message window with its title set to
253// the profile directory path.
[email protected]7c47ae3e2009-02-18 00:34:21254ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
[email protected]0a194552011-09-14 17:53:35255 : window_(NULL), locked_(false), foreground_window_(NULL),
[email protected]2b7ff5b92012-07-17 22:45:18256 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE) {
[email protected]b3d791c92012-10-05 19:01:24257 FilePath default_user_data_dir;
258 // For Windows 8 and above check if we need to relaunch into Windows 8
259 // immersive mode.
260 if (ShouldLaunchInWindows8ImmersiveMode(user_data_dir)) {
261 bool immersive_chrome_launched = ActivateMetroChrome();
262 if (!immersive_chrome_launched) {
263 LOG(WARNING) << "Failed to launch immersive chrome";
264 } else {
265 // Sleep to allow the immersive chrome process to create its initial
266 // message window.
267 SleepEx(kImmersiveChromeInitTimeout, FALSE);
268 }
269 }
[email protected]bbef41f02010-03-04 16:16:19270 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL,
271 chrome::kMessageWindowClass,
[email protected]8a205c02011-02-04 20:41:33272 user_data_dir.value().c_str());
[email protected]0a194552011-09-14 17:53:35273 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) {
[email protected]bbef41f02010-03-04 16:16:19274 // Make sure we will be the one and only process creating the window.
275 // We use a named Mutex since we are protecting against multi-process
276 // access. As documented, it's clearer to NOT request ownership on creation
277 // since it isn't guaranteed we will get it. It is better to create it
278 // without ownership and explicitly get the ownership afterward.
[email protected]e132804b2010-12-22 12:48:25279 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!");
[email protected]b90d7e802011-01-09 16:32:20280 base::win::ScopedHandle only_me(
281 CreateMutex(NULL, FALSE, mutex_name.c_str()));
[email protected]bbef41f02010-03-04 16:16:19282 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError();
283
284 // This is how we acquire the mutex (as opposed to the initial ownership).
285 DWORD result = WaitForSingleObject(only_me, INFINITE);
286 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result <<
287 "GetLastError = " << GetLastError();
288
289 // We now own the mutex so we are the only process that can create the
290 // window at this time, but we must still check if someone created it
291 // between the time where we looked for it above and the time the mutex
292 // was given to us.
293 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL,
294 chrome::kMessageWindowClass,
[email protected]8a205c02011-02-04 20:41:33295 user_data_dir.value().c_str());
[email protected]9a182832012-02-10 18:45:58296 if (!remote_window_) {
[email protected]2b7ff5b92012-07-17 22:45:18297 // We have to make sure there is no Chrome instance running on another
298 // machine that uses the same profile.
299 FilePath lock_file_path = user_data_dir.AppendASCII(kLockfile);
300 lock_file_ = CreateFile(lock_file_path.value().c_str(),
301 GENERIC_WRITE,
302 FILE_SHARE_READ,
303 NULL,
304 CREATE_ALWAYS,
305 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
306 NULL);
307 DWORD error = GetLastError();
308 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
309 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
310 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
311 << "Lock file can not be created! Error code: " << error;
[email protected]9a182832012-02-10 18:45:58312
[email protected]2b7ff5b92012-07-17 22:45:18313 if (lock_file_ != INVALID_HANDLE_VALUE) {
314 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc);
[email protected]9a182832012-02-10 18:45:58315
[email protected]2b7ff5b92012-07-17 22:45:18316 WNDCLASSEX wc = {0};
317 wc.cbSize = sizeof(wc);
318 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>;
319 wc.hInstance = hinst;
320 wc.lpszClassName = chrome::kMessageWindowClass;
321 ATOM clazz = ::RegisterClassEx(&wc);
322 DCHECK(clazz);
323
324 // Set the window's title to the path of our user data directory so
325 // other Chrome instances can decide if they should forward to us.
326 window_ = ::CreateWindow(MAKEINTATOM(clazz),
327 user_data_dir.value().c_str(),
328 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this);
329 CHECK(window_);
330 }
[email protected]9a182832012-02-10 18:45:58331 }
[email protected]bbef41f02010-03-04 16:16:19332 BOOL success = ReleaseMutex(only_me);
333 DCHECK(success) << "GetLastError = " << GetLastError();
334 }
[email protected]fc14cef2009-01-27 22:17:29335}
336
[email protected]7c47ae3e2009-02-18 00:34:21337ProcessSingleton::~ProcessSingleton() {
[email protected]a9b36c92012-06-18 08:47:57338 // We need to unregister the window as late as possible so that we can detect
339 // another instance of chrome running. Otherwise we may end up writing out
340 // data while a new chrome is starting up.
341 if (window_) {
342 ::DestroyWindow(window_);
343 ::UnregisterClass(chrome::kMessageWindowClass,
344 base::GetModuleFromAddress(&ThunkWndProc));
345 }
[email protected]2b7ff5b92012-07-17 22:45:18346 if (lock_file_ != INVALID_HANDLE_VALUE)
347 CloseHandle(lock_file_);
[email protected]fc14cef2009-01-27 22:17:29348}
349
[email protected]9f20a6d02009-08-21 01:18:37350ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
[email protected]0a194552011-09-14 17:53:35351 if (is_virtualized_)
352 return PROCESS_NOTIFIED; // We already spawned the process in this case.
[email protected]2b7ff5b92012-07-17 22:45:18353 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_)
354 return LOCK_ERROR;
[email protected]0a194552011-09-14 17:53:35355 else if (!remote_window_)
[email protected]9f20a6d02009-08-21 01:18:37356 return PROCESS_NONE;
[email protected]fc14cef2009-01-27 22:17:29357
[email protected]f394bc62012-08-22 21:42:29358 DWORD process_id = 0;
359 DWORD thread_id = GetWindowThreadProcessId(remote_window_, &process_id);
360 // It is possible that the process owning this window may have died by now.
361 if (!thread_id || !process_id) {
362 remote_window_ = NULL;
363 return PROCESS_NONE;
364 }
365
366 if (base::win::IsMetroProcess()) {
367 // Interesting corner case. We are launched as a metro process but we
368 // found another chrome running. Since metro enforces single instance then
369 // the other chrome must be desktop chrome and this must be a search charm
370 // activation. This scenario is unique; other cases should be properly
371 // handled by the delegate_execute which will not activate a second chrome.
372 string16 terms;
373 base::win::MetroLaunchType launch = base::win::GetMetroLaunchParams(&terms);
374 if (launch != base::win::METRO_SEARCH) {
375 LOG(WARNING) << "In metro mode, but and launch is " << launch;
376 } else {
377 std::string query = net::EscapeQueryParamValue(UTF16ToUTF8(terms), true);
378 std::string url = base::StringPrintf(kSearchUrl, query.c_str());
379 SHELLEXECUTEINFOA sei = { sizeof(sei) };
380 sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
381 sei.nShow = SW_SHOWNORMAL;
382 sei.lpFile = url.c_str();
383 OutputDebugStringA(sei.lpFile);
384 sei.lpDirectory = "";
385 ::ShellExecuteExA(&sei);
386 }
387 return PROCESS_NOTIFIED;
388 }
389 // Non-metro mode, send our command line to the other chrome message window.
[email protected]fc14cef2009-01-27 22:17:29390 // format is "START\0<<<current directory>>>\0<<<commandline>>>".
391 std::wstring to_send(L"START\0", 6); // want the NULL in the string.
[email protected]b9696482010-11-30 23:56:18392 FilePath cur_dir;
[email protected]fc14cef2009-01-27 22:17:29393 if (!PathService::Get(base::DIR_CURRENT, &cur_dir))
[email protected]9f20a6d02009-08-21 01:18:37394 return PROCESS_NONE;
[email protected]b9696482010-11-30 23:56:18395 to_send.append(cur_dir.value());
[email protected]fc14cef2009-01-27 22:17:29396 to_send.append(L"\0", 1); // Null separator.
397 to_send.append(GetCommandLineW());
398 to_send.append(L"\0", 1); // Null separator.
399
400 // Allow the current running browser window making itself the foreground
401 // window (otherwise it will just flash in the taskbar).
[email protected]fc14cef2009-01-27 22:17:29402 AllowSetForegroundWindow(process_id);
403
[email protected]fc14cef2009-01-27 22:17:29404 COPYDATASTRUCT cds;
405 cds.dwData = 0;
406 cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
407 cds.lpData = const_cast<wchar_t*>(to_send.c_str());
408 DWORD_PTR result = 0;
409 if (SendMessageTimeout(remote_window_,
410 WM_COPYDATA,
411 NULL,
412 reinterpret_cast<LPARAM>(&cds),
413 SMTO_ABORTIFHUNG,
[email protected]8b08cbd2009-08-04 05:34:19414 kTimeoutInSeconds * 1000,
[email protected]fc14cef2009-01-27 22:17:29415 &result)) {
[email protected]0815b6d2009-02-11 00:39:37416 // It is possible that the process owning this window may have died by now.
417 if (!result) {
418 remote_window_ = NULL;
[email protected]9f20a6d02009-08-21 01:18:37419 return PROCESS_NONE;
[email protected]0815b6d2009-02-11 00:39:37420 }
[email protected]6927f2e02012-09-18 00:13:49421
422 base::win::ScopedHandle process_handle;
423 if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
424 base::OpenProcessHandleWithAccess(
425 process_id, PROCESS_QUERY_INFORMATION,
426 process_handle.Receive())) {
427 if (base::win::IsProcessImmersive(process_handle.Get()))
428 ActivateMetroChrome();
429 }
[email protected]9f20a6d02009-08-21 01:18:37430 return PROCESS_NOTIFIED;
[email protected]fc14cef2009-01-27 22:17:29431 }
432
[email protected]0815b6d2009-02-11 00:39:37433 // It is possible that the process owning this window may have died by now.
434 if (!IsWindow(remote_window_)) {
435 remote_window_ = NULL;
[email protected]9f20a6d02009-08-21 01:18:37436 return PROCESS_NONE;
[email protected]0815b6d2009-02-11 00:39:37437 }
438
[email protected]fc14cef2009-01-27 22:17:29439 // The window is hung. Scan for every window to find a visible one.
440 bool visible_window = false;
441 EnumThreadWindows(thread_id,
442 &BrowserWindowEnumeration,
443 reinterpret_cast<LPARAM>(&visible_window));
444
445 // If there is a visible browser window, ask the user before killing it.
[email protected]d33220292012-07-04 01:41:27446 if (visible_window && chrome::ShowMessageBox(NULL,
[email protected]5da155e2012-05-26 16:31:16447 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
448 l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE),
[email protected]d33220292012-07-04 01:41:27449 chrome::MESSAGE_BOX_TYPE_QUESTION) == chrome::MESSAGE_BOX_RESULT_NO) {
[email protected]5da155e2012-05-26 16:31:16450 // The user denied. Quit silently.
451 return PROCESS_NOTIFIED;
[email protected]fc14cef2009-01-27 22:17:29452 }
453
454 // Time to take action. Kill the browser process.
[email protected]1fcfb202011-07-19 19:53:14455 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true);
[email protected]fc14cef2009-01-27 22:17:29456 remote_window_ = NULL;
[email protected]9f20a6d02009-08-21 01:18:37457 return PROCESS_NONE;
[email protected]fc14cef2009-01-27 22:17:29458}
459
[email protected]5d364542012-04-05 07:15:39460ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate(
461 const NotificationCallback& notification_callback) {
[email protected]4a44bc32010-05-28 22:22:44462 NotifyResult result = NotifyOtherProcess();
463 if (result != PROCESS_NONE)
464 return result;
[email protected]5d364542012-04-05 07:15:39465 return Create(notification_callback) ? PROCESS_NONE : PROFILE_IN_USE;
[email protected]4a44bc32010-05-28 22:22:44466}
467
[email protected]9a182832012-02-10 18:45:58468// On Windows, there is no need to call Create() since the message
469// window is created in the constructor but to avoid having more
470// platform specific code in browser_main.cc we tolerate calls to
[email protected]5d364542012-04-05 07:15:39471// Create().
472bool ProcessSingleton::Create(
473 const NotificationCallback& notification_callback) {
[email protected]fc14cef2009-01-27 22:17:29474 DCHECK(!remote_window_);
[email protected]5d364542012-04-05 07:15:39475 DCHECK(notification_callback_.is_null());
476
477 if (window_ != NULL)
478 notification_callback_ = notification_callback;
479
[email protected]9a182832012-02-10 18:45:58480 return window_ != NULL;
[email protected]fc14cef2009-01-27 22:17:29481}
482
[email protected]9f20a6d02009-08-21 01:18:37483void ProcessSingleton::Cleanup() {
[email protected]9f20a6d02009-08-21 01:18:37484}
485
[email protected]7c47ae3e2009-02-18 00:34:21486LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) {
[email protected]175a7a22009-05-03 15:57:53487 // If locked, it means we are not ready to process this message because
[email protected]afd20c022010-06-10 00:48:20488 // we are probably in a first run critical phase.
[email protected]175a7a22009-05-03 15:57:53489 if (locked_) {
[email protected]95259c62011-10-25 23:23:53490#if defined(USE_AURA)
491 NOTIMPLEMENTED();
492#else
[email protected]175a7a22009-05-03 15:57:53493 // Attempt to place ourselves in the foreground / flash the task bar.
[email protected]edf04b512012-02-23 09:47:43494 if (foreground_window_ != NULL && IsWindow(foreground_window_)) {
[email protected]175a7a22009-05-03 15:57:53495 SetForegroundWindow(foreground_window_);
[email protected]edf04b512012-02-23 09:47:43496 } else {
497 // Read the command line and store it. It will be replayed when the
498 // ProcessSingleton becomes unlocked.
499 CommandLine parsed_command_line(CommandLine::NO_PROGRAM);
500 FilePath current_directory;
501 if (ParseCommandLine(cds, &parsed_command_line, &current_directory))
502 saved_startup_messages_.push_back(
503 std::make_pair(parsed_command_line.argv(), current_directory));
504 }
[email protected]95259c62011-10-25 23:23:53505#endif
[email protected]175a7a22009-05-03 15:57:53506 return TRUE;
507 }
508
[email protected]edf04b512012-02-23 09:47:43509 CommandLine parsed_command_line(CommandLine::NO_PROGRAM);
510 FilePath current_directory;
511 if (!ParseCommandLine(cds, &parsed_command_line, &current_directory))
[email protected]fc14cef2009-01-27 22:17:29512 return TRUE;
[email protected]5d364542012-04-05 07:15:39513 return notification_callback_.Run(parsed_command_line, current_directory) ?
514 TRUE : FALSE;
[email protected]fc14cef2009-01-27 22:17:29515}
516
[email protected]e3ce40a2012-01-31 03:03:03517LRESULT ProcessSingleton::WndProc(HWND hwnd, UINT message,
518 WPARAM wparam, LPARAM lparam) {
[email protected]fc14cef2009-01-27 22:17:29519 switch (message) {
520 case WM_COPYDATA:
521 return OnCopyData(reinterpret_cast<HWND>(wparam),
522 reinterpret_cast<COPYDATASTRUCT*>(lparam));
523 default:
524 break;
525 }
526
527 return ::DefWindowProc(hwnd, message, wparam, lparam);
528}