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