Chromium Code Reviews| 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 #include <shobjidl.h> | 8 #include <shobjidl.h> |
| 9 | 9 |
| 10 #include "base/base_paths.h" | 10 #include "base/base_paths.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 #include "ui/base/l10n/l10n_util.h" | 40 #include "ui/base/l10n/l10n_util.h" |
| 41 #include "ui/base/win/hwnd_util.h" | 41 #include "ui/base/win/hwnd_util.h" |
| 42 | 42 |
| 43 namespace { | 43 namespace { |
| 44 | 44 |
| 45 const char kLockfile[] = "lockfile"; | 45 const char kLockfile[] = "lockfile"; |
| 46 | 46 |
| 47 const char kSearchUrl[] = | 47 const char kSearchUrl[] = |
| 48 "http://www.google.com/search?q=%s&sourceid=chrome&ie=UTF-8"; | 48 "http://www.google.com/search?q=%s&sourceid=chrome&ie=UTF-8"; |
| 49 | 49 |
| 50 const int kImmersiveChromeInitTimeout = 500; | 50 const int kMetroChromeActivationTimeoutMs = 3000; |
| 51 | |
| 52 // A helper class that acquires the given |mutex| while the AutoLockMutex is in | |
| 53 // scope. | |
| 54 class AutoLockMutex { | |
| 55 public: | |
| 56 explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) { | |
| 57 DWORD result = WaitForSingleObject(mutex_, INFINITE); | |
| 58 DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; | |
| 59 } | |
| 60 | |
| 61 ~AutoLockMutex() { | |
| 62 BOOL released = ReleaseMutex(mutex_); | |
| 63 DPCHECK(released); | |
| 64 } | |
| 65 | |
| 66 private: | |
| 67 HANDLE mutex_; | |
| 68 DISALLOW_COPY_AND_ASSIGN(AutoLockMutex); | |
| 69 }; | |
| 70 | |
| 71 // A helper class that releases the given |mutex| while the AutoUnlockMutex is | |
| 72 // in scope and immediately re-acquires it when going out of scope. | |
| 73 class AutoUnlockMutex { | |
| 74 public: | |
| 75 explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) { | |
| 76 BOOL released = ReleaseMutex(mutex_); | |
| 77 DPCHECK(released); | |
| 78 } | |
| 79 | |
| 80 ~AutoUnlockMutex() { | |
| 81 DWORD result = WaitForSingleObject(mutex_, INFINITE); | |
| 82 DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result; | |
| 83 } | |
| 84 | |
| 85 private: | |
| 86 HANDLE mutex_; | |
| 87 DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex); | |
| 88 }; | |
| 51 | 89 |
| 52 // Checks the visibility of the enumerated window and signals once a visible | 90 // Checks the visibility of the enumerated window and signals once a visible |
| 53 // window has been found. | 91 // window has been found. |
| 54 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { | 92 BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) { |
| 55 bool* result = reinterpret_cast<bool*>(param); | 93 bool* result = reinterpret_cast<bool*>(param); |
| 56 *result = IsWindowVisible(window) != 0; | 94 *result = IsWindowVisible(window) != 0; |
| 57 // Stops enumeration if a visible window has been found. | 95 // Stops enumeration if a visible window has been found. |
| 58 return !*result; | 96 return !*result; |
| 59 } | 97 } |
| 60 | 98 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 if (integrity_level == base::HIGH_INTEGRITY) | 239 if (integrity_level == base::HIGH_INTEGRITY) |
| 202 return false; | 240 return false; |
| 203 | 241 |
| 204 FilePath default_user_data_dir; | 242 FilePath default_user_data_dir; |
| 205 if (!chrome::GetDefaultUserDataDirectory(&default_user_data_dir)) | 243 if (!chrome::GetDefaultUserDataDirectory(&default_user_data_dir)) |
| 206 return false; | 244 return false; |
| 207 | 245 |
| 208 if (default_user_data_dir != user_data_dir) | 246 if (default_user_data_dir != user_data_dir) |
| 209 return false; | 247 return false; |
| 210 | 248 |
| 211 // TODO(gab): This is a temporary solution to avoid activating Metro Chrome | |
| 212 // when chrome.exe is invoked with one of the short-lived commands below. The | |
| 213 // long-term and correct solution is to only check/activate Chrome later; | |
| 214 // after handling of these short-lived commands has occured | |
| 215 // (http://crbug.com/155585). | |
| 216 // This is a 1:1 mapping of the switches that force an early exit of Chrome in | |
| 217 // ChromeBrowserMainParts::PreMainMessageLoopRunImpl(). | |
| 218 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUninstall) || | |
| 219 CommandLine::ForCurrentProcess()->HasSwitch(switches::kHideIcons) || | |
| 220 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowIcons) || | |
| 221 CommandLine::ForCurrentProcess()->HasSwitch( | |
| 222 switches::kMakeDefaultBrowser) || | |
| 223 CommandLine::ForCurrentProcess()->HasSwitch(switches::kPackExtension)) { | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 base::win::RegKey reg_key; | 249 base::win::RegKey reg_key; |
| 228 DWORD reg_value = 0; | 250 DWORD reg_value = 0; |
| 229 if (reg_key.Create(HKEY_CURRENT_USER, chrome::kMetroRegistryPath, | 251 if (reg_key.Create(HKEY_CURRENT_USER, chrome::kMetroRegistryPath, |
| 230 KEY_READ) == ERROR_SUCCESS && | 252 KEY_READ) == ERROR_SUCCESS && |
| 231 reg_key.ReadValueDW(chrome::kLaunchModeValue, | 253 reg_key.ReadValueDW(chrome::kLaunchModeValue, |
| 232 ®_value) == ERROR_SUCCESS) { | 254 ®_value) == ERROR_SUCCESS) { |
| 233 return reg_value == 1; | 255 return reg_value == 1; |
| 234 } | 256 } |
| 235 return base::win::IsMachineATablet(); | 257 return base::win::IsMachineATablet(); |
| 236 } | 258 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 261 ::SetForegroundWindow(hwnd); | 283 ::SetForegroundWindow(hwnd); |
| 262 break; | 284 break; |
| 263 } | 285 } |
| 264 ::Sleep(10); | 286 ::Sleep(10); |
| 265 } | 287 } |
| 266 return true; | 288 return true; |
| 267 } | 289 } |
| 268 return false; | 290 return false; |
| 269 } | 291 } |
| 270 | 292 |
| 271 // Look for a Chrome instance that uses the same profile directory. | |
| 272 // If there isn't one, create a message window with its title set to | |
| 273 // the profile directory path. | |
| 274 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) | 293 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) |
| 275 : window_(NULL), locked_(false), foreground_window_(NULL), | 294 : window_(NULL), locked_(false), foreground_window_(NULL), |
| 276 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE) { | 295 is_virtualized_(false), lock_file_(INVALID_HANDLE_VALUE), |
| 277 // For Windows 8 and above check if we need to relaunch into Windows 8 | 296 user_data_dir_(user_data_dir) { |
| 278 // immersive mode. | |
| 279 if (ShouldLaunchInWindows8ImmersiveMode(user_data_dir)) { | |
| 280 bool immersive_chrome_launched = ActivateMetroChrome(); | |
| 281 if (!immersive_chrome_launched) { | |
| 282 LOG(WARNING) << "Failed to launch immersive chrome"; | |
| 283 } else { | |
| 284 // Sleep to allow the immersive chrome process to create its initial | |
| 285 // message window. | |
| 286 SleepEx(kImmersiveChromeInitTimeout, FALSE); | |
| 287 } | |
| 288 } | |
| 289 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | |
| 290 chrome::kMessageWindowClass, | |
| 291 user_data_dir.value().c_str()); | |
| 292 if (!remote_window_ && !EscapeVirtualization(user_data_dir)) { | |
| 293 // Make sure we will be the one and only process creating the window. | |
| 294 // We use a named Mutex since we are protecting against multi-process | |
| 295 // access. As documented, it's clearer to NOT request ownership on creation | |
| 296 // since it isn't guaranteed we will get it. It is better to create it | |
| 297 // without ownership and explicitly get the ownership afterward. | |
| 298 std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!"); | |
| 299 base::win::ScopedHandle only_me( | |
| 300 CreateMutex(NULL, FALSE, mutex_name.c_str())); | |
| 301 DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError(); | |
| 302 | |
| 303 // This is how we acquire the mutex (as opposed to the initial ownership). | |
| 304 DWORD result = WaitForSingleObject(only_me, INFINITE); | |
| 305 DCHECK(result == WAIT_OBJECT_0) << "Result = " << result << | |
| 306 "GetLastError = " << GetLastError(); | |
| 307 | |
| 308 // We now own the mutex so we are the only process that can create the | |
| 309 // window at this time, but we must still check if someone created it | |
| 310 // between the time where we looked for it above and the time the mutex | |
| 311 // was given to us. | |
| 312 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | |
| 313 chrome::kMessageWindowClass, | |
| 314 user_data_dir.value().c_str()); | |
| 315 if (!remote_window_) { | |
| 316 // We have to make sure there is no Chrome instance running on another | |
| 317 // machine that uses the same profile. | |
| 318 FilePath lock_file_path = user_data_dir.AppendASCII(kLockfile); | |
| 319 lock_file_ = CreateFile(lock_file_path.value().c_str(), | |
| 320 GENERIC_WRITE, | |
| 321 FILE_SHARE_READ, | |
| 322 NULL, | |
| 323 CREATE_ALWAYS, | |
| 324 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, | |
| 325 NULL); | |
| 326 DWORD error = GetLastError(); | |
| 327 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && | |
| 328 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; | |
| 329 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) | |
| 330 << "Lock file can not be created! Error code: " << error; | |
| 331 | |
| 332 if (lock_file_ != INVALID_HANDLE_VALUE) { | |
| 333 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | |
| 334 | |
| 335 WNDCLASSEX wc = {0}; | |
| 336 wc.cbSize = sizeof(wc); | |
| 337 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | |
| 338 wc.hInstance = hinst; | |
| 339 wc.lpszClassName = chrome::kMessageWindowClass; | |
| 340 ATOM clazz = ::RegisterClassEx(&wc); | |
| 341 DCHECK(clazz); | |
| 342 | |
| 343 // Set the window's title to the path of our user data directory so | |
| 344 // other Chrome instances can decide if they should forward to us. | |
| 345 window_ = ::CreateWindow(MAKEINTATOM(clazz), | |
| 346 user_data_dir.value().c_str(), | |
| 347 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); | |
| 348 CHECK(window_); | |
| 349 } | |
| 350 } | |
| 351 BOOL success = ReleaseMutex(only_me); | |
| 352 DCHECK(success) << "GetLastError = " << GetLastError(); | |
| 353 } | |
| 354 } | 297 } |
| 355 | 298 |
| 356 ProcessSingleton::~ProcessSingleton() { | 299 ProcessSingleton::~ProcessSingleton() { |
| 357 // We need to unregister the window as late as possible so that we can detect | 300 // We need to unregister the window as late as possible so that we can detect |
| 358 // another instance of chrome running. Otherwise we may end up writing out | 301 // another instance of chrome running. Otherwise we may end up writing out |
| 359 // data while a new chrome is starting up. | 302 // data while a new chrome is starting up. |
| 360 if (window_) { | 303 if (window_) { |
| 361 ::DestroyWindow(window_); | 304 ::DestroyWindow(window_); |
| 362 ::UnregisterClass(chrome::kMessageWindowClass, | 305 ::UnregisterClass(chrome::kMessageWindowClass, |
| 363 base::GetModuleFromAddress(&ThunkWndProc)); | 306 base::GetModuleFromAddress(&ThunkWndProc)); |
| 364 } | 307 } |
| 365 if (lock_file_ != INVALID_HANDLE_VALUE) | 308 if (lock_file_ != INVALID_HANDLE_VALUE) |
| 366 CloseHandle(lock_file_); | 309 CloseHandle(lock_file_); |
| 367 } | 310 } |
| 368 | 311 |
| 312 // Code roughly based on Mozilla. | |
| 369 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { | 313 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { |
| 370 if (is_virtualized_) | 314 if (is_virtualized_) |
| 371 return PROCESS_NOTIFIED; // We already spawned the process in this case. | 315 return PROCESS_NOTIFIED; // We already spawned the process in this case. |
| 372 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { | 316 if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) { |
| 373 return LOCK_ERROR; | 317 return LOCK_ERROR; |
| 374 } else if (!remote_window_) { | 318 } else if (!remote_window_) { |
| 375 g_browser_process->PlatformSpecificCommandLineProcessing( | 319 g_browser_process->PlatformSpecificCommandLineProcessing( |
| 376 *CommandLine::ForCurrentProcess()); | 320 *CommandLine::ForCurrentProcess()); |
| 377 return PROCESS_NONE; | 321 return PROCESS_NONE; |
| 378 } | 322 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 474 } | 418 } |
| 475 | 419 |
| 476 // Time to take action. Kill the browser process. | 420 // Time to take action. Kill the browser process. |
| 477 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); | 421 base::KillProcessById(process_id, content::RESULT_CODE_HUNG, true); |
| 478 remote_window_ = NULL; | 422 remote_window_ = NULL; |
| 479 return PROCESS_NONE; | 423 return PROCESS_NONE; |
| 480 } | 424 } |
| 481 | 425 |
| 482 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate( | 426 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate( |
| 483 const NotificationCallback& notification_callback) { | 427 const NotificationCallback& notification_callback) { |
| 484 NotifyResult result = NotifyOtherProcess(); | 428 ProcessSingleton::NotifyResult result = PROCESS_NONE; |
| 485 if (result != PROCESS_NONE) | 429 if (!Create(notification_callback)) { |
| 486 return result; | 430 result = NotifyOtherProcess(); |
| 487 return Create(notification_callback) ? PROCESS_NONE : PROFILE_IN_USE; | 431 if (result == PROCESS_NONE) |
| 432 result = PROFILE_IN_USE; | |
| 433 } | |
| 434 return result; | |
| 488 } | 435 } |
| 489 | 436 |
| 490 // On Windows, there is no need to call Create() since the message | 437 // Look for a Chrome instance that uses the same profile directory. If there |
| 491 // window is created in the constructor but to avoid having more | 438 // isn't one, create a message window with its title set to the profile |
| 492 // platform specific code in browser_main.cc we tolerate calls to | 439 // directory path. |
| 493 // Create(). | |
| 494 bool ProcessSingleton::Create( | 440 bool ProcessSingleton::Create( |
| 495 const NotificationCallback& notification_callback) { | 441 const NotificationCallback& notification_callback) { |
| 496 DCHECK(!remote_window_); | |
| 497 DCHECK(notification_callback_.is_null()); | 442 DCHECK(notification_callback_.is_null()); |
| 498 | 443 |
| 444 static const wchar_t kMutexName[] = L"Local\\ChromeProcessSingletonStartup!"; | |
| 445 static const wchar_t kMetroActivationEventName[] = | |
| 446 L"Local\\ChromeProcessSingletonStartupMetroActivation!"; | |
| 447 | |
| 448 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | |
| 449 chrome::kMessageWindowClass, | |
| 450 user_data_dir_.value().c_str()); | |
| 451 if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) { | |
| 452 // Make sure we will be the one and only process creating the window. | |
| 453 // We use a named Mutex since we are protecting against multi-process | |
| 454 // access. As documented, it's clearer to NOT request ownership on creation | |
| 455 // since it isn't guaranteed we will get it. It is better to create it | |
| 456 // without ownership and explicitly get the ownership afterward. | |
| 457 base::win::ScopedHandle only_me(CreateMutex(NULL, FALSE, kMutexName)); | |
|
ananta
2012/12/04 19:11:54
I think the mutex name needs to be formed off the
gab
2012/12/04 19:44:18
As discussed offline,
1) This has always been the
grt (UTC plus 2)
2012/12/04 19:55:23
We switched to using a global mutex about two year
| |
| 458 DPCHECK(only_me.IsValid()); | |
| 459 | |
| 460 AutoLockMutex auto_lock_only_me(only_me); | |
| 461 | |
| 462 // We now own the mutex so we are the only process that can create the | |
| 463 // window at this time, but we must still check if someone created it | |
| 464 // between the time where we looked for it above and the time the mutex | |
| 465 // was given to us. | |
| 466 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | |
| 467 chrome::kMessageWindowClass, | |
| 468 user_data_dir_.value().c_str()); | |
| 469 | |
| 470 | |
| 471 // In Win8+, a new Chrome process launched in Desktop mode may need to be | |
| 472 // transmuted into Metro Chrome (see ShouldLaunchInWindows8ImmersiveMode for | |
| 473 // heuristics). To accomplish this, the current Chrome activates Metro | |
| 474 // Chrome, releases the startup mutex, and waits for metro Chrome to take | |
| 475 // the singleton. From that point onward, the command line for this Chrome | |
| 476 // process will be sent to Metro Chrome by the usual channels. | |
| 477 if (!remote_window_ && base::win::GetVersion() >= base::win::VERSION_WIN8 && | |
| 478 !base::win::IsMetroProcess()) { | |
| 479 // |metro_activation_event| is created right before activating a Metro | |
| 480 // Chrome (note that there can only be one Metro Chrome process; by OS | |
| 481 // design); all following Desktop processes will then wait for this event | |
| 482 // to be signaled by Metro Chrome which will do so as soon as it grabs | |
| 483 // this singleton (should any of the waiting processes timeout waiting for | |
| 484 // the signal they will try to grab the singleton for themselves which | |
| 485 // will result in a forced Desktop Chrome launch in the worst case). | |
| 486 base::win::ScopedHandle metro_activation_event( | |
| 487 OpenEvent(SYNCHRONIZE, FALSE, kMetroActivationEventName)); | |
| 488 if (!metro_activation_event.IsValid() && | |
| 489 ShouldLaunchInWindows8ImmersiveMode(user_data_dir_)) { | |
| 490 // No Metro activation is under way, but the desire is to launch in | |
| 491 // Metro mode: activate and rendez-vous with the activated process. | |
| 492 metro_activation_event.Set( | |
| 493 CreateEvent(NULL, TRUE, FALSE, kMetroActivationEventName)); | |
| 494 if (!ActivateMetroChrome()) { | |
| 495 // Failed to launch immersive Chrome, default to launching on Desktop. | |
| 496 LOG(ERROR) << "Failed to launch immersive chrome"; | |
| 497 metro_activation_event.Close(); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 if (metro_activation_event.IsValid()) { | |
| 502 // Release |only_me| (to let Metro Chrome grab this singleton) and wait | |
| 503 // until the event is signaled (i.e. Metro Chrome was successfully | |
| 504 // activated). Ignore timeout waiting for |metro_activation_event|. | |
| 505 { | |
| 506 AutoUnlockMutex auto_unlock_only_me(only_me); | |
| 507 | |
| 508 DWORD result = WaitForSingleObject(metro_activation_event, | |
| 509 kMetroChromeActivationTimeoutMs); | |
| 510 DPCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT) | |
| 511 << "Result = " << result; | |
| 512 } | |
| 513 | |
| 514 // Check if this singleton was successfully grabbed by another process | |
| 515 // (hopefully Metro Chrome). Failing to do so, this process will grab | |
| 516 // the singleton and launch in Desktop mode. | |
| 517 remote_window_ = FindWindowEx(HWND_MESSAGE, NULL, | |
| 518 chrome::kMessageWindowClass, | |
| 519 user_data_dir_.value().c_str()); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 if (!remote_window_) { | |
| 524 // We have to make sure there is no Chrome instance running on another | |
| 525 // machine that uses the same profile. | |
| 526 FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile); | |
| 527 lock_file_ = CreateFile(lock_file_path.value().c_str(), | |
| 528 GENERIC_WRITE, | |
| 529 FILE_SHARE_READ, | |
| 530 NULL, | |
| 531 CREATE_ALWAYS, | |
| 532 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, | |
| 533 NULL); | |
| 534 DWORD error = GetLastError(); | |
| 535 LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE && | |
| 536 error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable."; | |
| 537 LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE) | |
| 538 << "Lock file can not be created! Error code: " << error; | |
| 539 | |
| 540 if (lock_file_ != INVALID_HANDLE_VALUE) { | |
| 541 HINSTANCE hinst = base::GetModuleFromAddress(&ThunkWndProc); | |
| 542 | |
| 543 WNDCLASSEX wc = {0}; | |
| 544 wc.cbSize = sizeof(wc); | |
| 545 wc.lpfnWndProc = base::win::WrappedWindowProc<ThunkWndProc>; | |
| 546 wc.hInstance = hinst; | |
| 547 wc.lpszClassName = chrome::kMessageWindowClass; | |
| 548 ATOM clazz = ::RegisterClassEx(&wc); | |
| 549 DCHECK(clazz); | |
| 550 | |
| 551 // Set the window's title to the path of our user data directory so | |
| 552 // other Chrome instances can decide if they should forward to us. | |
| 553 window_ = ::CreateWindow(MAKEINTATOM(clazz), | |
| 554 user_data_dir_.value().c_str(), | |
| 555 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, this); | |
| 556 CHECK(window_); | |
| 557 } | |
| 558 | |
| 559 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { | |
| 560 // Make sure no one is still waiting on Metro activation whether it | |
| 561 // succeeded (i.e., this is the Metro process) or failed. | |
| 562 base::win::ScopedHandle metro_activation_event( | |
| 563 OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName)); | |
| 564 if (metro_activation_event.IsValid()) | |
| 565 SetEvent(metro_activation_event); | |
| 566 } | |
| 567 } | |
| 568 } | |
| 569 | |
| 499 if (window_ != NULL) | 570 if (window_ != NULL) |
| 500 notification_callback_ = notification_callback; | 571 notification_callback_ = notification_callback; |
| 501 | 572 |
| 502 return window_ != NULL; | 573 return window_ != NULL; |
| 503 } | 574 } |
| 504 | 575 |
| 505 void ProcessSingleton::Cleanup() { | 576 void ProcessSingleton::Cleanup() { |
| 506 } | 577 } |
| 507 | 578 |
| 508 LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { | 579 LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 switch (message) { | 612 switch (message) { |
| 542 case WM_COPYDATA: | 613 case WM_COPYDATA: |
| 543 return OnCopyData(reinterpret_cast<HWND>(wparam), | 614 return OnCopyData(reinterpret_cast<HWND>(wparam), |
| 544 reinterpret_cast<COPYDATASTRUCT*>(lparam)); | 615 reinterpret_cast<COPYDATASTRUCT*>(lparam)); |
| 545 default: | 616 default: |
| 546 break; | 617 break; |
| 547 } | 618 } |
| 548 | 619 |
| 549 return ::DefWindowProc(hwnd, message, wparam, lparam); | 620 return ::DefWindowProc(hwnd, message, wparam, lparam); |
| 550 } | 621 } |
| OLD | NEW |