diff options
-rw-r--r-- | base/file_util.h | 47 | ||||
-rw-r--r-- | base/file_util_unittest.cc | 9 | ||||
-rw-r--r-- | base/file_util_win.cc | 104 | ||||
-rw-r--r-- | base/win/win_util.cc | 89 | ||||
-rw-r--r-- | base/win/win_util.h | 4 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_main_win.cc | 4 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_win.cc | 5 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_shortcut_manager_win.cc | 6 | ||||
-rw-r--r-- | chrome/browser/shell_integration_win.cc | 6 | ||||
-rw-r--r-- | chrome/browser/ui/web_applications/web_app_ui.cc | 6 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app_win.cc | 6 | ||||
-rw-r--r-- | chrome/installer/setup/install.cc | 33 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 16 | ||||
-rw-r--r-- | chrome/installer/util/shell_util.cc | 63 | ||||
-rw-r--r-- | chrome/installer/util/shell_util.h | 37 | ||||
-rw-r--r-- | chrome/installer/util/shell_util_unittest.cc | 199 |
16 files changed, 354 insertions, 280 deletions
diff --git a/base/file_util.h b/base/file_util.h index 45f590b..b6e634d 100644 --- a/base/file_util.h +++ b/base/file_util.h @@ -196,45 +196,40 @@ BASE_EXPORT bool ReadSymbolicLink(const FilePath& symlink, FilePath* target); #endif // defined(OS_POSIX) #if defined(OS_WIN) +enum ShortcutOptions { + SHORTCUT_NO_OPTIONS = 0, + // Set DualMode property for Windows 8 Metro-enabled shortcuts. + SHORTCUT_DUAL_MODE = 1 << 0, + // Create a new shortcut (overwriting if necessary). If not specified, only + // non-null properties on an existing shortcut will be modified. + SHORTCUT_CREATE_ALWAYS = 1 << 1, +}; + // Resolve Windows shortcut (.LNK file) // This methods tries to resolve a shortcut .LNK file. If the |path| is valid // returns true and puts the target into the |path|, otherwise returns // false leaving the path as it is. BASE_EXPORT bool ResolveShortcut(FilePath* path); -// Create a Windows shortcut (.LNK file) -// This method creates a shortcut link using the information given. Ensure -// you have initialized COM before calling into this function. 'source' -// and 'destination' parameters are required, everything else can be NULL. -// 'source' is the existing file, 'destination' is the new link file to be +// Creates (or updates) a Windows shortcut (.LNK file) +// This method creates (or updates) a shortcut link using the information given. +// Ensure you have initialized COM before calling into this function. +// |destination| is required. |source| is required when SHORTCUT_CREATE_ALWAYS +// is specified in |options|. All other parameters are optional and may be NULL. +// |source| is the existing file, |destination| is the new link file to be // created; for best results pass the filename with the .lnk extension. -// The 'icon' can specify a dll or exe in which case the icon index is the -// resource id. 'app_id' is the app model id for the shortcut on Win7. -// Note that if the shortcut exists it will overwrite it. -BASE_EXPORT bool CreateShortcutLink(const wchar_t *source, - const wchar_t *destination, - const wchar_t *working_dir, - const wchar_t *arguments, - const wchar_t *description, - const wchar_t *icon, - int icon_index, - const wchar_t* app_id); - -// Update a Windows shortcut (.LNK file). This method assumes the shortcut -// link already exists (otherwise false is returned). Ensure you have -// initialized COM before calling into this function. Only 'destination' -// parameter is required, everything else can be NULL (but if everything else -// is NULL no changes are made to the shortcut). 'destination' is the link -// file to be updated. 'app_id' is the app model id for the shortcut on Win7. -// For best results pass the filename with the .lnk extension. -BASE_EXPORT bool UpdateShortcutLink(const wchar_t *source, +// The |icon| can specify a dll or exe in which case the icon index is the +// resource id. |app_id| is the app model id for the shortcut on Win7. +// |options|: bitfield for which the options come from ShortcutOptions. +BASE_EXPORT bool CreateOrUpdateShortcutLink(const wchar_t *source, const wchar_t *destination, const wchar_t *working_dir, const wchar_t *arguments, const wchar_t *description, const wchar_t *icon, int icon_index, - const wchar_t* app_id); + const wchar_t* app_id, + uint32 options); // Pins a shortcut to the Windows 7 taskbar. The shortcut file must already // exist and be a shortcut that points to an executable. diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc index 4542af4..30db82c 100644 --- a/base/file_util_unittest.cc +++ b/base/file_util_unittest.cc @@ -1458,16 +1458,17 @@ TEST_F(FileUtilTest, ResolveShortcutTest) { } TEST_F(FileUtilTest, CreateShortcutTest) { - const wchar_t file_contents[] = L"This is another target."; + const wchar_t* file_contents = L"This is another target."; FilePath target_file = temp_dir_.path().Append(L"Target1.txt"); CreateTextFile(target_file, file_contents); FilePath link_file = temp_dir_.path().Append(L"Link1.lnk"); CoInitialize(NULL); - EXPECT_TRUE(file_util::CreateShortcutLink(target_file.value().c_str(), - link_file.value().c_str(), - NULL, NULL, NULL, NULL, 0, NULL)); + EXPECT_TRUE(file_util::CreateOrUpdateShortcutLink( + target_file.value().c_str(), link_file.value().c_str(), NULL, + NULL, NULL, NULL, 0, NULL, + file_util::SHORTCUT_CREATE_ALWAYS)); FilePath resolved_name = link_file; EXPECT_TRUE(file_util::ResolveShortcut(&resolved_name)); std::wstring read_contents = ReadTextFile(resolved_name); diff --git a/base/file_util_win.cc b/base/file_util_win.cc index 7ea1aa3..7d28f5c 100644 --- a/base/file_util_win.cc +++ b/base/file_util_win.cc @@ -365,81 +365,40 @@ bool ResolveShortcut(FilePath* path) { return is_resolved; } -bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination, - const wchar_t *working_dir, const wchar_t *arguments, - const wchar_t *description, const wchar_t *icon, - int icon_index, const wchar_t* app_id) { +bool CreateOrUpdateShortcutLink(const wchar_t *source, + const wchar_t *destination, + const wchar_t *working_dir, + const wchar_t *arguments, + const wchar_t *description, + const wchar_t *icon, + int icon_index, + const wchar_t* app_id, + uint32 options) { base::ThreadRestrictions::AssertIOAllowed(); - // Length of description must be less than MAX_PATH. - DCHECK(lstrlen(description) < MAX_PATH); - - base::win::ScopedComPtr<IShellLink> i_shell_link; - base::win::ScopedComPtr<IPersistFile> i_persist_file; - - // Get pointer to the IShellLink interface - HRESULT result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER); - if (FAILED(result)) - return false; - - // Query IShellLink for the IPersistFile interface - result = i_persist_file.QueryFrom(i_shell_link); - if (FAILED(result)) - return false; + bool create = (options & SHORTCUT_CREATE_ALWAYS) != 0; - if (FAILED(i_shell_link->SetPath(source))) - return false; - - if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) - return false; - - if (arguments && FAILED(i_shell_link->SetArguments(arguments))) - return false; - - if (description && FAILED(i_shell_link->SetDescription(description))) - return false; - - if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) - return false; - - if (app_id && (base::win::GetVersion() >= base::win::VERSION_WIN7)) { - base::win::ScopedComPtr<IPropertyStore> property_store; - if (FAILED(property_store.QueryFrom(i_shell_link))) - return false; - - if (!base::win::SetAppIdForPropertyStore(property_store, app_id)) - return false; - } - - result = i_persist_file->Save(destination, TRUE); - return SUCCEEDED(result); -} - -bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination, - const wchar_t *working_dir, const wchar_t *arguments, - const wchar_t *description, const wchar_t *icon, - int icon_index, const wchar_t* app_id) { - base::ThreadRestrictions::AssertIOAllowed(); + // |source| is required when SHORTCUT_CREATE_ALWAYS is specified. + DCHECK(source || !create); // Length of arguments and description must be less than MAX_PATH. DCHECK(lstrlen(arguments) < MAX_PATH); DCHECK(lstrlen(description) < MAX_PATH); - // Get pointer to the IPersistFile interface and load existing link base::win::ScopedComPtr<IShellLink> i_shell_link; - if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER))) - return false; - base::win::ScopedComPtr<IPersistFile> i_persist_file; - if (FAILED(i_persist_file.QueryFrom(i_shell_link))) + + // Get pointer to the IShellLink interface + if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER)) || + FAILED(i_persist_file.QueryFrom(i_shell_link))) { return false; + } - if (FAILED(i_persist_file->Load(destination, STGM_READWRITE))) + if (!create && FAILED(i_persist_file->Load(destination, STGM_READWRITE))) return false; - if (source && FAILED(i_shell_link->SetPath(source))) + if ((source || create) && FAILED(i_shell_link->SetPath(source))) return false; if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) @@ -454,22 +413,31 @@ bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination, if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) return false; - if (app_id && base::win::GetVersion() >= base::win::VERSION_WIN7) { + bool is_dual_mode = (options & SHORTCUT_DUAL_MODE) != 0; + if ((app_id || is_dual_mode) && + base::win::GetVersion() >= base::win::VERSION_WIN7) { base::win::ScopedComPtr<IPropertyStore> property_store; - if (FAILED(property_store.QueryFrom(i_shell_link))) + if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get()) return false; - if (!base::win::SetAppIdForPropertyStore(property_store, app_id)) + if (app_id && !base::win::SetAppIdForPropertyStore(property_store, app_id)) return false; + if (is_dual_mode && + base::win::GetVersion() >= base::win::VERSION_WIN8 && + !base::win::SetDualModeForPropertyStore(property_store)) { + return false; + } } HRESULT result = i_persist_file->Save(destination, TRUE); - i_persist_file.Release(); - i_shell_link.Release(); - // If we successfully updated the icon, notify the shell that we have done so. - if (SUCCEEDED(result)) { + if (!create && SUCCEEDED(result)) { + // Release the interfaces in case the SHChangeNotify call below depends on + // the operations above being fully completed. + i_persist_file.Release(); + i_shell_link.Release(); + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSHNOWAIT, NULL, NULL); } diff --git a/base/win/win_util.cc b/base/win/win_util.cc index 8dd5afc..c72a474 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc @@ -20,6 +20,49 @@ #include "base/win/scoped_handle.h" #include "base/win/windows_version.h" +namespace { + +#if !defined(_WIN32_WINNT_WIN8) +// TODO(gab): These definitions are temporary and should be removed once the +// win8 SDK has been imported into third_party/ + +// Using the same definition as in +// third_party\platformsdk_win7\files\Include\propkeydef.h +// without DECLSPEC_SELECTANY... +#define DEFINE_WIN8_PROPERTYKEY(name, l, w1, w2, \ + b1, b2, b3, b4, b5, b6, b7, b8, \ + pid) \ + const PROPERTYKEY name = { { l, w1, w2, \ + { b1, b2, b3, b4, b5, b6, b7, b8 } }, \ + pid } + +DEFINE_WIN8_PROPERTYKEY(PKEY_AppUserModel_DualMode, 0x9F4C2855, 0x9F79, 0x4B39, + 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 11); +DEFINE_WIN8_PROPERTYKEY(PKEY_AppUserModel_DualMode_UK, 0x9F4C2855, 0x9F79, + 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, + 18); + +#undef DEFINE_WIN8_PROPERTYKEY +#endif + +// Sets the value of |property_key| to |property_value| in |property_store|. +// Clears the PropVariant contained in |property_value|. +bool SetPropVariantValueForPropertyStore( + IPropertyStore* property_store, + const PROPERTYKEY& property_key, + PROPVARIANT* property_value) { + DCHECK(property_store); + + HRESULT result = property_store->SetValue(property_key, *property_value); + if (result == S_OK) + result = property_store->Commit(); + + PropVariantClear(property_value); + return SUCCEEDED(result); +} + +} // namespace + namespace base { namespace win { @@ -99,21 +142,40 @@ bool UserAccountControlIsEnabled() { return (uac_enabled != 0); } +bool SetBooleanValueForPropertyStore(IPropertyStore* property_store, + const PROPERTYKEY& property_key, + bool property_bool_value) { + PROPVARIANT property_value; + if (FAILED(InitPropVariantFromBoolean(property_bool_value, &property_value))) + return false; + + return SetPropVariantValueForPropertyStore(property_store, + property_key, + &property_value); +} + +bool SetUInt32ValueForPropertyStore(IPropertyStore* property_store, + const PROPERTYKEY& property_key, + uint32 property_uint32_value) { + PROPVARIANT property_value; + if (FAILED(InitPropVariantFromUInt32(property_uint32_value, &property_value))) + return false; + + return SetPropVariantValueForPropertyStore(property_store, + property_key, + &property_value); +} + bool SetStringValueForPropertyStore(IPropertyStore* property_store, const PROPERTYKEY& property_key, const wchar_t* property_string_value) { - DCHECK(property_store); - PROPVARIANT property_value; if (FAILED(InitPropVariantFromString(property_string_value, &property_value))) return false; - HRESULT result = property_store->SetValue(property_key, property_value); - if (S_OK == result) - result = property_store->Commit(); - - PropVariantClear(&property_value); - return SUCCEEDED(result); + return SetPropVariantValueForPropertyStore(property_store, + property_key, + &property_value); } bool SetAppIdForPropertyStore(IPropertyStore* property_store, @@ -128,6 +190,17 @@ bool SetAppIdForPropertyStore(IPropertyStore* property_store, app_id); } +bool SetDualModeForPropertyStore(IPropertyStore* property_store) { + DCHECK_GE(base::win::GetVersion(), base::win::VERSION_WIN8); + + return SetBooleanValueForPropertyStore(property_store, + PKEY_AppUserModel_DualMode, + true) && + SetUInt32ValueForPropertyStore(property_store, + PKEY_AppUserModel_DualMode_UK, + 1U); +} + static const char16 kAutoRunKeyPath[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; diff --git a/base/win/win_util.h b/base/win/win_util.h index 733f2092..e831cd7 100644 --- a/base/win/win_util.h +++ b/base/win/win_util.h @@ -79,6 +79,10 @@ BASE_EXPORT bool SetStringValueForPropertyStore( BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store, const wchar_t* app_id); +// Sets the DualModeApp property to true in |property_store|. The function is +// intended for tagging dual mode applications in Win8. +BASE_EXPORT bool SetDualModeForPropertyStore(IPropertyStore* property_store); + // Adds the specified |command| using the specified |name| to the AutoRun key. // |root_key| could be HKCU or HKLM or the root of any user hive. BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key, const string16& name, diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc index 44dde1a..22885d2 100644 --- a/chrome/browser/chrome_browser_main_win.cc +++ b/chrome/browser/chrome_browser_main_win.cc @@ -139,8 +139,8 @@ int DoUninstallTasks(bool chrome_still_running) { // We want to remove user level shortcuts and we only care about the ones // created by us and not by the installer so |alternate| is false. BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER, - false)) { + if (!ShellUtil::RemoveChromeDesktopShortcut( + dist, ShellUtil::CURRENT_USER, ShellUtil::SHORTCUT_NO_OPTIONS)) { VLOG(1) << "Failed to delete desktop shortcut."; } if (!ShellUtil::RemoveChromeDesktopShortcutsWithAppendedNames( diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc index b2e0479..257d5d0 100644 --- a/chrome/browser/first_run/first_run_win.cc +++ b/chrome/browser/first_run/first_run_win.cc @@ -122,8 +122,7 @@ bool CreateChromeDesktopShortcut() { chrome_exe.value(), dist->GetIconIndex(), ShellUtil::CURRENT_USER, - false, - true); // create if doesn't exist. + ShellUtil::SHORTCUT_CREATE_ALWAYS); } // Creates the quick launch shortcut to chrome for the current user. Returns @@ -137,7 +136,7 @@ bool CreateChromeQuickLaunchShortcut() { dist, chrome_exe.value(), ShellUtil::CURRENT_USER, // create only for current user. - true); // create if doesn't exist. + ShellUtil::SHORTCUT_CREATE_ALWAYS); } void PlatformSetup(Profile* profile) { diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc index 5177c56..1e2632e 100644 --- a/chrome/browser/profiles/profile_shortcut_manager_win.cc +++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc @@ -150,8 +150,8 @@ void CreateChromeDesktopShortcutForProfile( icon_path.empty() ? chrome_exe.value() : icon_path.value(), icon_path.empty() ? dist->GetIconIndex() : 0, ShellUtil::CURRENT_USER, - false, // Use alternate text. - create); // Create if it doesn't already exist. + create ? ShellUtil::SHORTCUT_CREATE_ALWAYS : + ShellUtil::SHORTCUT_NO_OPTIONS); } // Renames an existing Chrome desktop profile shortcut. Must be called on the @@ -203,7 +203,7 @@ void UpdateChromeDesktopShortcutForProfile( description, icon_path.empty() ? chrome_exe.value() : icon_path.value(), icon_path.empty() ? dist->GetIconIndex() : 0, - false); + ShellUtil::SHORTCUT_NO_OPTIONS); } void DeleteAutoLaunchValueForProfile( diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index f4b75e6..14e5f82 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc @@ -181,8 +181,10 @@ void MigrateWin7ShortcutsInPath( GetShortcutAppId(shell_link, &existing_app_id); if (expected_app_id != existing_app_id) { - file_util::UpdateShortcutLink(NULL, shortcut.value().c_str(), NULL, NULL, - NULL, NULL, 0, expected_app_id.c_str()); + file_util::CreateOrUpdateShortcutLink(NULL, shortcut.value().c_str(), + NULL, NULL, NULL, NULL, 0, + expected_app_id.c_str(), + file_util::SHORTCUT_NO_OPTIONS); } } } diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc index 9413d2b..6a034f4 100644 --- a/chrome/browser/ui/web_applications/web_app_ui.cc +++ b/chrome/browser/ui/web_applications/web_app_ui.cc @@ -257,14 +257,16 @@ void UpdateShortcutWorker::UpdateShortcutsOnFileThread() { shortcut_info_.description.resize(MAX_PATH - 1); for (size_t i = 0; i < shortcut_files_.size(); ++i) { - file_util::UpdateShortcutLink(NULL, + file_util::CreateOrUpdateShortcutLink( + NULL, shortcut_files_[i].value().c_str(), NULL, NULL, shortcut_info_.description.c_str(), icon_file.value().c_str(), 0, - app_id.c_str()); + app_id.c_str(), + file_util::SHORTCUT_NO_OPTIONS); } } diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc index 97086c90..5a99442 100644 --- a/chrome/browser/web_applications/web_app_win.cc +++ b/chrome/browser/web_applications/web_app_win.cc @@ -229,14 +229,16 @@ void CreateShortcutTask(const FilePath& web_app_path, StringPrintf(" (%d)", unique_number)); } - success &= file_util::CreateShortcutLink(chrome_exe.value().c_str(), + success = file_util::CreateOrUpdateShortcutLink( + chrome_exe.value().c_str(), shortcut_file.value().c_str(), chrome_folder.value().c_str(), wide_switches.c_str(), description.c_str(), icon_file.value().c_str(), 0, - app_id.c_str()); + app_id.c_str(), + file_util::SHORTCUT_CREATE_ALWAYS) && success; // Any shortcut would work for the pinning. We use the first one. if (success && pin_to_taskbar && shortcut_to_pin.empty()) diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index f8c8e24..a434478 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -87,13 +87,13 @@ void CopyPreferenceFileForFirstRun(const InstallerState& installer_state, // // If the shortcuts do not exist, the function does not recreate them during // update. +// |options|: bitfield for which the options come from ChromeShortcutOptions. void CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, const FilePath& setup_path, const Version& new_version, installer::InstallStatus install_status, const Product& product, - bool create_all_shortcut, - bool alt_shortcut) { + uint32 options) { // TODO(tommi): Change this function to use WorkItemList. DCHECK(product.is_chrome()); @@ -135,7 +135,9 @@ void CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, << chrome_link.value(); if (ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(), chrome_link.value(), L"", product_desc, chrome_exe.value(), - browser_dist->GetIconIndex(), true)) { + browser_dist->GetIconIndex(), + ShellUtil::SHORTCUT_DUAL_MODE | + ShellUtil::SHORTCUT_CREATE_ALWAYS)) { if (base::win::GetVersion() >= base::win::VERSION_WIN7) { VLOG(1) << "Pinning new shortcut at " << chrome_link.value() << " to taskbar"; @@ -153,7 +155,7 @@ void CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, << " to point to " << chrome_exe.value(); if (!ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(), chrome_link.value(), L"", product_desc, chrome_exe.value(), - browser_dist->GetIconIndex(), false)) { + browser_dist->GetIconIndex(), ShellUtil::SHORTCUT_DUAL_MODE)) { LOG(ERROR) << "Failed to update start menu shortcut at " << chrome_link.value(); } @@ -183,10 +185,11 @@ void CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, AppendUninstallCommandLineFlags(installer_state, product, &arguments); VLOG(1) << "Creating/updating uninstall link at " << uninstall_link.value(); - if (!file_util::CreateShortcutLink(setup_exe.value().c_str(), + if (!file_util::CreateOrUpdateShortcutLink(setup_exe.value().c_str(), uninstall_link.value().c_str(), NULL, arguments.GetCommandLineString().c_str(), NULL, - setup_exe.value().c_str(), 0, NULL)) { + setup_exe.value().c_str(), 0, NULL, + file_util::SHORTCUT_CREATE_ALWAYS)) { LOG(ERROR) << "Failed to create/update uninstall link in start menu " << " at " << uninstall_link.value(); } @@ -205,21 +208,20 @@ void CreateOrUpdateChromeShortcuts(const InstallerState& installer_state, } VLOG(1) << "Creating/updating desktop shortcut for " << chrome_exe.value() - << " will create new: " << create_all_shortcut; + << " will create new: " + << ((options & ShellUtil::SHORTCUT_CREATE_ALWAYS) != 0); if (!ShellUtil::CreateChromeDesktopShortcut(browser_dist, chrome_exe.value(), product_desc, L"", L"", chrome_exe.value(), - browser_dist->GetIconIndex(), desktop_level, alt_shortcut, - create_all_shortcut)) { + browser_dist->GetIconIndex(), desktop_level, options)) { LOG(WARNING) << "Did not create/update desktop shortcut for " << chrome_exe.value(); } VLOG(1) << "Creating/updating quick launch shortcut for " << chrome_exe.value() << " will create new: " - << create_all_shortcut; + << ((options & ShellUtil::SHORTCUT_CREATE_ALWAYS) != 0); if (!ShellUtil::CreateChromeQuickLaunchShortcut( - browser_dist, chrome_exe.value(), quick_launch_levels, - create_all_shortcut)) { + browser_dist, chrome_exe.value(), quick_launch_levels, options)) { LOG(WARNING) << "Did not create/update quick launch shortcut for " << chrome_exe.value(); } @@ -410,9 +412,14 @@ InstallStatus InstallOrUpdateProduct( &create_all_shortcut); bool alt_shortcut = false; prefs.GetBool(master_preferences::kAltShortcutText, &alt_shortcut); + uint32 shortcut_options = ShellUtil::SHORTCUT_NO_OPTIONS; + if (create_all_shortcut) + shortcut_options |= ShellUtil::SHORTCUT_CREATE_ALWAYS; + if (alt_shortcut) + shortcut_options |= ShellUtil::SHORTCUT_ALTERNATE; CreateOrUpdateChromeShortcuts(installer_state, setup_path, new_version, result, *chrome_install, - create_all_shortcut, alt_shortcut); + shortcut_options); bool make_chrome_default = false; prefs.GetBool(master_preferences::kMakeChromeDefault, diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 70284cc..83953e4 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -263,10 +263,14 @@ void DeleteChromeShortcuts(const InstallerState& installer_state, FilePath shortcut_path; if (installer_state.system_install()) { PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path); - if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), - ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, false)) { - ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), - ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, true); + if (!ShellUtil::RemoveChromeDesktopShortcut( + product.distribution(), + ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_NO_OPTIONS)) { + ShellUtil::RemoveChromeDesktopShortcut( + product.distribution(), + ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_ALTERNATE); } ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(), @@ -274,9 +278,9 @@ void DeleteChromeShortcuts(const InstallerState& installer_state, } else { PathService::Get(base::DIR_START_MENU, &shortcut_path); if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), - ShellUtil::CURRENT_USER, false)) { + ShellUtil::CURRENT_USER, ShellUtil::SHORTCUT_NO_OPTIONS)) { ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), - ShellUtil::CURRENT_USER, true); + ShellUtil::CURRENT_USER, ShellUtil::SHORTCUT_ALTERNATE); } ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(), diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index 6fc4224..5a5957b 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc @@ -511,6 +511,15 @@ bool LaunchApplicationAssociationDialog(const std::wstring& app_id) { return SUCCEEDED(hr); } +uint32 ConvertShellUtilShortcutOptionsToFileUtil(uint32 options) { + uint32 converted_options = 0; + if (options & ShellUtil::SHORTCUT_DUAL_MODE) + converted_options |= file_util::SHORTCUT_DUAL_MODE; + if (options & ShellUtil::SHORTCUT_CREATE_ALWAYS) + converted_options |= file_util::SHORTCUT_CREATE_ALWAYS; + return converted_options; +} + } // namespace const wchar_t* ShellUtil::kRegDefaultIcon = L"\\DefaultIcon"; @@ -567,9 +576,9 @@ bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, const std::wstring& icon_path, int icon_index, ShellChange shell_change, - bool alternate, - bool create_new) { + uint32 options) { std::wstring shortcut_name; + bool alternate = (options & ShellUtil::SHORTCUT_ALTERNATE) != 0; if (!ShellUtil::GetChromeShortcutName(dist, alternate, appended_name, &shortcut_name)) return false; @@ -594,7 +603,7 @@ bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, description, icon_path, icon_index, - create_new); + options); } } } else if (shell_change == ShellUtil::SYSTEM_LEVEL) { @@ -608,7 +617,7 @@ bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, description, icon_path, icon_index, - create_new); + options); } } else { NOTREACHED(); @@ -619,7 +628,7 @@ bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist, bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, int shell_change, - bool create_new) { + uint32 options) { std::wstring shortcut_name; if (!ShellUtil::GetChromeShortcutName(dist, false, L"", &shortcut_name)) return false; @@ -634,7 +643,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, user_ql_path.value(), L"", L"", chrome_exe, dist->GetIconIndex(), - create_new); + options); } else { ret = false; } @@ -650,7 +659,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, default_ql_path.value(), L"", L"", chrome_exe, dist->GetIconIndex(), - create_new) && ret; + options) && ret; } else { ret = false; } @@ -1009,8 +1018,12 @@ bool ShellUtil::RegisterChromeForProtocol(BrowserDistribution* dist, } bool ShellUtil::RemoveChromeDesktopShortcut(BrowserDistribution* dist, - int shell_change, bool alternate) { + int shell_change, uint32 options) { + // Only SHORTCUT_ALTERNATE is a valid option for this function. + DCHECK(!options || options == ShellUtil::SHORTCUT_ALTERNATE); + std::wstring shortcut_name; + bool alternate = (options & ShellUtil::SHORTCUT_ALTERNATE) != 0; if (!ShellUtil::GetChromeShortcutName(dist, alternate, L"", &shortcut_name)) return false; @@ -1095,7 +1108,7 @@ bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist, const std::wstring& description, const std::wstring& icon_path, int icon_index, - bool create_new) { + uint32 options) { std::wstring chrome_path = FilePath(chrome_exe).DirName().value(); FilePath prefs_path(chrome_path); @@ -1105,25 +1118,15 @@ bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist, prefs.GetInt(installer::master_preferences::kChromeShortcutIconIndex, &icon_index); } - if (create_new) { - return file_util::CreateShortcutLink( - chrome_exe.c_str(), // target - shortcut.c_str(), // shortcut - chrome_path.c_str(), // working dir - arguments.c_str(), // arguments - description.c_str(), // description - icon_path.c_str(), // icon file - icon_index, // icon index - dist->GetBrowserAppId().c_str()); // app id - } else { - return file_util::UpdateShortcutLink( - chrome_exe.c_str(), // target - shortcut.c_str(), // shortcut - chrome_path.c_str(), // working dir - arguments.c_str(), // arguments - description.c_str(), // description - icon_path.c_str(), // icon file - icon_index, // icon index - dist->GetBrowserAppId().c_str()); // app id - } + + return file_util::CreateOrUpdateShortcutLink( + chrome_exe.c_str(), + shortcut.c_str(), + chrome_path.c_str(), + arguments.c_str(), + description.c_str(), + icon_path.c_str(), + icon_index, + dist->GetBrowserAppId().c_str(), + ConvertShellUtilShortcutOptionsToFileUtil(options)); } diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h index 31b2f8b..8f55943 100644 --- a/chrome/installer/util/shell_util.h +++ b/chrome/installer/util/shell_util.h @@ -106,9 +106,7 @@ class ShellUtil { // Desktop folder of current user's profile. // If |shell_change| is SYSTEM_LEVEL, the shortcut is created in the // Desktop folder of the "All Users" profile. - // If |alternate| is true, an alternate text for the shortcut is used. - // If |create_new| is false, an existing shortcut will be updated, but if - // no shortcut exists, it will not be created. + // |options|: bitfield for which the options come from ChromeShortcutOptions. // Returns true iff the method causes a shortcut to be created / updated. static bool CreateChromeDesktopShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, @@ -118,8 +116,7 @@ class ShellUtil { const std::wstring& icon_path, int icon_index, ShellChange shell_change, - bool alternate, - bool create_new); + uint32 options); // Create Chrome shortcut on Quick Launch Bar. // If shell_change is CURRENT_USER, the shortcut is created in the @@ -128,12 +125,11 @@ class ShellUtil { // Quick Launch folder of "Default User" profile. This will make sure // that this shortcut will be seen by all the new users logging into the // system. - // create_new: If false, will only update the shortcut. If true, the function - // will create a new shortcut if it doesn't exist already. + // |options|: bitfield for which the options come from ChromeShortcutOptions. static bool CreateChromeQuickLaunchShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, int shell_change, - bool create_new); + uint32 options); // This method appends the Chrome icon index inside chrome.exe to the // chrome.exe path passed in as input, to generate the full path for @@ -264,15 +260,15 @@ class ShellUtil { bool elevate_if_not_admin); // Remove Chrome shortcut from Desktop. - // If shell_change is CURRENT_USER, the shortcut is removed from the + // If |shell_change| is CURRENT_USER, the shortcut is removed from the // Desktop folder of current user's profile. - // If shell_change is SYSTEM_LEVEL, the shortcut is removed from the + // If |shell_change| is SYSTEM_LEVEL, the shortcut is removed from the // Desktop folder of "All Users" profile. - // If alternate is true, the shortcut with the alternate name is removed. See - // CreateChromeDesktopShortcut() for more information. + // |options|: bitfield for which the options come from ChromeShortcutOptions. + // Only SHORTCUT_ALTERNATE is a valid option for this function. static bool RemoveChromeDesktopShortcut(BrowserDistribution* dist, int shell_change, - bool alternate); + uint32 options); // Removes a set of existing Chrome desktop shortcuts. |appended_names| is a // list of shortcut file names as obtained from @@ -288,11 +284,24 @@ class ShellUtil { static bool RemoveChromeQuickLaunchShortcut(BrowserDistribution* dist, int shell_change); + enum ChromeShortcutOptions { + SHORTCUT_NO_OPTIONS = 0, + // Set DualMode property for Windows 8 Metro-enabled shortcuts. + SHORTCUT_DUAL_MODE = 1 << 0, + // Create a new shortcut (overwriting if necessary). If not specified, only + // specified (non-null) properties are going to be modified on the existing + // shortcut (which has to exist). + SHORTCUT_CREATE_ALWAYS = 1 << 1, + // Use an alternate, localized, application name for the shortcut. + SHORTCUT_ALTERNATE = 1 << 2, + }; + // Updates shortcut (or creates a new shortcut) at destination given by // shortcut to a target given by chrome_exe. The arguments are given by // |arguments| for the target and icon is set based on |icon_path| and // |icon_index|. If create_new is set to true, the function will create a new // shortcut if it doesn't exist. + // |options|: bitfield for which the options come from ChromeShortcutOptions. static bool UpdateChromeShortcut(BrowserDistribution* dist, const std::wstring& chrome_exe, const std::wstring& shortcut, @@ -300,7 +309,7 @@ class ShellUtil { const std::wstring& description, const std::wstring& icon_path, int icon_index, - bool create_new); + uint32 options); private: DISALLOW_COPY_AND_ASSIGN(ShellUtil); diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc index 4df10aa..2ad39ac 100644 --- a/chrome/installer/util/shell_util_unittest.cc +++ b/chrome/installer/util/shell_util_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -109,14 +109,15 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { FilePath shortcut_path = temp_dir_.path().AppendASCII("shortcut.lnk"); const std::wstring description(L"dummy description"); - EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, - exe_path.value(), - shortcut_path.value(), - L"", - description, - exe_path.value(), - dist->GetIconIndex(), - true)); + EXPECT_TRUE(ShellUtil::UpdateChromeShortcut( + dist, + exe_path.value(), + shortcut_path.value(), + L"", + description, + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description, 0)); @@ -135,14 +136,15 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { "}"; file.close(); ASSERT_TRUE(file_util::Delete(shortcut_path, false)); - EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, - exe_path.value(), - shortcut_path.value(), - L"", - description, - exe_path.value(), - dist->GetIconIndex(), - true)); + EXPECT_TRUE(ShellUtil::UpdateChromeShortcut( + dist, + exe_path.value(), + shortcut_path.value(), + L"", + description, + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description, 1)); @@ -157,7 +159,7 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) { description2, exe_path.value(), dist->GetIconIndex(), - false)); + ShellUtil::SHORTCUT_NO_OPTIONS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), shortcut_path.value(), description2, 1)); @@ -211,96 +213,99 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { second_profile_shortcut_name); // Test simple creation of a user-level shortcut. - EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::CURRENT_USER, - false, - true)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::CURRENT_USER, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), user_shortcut_path.value(), description, 0)); - EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, - ShellUtil::CURRENT_USER, - false)); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut( + dist, + ShellUtil::CURRENT_USER, + ShellUtil::SHORTCUT_NO_OPTIONS)); // Test simple creation of a system-level shortcut. - EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::SYSTEM_LEVEL, - false, - true)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), system_shortcut_path.value(), description, 0)); - EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, - ShellUtil::SYSTEM_LEVEL, - false)); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut( + dist, + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_NO_OPTIONS)); // Test creation of a user-level shortcut when a system-level shortcut // is already present (should fail). - EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::SYSTEM_LEVEL, - false, - true)); - EXPECT_FALSE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::CURRENT_USER, - false, - true)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); + EXPECT_FALSE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::CURRENT_USER, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), system_shortcut_path.value(), description, 0)); EXPECT_FALSE(file_util::PathExists(user_shortcut_path)); - EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, - ShellUtil::SYSTEM_LEVEL, - false)); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut( + dist, + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_NO_OPTIONS)); // Test creation of a system-level shortcut when a user-level shortcut // is already present (should succeed). - EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::CURRENT_USER, - false, - true)); - EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(dist, - exe_path.value(), - description, - L"", - L"", - exe_path.value(), - dist->GetIconIndex(), - ShellUtil::SYSTEM_LEVEL, - false, - true)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::CURRENT_USER, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); + EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut( + dist, + exe_path.value(), + description, + L"", + L"", + exe_path.value(), + dist->GetIconIndex(), + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), user_shortcut_path.value(), description, @@ -309,12 +314,14 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { system_shortcut_path.value(), description, 0)); - EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, - ShellUtil::CURRENT_USER, - false)); - EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(dist, - ShellUtil::SYSTEM_LEVEL, - false)); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut( + dist, + ShellUtil::CURRENT_USER, + ShellUtil::SHORTCUT_NO_OPTIONS)); + EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut( + dist, + ShellUtil::SYSTEM_LEVEL, + ShellUtil::SHORTCUT_NO_OPTIONS)); // Test creation of two profile-specific shortcuts (these are always // user-level). @@ -327,8 +334,7 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { exe_path.value(), dist->GetIconIndex(), ShellUtil::CURRENT_USER, - false, - true)); + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), default_profile_shortcut_path.value(), description, @@ -342,8 +348,7 @@ TEST_F(ShellUtilTest, CreateChromeDesktopShortcutTest) { exe_path.value(), dist->GetIconIndex(), ShellUtil::CURRENT_USER, - false, - true)); + ShellUtil::SHORTCUT_CREATE_ALWAYS)); EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(), second_profile_shortcut_path.value(), description, |