| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/process_singleton.h" | 5 #include "chrome/browser/process_singleton.h" |
| 6 | 6 |
| 7 #include <shellapi.h> | 7 #include <shellapi.h> |
| 8 | 8 |
| 9 #include "base/base_paths.h" | 9 #include "base/base_paths.h" |
| 10 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 12 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 13 #include "base/process_info.h" | 14 #include "base/process_info.h" |
| 14 #include "base/process_util.h" | 15 #include "base/process_util.h" |
| 15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
| 19 #include "base/win/metro.h" | 20 #include "base/win/metro.h" |
| 20 #include "base/win/registry.h" | 21 #include "base/win/registry.h" |
| 21 #include "base/win/scoped_handle.h" | 22 #include "base/win/scoped_handle.h" |
| 22 #include "base/win/win_util.h" | 23 #include "base/win/win_util.h" |
| 23 #include "base/win/windows_version.h" | 24 #include "base/win/windows_version.h" |
| 24 #include "base/win/wrapped_window_proc.h" | |
| 25 #include "chrome/browser/browser_process.h" | 25 #include "chrome/browser/browser_process.h" |
| 26 #include "chrome/browser/browser_process_platform_part.h" | 26 #include "chrome/browser/browser_process_platform_part.h" |
| 27 #include "chrome/browser/chrome_process_finder_win.h" | 27 #include "chrome/browser/chrome_process_finder_win.h" |
| 28 #include "chrome/browser/metro_utils/metro_chrome_win.h" | 28 #include "chrome/browser/metro_utils/metro_chrome_win.h" |
| 29 #include "chrome/browser/shell_integration.h" | 29 #include "chrome/browser/shell_integration.h" |
| 30 #include "chrome/browser/ui/simple_message_box.h" | 30 #include "chrome/browser/ui/simple_message_box.h" |
| 31 #include "chrome/common/chrome_constants.h" | 31 #include "chrome/common/chrome_constants.h" |
| 32 #include "chrome/common/chrome_paths.h" | 32 #include "chrome/common/chrome_paths.h" |
| 33 #include "chrome/common/chrome_paths_internal.h" | 33 #include "chrome/common/chrome_paths_internal.h" |
| 34 #include "chrome/common/chrome_switches.h" | 34 #include "chrome/common/chrome_switches.h" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 86 |
| 87 // Checks the visibility of the enumerated window and signals once a visible | 87 // Checks the visibility of the enumerated window and signals once a visible |
| 88 // window has been found. | 88 // window has been found. |
| 89 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { | 89 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { |
| 90 bool* result = reinterpret_cast<bool*>(param); | 90 bool* result = reinterpret_cast<bool*>(param); |
| 91 *result = ::IsWindowVisible(window) != 0; | 91 *result = ::IsWindowVisible(window) != 0; |
| 92 // Stops enumeration if a visible window has been found. | 92 // Stops enumeration if a visible window has been found. |
| 93 return !*result; | 93 return !*result; |
| 94 } | 94 } |
| 95 | 95 |
| 96 // This function thunks to the object's version of the windowproc, taking in | |
| 97 // consideration that there are several messages being dispatched before | |
| 98 // WM_NCCREATE which we let windows handle. | |
| 99 LRESULT CALLBACK ThunkWndProc(HWND hwnd, UINT message, | |
| 100 WPARAM wparam, LPARAM lparam) { | |
| 101 ProcessSingleton* singleton = | |
| 102 reinterpret_cast<ProcessSingleton*>(ui::GetWindowUserData(hwnd)); | |
| 103 if (message == WM_NCCREATE) { | |
| 104 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam); | |
| 105 singleton = reinterpret_cast<ProcessSingleton*>(cs->lpCreateParams); | |
| 106 CHECK(singleton); | |
| 107 ui::SetWindowUserData(hwnd, singleton); | |
| 108 } else if (!singleton) { | |
| 109 return ::DefWindowProc(hwnd, message, wparam, lparam); | |
| 110 } | |
| 111 return singleton->WndProc(hwnd, message, wparam, lparam); | |
| 112 } | |
| 113 | |
| 114 bool ParseCommandLine(const COPYDATASTRUCT* cds, | 96 bool ParseCommandLine(const COPYDATASTRUCT* cds, |
| 115 CommandLine* parsed_command_line, | 97 CommandLine* parsed_command_line, |
| 116 base::FilePath* current_directory) { | 98 base::FilePath* current_directory) { |
| 117 // We should have enough room for the shortest command (min_message_size) | 99 // We should have enough room for the shortest command (min_message_size) |
| 118 // and also be a multiple of wchar_t bytes. The shortest command | 100 // and also be a multiple of wchar_t bytes. The shortest command |
| 119 // possible is L"START\0\0" (empty current directory and command line). | 101 // possible is L"START\0\0" (empty current directory and command line). |
| 120 static const int min_message_size = 7; | 102 static const int min_message_size = 7; |
| 121 if (cds->cbData < min_message_size * sizeof(wchar_t) || | 103 if (cds->cbData < min_message_size * sizeof(wchar_t) || |
| 122 cds->cbData % sizeof(wchar_t) != 0) { | 104 cds->cbData % sizeof(wchar_t) != 0) { |
| 123 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData; | 105 LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 | 146 |
| 165 // Get command line. | 147 // Get command line. |
| 166 const std::wstring cmd_line = | 148 const std::wstring cmd_line = |
| 167 msg.substr(second_null + 1, third_null - second_null); | 149 msg.substr(second_null + 1, third_null - second_null); |
| 168 *parsed_command_line = CommandLine::FromString(cmd_line); | 150 *parsed_command_line = CommandLine::FromString(cmd_line); |
| 169 return true; | 151 return true; |
| 170 } | 152 } |
| 171 return false; | 153 return false; |
| 172 } | 154 } |
| 173 | 155 |
| 156 bool ProcessLaunchNotification( |
| 157 const ProcessSingleton::NotificationCallback& notification_callback, |
| 158 UINT message, |
| 159 WPARAM wparam, |
| 160 LPARAM lparam, |
| 161 LRESULT* result) { |
| 162 if (message != WM_COPYDATA) |
| 163 return false; |
| 164 |
| 165 // Handle the WM_COPYDATA message from another process. |
| 166 HWND hwnd = reinterpret_cast<HWND>(wparam); |
| 167 const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam); |
| 168 |
| 169 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); |
| 170 base::FilePath current_directory; |
| 171 if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) { |
| 172 *result = TRUE; |
| 173 return true; |
| 174 } |
| 175 |
| 176 *result = notification_callback.Run(parsed_command_line, current_directory) ? |
| 177 TRUE : FALSE; |
| 178 return true; |
| 179 } |
| 180 |
| 174 // Returns true if Chrome needs to be relaunched into Windows 8 immersive mode. | 181 // Returns true if Chrome needs to be relaunched into Windows 8 immersive mode. |
| 175 // Following conditions apply:- | 182 // Following conditions apply:- |
| 176 // 1. Windows 8 or greater. | 183 // 1. Windows 8 or greater. |
| 177 // 2. Not in Windows 8 immersive mode. | 184 // 2. Not in Windows 8 immersive mode. |
| 178 // 3. Chrome is default browser. | 185 // 3. Chrome is default browser. |
| 179 // 4. Process integrity level is not high. | 186 // 4. Process integrity level is not high. |
| 180 // 5. The profile data directory is the default directory. | 187 // 5. The profile data directory is the default directory. |
| 181 // 6. Last used mode was immersive/machine is a tablet. | 188 // 6. Last used mode was immersive/machine is a tablet. |
| 182 // TODO(ananta) | 189 // TODO(ananta) |
| 183 // Move this function to a common place as the Windows 8 delegate_execute | 190 // Move this function to a common place as the Windows 8 delegate_execute |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 ::Sleep(10); | 260 ::Sleep(10); |
| 254 } | 261 } |
| 255 return true; | 262 return true; |
| 256 } | 263 } |
| 257 return false; | 264 return false; |
| 258 } | 265 } |
| 259 | 266 |
| 260 ProcessSingleton::ProcessSingleton( | 267 ProcessSingleton::ProcessSingleton( |
| 261 const base::FilePath& user_data_dir, | 268 const base::FilePath& user_data_dir, |
| 262 const NotificationCallback& notification_callback) | 269 const NotificationCallback& notification_callback) |
| 263 : window_(NULL), notification_callback_(notification_callback), | 270 : notification_callback_(notification_callback), |
| 264 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE), | 271 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE), |
| 265 user_data_dir_(user_data_dir) { | 272 user_data_dir_(user_data_dir) { |
| 266 } | 273 } |
| 267 | 274 |
| 268 ProcessSingleton::~ProcessSingleton() { | 275 ProcessSingleton::~ProcessSingleton() { |
| 269 // We need to unregister the window as late as possible so that we can detect | |
| 270 // another instance of chrome running. Otherwise we may end up writing out | |
| 271 // data while a new chrome is starting up. | |
| 272 if (window_) { | |
| 273 ::DestroyWindow(window_); | |
| 274 ::UnregisterClass(chrome::kMessageWindowClass, | |
| 275 base::GetModuleFromAddress(&ThunkWndProc)); | |
| 276 } | |
| 277 if (lock_file_ != INVALID_HANDLE_VALUE) | 276 if (lock_file_ != INVALID_HANDLE_VALUE) |
| 278 ::CloseHandle(lock_file_); | 277 ::CloseHandle(lock_file_); |
| 279 } | 278 } |
| 280 | 279 |
| 281 // Code roughly based on Mozilla. | 280 // Code roughly based on Mozilla. |
| 282 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { | 281 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
| 283 if (is_virtualized_) | 282 if (is_virtualized_) |
| 284 return PROCESS_NOTIFIED; // We already spawned the process in this case. | 283 return PROCESS_NOTIFIED; // We already spawned the process in this case. |
| 285 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { | 284 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { |
| 286 return LOCK_ERROR; | 285 return LOCK_ERROR; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 FILE_ATTRIBUTE_NORMAL | | 431 FILE_ATTRIBUTE_NORMAL | |
| 433 FILE_FLAG_DELETE_ON_CLOSE, | 432 FILE_FLAG_DELETE_ON_CLOSE, |
| 434 NULL); | 433 NULL); |
| 435 DWORD error = ::GetLastError(); | 434 DWORD error = ::GetLastError(); |
| 436 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && | 435 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && |
| 437 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; | 436 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; |
| 438 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) | 437 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) |
| 439 << "Lock file can not be created! Error code: " << error; | 438 << "Lock file can not be created! Error code: " << error; |
| 440 | 439 |
| 441 if (lock_file_ != INVALID_HANDLE_VALUE) { | 440 if (lock_file_ != INVALID_HANDLE_VALUE) { |
| 442 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | |
| 443 | |
| 444 WNDCLASSEX wc = {0}; | |
| 445 wc.cbSize = sizeof(wc); | |
| 446 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | |
| 447 wc.hInstance = hinst; | |
| 448 wc.lpszClassName = chrome::kMessageWindowClass; | |
| 449 ATOM clazz = ::RegisterClassEx(&wc); | |
| 450 DCHECK(clazz); | |
| 451 | |
| 452 // Set the window's title to the path of our user data directory so | 441 // Set the window's title to the path of our user data directory so |
| 453 // other Chrome instances can decide if they should forward to us. | 442 // other Chrome instances can decide if they should forward to us. |
| 454 window_ = ::CreateWindow(MAKEINTATOM(clazz), | 443 bool result = window_.CreateNamed( |
| 455 user_data_dir_.value().c_str(), | 444 base::Bind(&ProcessLaunchNotification, notification_callback_), |
| 456 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); | 445 user_data_dir_.value()); |
| 457 CHECK(window_); | 446 CHECK(result && window_.hwnd()); |
| 458 } | 447 } |
| 459 | 448 |
| 460 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | 449 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { |
| 461 // Make sure no one is still waiting on Metro activation whether it | 450 // Make sure no one is still waiting on Metro activation whether it |
| 462 // succeeded (i.e., this is the Metro process) or failed. | 451 // succeeded (i.e., this is the Metro process) or failed. |
| 463 base::win::ScopedHandle metro_activation_event( | 452 base::win::ScopedHandle metro_activation_event( |
| 464 ::OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName)); | 453 ::OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName)); |
| 465 if (metro_activation_event.IsValid()) | 454 if (metro_activation_event.IsValid()) |
| 466 ::SetEvent(metro_activation_event); | 455 ::SetEvent(metro_activation_event); |
| 467 } | 456 } |
| 468 } | 457 } |
| 469 } | 458 } |
| 470 | 459 |
| 471 return window_ != NULL; | 460 return window_.hwnd() != NULL; |
| 472 } | 461 } |
| 473 | 462 |
| 474 void ProcessSingleton::Cleanup() { | 463 void ProcessSingleton::Cleanup() { |
| 475 } | 464 } |
| 476 | |
| 477 LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { | |
| 478 CommandLine parsed_command_line(CommandLine::NO_PROGRAM); | |
| 479 base::FilePath current_directory; | |
| 480 if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) | |
| 481 return TRUE; | |
| 482 return notification_callback_.Run(parsed_command_line, current_directory) ? | |
| 483 TRUE : FALSE; | |
| 484 } | |
| 485 | |
| 486 LRESULT ProcessSingleton::WndProc(HWND hwnd, UINT message, | |
| 487 WPARAM wparam, LPARAM lparam) { | |
| 488 switch (message) { | |
| 489 case WM_COPYDATA: | |
| 490 return OnCopyData(reinterpret_cast<HWND>(wparam), | |
| 491 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | |
| 492 default: | |
| 493 break; | |
| 494 } | |
| 495 | |
| 496 return ::DefWindowProc(hwnd, message, wparam, lparam); | |
| 497 } | |
| OLD | NEW |