Index: chrome/browser/shell_integration_win.cc |
=================================================================== |
--- chrome/browser/shell_integration_win.cc (revision 175243) |
+++ chrome/browser/shell_integration_win.cc (working copy) |
@@ -8,8 +8,6 @@ |
#include <shobjidl.h> |
#include <propkey.h> |
#include <propvarutil.h> |
-#include <tchar.h> |
-#include <strsafe.h> |
#include "base/bind.h" |
#include "base/command_line.h" |
@@ -39,9 +37,6 @@ |
#include "chrome/installer/util/work_item_list.h" |
#include "content/public/browser/browser_thread.h" |
-// propsys.lib is required for PropvariantTo*(). |
-#pragma comment(lib, "propsys.lib") |
- |
using content::BrowserThread; |
namespace { |
@@ -88,10 +83,54 @@ |
return profile_id; |
} |
-// Gets expected app id for given Chrome (based on |command_line| and |
-// |is_per_user_install|). |
-string16 GetExpectedAppId(const CommandLine& command_line, |
- bool is_per_user_install) { |
+bool GetShortcutAppId(IShellLink* shell_link, string16* app_id) { |
+ DCHECK(shell_link); |
+ DCHECK(app_id); |
+ |
+ app_id->clear(); |
+ |
+ base::win::ScopedComPtr<IPropertyStore> property_store; |
+ if (FAILED(property_store.QueryFrom(shell_link))) |
+ return false; |
+ |
+ PROPVARIANT appid_value; |
+ PropVariantInit(&appid_value); |
+ if (FAILED(property_store->GetValue(PKEY_AppUserModel_ID, &appid_value))) |
+ return false; |
+ |
+ if (appid_value.vt == VT_LPWSTR || appid_value.vt == VT_BSTR) |
+ app_id->assign(appid_value.pwszVal); |
+ |
+ PropVariantClear(&appid_value); |
+ return true; |
+} |
+ |
+// Gets expected app id for given chrome shortcut. Returns true if the shortcut |
+// points to chrome and expected app id is successfully derived. |
+bool GetExpectedAppId(const FilePath& chrome_exe, |
+ IShellLink* shell_link, |
+ string16* expected_app_id) { |
+ DCHECK(shell_link); |
+ DCHECK(expected_app_id); |
+ |
+ expected_app_id->clear(); |
+ |
+ // Check if the shortcut points to chrome_exe. |
+ string16 source; |
+ if (FAILED(shell_link->GetPath(WriteInto(&source, MAX_PATH), MAX_PATH, NULL, |
+ SLGP_RAWPATH)) || |
+ lstrcmpi(chrome_exe.value().c_str(), source.c_str())) |
+ return false; |
+ |
+ string16 arguments; |
+ if (FAILED(shell_link->GetArguments(WriteInto(&arguments, MAX_PATH), |
+ MAX_PATH))) |
+ return false; |
+ |
+ // Get expected app id from shortcut command line. |
+ CommandLine command_line = CommandLine::FromString(base::StringPrintf( |
+ L"\"%ls\" %ls", source.c_str(), arguments.c_str())); |
+ |
FilePath profile_path; |
if (command_line.HasSwitch(switches::kUserDataDir)) { |
profile_path = |
@@ -110,12 +149,59 @@ |
app_name = kAppListAppName; |
} else { |
BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
- app_name = ShellUtil::GetBrowserModelId(dist, is_per_user_install); |
+ app_name = ShellUtil::GetBrowserModelId( |
+ dist, InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())); |
} |
- return ShellIntegration::GetAppModelIdForProfile(app_name, profile_path); |
+ expected_app_id->assign( |
+ ShellIntegration::GetAppModelIdForProfile(app_name, profile_path)); |
+ return true; |
} |
+void MigrateWin7ShortcutsInPath( |
+ const FilePath& chrome_exe, const FilePath& path) { |
+ // Enumerate all pinned shortcuts in the given path directly. |
+ file_util::FileEnumerator shortcuts_enum( |
+ path, false, // not recursive |
+ file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk")); |
+ |
+ for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty(); |
+ shortcut = shortcuts_enum.Next()) { |
+ // Load the shortcut. |
+ base::win::ScopedComPtr<IShellLink> shell_link; |
+ if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL, |
+ CLSCTX_INPROC_SERVER))) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ base::win::ScopedComPtr<IPersistFile> persist_file; |
+ if (FAILED(persist_file.QueryFrom(shell_link)) || |
+ FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ // Get expected app id from shortcut. |
+ string16 expected_app_id; |
+ if (!GetExpectedAppId(chrome_exe, shell_link, &expected_app_id) || |
+ expected_app_id.empty()) |
+ continue; |
+ |
+ // Get existing app id from shortcut if any. |
+ string16 existing_app_id; |
+ GetShortcutAppId(shell_link, &existing_app_id); |
+ |
+ if (expected_app_id != existing_app_id) { |
+ base::win::ShortcutProperties properties_app_id_only; |
+ properties_app_id_only.set_app_id(expected_app_id); |
+ base::win::CreateOrUpdateShortcutLink( |
+ shortcut, properties_app_id_only, |
+ base::win::SHORTCUT_UPDATE_EXISTING); |
+ } |
+ } |
+} |
+ |
void MigrateChromiumShortcutsCallback() { |
// This should run on the file thread. |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
@@ -155,9 +241,7 @@ |
if (kLocations[i].sub_dir) |
path = path.Append(kLocations[i].sub_dir); |
- bool check_dual_mode = (kLocations[i].location_id == base::DIR_START_MENU); |
- ShellIntegration::MigrateShortcutsInPathInternal(chrome_exe, path, |
- check_dual_mode); |
+ MigrateWin7ShortcutsInPath(chrome_exe, path); |
} |
} |
@@ -369,125 +453,6 @@ |
base::TimeDelta::FromSeconds(kMigrateChromiumShortcutsDelaySeconds)); |
} |
-int ShellIntegration::MigrateShortcutsInPathInternal(const FilePath& chrome_exe, |
- const FilePath& path, |
- bool check_dual_mode) { |
- DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7); |
- |
- // Enumerate all pinned shortcuts in the given path directly. |
- file_util::FileEnumerator shortcuts_enum( |
- path, false, // not recursive |
- file_util::FileEnumerator::FILES, FILE_PATH_LITERAL("*.lnk")); |
- |
- bool is_per_user_install = |
- InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); |
- |
- int shortcuts_migrated = 0; |
- FilePath target_path; |
- string16 arguments; |
- string16 existing_app_id; |
- for (FilePath shortcut = shortcuts_enum.Next(); !shortcut.empty(); |
- shortcut = shortcuts_enum.Next()) { |
- // TODO(gab): Use ProgramCompare instead of comparing FilePaths below once |
- // it is fixed to work with FilePaths with spaces. |
- if (!base::win::ResolveShortcut(shortcut, &target_path, &arguments) || |
- chrome_exe != target_path) { |
- continue; |
- } |
- CommandLine command_line(CommandLine::FromString(base::StringPrintf( |
- L"\"%ls\" %ls", target_path.value().c_str(), arguments.c_str()))); |
- |
- // Get the expected AppId for this Chrome shortcut. |
- string16 expected_app_id( |
- GetExpectedAppId(command_line, is_per_user_install)); |
- if (expected_app_id.empty()) |
- continue; |
- |
- // Load the shortcut. |
- base::win::ScopedComPtr<IShellLink> shell_link; |
- base::win::ScopedComPtr<IPersistFile> persist_file; |
- if (FAILED(shell_link.CreateInstance(CLSID_ShellLink, NULL, |
- CLSCTX_INPROC_SERVER)) || |
- FAILED(persist_file.QueryFrom(shell_link)) || |
- FAILED(persist_file->Load(shortcut.value().c_str(), STGM_READ))) { |
- DLOG(WARNING) << "Failed loading shortcut at " << shortcut.value(); |
- continue; |
- } |
- |
- // Any properties that need to be updated on the shortcut will be stored in |
- // |updated_properties|. |
- base::win::ShortcutProperties updated_properties; |
- |
- // Validate the existing app id for the shortcut. |
- base::win::ScopedComPtr<IPropertyStore> property_store; |
- PROPVARIANT pv_app_id; |
- PropVariantInit(&pv_app_id); |
- if (FAILED(property_store.QueryFrom(shell_link)) || |
- property_store->GetValue(PKEY_AppUserModel_ID, &pv_app_id) != S_OK) { |
- // When in doubt, prefer not updating the shortcut. |
- NOTREACHED(); |
- continue; |
- } else if (pv_app_id.vt == VT_EMPTY) { |
- // If there is no app_id set, set our app_id if one is expected. |
- if (!expected_app_id.empty()) |
- updated_properties.set_app_id(expected_app_id); |
- } else { |
- // Validate that the existing app_id is the expected app_id; if not, set |
- // the expected app_id on the shortcut. |
- size_t expected_size = expected_app_id.size() + 1; |
- HRESULT result = PropVariantToString( |
- pv_app_id, WriteInto(&existing_app_id, expected_size), expected_size); |
- PropVariantClear(&pv_app_id); |
- if (result != S_OK && result != STRSAFE_E_INSUFFICIENT_BUFFER) { |
- // Accept the STRSAFE_E_INSUFFICIENT_BUFFER error state as it means the |
- // existing appid is longer than |expected_app_id| and thus we will |
- // simply assume inequality. |
- NOTREACHED(); |
- continue; |
- } else if (result == STRSAFE_E_INSUFFICIENT_BUFFER || |
- expected_app_id != existing_app_id) { |
- updated_properties.set_app_id(expected_app_id); |
- } |
- } |
- |
- if (check_dual_mode) { |
- BOOL existing_dual_mode; |
- PROPVARIANT pv_dual_mode; |
- PropVariantInit(&pv_dual_mode); |
- if (property_store->GetValue(PKEY_AppUserModel_IsDualMode, |
- &pv_dual_mode) != S_OK) { |
- // When in doubt, prefer to not update the shortcut. |
- NOTREACHED(); |
- continue; |
- } else if (pv_dual_mode.vt == VT_EMPTY) { |
- // If dual_mode is not set at all, make sure it gets set to true. |
- updated_properties.set_dual_mode(true); |
- } else { |
- // If it is set to false, make sure it gets set to true as well. |
- if (PropVariantToBoolean(pv_dual_mode, &existing_dual_mode) != S_OK) { |
- NOTREACHED(); |
- continue; |
- } |
- PropVariantClear(&pv_dual_mode); |
- if (!existing_dual_mode) |
- updated_properties.set_dual_mode(true); |
- } |
- } |
- |
- persist_file.Release(); |
- shell_link.Release(); |
- |
- // Update the shortcut if some of its properties need to be updated. |
- if (updated_properties.options && |
- base::win::CreateOrUpdateShortcutLink( |
- shortcut, updated_properties, |
- base::win::SHORTCUT_UPDATE_EXISTING)) { |
- ++shortcuts_migrated; |
- } |
- } |
- return shortcuts_migrated; |
-} |
- |
FilePath ShellIntegration::GetStartMenuShortcut(const FilePath& chrome_exe) { |
static const int kFolderIds[] = { |
base::DIR_COMMON_START_MENU, |