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>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <shlwapi.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shobjidl.h>
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <propkey.h>  // Needs to come after shobjidl.h.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_propvariant.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/shortcut.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/policy/policy_path_parser.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths_internal.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/setup/setup_util.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/browser_distribution.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/create_reg_key_work_item.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/set_reg_value_work_item.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/shell_util.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/work_item_list.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kAppListAppNameSuffix[] = L"AppList";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function for ShellIntegration::GetAppId to generates profile id
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from profile path. "profile_id" is composed of sanitized basenames of
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// user data dir and profile dir joined by a ".".
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetProfileIdFromPath(const base::FilePath& profile_path) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return empty string if profile_path is empty
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_path.empty())
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::string16();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath default_user_data_dir;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Return empty string if profile_path is in default user data
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dir and is the default profile.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) &&
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_path.DirName() == default_user_data_dir &&
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_path.BaseName().value() ==
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::ASCIIToUTF16(chrome::kInitialProfile)) {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::string16();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get joined basenames of user data dir and profile.
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 basenames = profile_path.DirName().BaseName().value() +
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      L"." + profile_path.BaseName().value();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 profile_id;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_id.reserve(basenames.size());
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate profile_id from sanitized basenames.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < basenames.length(); ++i) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsAsciiAlpha(basenames[i]) ||
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IsAsciiDigit(basenames[i]) ||
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        basenames[i] == L'.')
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_id += basenames[i];
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_id;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetAppListAppName() {
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 app_name(dist->GetBaseAppId());
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  app_name.append(kAppListAppNameSuffix);
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app_name;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Gets expected app id for given Chrome (based on |command_line| and
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |is_per_user_install|).
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetExpectedAppId(const CommandLine& command_line,
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                bool is_per_user_install) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath user_data_dir;
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (command_line.HasSwitch(switches::kUserDataDir))
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    user_data_dir = command_line.GetSwitchValuePath(switches::kUserDataDir);
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    chrome::GetDefaultUserDataDirectory(&user_data_dir);
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Adjust with any policy that overrides any other way to set the path.
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  policy::path_parser::CheckUserDataDirPolicy(&user_data_dir);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!user_data_dir.empty());
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath profile_subdir;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (command_line.HasSwitch(switches::kProfileDirectory)) {
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    profile_subdir =
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        command_line.GetSwitchValuePath(switches::kProfileDirectory);
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    profile_subdir =
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::FilePath(base::ASCIIToUTF16(chrome::kInitialProfile));
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!profile_subdir.empty());
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath profile_path = user_data_dir.Append(profile_subdir);
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 app_name;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command_line.HasSwitch(switches::kApp)) {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_name = base::UTF8ToUTF16(web_app::GenerateApplicationNameFromURL(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL(command_line.GetSwitchValueASCII(switches::kApp))));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command_line.HasSwitch(switches::kAppId)) {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app_name = base::UTF8ToUTF16(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        web_app::GenerateApplicationNameFromExtensionId(
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            command_line.GetSwitchValueASCII(switches::kAppId)));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (command_line.HasSwitch(switches::kShowAppList)) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    app_name = GetAppListAppName();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!app_name.empty());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MigrateChromiumShortcutsCallback() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This should run on the file thread.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get full path of chrome.
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe))
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locations to check for shortcuts migration.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const struct {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int location_id;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* sub_dir;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } kLocations[] = {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_TASKBAR_PINS,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_USER_DESKTOP,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_START_MENU,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_APP_DATA,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < arraysize(kLocations); ++i) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!PathService::Get(kLocations[i].location_id, &path)) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kLocations[i].sub_dir)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path = path.Append(kLocations[i].sub_dir);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path,
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                     check_dual_mode);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Windows 8 introduced a new protocol->executable binding system which cannot
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// be retrieved in the HKCR registry subkey method implemented below. We call
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// AssocQueryString with the new Win8-only flag ASSOCF_IS_PROTOCOL instead.
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::string16 GetAppForProtocolUsingAssocQuery(const GURL& url) {
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::string16 url_scheme = base::ASCIIToWide(url.scheme());
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Don't attempt to query protocol association on an empty string.
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (url_scheme.empty())
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return base::string16();
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Query AssocQueryString for a human-readable description of the program
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // that will be invoked given the provided URL spec. This is used only to
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // populate the external protocol dialog box the user sees when invoking
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // an unknown external protocol.
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  wchar_t out_buffer[1024];
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DWORD buffer_size = arraysize(out_buffer);
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HRESULT hr = AssocQueryString(ASSOCF_IS_PROTOCOL,
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                ASSOCSTR_FRIENDLYAPPNAME,
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                url_scheme.c_str(),
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                NULL,
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                out_buffer,
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                &buffer_size);
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (FAILED(hr)) {
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DLOG(WARNING) << "AssocQueryString failed!";
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return base::string16();
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::string16(out_buffer);
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::string16 GetAppForProtocolUsingRegistry(const GURL& url) {
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::string16 url_spec = base::ASCIIToWide(url.possibly_invalid_spec());
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const base::string16 cmd_key_path =
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::ASCIIToWide(url.scheme() + "\\shell\\open\\command");
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::win::RegKey cmd_key(HKEY_CLASSES_ROOT,
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            cmd_key_path.c_str(),
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            KEY_READ);
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  size_t split_offset = url_spec.find(L':');
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (split_offset == base::string16::npos)
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return base::string16();
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const base::string16 parameters = url_spec.substr(split_offset + 1,
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                    url_spec.length() - 1);
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::string16 application_to_launch;
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (cmd_key.ReadValue(NULL, &application_to_launch) == ERROR_SUCCESS) {
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ReplaceSubstringsAfterOffset(&application_to_launch,
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 0,
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 L"%1",
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 parameters);
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return application_to_launch;
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::string16();
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientState
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GetDefaultWebClientStateFromShellUtilDefaultState(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShellUtil::DefaultState default_state) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (default_state) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::NOT_DEFAULT:
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ShellIntegration::NOT_DEFAULT;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ShellUtil::IS_DEFAULT:
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ShellIntegration::IS_DEFAULT;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(ShellUtil::UNKNOWN_DEFAULT, default_state);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ShellIntegration::UNKNOWN_DEFAULT;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientSetPermission
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellIntegration::CanSetAsDefaultBrowser() {
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (distribution->GetDefaultBrowserControlPolicy() !=
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          BrowserDistribution::DEFAULT_BROWSER_FULL_CONTROL)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SET_DEFAULT_NOT_ALLOWED;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShellUtil::CanMakeChromeDefaultUnattended())
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SET_DEFAULT_UNATTENDED;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SET_DEFAULT_INTERACTIVE;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultBrowser() {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error getting app exe path";
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // From UI currently we only allow setting default browser for current user.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    chrome_exe.value(), true)) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Chrome could not be set as default browser.";
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Chrome registered as default browser.";
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultProtocolClient(const std::string& protocol) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (protocol.empty())
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error getting app exe path";
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 wprotocol(base::UTF8ToUTF16(protocol));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::MakeChromeDefaultProtocolClient(dist, chrome_exe.value(),
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wprotocol)) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Chrome could not be set as default handler for "
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << protocol << ".";
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Chrome registered as default handler for " << protocol << ".";
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultBrowserInteractive() {
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Error getting app exe path";
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::ShowMakeChromeDefaultSystemUI(dist, chrome_exe.value())) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to launch the set-default-browser Windows UI.";
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Set-default-browser Windows UI completed.";
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::SetAsDefaultProtocolClientInteractive(
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& protocol) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Error getting app exe path";
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 wprotocol(base::UTF8ToUTF16(protocol));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ShellUtil::ShowMakeChromeDefaultProtocolClientSystemUI(
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          dist, chrome_exe.value(), wprotocol)) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to launch the set-default-client Windows UI.";
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Set-default-client Windows UI completed.";
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ShellIntegration::DefaultWebClientState ShellIntegration::GetDefaultBrowser() {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetDefaultWebClientStateFromShellUtilDefaultState(
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellUtil::GetChromeDefaultState());
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ShellIntegration::DefaultWebClientState
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShellIntegration::IsDefaultProtocolClient(const std::string& protocol) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetDefaultWebClientStateFromShellUtilDefaultState(
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ShellUtil::GetChromeDefaultProtocolClientState(
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::UTF8ToUTF16(protocol)));
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::string16 ShellIntegration::GetApplicationNameForProtocol(
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const GURL& url) {
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Windows 8 or above requires a new protocol association query.
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_WIN8)
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return GetAppForProtocolUsingAssocQuery(url);
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return GetAppForProtocolUsingRegistry(url);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There is no reliable way to say which browser is default on a machine (each
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// browser can have some of the protocols/shortcuts). So we look for only HTTP
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// protocol handler. Even this handler is located at different places in
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registry on XP and Vista:
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - HKCR\http\shell\open\command (XP)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   http\UserChoice (Vista)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method checks if Firefox is defualt browser by checking these
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// locations and returns true if Firefox traces are found there. In case of
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error (or if Firefox is not found)it returns the default value which
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is false.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellIntegration::IsFirefoxDefaultBrowser() {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ff_default = false;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 app_cmd;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::RegKey key(HKEY_CURRENT_USER,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          ShellUtil::kRegVistaUrlPrefs, KEY_READ);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) &&
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        app_cmd == L"FirefoxURL")
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ff_default = true;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 key_path(L"http");
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_path.append(ShellUtil::kRegShellOpen);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ);
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 app_cmd;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) &&
3876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        base::string16::npos !=
3886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        base::StringToLowerASCII(app_cmd).find(L"firefox"))
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ff_default = true;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ff_default;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellIntegration::GetAppModelIdForProfile(
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& app_name,
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& profile_path) {
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<base::string16> components;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  components.push_back(app_name);
399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16 profile_id(GetProfileIdFromPath(profile_path));
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!profile_id.empty())
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    components.push_back(profile_id);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellUtil::BuildAppModelId(components);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellIntegration::GetChromiumModelIdForProfile(
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& profile_path) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return dist->GetBaseAppId();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAppModelIdForProfile(
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellUtil::GetBrowserModelId(
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())),
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_path);
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ShellIntegration::GetAppListAppModelIdForProfile(
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& profile_path) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ShellIntegration::GetAppModelIdForProfile(
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetAppListAppName(), profile_path);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ShellIntegration::MigrateChromiumShortcuts() {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_WIN7)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This needs to happen eventually (e.g. so that the appid is fixed and the
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // run-time Chrome icon is merged with the taskbar shortcut), but this is not
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // urgent and shouldn't delay Chrome startup.
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const int64 kMigrateChromiumShortcutsDelaySeconds = 15;
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostDelayedTask(
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&MigrateChromiumShortcutsCallback),
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta::FromSeconds(kMigrateChromiumShortcutsDelaySeconds));
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ShellIntegration::MigrateShortcutsInPathInternal(
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& chrome_exe,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path,
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool check_dual_mode) {
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7);
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Enumerate all pinned shortcuts in the given path directly.
446868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator shortcuts_enum(
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path, false,  // not recursive
448868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk"));
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_per_user_install =
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      InstallUtil::IsPerUserInstall(chrome_exe.value().c_str());
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int shortcuts_migrated = 0;
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath target_path;
455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 arguments;
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedPropVariant propvariant;
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       shortcut = shortcuts_enum.Next()) {
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(gab): Use ProgramCompare instead of comparing FilePaths below once
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // it is fixed to work with FilePaths with spaces.
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!base::win::ResolveShortcut(shortcut, &target_path, &arguments) ||
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        chrome_exe != target_path) {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CommandLine command_line(CommandLine::FromString(base::StringPrintf(
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        L"\"%ls\" %ls", target_path.value().c_str(), arguments.c_str())));
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Get the expected AppId for this Chrome shortcut.
469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 expected_app_id(
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetExpectedAppId(command_line, is_per_user_install));
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (expected_app_id.empty())
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Load the shortcut.
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::win::ScopedComPtr<IShellLink> shell_link;
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::win::ScopedComPtr<IPersistFile> persist_file;
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL,
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         CLSCTX_INPROC_SERVER)) ||
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FAILED(persist_file.QueryFrom(shell_link)) ||
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) {
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DLOG(WARNING) << "Failed loading shortcut at " << shortcut.value();
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Any properties that need to be updated on the shortcut will be stored in
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // |updated_properties|.
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::win::ShortcutProperties updated_properties;
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Validate the existing app id for the shortcut.
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::win::ScopedComPtr<IPropertyStore> property_store;
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    propvariant.Reset();
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (FAILED(property_store.QueryFrom(shell_link)) ||
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        property_store->GetValue(PKEY_AppUserModel_ID,
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 propvariant.Receive()) != S_OK) {
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // When in doubt, prefer not updating the shortcut.
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      switch (propvariant.get().vt) {
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case VT_EMPTY:
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          // If there is no app_id set, set our app_id if one is expected.
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (!expected_app_id.empty())
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            updated_properties.set_app_id(expected_app_id);
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case VT_LPWSTR:
506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          if (expected_app_id != base::string16(propvariant.get().pwszVal))
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            updated_properties.set_app_id(expected_app_id);
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        default:
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NOTREACHED();
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Only set dual mode if the expected app id is the default app id.
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 default_chromium_model_id(
518c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ShellUtil::GetBrowserModelId(dist, is_per_user_install));
519c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (check_dual_mode && expected_app_id == default_chromium_model_id) {
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      propvariant.Reset();
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   propvariant.Receive()) != S_OK) {
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // When in doubt, prefer to not update the shortcut.
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NOTREACHED();
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        switch (propvariant.get().vt) {
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          case VT_EMPTY:
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If dual_mode is not set at all, make sure it gets set to true.
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            updated_properties.set_dual_mode(true);
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            break;
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          case VT_BOOL:
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // If it is set to false, make sure it gets set to true as well.
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (!propvariant.get().boolVal)
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              updated_properties.set_dual_mode(true);
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            break;
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          default:
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            NOTREACHED();
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            continue;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    persist_file.Release();
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    shell_link.Release();
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Update the shortcut if some of its properties need to be updated.
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (updated_properties.options &&
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::win::CreateOrUpdateShortcutLink(
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            shortcut, updated_properties,
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::win::SHORTCUT_UPDATE_EXISTING)) {
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++shortcuts_migrated;
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return shortcuts_migrated;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath ShellIntegration::GetStartMenuShortcut(
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& chrome_exe) {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kFolderIds[] = {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DIR_COMMON_START_MENU,
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DIR_START_MENU,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
565a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 shortcut_name(
5663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME));
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath shortcut;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check both the common and the per-user Start Menu folders for system-level
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // installs.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t folder =
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()) ? 1 : 0;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; folder < arraysize(kFolderIds); ++folder) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!PathService::Get(kFolderIds[folder], &shortcut)) {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut = shortcut.Append(shortcut_name).Append(shortcut_name +
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     installer::kLnkExt);
5817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (base::PathExists(shortcut))
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return shortcut;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath();
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
587