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.h" | 19 #include "base/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 |