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