shell_integration_win.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shobjidl.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <propkey.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h" 159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_propvariant.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/shortcut.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h" 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/policy/policy_path_parser.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths_internal.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/setup/setup_util.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/browser_distribution.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/create_reg_key_work_item.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/set_reg_value_work_item.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/shell_util.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item_list.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kAppListAppNameSuffix[] = L"AppList"; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function for ShellIntegration::GetAppId to generates profile id 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from profile path. "profile_id" is composed of sanitized basenames of 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// user data dir and profile dir joined by a ".". 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 GetProfileIdFromPath(const base::FilePath& profile_path) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return empty string if profile_path is empty 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile_path.empty()) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return string16(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath default_user_data_dir; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return empty string if profile_path is in default user data 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dir and is the default profile. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) && 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_path.DirName() == default_user_data_dir && 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_path.BaseName().value() == 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASCIIToUTF16(chrome::kInitialProfile)) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return string16(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get joined basenames of user data dir and profile. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 basenames = profile_path.DirName().BaseName().value() + 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"." + profile_path.BaseName().value(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 profile_id; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_id.reserve(basenames.size()); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generate profile_id from sanitized basenames. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < basenames.length(); ++i) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsAsciiAlpha(basenames[i]) || 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsAsciiDigit(basenames[i]) || 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) basenames[i] == L'.') 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_id += basenames[i]; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return profile_id; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 GetAppListAppName() { 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 app_name(dist->GetBaseAppId()); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_name.append(kAppListAppNameSuffix); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return app_name; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Gets expected app id for given Chrome (based on |command_line| and 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |is_per_user_install|). 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 GetExpectedAppId(const CommandLine& command_line, 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_per_user_install) { 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath user_data_dir; 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (command_line.HasSwitch(switches::kUserDataDir)) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_data_dir = command_line.GetSwitchValuePath(switches::kUserDataDir); 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) else 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) chrome::GetDefaultUserDataDirectory(&user_data_dir); 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Adjust with any policy that overrides any other way to set the path. 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch policy::path_parser::CheckUserDataDirPolicy(&user_data_dir); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!user_data_dir.empty()); 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath profile_subdir; 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (command_line.HasSwitch(switches::kProfileDirectory)) { 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_subdir = 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) command_line.GetSwitchValuePath(switches::kProfileDirectory); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile_subdir = base::FilePath(ASCIIToUTF16(chrome::kInitialProfile)); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!profile_subdir.empty()); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::FilePath profile_path = user_data_dir.Append(profile_subdir); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 app_name; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (command_line.HasSwitch(switches::kApp)) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromURL( 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(command_line.GetSwitchValueASCII(switches::kApp)))); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (command_line.HasSwitch(switches::kAppId)) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_name = UTF8ToUTF16(web_app::GenerateApplicationNameFromExtensionId( 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_line.GetSwitchValueASCII(switches::kAppId))); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (command_line.HasSwitch(switches::kShowAppList)) { 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_name = GetAppListAppName(); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!app_name.empty()); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MigrateChromiumShortcutsCallback() { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This should run on the file thread. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get full path of chrome. 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Locations to check for shortcuts migration. 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const struct { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int location_id; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const wchar_t* sub_dir; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } kLocations[] = { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_TASKBAR_PINS, 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_USER_DESKTOP, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_START_MENU, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }, { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_APP_DATA, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu" 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < arraysize(kLocations); ++i) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(kLocations[i].location_id, &path)) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kLocations[i].sub_dir) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = path.Append(kLocations[i].sub_dir); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path, 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) check_dual_mode); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientState 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDefaultWebClientStateFromShellUtilDefaultState( 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellUtil::DefaultState default_state) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (default_state) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ShellUtil::NOT_DEFAULT: 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ShellIntegration::NOT_DEFAULT; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case ShellUtil::IS_DEFAULT: 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ShellIntegration::IS_DEFAULT; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state); 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ShellIntegration::UNKNOWN_DEFAULT; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientSetPermission 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellIntegration::CanSetAsDefaultBrowser() { 1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); 1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (distribution->GetDefaultBrowserControlPolicy() != 1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SET_DEFAULT_NOT_ALLOWED; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShellUtil::CanMakeChromeDefaultUnattended()) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SET_DEFAULT_UNATTENDED; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SET_DEFAULT_INTERACTIVE; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultBrowser() { 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Error getting app exe path"; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // From UI currently we only allow setting default browser for current user. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER, 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome_exe.value(), true)) { 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Chrome could not be set as default browser."; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Chrome registered as default browser."; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (protocol.empty()) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Error getting app exe path"; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 wprotocol(UTF8ToUTF16(protocol)); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ShellUtil::MakeChromeDefaultProtocolClient(dist, chrome_exe.value(), 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wprotocol)) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Chrome could not be set as default handler for " 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << protocol << "."; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Chrome registered as default handler for " << protocol << "."; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultBrowserInteractive() { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Error getting app exe path"; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ShellUtil::ShowMakeChromeDefaultSystemUI(dist, chrome_exe.value())) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to launch the set-default-browser Windows UI."; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Set-default-browser Windows UI completed."; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultProtocolClientInteractive( 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& protocol) { 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Error getting app exe path"; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 wprotocol(UTF8ToUTF16(protocol)); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI( 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dist, chrome_exe.value(), wprotocol)) { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to launch the set-default-client Windows UI."; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Set-default-client Windows UI completed."; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ShellIntegration::DefaultWebClientState ShellIntegration::GetDefaultBrowser() { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDefaultWebClientStateFromShellUtilDefaultState( 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellUtil::GetChromeDefaultState()); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientState 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDefaultWebClientStateFromShellUtilDefaultState( 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellUtil::GetChromeDefaultProtocolClientState(UTF8ToUTF16(protocol))); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string ShellIntegration::GetApplicationForProtocol(const GURL& url) { 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(calamity): this will be implemented when external_protocol_dialog is 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // refactored on windows. 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return std::string(); 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There is no reliable way to say which browser is default on a machine (each 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// browser can have some of the protocols/shortcuts). So we look for only HTTP 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// protocol handler. Even this handler is located at different places in 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registry on XP and Vista: 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - HKCR\http\shell\open\command (XP) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\ 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http\UserChoice (Vista) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method checks if Firefox is defualt browser by checking these 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// locations and returns true if Firefox traces are found there. In case of 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error (or if Firefox is not found)it returns the default value which 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is false. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::IsFirefoxDefaultBrowser() { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ff_default = false; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 app_cmd; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegKey key(HKEY_CURRENT_USER, 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellUtil::kRegVistaUrlPrefs, KEY_READ); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) && 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) app_cmd == L"FirefoxURL") 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ff_default = true; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 key_path(L"http"); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path.append(ShellUtil::kRegShellOpen); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ); 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16 app_cmd; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) && 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string16::npos != StringToLowerASCII(app_cmd).find(L"firefox")) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ff_default = true; 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ff_default; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 ShellIntegration::GetAppModelIdForProfile( 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16& app_name, 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& profile_path) { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<string16> components; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) components.push_back(app_name); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string16 profile_id(GetProfileIdFromPath(profile_path)); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!profile_id.empty()) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) components.push_back(profile_id); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ShellUtil::BuildAppModelId(components); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 ShellIntegration::GetChromiumModelIdForProfile( 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& profile_path) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath chrome_exe; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return dist->GetBaseAppId(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetAppModelIdForProfile( 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShellUtil::GetBrowserModelId( 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())), 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_path); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 ShellIntegration::GetAppListAppModelIdForProfile( 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& profile_path) { 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return ShellIntegration::GetAppModelIdForProfile( 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetAppListAppName(), profile_path); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShellIntegration::MigrateChromiumShortcuts() { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::win::GetVersion() < base::win::VERSION_WIN7) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This needs to happen eventually (e.g. so that the appid is fixed and the 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // run-time Chrome icon is merged with the taskbar shortcut), but this is not 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // urgent and shouldn't delay Chrome startup. 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const int64 kMigrateChromiumShortcutsDelaySeconds = 15; 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostDelayedTask( 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&MigrateChromiumShortcutsCallback), 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromSeconds(kMigrateChromiumShortcutsDelaySeconds)); 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ShellIntegration::MigrateShortcutsInPathInternal( 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& chrome_exe, 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& path, 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool check_dual_mode) { 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7); 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Enumerate all pinned shortcuts in the given path directly. 387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator shortcuts_enum( 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) path, false, // not recursive 389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk")); 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_per_user_install = 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int shortcuts_migrated = 0; 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath target_path; 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 arguments; 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedPropVariant propvariant; 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (base::FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty(); 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shortcut = shortcuts_enum.Next()) { 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(gab): Use ProgramCompare instead of comparing FilePaths below once 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it is fixed to work with FilePaths with spaces. 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!base::win::ResolveShortcut(shortcut, &target_path, &arguments) || 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) chrome_exe != target_path) { 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CommandLine command_line(CommandLine::FromString(base::StringPrintf( 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"\"%ls\" %ls", target_path.value().c_str(), arguments.c_str()))); 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Get the expected AppId for this Chrome shortcut. 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) string16 expected_app_id( 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetExpectedAppId(command_line, is_per_user_install)); 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (expected_app_id.empty()) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Load the shortcut. 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedComPtr<IShellLink> shell_link; 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedComPtr<IPersistFile> persist_file; 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL, 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CLSCTX_INPROC_SERVER)) || 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FAILED(persist_file.QueryFrom(shell_link)) || 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) { 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(WARNING) << "Failed loading shortcut at " << shortcut.value(); 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Any properties that need to be updated on the shortcut will be stored in 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |updated_properties|. 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ShortcutProperties updated_properties; 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Validate the existing app id for the shortcut. 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedComPtr<IPropertyStore> property_store; 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) propvariant.Reset(); 4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(property_store.QueryFrom(shell_link)) || 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) property_store->GetValue(PKEY_AppUserModel_ID, 4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) propvariant.Receive()) != S_OK) { 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // When in doubt, prefer not updating the shortcut. 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (propvariant.get().vt) { 4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_EMPTY: 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If there is no app_id set, set our app_id if one is expected. 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!expected_app_id.empty()) 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) updated_properties.set_app_id(expected_app_id); 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_LPWSTR: 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (expected_app_id != string16(propvariant.get().pwszVal)) 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) updated_properties.set_app_id(expected_app_id); 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Only set dual mode if the expected app id is the default app id. 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16 default_chromium_model_id( 459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ShellUtil::GetBrowserModelId(dist, is_per_user_install)); 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (check_dual_mode && expected_app_id == default_chromium_model_id) { 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) propvariant.Reset(); 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (property_store->GetValue(PKEY_AppUserModel_IsDualMode, 4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) propvariant.Receive()) != S_OK) { 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // When in doubt, prefer to not update the shortcut. 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (propvariant.get().vt) { 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_EMPTY: 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If dual_mode is not set at all, make sure it gets set to true. 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) updated_properties.set_dual_mode(true); 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_BOOL: 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If it is set to false, make sure it gets set to true as well. 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!propvariant.get().boolVal) 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) updated_properties.set_dual_mode(true); 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) persist_file.Release(); 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shell_link.Release(); 4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Update the shortcut if some of its properties need to be updated. 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (updated_properties.options && 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::CreateOrUpdateShortcutLink( 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shortcut, updated_properties, 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::SHORTCUT_UPDATE_EXISTING)) { 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++shortcuts_migrated; 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return shortcuts_migrated; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath ShellIntegration::GetStartMenuShortcut( 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& chrome_exe) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kFolderIds[] = { 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_COMMON_START_MENU, 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::DIR_START_MENU, 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) string16 shortcut_name( 5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME)); 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath shortcut; 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check both the common and the per-user Start Menu folders for system-level 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // installs. 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t folder = 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0; 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; folder < arraysize(kFolderIds); ++folder) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!PathService::Get(kFolderIds[folder], &shortcut)) { 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shortcut = shortcut.Append(shortcut_name).Append(shortcut_name + 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) installer::kLnkExt); 5227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (base::PathExists(shortcut)) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return shortcut; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 528