13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/process_singleton.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base_paths.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/process_util.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/utf_string_conversions.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/scoped_handle.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/win/wrapped_window_proc.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
16731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/extensions/extensions_startup.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/platform_util.h"
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser_init.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/chrome_switches.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/result_codes.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/chromium_strings.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/win/hwnd_util.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Checks the visibility of the enumerated window and signals once a visible
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// window has been found.
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool* result = reinterpret_cast<bool*>(param);
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *result = IsWindowVisible(window) != 0;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Stops enumeration if a visible window has been found.
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !*result;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Look for a Chrome instance that uses the same profile directory.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : window_(NULL), locked_(false), foreground_window_(NULL) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  remote_window_ = FindWindowEx(HWND_MESSAGE, NULL,
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                chrome::kMessageWindowClass,
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                user_data_dir.value().c_str());
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!remote_window_) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Make sure we will be the one and only process creating the window.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We use a named Mutex since we are protecting against multi-process
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // access. As documented, it's clearer to NOT request ownership on creation
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // since it isn't guaranteed we will get it. It is better to create it
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // without ownership and explicitly get the ownership afterward.
5521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!");
563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    base::win::ScopedHandle only_me(
573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        CreateMutex(NULL, FALSE, mutex_name.c_str()));
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError();
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This is how we acquire the mutex (as opposed to the initial ownership).
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DWORD result = WaitForSingleObject(only_me, INFINITE);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(result == WAIT_OBJECT_0) << "Result = " << result <<
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "GetLastError = " << GetLastError();
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We now own the mutex so we are the only process that can create the
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // window at this time, but we must still check if someone created it
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // between the time where we looked for it above and the time the mutex
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // was given to us.
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    remote_window_ = FindWindowEx(HWND_MESSAGE, NULL,
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  chrome::kMessageWindowClass,
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  user_data_dir.value().c_str());
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!remote_window_)
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Create();
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BOOL success = ReleaseMutex(only_me);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(success) << "GetLastError = " << GetLastError();
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::~ProcessSingleton() {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (window_) {
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DestroyWindow(window_);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UnregisterClass(chrome::kMessageWindowClass, GetModuleHandle(NULL));
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!remote_window_)
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return PROCESS_NONE;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Found another window, send our command line to it
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // format is "START\0<<<current directory>>>\0<<<commandline>>>".
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring to_send(L"START\0", 6);  // want the NULL in the string.
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  FilePath cur_dir;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PathService::Get(base::DIR_CURRENT, &cur_dir))
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return PROCESS_NONE;
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  to_send.append(cur_dir.value());
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  to_send.append(L"\0", 1);  // Null separator.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  to_send.append(GetCommandLineW());
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  to_send.append(L"\0", 1);  // Null separator.
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Allow the current running browser window making itself the foreground
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // window (otherwise it will just flash in the taskbar).
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DWORD process_id = 0;
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DWORD thread_id = GetWindowThreadProcessId(remote_window_, &process_id);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It is possible that the process owning this window may have died by now.
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!thread_id || !process_id) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    remote_window_ = NULL;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return PROCESS_NONE;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AllowSetForegroundWindow(process_id);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  COPYDATASTRUCT cds;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cds.dwData = 0;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cds.lpData = const_cast<wchar_t*>(to_send.c_str());
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DWORD_PTR result = 0;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (SendMessageTimeout(remote_window_,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         WM_COPYDATA,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         NULL,
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         reinterpret_cast<LPARAM>(&cds),
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         SMTO_ABORTIFHUNG,
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         kTimeoutInSeconds * 1000,
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         &result)) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // It is possible that the process owning this window may have died by now.
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!result) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      remote_window_ = NULL;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return PROCESS_NONE;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return PROCESS_NOTIFIED;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // It is possible that the process owning this window may have died by now.
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsWindow(remote_window_)) {
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    remote_window_ = NULL;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return PROCESS_NONE;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The window is hung. Scan for every window to find a visible one.
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool visible_window = false;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EnumThreadWindows(thread_id,
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    &BrowserWindowEnumeration,
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    reinterpret_cast<LPARAM>(&visible_window));
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If there is a visible browser window, ask the user before killing it.
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visible_window) {
1473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    std::wstring text =
1483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        UTF16ToWide(l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE));
1493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    std::wstring caption =
1503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        UTF16ToWide(l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!platform_util::SimpleYesNoBox(NULL, caption, text)) {
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The user denied. Quit silently.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return PROCESS_NOTIFIED;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Time to take action. Kill the browser process.
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::KillProcessById(process_id, ResultCodes::HUNG, true);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  remote_window_ = NULL;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return PROCESS_NONE;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotifyResult result = NotifyOtherProcess();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result != PROCESS_NONE)
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return Create() ? PROCESS_NONE : PROFILE_IN_USE;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For windows, there is no need to call Create() since the call is made in
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the constructor but to avoid having more platform specific code in
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// browser_main.cc we tolerate a second call which will do nothing.
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ProcessSingleton::Create() {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!remote_window_);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (window_)
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HINSTANCE hinst = GetModuleHandle(NULL);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WNDCLASSEX wc = {0};
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wc.cbSize = sizeof(wc);
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  wc.lpfnWndProc =
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::win::WrappedWindowProc<ProcessSingleton::WndProcStatic>;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wc.hInstance = hinst;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  wc.lpszClassName = chrome::kMessageWindowClass;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ATOM clazz = RegisterClassEx(&wc);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(clazz);
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath user_data_dir;
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set the window's title to the path of our user data directory so other
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Chrome instances can decide if they should forward to us or not.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  window_ = CreateWindow(chrome::kMessageWindowClass,
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         user_data_dir.value().c_str(),
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0);
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ui::CheckWindowCreated(window_);
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ui::SetWindowUserData(window_, this);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessSingleton::Cleanup() {
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochLRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) {
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If locked, it means we are not ready to process this message because
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we are probably in a first run critical phase.
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (locked_) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Attempt to place ourselves in the foreground / flash the task bar.
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (IsWindow(foreground_window_))
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SetForegroundWindow(foreground_window_);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ignore the request if the browser process is already in shutdown path.
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!g_browser_process || g_browser_process->IsShuttingDown()) {
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Not handling WM_COPYDATA as browser is shutting down";
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return FALSE;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We should have enough room for the shortest command (min_message_size)
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and also be a multiple of wchar_t bytes. The shortest command
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // possible is L"START\0\0" (empty current directory and command line).
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int min_message_size = 7;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (cds->cbData < min_message_size * sizeof(wchar_t) ||
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cds->cbData % sizeof(wchar_t) != 0) {
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We split the string into 4 parts on NULLs.
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(cds->lpData);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         cds->cbData / sizeof(wchar_t));
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring::size_type first_null = msg.find_first_of(L'\0');
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (first_null == 0 || first_null == std::wstring::npos) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // no NULL byte, don't know what to do
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ", first null = " << first_null;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decode the command, which is everything until the first NULL.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (msg.substr(0, first_null) == L"START") {
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Another instance is starting parse the command line & do what it would
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // have done.
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Handling STARTUP request from another process";
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring::size_type second_null =
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      msg.find_first_of(L'\0', first_null + 1);
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (second_null == std::wstring::npos ||
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        first_null == msg.length() - 1 || second_null == msg.length()) {
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "parts separated by NULLs";
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TRUE;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Get current directory.
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const FilePath cur_dir(msg.substr(first_null + 1,
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      second_null - first_null));
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring::size_type third_null =
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        msg.find_first_of(L'\0', second_null + 1);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (third_null == std::wstring::npos ||
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        third_null == msg.length()) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "parts separated by NULLs";
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Get command line.
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::wstring cmd_line =
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      msg.substr(second_null + 1, third_null - second_null);
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CommandLine parsed_command_line = CommandLine::FromString(cmd_line);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PrefService* prefs = g_browser_process->local_state();
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(prefs);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile = ProfileManager::GetDefaultProfile();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!profile) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We should only be able to get here if the profile already exists and
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // has been created.
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return TRUE;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Handle the --uninstall-extension startup action. This needs to done here
286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // in the process that is running with the target profile, otherwise the
287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // uninstall will fail to unload and remove all components.
288731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) {
28921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      ExtensionsStartupUtil ext_startup_util;
29021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      ext_startup_util.UninstallExtension(parsed_command_line, profile);
291731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return TRUE;
292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
293731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Run the browser startup sequence again, with the command line of the
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // signalling process.
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BrowserInit::ProcessCommandLine(parsed_command_line, cur_dir, false,
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    profile, NULL);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochLRESULT CALLBACK ProcessSingleton::WndProc(HWND hwnd, UINT message,
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           WPARAM wparam, LPARAM lparam) {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (message) {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case WM_COPYDATA:
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return OnCopyData(reinterpret_cast<HWND>(wparam),
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        reinterpret_cast<COPYDATASTRUCT*>(lparam));
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ::DefWindowProc(hwnd, message, wparam, lparam);
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
315