1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/shell_integration.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <windows.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <shobjidl.h>
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <propkey.h>
10731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <propvarutil.h>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/registry.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/win/scoped_comptr.h"
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/win/windows_version.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_applications/web_app.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths_internal.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/browser_distribution.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/create_reg_key_work_item.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/set_reg_value_work_item.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/shell_util.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/util_constants.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/work_item.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/work_item_list.h"
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper function for ShellIntegration::GetAppId to generates profile id
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// from profile path. "profile_id" is composed of sanitized basenames of
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// user data dir and profile dir joined by a ".".
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring GetProfileIdFromPath(const FilePath& profile_path) {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return empty string if profile_path is empty
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (profile_path.empty())
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return std::wstring();
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath default_user_data_dir;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return empty string if profile_path is in default user data
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // dir and is the default profile.
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (chrome::GetDefaultUserDataDirectory(&default_user_data_dir) &&
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_path.DirName() == default_user_data_dir &&
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_path.BaseName().value() ==
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          ASCIIToUTF16(chrome::kNotSignedInProfile)) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return std::wstring();
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get joined basenames of user data dir and profile.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring basenames = profile_path.DirName().BaseName().value() +
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      L"." + profile_path.BaseName().value();
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring profile_id;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_id.reserve(basenames.size());
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Generate profile_id from sanitized basenames.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < basenames.length(); ++i) {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (IsAsciiAlpha(basenames[i]) ||
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        IsAsciiDigit(basenames[i]) ||
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        basenames[i] == L'.')
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile_id += basenames[i];
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return profile_id;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Migrates existing chromium shortucts for Win7.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MigrateChromiumShortcutsTask : public Task {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MigrateChromiumShortcutsTask() { }
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run();
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void MigrateWin7Shortcuts();
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void MigrateWin7ShortcutsInPath(const FilePath& path) const;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get expected app id for given chrome shortcut.
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Returns true if the shortcut point to chrome and expected app id is
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // successfully derived.
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool GetExpectedAppId(IShellLink* shell_link,
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        std::wstring* expected_app_id) const;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get app id associated with given shortcut.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool GetShortcutAppId(IShellLink* shell_link, std::wstring* app_id) const;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath chrome_exe_;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(MigrateChromiumShortcutsTask);
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MigrateChromiumShortcutsTask::Run() {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This should run on the file thread.
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MigrateWin7Shortcuts();
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MigrateChromiumShortcutsTask::MigrateWin7Shortcuts() {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get full path of chrome.
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PathService::Get(base::FILE_EXE, &chrome_exe_))
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Locations to check for shortcuts migration.
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const struct {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int location_id;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const wchar_t* sub_dir;
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } kLocations[] = {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::DIR_APP_DATA,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar"
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }, {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::DIR_USER_DESKTOP,
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }, {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::DIR_START_MENU,
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NULL
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }, {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::DIR_APP_DATA,
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\StartMenu"
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < arraysize(kLocations); ++i) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    FilePath path;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!PathService::Get(kLocations[i].location_id, &path)) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (kLocations[i].sub_dir)
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      path = path.Append(kLocations[i].sub_dir);
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MigrateWin7ShortcutsInPath(path);
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid MigrateChromiumShortcutsTask::MigrateWin7ShortcutsInPath(
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const FilePath& path) const {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Enumerate all pinned shortcuts in the given path directly.
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_util::FileEnumerator shortcuts_enum(
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      path,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      false,  // not recursive
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      file_util::FileEnumerator::FILES,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FILE_PATH_LITERAL("*.lnk"));
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty();
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       shortcut = shortcuts_enum.Next()) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Load the shortcut.
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::win::ScopedComPtr<IShellLink> shell_link;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (FAILED(shell_link.CreateInstance(CLSID_ShellLink,
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         NULL,
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         CLSCTX_INPROC_SERVER))) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::win::ScopedComPtr<IPersistFile> persist_file;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (FAILED(persist_file.QueryFrom(shell_link)) ||
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Get expected app id from shortcut.
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring expected_app_id;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetExpectedAppId(shell_link, &expected_app_id) ||
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        expected_app_id.empty())
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Get existing app id from shortcut if any.
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring existing_app_id;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetShortcutAppId(shell_link, &existing_app_id);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (expected_app_id != existing_app_id) {
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      file_util::UpdateShortcutLink(NULL,
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    shortcut.value().c_str(),
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL,
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL,
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    NULL,
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    0,
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    expected_app_id.c_str());
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MigrateChromiumShortcutsTask::GetExpectedAppId(
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IShellLink* shell_link,
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring* expected_app_id) const {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(shell_link);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_app_id);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expected_app_id->clear();
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check if the shortcut points to chrome_exe.
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring source;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (FAILED(shell_link->GetPath(WriteInto(&source, MAX_PATH),
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 MAX_PATH,
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 NULL,
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 SLGP_RAWPATH)) ||
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      lstrcmpi(chrome_exe_.value().c_str(), source.c_str()))
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring arguments;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (FAILED(shell_link->GetArguments(WriteInto(&arguments, MAX_PATH),
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      MAX_PATH)))
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get expected app id from shortcut command line.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CommandLine command_line = CommandLine::FromString(StringPrintf(
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      L"\"%ls\" %ls", source.c_str(), arguments.c_str()));
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath profile_path;
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (command_line.HasSwitch(switches::kUserDataDir)) {
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    profile_path =
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        command_line.GetSwitchValuePath(switches::kUserDataDir).AppendASCII(
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            chrome::kNotSignedInProfile);
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring app_name;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (command_line.HasSwitch(switches::kApp)) {
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    app_name = UTF8ToWide(web_app::GenerateApplicationNameFromURL(
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        GURL(command_line.GetSwitchValueASCII(switches::kApp))));
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else if (command_line.HasSwitch(switches::kAppId)) {
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    app_name = UTF8ToWide(web_app::GenerateApplicationNameFromExtensionId(
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        command_line.GetSwitchValueASCII(switches::kAppId)));
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    app_name = BrowserDistribution::GetDistribution()->GetBrowserAppId();
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  expected_app_id->assign(ShellIntegration::GetAppId(app_name, profile_path));
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MigrateChromiumShortcutsTask::GetShortcutAppId(
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IShellLink* shell_link,
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring* app_id) const {
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(shell_link);
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(app_id);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  app_id->clear();
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::win::ScopedComPtr<IPropertyStore> property_store;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (FAILED(property_store.QueryFrom(shell_link)))
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PROPVARIANT appid_value;
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PropVariantInit(&appid_value);
257731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (FAILED(property_store->GetValue(PKEY_AppUserModel_ID,
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &appid_value)))
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (appid_value.vt == VT_LPWSTR ||
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      appid_value.vt == VT_BSTR)
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    app_id->assign(appid_value.pwszVal);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PropVariantClear(&appid_value);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShellIntegration::SetAsDefaultBrowser() {
27221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  FilePath chrome_exe;
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Error getting app exe path";
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From UI currently we only allow setting default browser for current user.
27921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
28021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
28121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                    chrome_exe.value(), true)) {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Chrome could not be set as default browser.";
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
286731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Chrome registered as default browser.";
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First determine the app path. If we can't determine what that is, we have
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // bigger fish to fry...
29321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  FilePath app_path;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!PathService::Get(base::FILE_EXE, &app_path)) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Error getting app exe path";
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return UNKNOWN_DEFAULT_BROWSER;
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When we check for default browser we don't necessarily want to count file
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // type handlers and icons as having changed the default browser status,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // since the user may have changed their shell settings to cause HTML files
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to open with a text editor for example. We also don't want to aggressively
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // claim FTP, since the user may have a separate FTP client. It is an open
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // question as to how to "heal" these settings. Perhaps the user should just
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // re-run the installer or run with the --set-default-browser command line
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // flag. There is doubtless some other key we can hook into to cause "Repair"
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to show up in Add/Remove programs for us.
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::wstring kChromeProtocols[] = {L"http", L"https"};
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IApplicationAssociationRegistration* pAAR;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration),
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (void**)&pAAR);
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!SUCCEEDED(hr))
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return NOT_DEFAULT_BROWSER;
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring app_name = dist->GetApplicationName();
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If a user specific default browser entry exists, we check for that
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // app name being default. If not, then default browser is just called
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Google Chrome or Chromium so we do not append suffix to app name.
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring suffix;
32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      app_name += suffix;
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < _countof(kChromeProtocols); i++) {
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BOOL result = TRUE;
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hr = pAAR->QueryAppIsDefault(kChromeProtocols[i].c_str(), AT_URLPROTOCOL,
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          AL_EFFECTIVE, app_name.c_str(), &result);
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!SUCCEEDED(hr) || result == FALSE) {
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        pAAR->Release();
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return NOT_DEFAULT_BROWSER;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    pAAR->Release();
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring short_app_path;
33821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    GetShortPathName(app_path.value().c_str(),
33921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                     WriteInto(&short_app_path, MAX_PATH),
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     MAX_PATH);
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // open command for protocol associations
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < _countof(kChromeProtocols); i++) {
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Check in HKEY_CLASSES_ROOT that is the result of merge between
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // HKLM and HKCU
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      HKEY root_key = HKEY_CLASSES_ROOT;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Check <protocol>\shell\open\command
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::wstring key_path(kChromeProtocols[i] + ShellUtil::kRegShellOpen);
349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      base::win::RegKey key(root_key, key_path.c_str(), KEY_READ);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::wstring value;
35172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!key.Valid() || (key.ReadValue(L"", &value) != ERROR_SUCCESS))
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return NOT_DEFAULT_BROWSER;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Need to normalize path in case it's been munged.
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CommandLine command_line = CommandLine::FromString(value);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::wstring short_path;
356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      GetShortPathName(command_line.GetProgram().value().c_str(),
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       WriteInto(&short_path, MAX_PATH), MAX_PATH);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!FilePath::CompareEqualIgnoreCase(short_path, short_app_path))
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return NOT_DEFAULT_BROWSER;
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IS_DEFAULT_BROWSER;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// There is no reliable way to say which browser is default on a machine (each
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// browser can have some of the protocols/shortcuts). So we look for only HTTP
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// protocol handler. Even this handler is located at different places in
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// registry on XP and Vista:
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// - HKCR\http\shell\open\command (XP)
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// - HKCU\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   http\UserChoice (Vista)
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method checks if Firefox is defualt browser by checking these
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// locations and returns true if Firefox traces are found there. In case of
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// error (or if Firefox is not found)it returns the default value which
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is false.
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ShellIntegration::IsFirefoxDefaultBrowser() {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool ff_default = false;
378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring app_cmd;
380731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::win::RegKey key(HKEY_CURRENT_USER,
381731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          ShellUtil::kRegVistaUrlPrefs, KEY_READ);
38272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (key.Valid() && (key.ReadValue(L"Progid", &app_cmd) == ERROR_SUCCESS) &&
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        app_cmd == L"FirefoxURL")
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ff_default = true;
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring key_path(L"http");
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    key_path.append(ShellUtil::kRegShellOpen);
388731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::win::RegKey key(HKEY_CLASSES_ROOT, key_path.c_str(), KEY_READ);
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::wstring app_cmd;
39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (key.Valid() && (key.ReadValue(L"", &app_cmd) == ERROR_SUCCESS) &&
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::wstring::npos != StringToLowerASCII(app_cmd).find(L"firefox"))
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ff_default = true;
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ff_default;
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring ShellIntegration::GetAppId(const std::wstring& app_name,
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const FilePath& profile_path) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring app_id(app_name);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring profile_id(GetProfileIdFromPath(profile_path));
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!profile_id.empty()) {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    app_id += L".";
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    app_id += profile_id;
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // App id should be less than 128 chars.
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(app_id.length() < 128);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return app_id;
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::wstring ShellIntegration::GetChromiumAppId(const FilePath& profile_path) {
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetAppId(BrowserDistribution::GetDistribution()->GetBrowserAppId(),
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  profile_path);
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ShellIntegration::MigrateChromiumShortcuts() {
418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (base::win::GetVersion() < base::win::VERSION_WIN7)
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
422731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE, new MigrateChromiumShortcutsTask());
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
424