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 // Implementation of the CommandExecuteImpl class which implements the | 4 // Implementation of the CommandExecuteImpl class which implements the |
| 5 // IExecuteCommand and related interfaces for handling ShellExecute based | 5 // IExecuteCommand and related interfaces for handling ShellExecute based |
| 6 // launches of the Chrome browser. | 6 // launches of the Chrome browser. |
| 7 | 7 |
| 8 #include "win8/delegate_execute/command_execute_impl.h" | 8 #include "win8/delegate_execute/command_execute_impl.h" |
| 9 | 9 |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/path_service.h" | 11 #include "base/path_service.h" |
| 12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
| 13 #include "base/win/registry.h" | |
| 13 #include "base/win/scoped_co_mem.h" | 14 #include "base/win/scoped_co_mem.h" |
| 14 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
| 16 #include "base/win/win_util.h" | |
| 15 #include "chrome/common/chrome_constants.h" | 17 #include "chrome/common/chrome_constants.h" |
| 16 #include "chrome/common/chrome_paths.h" | 18 #include "chrome/common/chrome_paths.h" |
| 17 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
| 18 #include "win8/delegate_execute/chrome_util.h" | 20 #include "win8/delegate_execute/chrome_util.h" |
| 19 | 21 |
| 20 // CommandExecuteImpl is resposible for activating chrome in Windows 8. The | 22 // CommandExecuteImpl is resposible for activating chrome in Windows 8. The |
| 21 // flow is complicated and this tries to highlight the important events. | 23 // flow is complicated and this tries to highlight the important events. |
| 22 // The current approach is to have a single instance of chrome either | 24 // The current approach is to have a single instance of chrome either |
| 23 // running in desktop or metro mode. If there is no current instance then | 25 // running in desktop or metro mode. If there is no current instance then |
| 24 // the desktop shortcut launches desktop chrome and the metro tile or search | 26 // the desktop shortcut launches desktop chrome and the metro tile or search |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 38 // CommandExecuteImpl::SetParameter | 40 // CommandExecuteImpl::SetParameter |
| 39 // CommandExecuteImpl::SetNoShowUI | 41 // CommandExecuteImpl::SetNoShowUI |
| 40 // CommandExecuteImpl::SetSelection | 42 // CommandExecuteImpl::SetSelection |
| 41 // CommandExecuteImpl::Initialize | 43 // CommandExecuteImpl::Initialize |
| 42 // Up to this point the code basically just gathers values passed in, like | 44 // Up to this point the code basically just gathers values passed in, like |
| 43 // the launch scheme (or url) and the activation verb. | 45 // the launch scheme (or url) and the activation verb. |
| 44 // 5- Windows calls CommandExecuteImpl::Getvalue() | 46 // 5- Windows calls CommandExecuteImpl::Getvalue() |
| 45 // Here we need to return AHE_IMMERSIVE or AHE_DESKTOP. That depends on: | 47 // Here we need to return AHE_IMMERSIVE or AHE_DESKTOP. That depends on: |
| 46 // a) if run in high-integrity return AHE_DESKTOP | 48 // a) if run in high-integrity return AHE_DESKTOP |
| 47 // b) if chrome is running return the AHE_ mode of chrome | 49 // b) if chrome is running return the AHE_ mode of chrome |
| 48 // c) if the current process is inmmersive return AHE_IMMERSIVE | 50 // c) else we return what GetLaunchMode() tells us, which is: |
| 49 // d) if the protocol is file and IExecuteCommandHost::GetUIMode() is not | 51 // i) if the command line --force-xxx is present return that |
| 50 // ECHUIM_DESKTOP then return AHE_IMMERSIVE | 52 // ii) if the registry 'launch_mode' exists return that |
| 51 // e) if none of the above return AHE_DESKTOP | 53 // iii) if IsMachineATablet() is true return AHE_IMMERSIVE |
| 52 // 6- If we returned AHE_DESKTOP in step 5 then CommandExecuteImpl::Execute() | 54 // iv) else return AHE_DESKTOP |
| 53 // is called, here we call GetLaunchMode() which: | 55 // 6- If we returned AHE_IMMERSIVE in step 5 windows might not call us back |
| 54 // a) if chrome is running return the mode of chrome or | 56 // and simply activate chrome in metro by itself, however in some cases |
| 55 // b) return IExecuteCommandHost::GetUIMode() | 57 // it might proceed at step 7. |
| 56 // 7- If GetLaunchMode() returns | 58 // As far as we know if we return AHE_DESKTOP then step 7 always happens. |
| 57 // a) ECHUIM_DESKTOP we call LaunchDestopChrome() that calls ::CreateProcess | 59 // 7- Windows calls CommandExecuteImpl::Execute() |
| 60 // Here we call GetLaunchMode() which returns the cached answer | |
| 61 // computed at step 5c. which can be: | |
| 62 // a) ECHUIM_DESKTOP then we call LaunchDestopChrome() that calls | |
| 63 // ::CreateProcess and we exit at this point even on failure. | |
| 58 // b) else we call one of the IApplicationActivationManager activation | 64 // b) else we call one of the IApplicationActivationManager activation |
| 59 // functions depending on the parameters passed in step 4. | 65 // functions depending on the parameters passed in step 4. |
| 66 // c) If the activation returns E_APPLICATION_NOT_REGISTERED, then we fall | |
| 67 // back to launching chrome on the desktop via LaunchDestopChrome(). | |
| 60 // | 68 // |
| 61 // Some examples will help clarify the common cases. | 69 // Note that if a command line --force-xxx is present we write that launch mode |
| 70 // in the registry so next time the logic reaches 5c-ii it will use the same | |
| 71 // mode again. | |
| 62 // | 72 // |
| 63 // I - No chrome running, taskbar icon launch: | 73 // Also note that if we are not the default browser and IsMachineATablet() |
| 64 // a) Scheme is 'file', Verb is 'open' | 74 // returns true, launching chrome can go all the way to 7c, which might be |
| 65 // b) GetValue() returns at e) step : AHE_DESKTOP | 75 // a slow way to start chrome. |
| 66 // c) Execute() calls LaunchDestopChrome() | |
| 67 // --> desktop chrome runs | |
| 68 // II- No chrome running, tile activation launch: | |
| 69 // a) Scheme is 'file', Verb is 'open' | |
| 70 // b) GetValue() returns at d) step : AHE_IMMERSIVE | |
| 71 // c) Windows does not call us back and just activates chrome | |
| 72 // --> metro chrome runs | |
| 73 // III- No chrome running, url link click on metro app: | |
| 74 // a) Scheme is 'http', Verb is 'open' | |
| 75 // b) Getvalue() returns at e) step : AHE_DESKTOP | |
| 76 // c) Execute() calls IApplicationActivationManager::ActivateForProtocol | |
| 77 // --> metro chrome runs | |
| 78 // | 76 // |
| 79 CommandExecuteImpl::CommandExecuteImpl() | 77 CommandExecuteImpl::CommandExecuteImpl() |
| 80 : integrity_level_(base::INTEGRITY_UNKNOWN), | 78 : integrity_level_(base::INTEGRITY_UNKNOWN), |
| 81 launch_scheme_(INTERNET_SCHEME_DEFAULT), | 79 launch_scheme_(INTERNET_SCHEME_DEFAULT), |
| 82 chrome_mode_(ECHUIM_SYSTEM_LAUNCHER) { | 80 chrome_mode_(ECHUIM_SYSTEM_LAUNCHER) { |
| 83 memset(&start_info_, 0, sizeof(start_info_)); | 81 memset(&start_info_, 0, sizeof(start_info_)); |
| 84 start_info_.cb = sizeof(start_info_); | 82 start_info_.cb = sizeof(start_info_); |
| 85 // We need to query the user data dir of chrome so we need chrome's | 83 // We need to query the user data dir of chrome so we need chrome's |
| 86 // path provider. | 84 // path provider. |
| 87 chrome::RegisterPathProvider(); | 85 chrome::RegisterPathProvider(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 chrome_mode_ = ECHUIM_IMMERSIVE; | 168 chrome_mode_ = ECHUIM_IMMERSIVE; |
| 171 *pahe = AHE_IMMERSIVE; | 169 *pahe = AHE_IMMERSIVE; |
| 172 } else { | 170 } else { |
| 173 AtlTrace("Chrome [%d] is Desktop, AHE_DESKTOP\n"); | 171 AtlTrace("Chrome [%d] is Desktop, AHE_DESKTOP\n"); |
| 174 chrome_mode_ = ECHUIM_DESKTOP; | 172 chrome_mode_ = ECHUIM_DESKTOP; |
| 175 *pahe = AHE_DESKTOP; | 173 *pahe = AHE_DESKTOP; |
| 176 } | 174 } |
| 177 return S_OK; | 175 return S_OK; |
| 178 } | 176 } |
| 179 | 177 |
| 180 if (IsImmersiveProcess(GetCurrentProcess())) { | 178 EC_HOST_UI_MODE mode = GetLaunchMode(); |
| 181 AtlTrace("Current process is inmmersive, AHE_IMMERSIVE\n"); | 179 *pahe = (mode == ECHUIM_DESKTOP) ? AHE_DESKTOP : AHE_IMMERSIVE; |
| 182 *pahe = AHE_IMMERSIVE; | |
| 183 return S_OK; | |
| 184 } | |
| 185 | |
| 186 if ((launch_scheme_ == INTERNET_SCHEME_FILE) && | |
| 187 (GetLaunchMode() != ECHUIM_DESKTOP)) { | |
| 188 AtlTrace("INTERNET_SCHEME_FILE, mode != ECHUIM_DESKTOP, AHE_IMMERSIVE\n"); | |
| 189 *pahe = AHE_IMMERSIVE; | |
| 190 return S_OK; | |
| 191 } | |
| 192 | |
| 193 AtlTrace("Fallback is AHE_DESKTOP\n"); | |
| 194 *pahe = AHE_DESKTOP; | |
| 195 return S_OK; | 180 return S_OK; |
| 196 } | 181 } |
| 197 | 182 |
| 198 STDMETHODIMP CommandExecuteImpl::Execute() { | 183 STDMETHODIMP CommandExecuteImpl::Execute() { |
| 199 AtlTrace("In %hs\n", __FUNCTION__); | 184 AtlTrace("In %hs\n", __FUNCTION__); |
| 200 | 185 |
| 201 if (integrity_level_ == base::HIGH_INTEGRITY) | 186 if (integrity_level_ == base::HIGH_INTEGRITY) |
| 202 return LaunchDesktopChrome(); | 187 return LaunchDesktopChrome(); |
| 203 | 188 |
| 204 EC_HOST_UI_MODE mode = GetLaunchMode(); | 189 EC_HOST_UI_MODE mode = GetLaunchMode(); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 CloseHandle(proc_info.hProcess); | 377 CloseHandle(proc_info.hProcess); |
| 393 CloseHandle(proc_info.hThread); | 378 CloseHandle(proc_info.hThread); |
| 394 } else { | 379 } else { |
| 395 AtlTrace("Process launch failed, error %d\n", ::GetLastError()); | 380 AtlTrace("Process launch failed, error %d\n", ::GetLastError()); |
| 396 } | 381 } |
| 397 | 382 |
| 398 return S_OK; | 383 return S_OK; |
| 399 } | 384 } |
| 400 | 385 |
| 401 EC_HOST_UI_MODE CommandExecuteImpl::GetLaunchMode() { | 386 EC_HOST_UI_MODE CommandExecuteImpl::GetLaunchMode() { |
| 402 // We are to return chrome's mode if chrome exists else we query our embedder | 387 // See the header file for an explanation of the mode selection logic. |
| 403 // IServiceProvider and learn the mode from them. | |
| 404 static bool launch_mode_determined = false; | 388 static bool launch_mode_determined = false; |
| 405 static EC_HOST_UI_MODE launch_mode = ECHUIM_DESKTOP; | 389 static EC_HOST_UI_MODE launch_mode = ECHUIM_DESKTOP; |
| 406 | 390 |
| 407 const char* modes[] = { "Desktop", "Inmmersive", "SysLauncher", "??" }; | 391 const char* modes[] = { "Desktop", "Immersive", "SysLauncher", "??" }; |
| 408 | 392 |
| 409 if (launch_mode_determined) | 393 if (launch_mode_determined) |
| 410 return launch_mode; | 394 return launch_mode; |
| 411 | 395 |
| 412 if (chrome_mode_ != ECHUIM_SYSTEM_LAUNCHER) { | 396 if (chrome_mode_ != ECHUIM_SYSTEM_LAUNCHER) { |
| 413 launch_mode = chrome_mode_; | 397 launch_mode = chrome_mode_; |
| 414 AtlTrace("Launch mode is that of chrome, %s\n", modes[launch_mode]); | 398 AtlTrace("Launch mode is that of chrome, %s\n", modes[launch_mode]); |
| 415 launch_mode_determined = true; | 399 launch_mode_determined = true; |
| 416 return launch_mode; | 400 return launch_mode; |
| 417 } | 401 } |
| 418 | 402 |
| 419 if (parameters_ == ASCIIToWide(switches::kForceImmersive)) { | 403 if (parameters_ == ASCIIToWide(switches::kForceImmersive)) { |
| 420 launch_mode = ECHUIM_IMMERSIVE; | 404 launch_mode = ECHUIM_IMMERSIVE; |
| 421 launch_mode_determined = true; | 405 launch_mode_determined = true; |
| 406 parameters_.clear(); | |
| 422 } else if (parameters_ == ASCIIToWide(switches::kForceDesktop)) { | 407 } else if (parameters_ == ASCIIToWide(switches::kForceDesktop)) { |
| 423 launch_mode = ECHUIM_DESKTOP; | 408 launch_mode = ECHUIM_DESKTOP; |
| 424 launch_mode_determined = true; | 409 launch_mode_determined = true; |
| 410 parameters_.clear(); | |
| 411 } | |
| 412 | |
| 413 base::win::RegKey reg_key; | |
| 414 LONG key_result = reg_key.Create(HKEY_CURRENT_USER, | |
| 415 chrome::kMetroRegistryPath, | |
| 416 KEY_ALL_ACCESS); | |
| 417 if (key_result != ERROR_SUCCESS) { | |
| 418 AtlTrace("Failed to open HKCU %ls key, error 0x%x\n", | |
|
grt (UTC plus 2)
2012/09/14 01:13:42
in this case, key_result is a last-error code. i
| |
| 419 chrome::kMetroRegistryPath, | |
| 420 key_result); | |
|
grt (UTC plus 2)
2012/09/14 01:13:42
nit: move up to previous line
| |
| 421 if (!launch_mode_determined) { | |
| 422 launch_mode = ECHUIM_DESKTOP; | |
| 423 launch_mode_determined = true; | |
| 424 } | |
| 425 return launch_mode; | |
| 425 } | 426 } |
| 426 | 427 |
| 427 if (launch_mode_determined) { | 428 if (launch_mode_determined) { |
| 428 parameters_.clear(); | 429 AtlTrace("Launch mode forced by cmdline to %s\n", modes[launch_mode]); |
| 429 AtlTrace("Launch mode forced to %s\n", modes[launch_mode]); | 430 reg_key.WriteValue(chrome::kLaunchModeValue, |
| 431 static_cast<DWORD>(launch_mode)); | |
| 430 return launch_mode; | 432 return launch_mode; |
| 431 } | 433 } |
| 432 | 434 |
| 433 CComPtr<IExecuteCommandHost> host; | 435 DWORD reg_value; |
| 434 CComQIPtr<IServiceProvider> service_provider = m_spUnkSite; | 436 if (reg_key.ReadValueDW(chrome::kLaunchModeValue, |
| 435 if (service_provider) { | 437 ®_value) != ERROR_SUCCESS) { |
| 436 service_provider->QueryService(IID_IExecuteCommandHost, &host); | 438 launch_mode = base::win::IsMachineATablet() ? |
| 437 if (host) { | 439 ECHUIM_IMMERSIVE : ECHUIM_DESKTOP; |
| 438 host->GetUIMode(&launch_mode); | 440 AtlTrace("Launch mode forced by heuristics to %s\n", modes[launch_mode]); |
| 439 } else { | 441 } else if (reg_value >= ECHUIM_SYSTEM_LAUNCHER) { |
| 440 AtlTrace("Failed to get IID_IExecuteCommandHost. Assuming desktop\n"); | 442 AtlTrace("Invalid registry launch mode value %u\n", reg_value); |
| 441 } | 443 launch_mode = ECHUIM_DESKTOP; |
| 442 } else { | 444 } else { |
| 443 AtlTrace("Failed to get IServiceProvider. Assuming desktop mode\n"); | 445 AtlTrace("Launch mode forced by registry to %s\n", modes[launch_mode]); |
| 446 launch_mode = static_cast<EC_HOST_UI_MODE>(reg_value); | |
| 444 } | 447 } |
| 445 AtlTrace("Launch mode is %s\n", modes[launch_mode]); | 448 |
| 446 launch_mode_determined = true; | 449 launch_mode_determined = true; |
| 447 return launch_mode; | 450 return launch_mode; |
| 448 } | 451 } |
| OLD | NEW |