summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgab@chromium.org <gab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 23:41:25 +0000
committergab@chromium.org <gab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-10 23:41:25 +0000
commitf2dd36c4bbe5926db2bf49741a50883610ff4137 (patch)
tree87f4e1f9ac3d4b9955bae7c3d5b16f629c6f7501
parenta99b6224b92e7dc822cd52d685a70194694e4074 (diff)
downloadchromium_src-f2dd36c4bbe5926db2bf49741a50883610ff4137.zip
chromium_src-f2dd36c4bbe5926db2bf49741a50883610ff4137.tar.gz
chromium_src-f2dd36c4bbe5926db2bf49741a50883610ff4137.tar.bz2
Refactoring and tests for the highly undertested file_util::CreateOrUpdateShortcutLink() method.
Simplify file_util::CreateOrUpdateShortcutLink()'s interface (use a struct to set parameters passed which allows callers to specify exactly what they want without having to pass in a bunch of NULLs for the unused parameters). The same concept will be used for ShellUtil's shortcut functions in an upcoming CL. Moved ShellUtil::VerifyChromeShortcut() to file_util::VerifyShortcut() and augmented it for every shortcut properties. This will also allow other shortcut creators (web apps, profiles, etc.) to have a broader test coverage on the shortcut they create (i.e. more testable properties available). I will leave it up to the owners of these various projects to augment their tests, this CL keeps the previously tested behavior, not more, not less. This is the 1st CL of a massive refactoring effort for shortcuts (http://goo.gl/Az889) in which ShellUtil's shortcut methods have to be refactored (http://codereview.chromium.org/10836247/ : soon to incorporate interface changes from this CL) which led me even lower to first refactor file_util's shortcut methods. BUG=132825 TEST=base_unittests --gtest_filter=FileUtilShortcutTest* installer_util_unitests --gtest_filter=ShellUtilTestWithDirAndDist* unit_tests --gtest_filter=ProfileShortcutManagerTest* Review URL: https://chromiumcodereview.appspot.com/10914109 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155869 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/base.gyp3
-rw-r--r--base/base.gypi2
-rw-r--r--base/file_util.h51
-rw-r--r--base/file_util_unittest.cc69
-rw-r--r--base/file_util_win.cc155
-rw-r--r--base/test/test_shortcut_win.cc142
-rw-r--r--base/test/test_shortcut_win.h38
-rw-r--r--base/win/shortcut.cc180
-rw-r--r--base/win/shortcut.h142
-rw-r--r--base/win/shortcut_unittest.cc221
-rw-r--r--base/win/win_util.cc10
-rw-r--r--base/win/win_util.h7
-rw-r--r--chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc56
-rw-r--r--chrome/browser/shell_integration_win.cc10
-rw-r--r--chrome/browser/ui/web_applications/web_app_ui.cc24
-rw-r--r--chrome/browser/web_applications/web_app_win.cc37
-rw-r--r--chrome/installer/setup/install.cc17
-rw-r--r--chrome/installer/setup/uninstall.cc3
-rw-r--r--chrome/installer/util/shell_util.cc78
-rw-r--r--chrome/installer/util/shell_util.h10
-rw-r--r--chrome/installer/util/shell_util_unittest.cc112
-rw-r--r--net/url_request/url_request_file_job.cc6
-rw-r--r--ui/base/dialogs/select_file_dialog_win.cc3
23 files changed, 907 insertions, 469 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 6384ac9..a24444b 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -523,6 +523,7 @@
'win/scoped_bstr_unittest.cc',
'win/scoped_comptr_unittest.cc',
'win/scoped_process_information_unittest.cc',
+ 'win/shortcut_unittest.cc',
'win/startup_information_unittest.cc',
'win/scoped_variant_unittest.cc',
'win/win_util_unittest.cc',
@@ -720,6 +721,8 @@
'test/test_listener_ios.mm',
'test/test_reg_util_win.cc',
'test/test_reg_util_win.h',
+ 'test/test_shortcut_win.cc',
+ 'test/test_shortcut_win.h',
'test/test_suite.cc',
'test/test_suite.h',
'test/test_support_android.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 84ba038..0652249 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -505,6 +505,8 @@
'win/scoped_process_information.cc',
'win/scoped_process_information.h',
'win/scoped_select_object.h',
+ 'win/shortcut.cc',
+ 'win/shortcut.h',
'win/startup_information.cc',
'win/startup_information.h',
'win/scoped_variant.cc',
diff --git a/base/file_util.h b/base/file_util.h
index 66fe51c..e6fad43 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -226,57 +226,6 @@ BASE_EXPORT bool SetPosixFilePermissions(const FilePath& path,
#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).
- SHORTCUT_CREATE_ALWAYS = 1 << 1,
-};
-
-// Resolve Windows shortcut (.LNK file)
-// This methods tries to resolve a shortcut .LNK file. The path of the shortcut
-// to resolve is in |shortcut_path|. If |target_path| is not NULL, the target
-// will be resolved and placed in |target_path|. If |args| is not NULL, the
-// arguments will be retrieved and placed in |args|. The function returns true
-// if all requested fields are are found successfully.
-// Callers can safely use the same variable for both |shortcut_path| and
-// |target_path|.
-BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
- FilePath* target_path,
- string16* args);
-
-// 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.
-// |options|: bitfield for which the options come from ShortcutOptions.
-// If SHORTCUT_CREATE_ALWAYS is not set in |options|, only specified (non-null)
-// properties on an existing shortcut will be modified. If the shortcut does not
-// exist, this method is a no-op and returns false.
-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,
- 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.
-BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
-
-// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
-// already be pinned to the taskbar.
-BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
-
// Copy from_path to to_path recursively and then delete from_path recursively.
// Returns true if all operations succeed.
// This function simulates Move(), but unlike Move() it works across volumes.
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index 5a99983..04de367 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -1592,75 +1592,6 @@ TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
// We don't need equivalent functionality outside of Windows.
#if defined(OS_WIN)
-TEST_F(FileUtilTest, ResolveShortcutTest) {
- FilePath target_file = temp_dir_.path().Append(L"Target.txt");
- CreateTextFile(target_file, L"This is the target.");
-
- FilePath link_file = temp_dir_.path().Append(L"Link.lnk");
-
- HRESULT result;
- IShellLink* shell = NULL;
- IPersistFile* persist = NULL;
-
- CoInitialize(NULL);
- // Temporarily create a shortcut for test
- result = CoCreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER, IID_IShellLink,
- reinterpret_cast<LPVOID*>(&shell));
- EXPECT_TRUE(SUCCEEDED(result));
- result = shell->QueryInterface(IID_IPersistFile,
- reinterpret_cast<LPVOID*>(&persist));
- EXPECT_TRUE(SUCCEEDED(result));
- result = shell->SetPath(target_file.value().c_str());
- EXPECT_TRUE(SUCCEEDED(result));
- result = shell->SetDescription(L"ResolveShortcutTest");
- EXPECT_TRUE(SUCCEEDED(result));
- result = shell->SetArguments(L"--args");
- EXPECT_TRUE(SUCCEEDED(result));
- result = persist->Save(link_file.value().c_str(), TRUE);
- EXPECT_TRUE(SUCCEEDED(result));
- if (persist)
- persist->Release();
- if (shell)
- shell->Release();
-
- bool is_solved;
- std::wstring args;
- is_solved = file_util::ResolveShortcut(link_file, &link_file, &args);
- EXPECT_TRUE(is_solved);
- EXPECT_EQ(L"--args", args);
- std::wstring contents;
- contents = ReadTextFile(link_file);
- EXPECT_EQ(L"This is the target.", contents);
-
- // Cleaning
- DeleteFile(target_file.value().c_str());
- DeleteFile(link_file.value().c_str());
- CoUninitialize();
-}
-
-TEST_F(FileUtilTest, CreateShortcutTest) {
- 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::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;
- EXPECT_TRUE(file_util::ResolveShortcut(link_file, &resolved_name, NULL));
- std::wstring read_contents = ReadTextFile(resolved_name);
- EXPECT_EQ(file_contents, read_contents);
-
- DeleteFile(target_file.value().c_str());
- DeleteFile(link_file.value().c_str());
- CoUninitialize();
-}
-
TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
// Create a directory
FilePath dir_name_from =
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index b88e131..e3ad3c2 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -5,7 +5,6 @@
#include "base/file_util.h"
#include <windows.h>
-#include <propvarutil.h>
#include <psapi.h>
#include <shellapi.h>
#include <shlobj.h>
@@ -23,10 +22,7 @@
#include "base/threading/thread_restrictions.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
-#include "base/win/pe_image.h"
-#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
-#include "base/win/win_util.h"
#include "base/win/windows_version.h"
namespace file_util {
@@ -332,157 +328,6 @@ bool GetFileCreationLocalTime(const std::wstring& filename,
return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
}
-bool ResolveShortcut(const FilePath& shortcut_path,
- FilePath* target_path,
- string16* args) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- HRESULT result;
- base::win::ScopedComPtr<IShellLink> i_shell_link;
-
- // Get pointer to the IShellLink interface.
- result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER);
- if (FAILED(result))
- return false;
-
- base::win::ScopedComPtr<IPersistFile> persist;
- // Query IShellLink for the IPersistFile interface.
- result = persist.QueryFrom(i_shell_link);
- if (FAILED(result))
- return false;
-
- // Load the shell link.
- result = persist->Load(shortcut_path.value().c_str(), STGM_READ);
- if (FAILED(result))
- return false;
-
- WCHAR temp[MAX_PATH];
- if (target_path) {
- // Try to find the target of a shortcut.
- result = i_shell_link->Resolve(0, SLR_NO_UI);
- if (FAILED(result))
- return false;
-
- result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY);
- if (FAILED(result))
- return false;
-
- *target_path = FilePath(temp);
- }
-
- if (args) {
- result = i_shell_link->GetArguments(temp, MAX_PATH);
- if (FAILED(result))
- return false;
-
- *args = string16(temp);
- }
- return true;
-}
-
-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();
-
- bool create = (options & SHORTCUT_CREATE_ALWAYS) != 0;
-
- // |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);
-
- base::win::ScopedComPtr<IShellLink> i_shell_link;
- base::win::ScopedComPtr<IPersistFile> i_persist_file;
-
- // 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 (!create && FAILED(i_persist_file->Load(destination, STGM_READWRITE)))
- return false;
-
- if ((source || create) && 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;
-
- 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)) || !property_store.get())
- return false;
-
- if (app_id && !base::win::SetAppIdForPropertyStore(property_store, app_id))
- return false;
- if (is_dual_mode &&
- !base::win::SetDualModeForPropertyStore(property_store)) {
- return false;
- }
- }
-
- HRESULT result = i_persist_file->Save(destination, TRUE);
-
- // If we successfully updated the icon, notify the shell that we have done so.
- 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, NULL, NULL);
- }
-
- return SUCCEEDED(result);
-}
-
-bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- // "Pin to taskbar" is only supported after Win7.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return false;
-
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
- NULL, NULL, 0));
- return result > 32;
-}
-
-bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- // "Unpin from taskbar" is only supported after Win7.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return false;
-
- int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
- shortcut, NULL, NULL, 0));
- return result > 32;
-}
-
bool GetTempDir(FilePath* path) {
base::ThreadRestrictions::AssertIOAllowed();
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc
new file mode 100644
index 0000000..b919e69
--- /dev/null
+++ b/base/test/test_shortcut_win.cc
@@ -0,0 +1,142 @@
+// 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.
+
+#include "base/test/test_shortcut_win.h"
+
+#include <windows.h>
+#include <shlobj.h>
+#include <propkey.h>
+#include <propvarutil.h>
+
+#include "base/file_path.h"
+#include "base/string16.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+
+// propsys.lib is required for PropvariantTo*().
+#pragma comment(lib, "propsys.lib")
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Returns true if |actual_path|'s LongPathName case-insensitively matches
+// |expected_path|'s LongPathName.
+bool PathsAreEqual(const FilePath& expected_path, const FilePath& actual_path) {
+ wchar_t long_expected_path_chars[MAX_PATH] = {0};
+ wchar_t long_actual_path_chars[MAX_PATH] = {0};
+
+ if (::GetLongPathName(
+ expected_path.value().c_str(), long_expected_path_chars,
+ MAX_PATH) == 0 ||
+ ::GetLongPathName(
+ actual_path.value().c_str(), long_actual_path_chars,
+ MAX_PATH) == 0) {
+ return false;
+ }
+
+ FilePath long_expected_path(long_expected_path_chars);
+ FilePath long_actual_path(long_actual_path_chars);
+ if(long_expected_path.empty() || long_actual_path.empty())
+ return false;
+
+ return long_expected_path == long_actual_path;
+}
+
+} // namespace
+
+VerifyShortcutStatus VerifyShortcut(const FilePath& shortcut_path,
+ const ShortcutProperties& properties) {
+ ScopedComPtr<IShellLink> i_shell_link;
+ ScopedComPtr<IPersistFile> i_persist_file;
+
+ wchar_t read_target[MAX_PATH] = {0};
+ wchar_t read_working_dir[MAX_PATH] = {0};
+ wchar_t read_arguments[MAX_PATH] = {0};
+ wchar_t read_description[MAX_PATH] = {0};
+ wchar_t read_icon[MAX_PATH] = {0};
+ int read_icon_index = 0;
+
+ // Initialize the shell interfaces.
+ if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER)) ||
+ FAILED(i_persist_file.QueryFrom(i_shell_link))) {
+ return VERIFY_SHORTCUT_FAILURE_UNEXPECTED;
+ }
+
+ // Load the shortcut.
+ if (FAILED(i_persist_file->Load(shortcut_path.value().c_str(), 0)))
+ return VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND;
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
+ (FAILED(i_shell_link->GetPath(
+ read_target, MAX_PATH, NULL, SLGP_SHORTPATH)) ||
+ !PathsAreEqual(properties.target, FilePath(read_target)))) {
+ return VERIFY_SHORTCUT_FAILURE_TARGET;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
+ (FAILED(i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)) ||
+ FilePath(read_working_dir) != properties.working_dir)) {
+ return VERIFY_SHORTCUT_FAILURE_WORKING_DIR;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) &&
+ (FAILED(i_shell_link->GetArguments(read_arguments, MAX_PATH)) ||
+ string16(read_arguments) != properties.arguments)) {
+ return VERIFY_SHORTCUT_FAILURE_ARGUMENTS;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
+ (FAILED(i_shell_link->GetDescription(read_description, MAX_PATH)) ||
+ string16(read_description) != properties.description)) {
+ return VERIFY_SHORTCUT_FAILURE_DESCRIPTION;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
+ (FAILED(i_shell_link->GetIconLocation(read_icon, MAX_PATH,
+ &read_icon_index)) ||
+ read_icon_index != properties.icon_index ||
+ !PathsAreEqual(properties.icon, FilePath(read_icon)))) {
+ return VERIFY_SHORTCUT_FAILURE_ICON;
+ }
+
+ if(GetVersion() >= VERSION_WIN7) {
+ ScopedComPtr<IPropertyStore> property_store;
+ // Note that, as mentioned on MSDN at http://goo.gl/M8h9g, if a property is
+ // not set, GetValue will return S_OK and the PROPVARIANT will be set to
+ // VT_EMPTY.
+ PROPVARIANT pv_app_id, pv_dual_mode;
+ if (FAILED(property_store.QueryFrom(i_shell_link)) ||
+ property_store->GetValue(PKEY_AppUserModel_ID, &pv_app_id) != S_OK ||
+ property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+ &pv_dual_mode) != S_OK) {
+ return VERIFY_SHORTCUT_FAILURE_UNEXPECTED;
+ }
+
+ // Note, as mentioned on MSDN at http://goo.gl/hZ3sO, if |pv_app_id| is a
+ // VT_EMPTY it is successfully converted to the empty string.
+ wchar_t read_app_id[MAX_PATH] = {0};
+ PropVariantToString(pv_app_id, read_app_id, MAX_PATH);
+ if((properties.options & ShortcutProperties::PROPERTIES_APP_ID) &&
+ string16(read_app_id) != properties.app_id) {
+ return VERIFY_SHORTCUT_FAILURE_APP_ID;
+ }
+
+ // Note, as mentioned on MSDN at http://goo.gl/9mBHB, if |pv_dual_mode| is a
+ // VT_EMPTY it is successfully converted to false.
+ BOOL read_dual_mode;
+ PropVariantToBoolean(pv_dual_mode, &read_dual_mode);
+ if((properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) &&
+ static_cast<bool>(read_dual_mode) != properties.dual_mode) {
+ return VERIFY_SHORTCUT_FAILURE_DUAL_MODE;
+ }
+ }
+
+ return VERIFY_SHORTCUT_SUCCESS;
+}
+
+} // namespace win
+} // namespace base
diff --git a/base/test/test_shortcut_win.h b/base/test/test_shortcut_win.h
new file mode 100644
index 0000000..cb5b2c3
--- /dev/null
+++ b/base/test/test_shortcut_win.h
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef BASE_TEST_TEST_SHORTCUT_WIN_H_
+#define BASE_TEST_TEST_SHORTCUT_WIN_H_
+
+#include "base/file_path.h"
+#include "base/win/shortcut.h"
+
+// Windows shortcut functions used only by tests.
+
+namespace base {
+namespace win {
+
+enum VerifyShortcutStatus {
+ VERIFY_SHORTCUT_SUCCESS = 0,
+ VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
+ VERIFY_SHORTCUT_FAILURE_TARGET,
+ VERIFY_SHORTCUT_FAILURE_WORKING_DIR,
+ VERIFY_SHORTCUT_FAILURE_ARGUMENTS,
+ VERIFY_SHORTCUT_FAILURE_DESCRIPTION,
+ VERIFY_SHORTCUT_FAILURE_ICON,
+ VERIFY_SHORTCUT_FAILURE_APP_ID,
+ VERIFY_SHORTCUT_FAILURE_DUAL_MODE,
+};
+
+// Verify that a shortcut exists at |shortcut_path| with the expected
+// |properties|.
+VerifyShortcutStatus VerifyShortcut(const FilePath& shortcut_path,
+ const ShortcutProperties& properties);
+
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_TEST_TEST_SHORTCUT_WIN_H_
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
new file mode 100644
index 0000000..570a5bd
--- /dev/null
+++ b/base/win/shortcut.cc
@@ -0,0 +1,180 @@
+// 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.
+
+#include "base/win/shortcut.h"
+
+#include <shellapi.h>
+#include <shlobj.h>
+
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
+ const ShortcutProperties& properties,
+ ShortcutOperation operation) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ // A target is required when |operation| is SHORTCUT_CREATE_ALWAYS.
+ if (operation == SHORTCUT_CREATE_ALWAYS &&
+ !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) {
+ NOTREACHED();
+ return false;
+ }
+
+ ScopedComPtr<IShellLink> i_shell_link;
+ ScopedComPtr<IPersistFile> i_persist_file;
+ if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER)) ||
+ FAILED(i_persist_file.QueryFrom(i_shell_link))) {
+ return false;
+ }
+
+ if (operation == SHORTCUT_UPDATE_EXISTING &&
+ FAILED(i_persist_file->Load(shortcut_path.value().c_str(),
+ STGM_READWRITE))) {
+ return false;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
+ FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) {
+ return false;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
+ FAILED(i_shell_link->SetWorkingDirectory(
+ properties.working_dir.value().c_str()))) {
+ return false;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) &&
+ FAILED(i_shell_link->SetArguments(properties.arguments.c_str()))) {
+ return false;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
+ FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
+ return false;
+ }
+
+ if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
+ FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(),
+ properties.icon_index))) {
+ return false;
+ }
+
+ bool has_app_id =
+ (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
+ bool has_dual_mode =
+ (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
+ if ((has_app_id || has_dual_mode) &&
+ GetVersion() >= VERSION_WIN7) {
+ ScopedComPtr<IPropertyStore> property_store;
+ if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get())
+ return false;
+
+ if (has_app_id &&
+ !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) {
+ return false;
+ }
+ if (has_dual_mode &&
+ !SetDualModeForPropertyStore(property_store, properties.dual_mode)) {
+ return false;
+ }
+ }
+
+ HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE);
+
+ // If we successfully updated the icon, notify the shell that we have done so.
+ if (operation == SHORTCUT_UPDATE_EXISTING && 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, NULL, NULL);
+ }
+
+ return SUCCEEDED(result);
+}
+
+bool ResolveShortcut(const FilePath& shortcut_path,
+ FilePath* target_path,
+ string16* args) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ HRESULT result;
+ ScopedComPtr<IShellLink> i_shell_link;
+
+ // Get pointer to the IShellLink interface.
+ result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER);
+ if (FAILED(result))
+ return false;
+
+ ScopedComPtr<IPersistFile> persist;
+ // Query IShellLink for the IPersistFile interface.
+ result = persist.QueryFrom(i_shell_link);
+ if (FAILED(result))
+ return false;
+
+ // Load the shell link.
+ result = persist->Load(shortcut_path.value().c_str(), STGM_READ);
+ if (FAILED(result))
+ return false;
+
+ WCHAR temp[MAX_PATH];
+ if (target_path) {
+ // Try to find the target of a shortcut.
+ result = i_shell_link->Resolve(0, SLR_NO_UI);
+ if (FAILED(result))
+ return false;
+
+ result = i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY);
+ if (FAILED(result))
+ return false;
+
+ *target_path = FilePath(temp);
+ }
+
+ if (args) {
+ result = i_shell_link->GetArguments(temp, MAX_PATH);
+ if (FAILED(result))
+ return false;
+
+ *args = string16(temp);
+ }
+ return true;
+}
+
+bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ // "Pin to taskbar" is only supported after Win7.
+ if (GetVersion() < VERSION_WIN7)
+ return false;
+
+ int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut,
+ NULL, NULL, 0));
+ return result > 32;
+}
+
+bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ // "Unpin from taskbar" is only supported after Win7.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return false;
+
+ int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin",
+ shortcut, NULL, NULL, 0));
+ return result > 32;
+}
+
+} // namespace win
+} // namespace base
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
new file mode 100644
index 0000000..7491069
--- /dev/null
+++ b/base/win/shortcut.h
@@ -0,0 +1,142 @@
+// 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.
+
+#ifndef BASE_WIN_SHORTCUT_H_
+#define BASE_WIN_SHORTCUT_H_
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+enum ShortcutOperation {
+ // Create a new shortcut (overwriting if necessary).
+ SHORTCUT_CREATE_ALWAYS = 0,
+ // Update specified (non-null) properties only on an existing shortcut.
+ SHORTCUT_UPDATE_EXISTING,
+};
+
+// Properties for shortcuts. Properties set will be applied to the shortcut on
+// creation/update, others will be ignored.
+// Callers are encouraged to use the setters provided which take care of
+// setting |options| as desired.
+struct ShortcutProperties {
+ enum IndividualProperties {
+ PROPERTIES_TARGET = 1 << 0,
+ PROPERTIES_WORKING_DIR = 1 << 1,
+ PROPERTIES_ARGUMENTS = 1 << 2,
+ PROPERTIES_DESCRIPTION = 1 << 3,
+ PROPERTIES_ICON = 1 << 4,
+ PROPERTIES_APP_ID = 1 << 5,
+ PROPERTIES_DUAL_MODE = 1 << 6,
+ };
+
+ ShortcutProperties() : options(0U) {}
+
+ void set_target(const FilePath& target_in) {
+ target = target_in;
+ options |= PROPERTIES_TARGET;
+ }
+
+ void set_working_dir(const FilePath& working_dir_in) {
+ working_dir = working_dir_in;
+ options |= PROPERTIES_WORKING_DIR;
+ }
+
+ void set_arguments(const string16& arguments_in) {
+ // Size restriction as per MSDN at http://goo.gl/TJ7q5.
+ DCHECK(arguments_in.size() < MAX_PATH);
+ arguments = arguments_in;
+ options |= PROPERTIES_ARGUMENTS;
+ }
+
+ void set_description(const string16& description_in) {
+ // Size restriction as per MSDN at http://goo.gl/OdNQq.
+ DCHECK(description_in.size() < MAX_PATH);
+ description = description_in;
+ options |= PROPERTIES_DESCRIPTION;
+ }
+
+ void set_icon(const FilePath& icon_in, int icon_index_in) {
+ icon = icon_in;
+ icon_index = icon_index_in;
+ options |= PROPERTIES_ICON;
+ }
+
+ void set_app_id(const string16& app_id_in) {
+ app_id = app_id_in;
+ options |= PROPERTIES_APP_ID;
+ }
+
+ void set_dual_mode(bool dual_mode_in) {
+ dual_mode = dual_mode_in;
+ options |= PROPERTIES_DUAL_MODE;
+ }
+
+ // The target to launch from this shortcut. This is mandatory when creating
+ // a shortcut.
+ FilePath target;
+ // The name of the working directory when launching the shortcut.
+ FilePath working_dir;
+ // The arguments to be applied to |target| when launching from this shortcut.
+ // The length of this string must be less than MAX_PATH.
+ string16 arguments;
+ // The localized description of the shortcut.
+ // The length of this string must be less than MAX_PATH.
+ string16 description;
+ // The path to the icon (can be a dll or exe, in which case |icon_index| is
+ // the resource id).
+ FilePath icon;
+ int icon_index;
+ // The app model id for the shortcut (Win7+).
+ string16 app_id;
+ // Whether this is a dual mode shortcut (Win8+).
+ // For now this property can only be set to true (i.e. once set it cannot be
+ // unset).
+ // TODO (gab): Make it possible to set this property to false.
+ bool dual_mode;
+ // Bitfield made of IndividualProperties. Properties set in |options| will be
+ // set on the shortcut, others will be ignored.
+ uint32 options;
+};
+
+// This method creates (or updates) a shortcut link at |shortcut_path| using the
+// information given through |properties|.
+// Ensure you have initialized COM before calling into this function.
+// |operation|: a choice from the ShortcutOperation enum.
+// If |operation| is SHORTCUT_UPDATE_EXISTING and |shortcut_path| does not
+// exist, this method is a no-op and returns false.
+BASE_EXPORT bool CreateOrUpdateShortcutLink(
+ const FilePath& shortcut_path,
+ const ShortcutProperties& properties,
+ ShortcutOperation operation);
+
+// Resolve Windows shortcut (.LNK file)
+// This methods tries to resolve a shortcut .LNK file. The path of the shortcut
+// to resolve is in |shortcut_path|. If |target_path| is not NULL, the target
+// will be resolved and placed in |target_path|. If |args| is not NULL, the
+// arguments will be retrieved and placed in |args|. The function returns true
+// if all requested fields are found successfully.
+// Callers can safely use the same variable for both |shortcut_path| and
+// |target_path|.
+BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
+ FilePath* target_path,
+ string16* args);
+
+// Pins a shortcut to the Windows 7 taskbar. The shortcut file must already
+// exist and be a shortcut that points to an executable.
+BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
+
+// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
+// already be pinned to the taskbar.
+BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SHORTCUT_H_
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
new file mode 100644
index 0000000..68d832f
--- /dev/null
+++ b/base/win/shortcut_unittest.cc
@@ -0,0 +1,221 @@
+// 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.
+
+#include "base/win/shortcut.h"
+
+#include <windows.h>
+#include <objbase.h>
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_shortcut_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const char kFileContents[] = "This is a target.";
+static const char kFileContents2[] = "This is another target.";
+
+class ShortcutTest : public testing::Test {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
+
+ EXPECT_EQ(S_OK, CoInitialize(NULL));
+
+ link_file_ = temp_dir_.path().Append(L"My Link.lnk");
+
+ // Shortcut 1's properties
+ {
+ const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
+ file_util::WriteFile(target_file, kFileContents,
+ arraysize(kFileContents));
+
+ link_properties_.set_target(target_file);
+ link_properties_.set_working_dir(temp_dir_.path());
+ link_properties_.set_arguments(L"--magic --awesome");
+ link_properties_.set_description(L"Chrome is awesome.");
+ link_properties_.set_icon(link_properties_.target, 4);
+ link_properties_.set_app_id(L"Chrome");
+ link_properties_.set_dual_mode(false);
+ }
+
+ // Shortcut 2's properties (all different from properties of shortcut 1).
+ {
+ const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
+ file_util::WriteFile(target_file_2, kFileContents2,
+ arraysize(kFileContents2));
+
+ FilePath icon_path_2;
+ file_util::CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
+
+ link_properties_2_.set_target(target_file_2);
+ link_properties_2_.set_working_dir(temp_dir_2_.path());
+ link_properties_2_.set_arguments(L"--super --crazy");
+ link_properties_2_.set_description(L"The best in the west.");
+ link_properties_2_.set_icon(icon_path_2, 0);
+ link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
+ link_properties_2_.set_dual_mode(true);
+ }
+ }
+
+ virtual void TearDown() OVERRIDE {
+ CoUninitialize();
+ }
+
+ ScopedTempDir temp_dir_;
+ ScopedTempDir temp_dir_2_;
+
+ // The link file to be created/updated in the shortcut tests below.
+ FilePath link_file_;
+
+ // Properties for the created shortcut.
+ base::win::ShortcutProperties link_properties_;
+
+ // Properties for the updated shortcut.
+ base::win::ShortcutProperties link_properties_2_;
+};
+
+} // namespace
+
+TEST_F(ShortcutTest, CreateAndResolveShortcut) {
+ base::win::ShortcutProperties only_target_properties;
+ only_target_properties.set_target(link_properties_.target);
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, only_target_properties, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ FilePath resolved_name;
+ EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, NULL));
+
+ char read_contents[arraysize(kFileContents)];
+ file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+ EXPECT_STREQ(kFileContents, read_contents);
+}
+
+TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ FilePath resolved_name;
+ string16 args;
+ EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, &args));
+
+ char read_contents[arraysize(kFileContents)];
+ file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+ EXPECT_STREQ(kFileContents, read_contents);
+ EXPECT_EQ(link_properties_.arguments, args);
+}
+
+TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
+ base::win::ShortcutProperties target_and_args_properties;
+ target_and_args_properties.set_target(link_properties_.target);
+ target_and_args_properties.set_arguments(link_properties_.arguments);
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, target_and_args_properties,
+ base::win::SHORTCUT_CREATE_ALWAYS));
+
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, target_and_args_properties));
+}
+
+TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, link_properties_));
+}
+
+TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_2_, base::win::SHORTCUT_UPDATE_EXISTING));
+
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, link_properties_2_));
+}
+
+TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ base::win::ShortcutProperties update_only_target_properties;
+ update_only_target_properties.set_target(link_properties_2_.target);
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, update_only_target_properties,
+ base::win::SHORTCUT_UPDATE_EXISTING));
+
+ base::win::ShortcutProperties expected_properties = link_properties_;
+ expected_properties.set_target(link_properties_2_.target);
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, expected_properties));
+
+ FilePath resolved_name;
+ EXPECT_TRUE(base::win::ResolveShortcut(link_file_, &resolved_name, NULL));
+
+ char read_contents[arraysize(kFileContents2)];
+ file_util::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+ EXPECT_STREQ(kFileContents2, read_contents);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ base::win::ShortcutProperties make_dual_mode_properties;
+ make_dual_mode_properties.set_dual_mode(true);
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, make_dual_mode_properties,
+ base::win::SHORTCUT_UPDATE_EXISTING));
+
+ base::win::ShortcutProperties expected_properties = link_properties_;
+ expected_properties.set_dual_mode(true);
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, expected_properties));
+}
+
+TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_2_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ base::win::ShortcutProperties remove_dual_mode_properties;
+ remove_dual_mode_properties.set_dual_mode(false);
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, remove_dual_mode_properties,
+ base::win::SHORTCUT_UPDATE_EXISTING));
+
+ base::win::ShortcutProperties expected_properties = link_properties_2_;
+ expected_properties.set_dual_mode(false);
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, expected_properties));
+}
+
+TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, link_properties_, base::win::SHORTCUT_CREATE_ALWAYS));
+
+ base::win::ShortcutProperties clear_arguments_properties;
+ clear_arguments_properties.set_arguments(string16());
+
+ ASSERT_TRUE(base::win::CreateOrUpdateShortcutLink(
+ link_file_, clear_arguments_properties,
+ base::win::SHORTCUT_UPDATE_EXISTING));
+
+ base::win::ShortcutProperties expected_properties = link_properties_;
+ expected_properties.set_arguments(string16());
+ ASSERT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ base::win::VerifyShortcut(link_file_, expected_properties));
+}
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 55a4c3c..37aae27 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -175,13 +175,17 @@ bool SetAppIdForPropertyStore(IPropertyStore* property_store,
app_id);
}
-bool SetDualModeForPropertyStore(IPropertyStore* property_store) {
+bool SetDualModeForPropertyStore(IPropertyStore* property_store,
+ bool is_dual_mode) {
return SetBooleanValueForPropertyStore(property_store,
PKEY_AppUserModel_DualMode,
- true) &&
+ is_dual_mode) &&
+ // TODO (gab): This property no longer exists in the final Win8 release
+ // and should be deleted from all shortcuts as it could interfere with
+ // a future (Win9+) property.
SetUInt32ValueForPropertyStore(property_store,
PKEY_AppUserModel_DualMode_UK,
- 1U);
+ is_dual_mode ? 1U : 0U);
}
static const char16 kAutoRunKeyPath[] =
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 09c66cd..51dfbd6 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -78,9 +78,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);
+// Sets the DualModeApp property to |is_dual_mode| in |property_store|. This
+// method is intended for tagging dual mode applications in Win8+.
+BASE_EXPORT bool SetDualModeForPropertyStore(IPropertyStore* property_store,
+ bool is_dual_mode);
// 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.
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index f1ddaed..826bb6d 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -7,6 +7,8 @@
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/win/shortcut.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_shortcut_manager.h"
@@ -25,10 +27,10 @@ using content::BrowserThread;
namespace {
-ShellUtil::VerifyShortcutStatus VerifyProfileShortcut(
+base::win::VerifyShortcutStatus VerifyProfileShortcut(
const string16& profile_name) {
FilePath exe_path;
- CHECK(PathService::Get(base::FILE_EXE, &exe_path));
+ EXPECT_TRUE(PathService::Get(base::FILE_EXE, &exe_path));
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
@@ -41,9 +43,13 @@ ShellUtil::VerifyShortcutStatus VerifyProfileShortcut(
&shortcut_name);
shortcut_path = shortcut_path.Append(shortcut_name);
- return ShellUtil::VerifyChromeShortcut(
- exe_path.value(), shortcut_path.value(), dist->GetAppDescription(),
- 0);
+ // TODO(hallielaine): With this new struct method for VerifyShortcut you can
+ // now test more properties like: arguments, icon, icon_index, and app_id.
+ base::win::ShortcutProperties expected_properties;
+ expected_properties.set_target(exe_path);
+ expected_properties.set_description(dist->GetAppDescription());
+ expected_properties.set_dual_mode(false);
+ return base::win::VerifyShortcut(shortcut_path, expected_properties);
}
} // namespace
@@ -94,7 +100,7 @@ class ProfileShortcutManagerTest : public testing::Test {
profile_path);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(profile_name));
ASSERT_FALSE(file_util::PathExists(profile_path.Append(
FILE_PATH_LITERAL("Google Profile.ico"))));
@@ -102,7 +108,7 @@ class ProfileShortcutManagerTest : public testing::Test {
}
void SetupDefaultProfileShortcut() {
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(profile_name_));
profile_manager_->profile_info_cache()->AddProfileToCache(
@@ -113,15 +119,15 @@ class ProfileShortcutManagerTest : public testing::Test {
MessageLoop::current()->Run();
// We now have 1 profile, so we expect a new shortcut with no profile
// information.
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(string16()));
}
void SetupAndCreateTwoShortcuts() {
ASSERT_EQ(0, profile_manager_->profile_info_cache()->GetNumberOfProfiles());
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(profile_name_));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(second_profile_name_));
profile_manager_->profile_info_cache()->AddProfileToCache(
@@ -134,9 +140,9 @@ class ProfileShortcutManagerTest : public testing::Test {
CreateProfileShortcut(second_dest_path_);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(profile_name_));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(second_profile_name_));
}
@@ -164,7 +170,7 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsCreate) {
// We now have 2 profiles, so we expect a new shortcut with profile
// information for this 2nd profile.
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(second_profile_name_));
ASSERT_TRUE(file_util::PathExists(second_dest_path_.Append(
FILE_PATH_LITERAL("Google Profile.ico"))));
@@ -175,7 +181,7 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsUpdate) {
return;
ProfileShortcutManagerTest::SetupDefaultProfileShortcut();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(second_profile_name_));
profile_manager_->profile_info_cache()->AddProfileToCache(
@@ -184,7 +190,7 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsUpdate) {
CreateProfileShortcut(second_dest_path_);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(second_profile_name_));
// Cause an update in ProfileShortcutManager by modifying the profile info
@@ -196,9 +202,9 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsUpdate) {
new_profile_name);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(second_profile_name_));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(new_profile_name));
}
@@ -212,15 +218,15 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsDeleteSecondToLast) {
second_dest_path_);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(second_profile_name_));
// Verify that the profile name has been removed from the remaining shortcut
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(string16()));
// Verify that an additional shortcut, with the default profile's name does
// not exist
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(profile_name_));
}
@@ -236,11 +242,11 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsCreateSecond) {
MessageLoop::current()->Run();
// Verify that a default shortcut exists (no profile name/avatar)
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(string16()));
// Verify that an additional shortcut, with the default profile's name does
// not exist
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(profile_name_));
// Create a second profile and shortcut
@@ -250,14 +256,14 @@ TEST_F(ProfileShortcutManagerTest, DesktopShortcutsCreateSecond) {
CreateProfileShortcut(second_dest_path_);
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
MessageLoop::current()->Run();
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(second_profile_name_));
// Verify that the original shortcut received the profile's name
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
VerifyProfileShortcut(profile_name_));
// Verify that a default shortcut no longer exists
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_FAILURE_UNEXPECTED,
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_FAILURE_FILE_NOT_FOUND,
VerifyProfileShortcut(string16()));
}
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 97dae75..08b9885 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -21,6 +21,7 @@
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_comptr.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_constants.h"
@@ -336,10 +337,11 @@ void MigrateWin7ShortcutsInPath(
GetShortcutAppId(shell_link, &existing_app_id);
if (expected_app_id != existing_app_id) {
- file_util::CreateOrUpdateShortcutLink(NULL, shortcut.value().c_str(),
- NULL, NULL, NULL, NULL, 0,
- expected_app_id.c_str(),
- file_util::SHORTCUT_NO_OPTIONS);
+ 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);
}
}
}
diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc
index a3ce59e..48ab162 100644
--- a/chrome/browser/ui/web_applications/web_app_ui.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui.cc
@@ -10,7 +10,6 @@
#include "base/path_service.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
-#include "base/win/windows_version.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
@@ -28,6 +27,11 @@
#include "base/environment.h"
#endif
+#if defined(OS_WIN)
+#include "base/win/shortcut.h"
+#include "base/win/windows_version.h"
+#endif
+
using content::BrowserThread;
using content::NavigationController;
using content::WebContents;
@@ -262,16 +266,14 @@ void UpdateShortcutWorker::UpdateShortcutsOnFileThread() {
shortcut_info_.description.resize(MAX_PATH - 1);
for (size_t i = 0; i < shortcut_files_.size(); ++i) {
- 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(),
- file_util::SHORTCUT_NO_OPTIONS);
+ base::win::ShortcutProperties shortcut_properties;
+ shortcut_properties.set_target(shortcut_files_[i]);
+ shortcut_properties.set_description(shortcut_info_.description);
+ shortcut_properties.set_icon(icon_file, 0);
+ shortcut_properties.set_app_id(app_id);
+ base::win::CreateOrUpdateShortcutLink(
+ shortcut_files_[i], shortcut_properties,
+ base::win::SHORTCUT_UPDATE_EXISTING);
}
}
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc
index b1aca7d..cfc68e1 100644
--- a/chrome/browser/web_applications/web_app_win.cc
+++ b/chrome/browser/web_applications/web_app_win.cc
@@ -13,6 +13,7 @@
#include "base/path_service.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -124,7 +125,7 @@ std::vector<FilePath> GetShortcutPaths(
bool ShortcutIsForProfile(const FilePath& shortcut_file_name,
const FilePath& profile_path) {
string16 cmd_line_string;
- if (file_util::ResolveShortcut(shortcut_file_name, NULL, &cmd_line_string)) {
+ if (base::win::ResolveShortcut(shortcut_file_name, NULL, &cmd_line_string)) {
cmd_line_string = L"program " + cmd_line_string;
CommandLine shortcut_cmd_line = CommandLine::FromString(cmd_line_string);
return shortcut_cmd_line.HasSwitch(switches::kProfileDirectory) &&
@@ -229,7 +230,7 @@ bool CreatePlatformShortcuts(
return false;
// Working directory.
- FilePath chrome_folder = chrome_exe.DirName();
+ FilePath chrome_folder(chrome_exe.DirName());
CommandLine cmd_line(CommandLine::NO_PROGRAM);
cmd_line = ShellIntegration::CommandLineArgsForLauncher(shortcut_info.url,
@@ -247,10 +248,9 @@ bool CreatePlatformShortcuts(
description.resize(MAX_PATH - 1);
// Generates app id from web app url and profile path.
- std::string app_name =
- web_app::GenerateApplicationNameFromInfo(shortcut_info);
- string16 app_id = ShellIntegration::GetAppModelIdForProfile(
- UTF8ToUTF16(app_name), shortcut_info.profile_path);
+ std::string app_name(web_app::GenerateApplicationNameFromInfo(shortcut_info));
+ string16 app_id(ShellIntegration::GetAppModelIdForProfile(
+ UTF8ToUTF16(app_name), shortcut_info.profile_path));
FilePath shortcut_to_pin;
bool success = true;
@@ -268,16 +268,17 @@ bool CreatePlatformShortcuts(
StringPrintf(" (%d)", unique_number));
}
- 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(),
- file_util::SHORTCUT_CREATE_ALWAYS) && success;
+ base::win::ShortcutProperties shortcut_properties;
+ shortcut_properties.set_target(chrome_exe);
+ shortcut_properties.set_working_dir(chrome_folder);
+ shortcut_properties.set_arguments(wide_switches);
+ shortcut_properties.set_description(description);
+ shortcut_properties.set_icon(icon_file, 0);
+ shortcut_properties.set_app_id(app_id);
+ shortcut_properties.set_dual_mode(false);
+ success = base::win::CreateOrUpdateShortcutLink(
+ shortcut_file, shortcut_properties,
+ base::win::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())
@@ -286,7 +287,7 @@ bool CreatePlatformShortcuts(
if (success && pin_to_taskbar) {
if (!shortcut_to_pin.empty()) {
- success &= file_util::TaskbarPinShortcutLink(
+ success &= base::win::TaskbarPinShortcutLink(
shortcut_to_pin.value().c_str());
} else {
success = false;
@@ -320,7 +321,7 @@ void DeletePlatformShortcuts(
j != shortcut_files.end(); ++j) {
// Any shortcut could have been pinned, either by chrome or the user, so
// they are all unpinned.
- file_util::TaskbarUnpinShortcutLink(j->value().c_str());
+ base::win::TaskbarUnpinShortcutLink(j->value().c_str());
file_util::Delete(*j, false);
}
}
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 05efc3c..82e13fb 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -17,6 +17,7 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/installer/setup/setup_constants.h"
@@ -309,7 +310,7 @@ void CreateOrUpdateStartMenuAndTaskbarShortcuts(
// proceed to pin the Start Menu shortcut to the taskbar on Win7+.
VLOG(1) << "Pinning new shortcut at " << chrome_link.value()
<< " to taskbar";
- if (!file_util::TaskbarPinShortcutLink(chrome_link.value().c_str())) {
+ if (!base::win::TaskbarPinShortcutLink(chrome_link.value().c_str())) {
LOG(ERROR) << "Failed to pin shortcut to taskbar: "
<< chrome_link.value();
}
@@ -327,12 +328,14 @@ void CreateOrUpdateStartMenuAndTaskbarShortcuts(
CommandLine arguments(CommandLine::NO_PROGRAM);
AppendUninstallCommandLineFlags(installer_state, product, &arguments);
VLOG(1) << operation << " uninstall link at " << uninstall_link.value();
- 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,
- create_always ? file_util::SHORTCUT_CREATE_ALWAYS :
- file_util::SHORTCUT_NO_OPTIONS)) {
+ base::win::ShortcutProperties shortcut_properties;
+ shortcut_properties.set_target(setup_exe);
+ shortcut_properties.set_arguments(arguments.GetCommandLineString());
+ shortcut_properties.set_icon(setup_exe, 0);
+ if (!base::win::CreateOrUpdateShortcutLink(
+ uninstall_link, shortcut_properties,
+ create_always ? base::win::SHORTCUT_CREATE_ALWAYS :
+ base::win::SHORTCUT_UPDATE_EXISTING)) {
LOG(WARNING) << operation << " uninstall link at "
<< uninstall_link.value() << " failed.";
}
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index a73a7f6..20fc91f 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -19,6 +19,7 @@
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
@@ -307,7 +308,7 @@ void DeleteChromeShortcuts(const InstallerState& installer_state,
VLOG(1) << "Unpinning shortcut at " << shortcut_link.value()
<< " from taskbar";
// Ignore return value: keep uninstalling if the unpin fails.
- file_util::TaskbarUnpinShortcutLink(shortcut_link.value().c_str());
+ base::win::TaskbarUnpinShortcutLink(shortcut_link.value().c_str());
VLOG(1) << "Deleting shortcut " << shortcut_path.value();
if (!file_util::Delete(shortcut_path, true))
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 99c2fb9..f6e696c 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -32,6 +32,7 @@
#include "base/values.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
+#include "base/win/shortcut.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_constants.h"
@@ -730,15 +731,6 @@ bool LaunchApplicationAssociationDialog(const string16& 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;
-}
-
// As of r133333, the DelegateExecute verb handler was being registered for
// Google Chrome installs on Windows 8 even though the binary itself wasn't
// present. This affected Chrome 20.0.1115.1 on the dev channel (and anyone who
@@ -1672,56 +1664,24 @@ bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist,
}
const string16 app_id(GetBrowserModelId(dist, chrome_exe));
-
- return file_util::CreateOrUpdateShortcutLink(
- chrome_exe.c_str(),
- shortcut.c_str(),
- chrome_path.value().c_str(),
- arguments.c_str(),
- description.c_str(),
- icon_path.c_str(),
- icon_index,
- app_id.c_str(),
- ConvertShellUtilShortcutOptionsToFileUtil(options));
-}
-
-ShellUtil::VerifyShortcutStatus ShellUtil::VerifyChromeShortcut(
- const string16& exe_path, const string16& shortcut,
- const string16& description, int icon_index) {
- base::win::ScopedComPtr<IShellLink> i_shell_link;
- base::win::ScopedComPtr<IPersistFile> i_persist_file;
- wchar_t long_path[MAX_PATH] = {0};
- wchar_t short_path[MAX_PATH] = {0};
- wchar_t file_path[MAX_PATH] = {0};
- wchar_t icon_path[MAX_PATH] = {0};
- wchar_t desc[MAX_PATH] = {0};
- int index = 0;
-
- // Get the shortcut's properties.
- if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
- CLSCTX_INPROC_SERVER)) ||
- FAILED(i_persist_file.QueryFrom(i_shell_link)) ||
- FAILED(i_persist_file->Load(shortcut.c_str(), 0)) ||
- ::GetLongPathName(exe_path.c_str(), long_path, MAX_PATH) == 0 ||
- ::GetShortPathName(exe_path.c_str(), short_path, MAX_PATH) == 0 ||
- FAILED(i_shell_link->GetPath(file_path, MAX_PATH, NULL,
- SLGP_UNCPRIORITY)) ||
- FAILED(i_shell_link->GetIconLocation(icon_path, MAX_PATH, &index)) ||
- FAILED(i_shell_link->GetDescription(desc, MAX_PATH)) ||
- FAILED(i_shell_link->GetDescription(desc, MAX_PATH)))
- return VERIFY_SHORTCUT_FAILURE_UNEXPECTED;
-
- FilePath path(file_path);
- if (path != FilePath(long_path) && path != FilePath(short_path))
- return VERIFY_SHORTCUT_FAILURE_PATH;
-
- if (string16(desc) != string16(description))
- return VERIFY_SHORTCUT_FAILURE_DESCRIPTION;
-
- if (index != icon_index)
- return VERIFY_SHORTCUT_FAILURE_ICON_INDEX;
-
- return VERIFY_SHORTCUT_SUCCESS;
+ const bool is_dual_mode = ((options & ShellUtil::SHORTCUT_DUAL_MODE) != 0);
+ const base::win::ShortcutOperation operation =
+ (options & ShellUtil::SHORTCUT_CREATE_ALWAYS) != 0 ?
+ base::win::SHORTCUT_CREATE_ALWAYS :
+ base::win::SHORTCUT_UPDATE_EXISTING;
+
+ // TODO(gab): The shell_util interface will also be refactored in an upcoming
+ // CL to use a ShortcutProperties like interface for its shortcut methods.
+ base::win::ShortcutProperties shortcut_properties;
+ shortcut_properties.set_target(FilePath(chrome_exe));
+ shortcut_properties.set_working_dir(chrome_path);
+ shortcut_properties.set_arguments(arguments);
+ shortcut_properties.set_description(description);
+ shortcut_properties.set_icon(FilePath(icon_path), icon_index);
+ shortcut_properties.set_app_id(app_id);
+ shortcut_properties.set_dual_mode(is_dual_mode);
+ return base::win::CreateOrUpdateShortcutLink(
+ FilePath(shortcut), shortcut_properties, operation);
}
bool ShellUtil::GetUserSpecificRegistrySuffix(string16* suffix) {
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index bc3bf8a..096b7dc 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -424,16 +424,6 @@ class ShellUtil {
int icon_index,
uint32 options);
- // Verify that a shortcut exists with the expected information.
- // |exe_path| The shortcut's exe.
- // |shortcut| The path to the shortcut.
- // |description| The shortcut's description.
- // |icon_index| The icon's index in the exe.
- static VerifyShortcutStatus VerifyChromeShortcut(const string16& exe_path,
- const string16& shortcut,
- const string16& description,
- int icon_index);
-
// Sets |suffix| to the base 32 encoding of the md5 hash of this user's sid
// preceded by a dot.
// This is guaranteed to be unique on the machine and 27 characters long
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index a73452a..298a9a4 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -13,6 +13,8 @@
#include "base/scoped_temp_dir.h"
#include "base/string16.h"
#include "base/string_util.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/master_preferences.h"
@@ -35,6 +37,24 @@ class ShellUtilTestWithDirAndDist : public testing::Test {
ScopedTempDir temp_dir_;
};
+// Returns the status of a call to base::win::VerifyShorcut for the properties
+// passed in.
+// TODO(gab): This is only temporary while waiting for my upcoming CL that will
+// massively refactor the shell_util shortcut methods' interface (i.e. I didn't
+// want to adapt every test here for this half-changed state as they will change
+// again very soon).
+base::win::VerifyShortcutStatus VerifyChromeShortcut(
+ const FilePath& exe_path,
+ const FilePath& shortcut_path,
+ const string16& description,
+ int icon_index) {
+ base::win::ShortcutProperties expected_properties;
+ expected_properties.set_target(exe_path);
+ expected_properties.set_description(description);
+ expected_properties.set_icon(exe_path, icon_index);
+ return base::win::VerifyShortcut(shortcut_path, expected_properties);
+}
+
}
// Test that we can open archives successfully.
@@ -53,14 +73,13 @@ TEST_F(ShellUtilTestWithDirAndDist, UpdateChromeShortcutTest) {
dist_,
exe_path.value(),
shortcut_path.value(),
- L"",
+ string16(),
description,
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), shortcut_path.value(), description, 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(exe_path, shortcut_path, description, 0));
// Now specify an icon index in master prefs and make sure it works.
FilePath prefs_path = temp_dir_.path().AppendASCII(
@@ -80,14 +99,13 @@ TEST_F(ShellUtilTestWithDirAndDist, UpdateChromeShortcutTest) {
dist_,
exe_path.value(),
shortcut_path.value(),
- L"",
+ string16(),
description,
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), shortcut_path.value(), description, 1));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(exe_path, shortcut_path, description, 1));
// Now change only description to update shortcut and make sure icon index
// doesn't change.
@@ -95,14 +113,13 @@ TEST_F(ShellUtilTestWithDirAndDist, UpdateChromeShortcutTest) {
EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist_,
exe_path.value(),
shortcut_path.value(),
- L"",
+ string16(),
description2,
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SHORTCUT_NO_OPTIONS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), shortcut_path.value(), description2, 1));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(exe_path, shortcut_path, description2, 1));
}
TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
@@ -128,7 +145,7 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
EXPECT_TRUE(ShellUtil::GetDesktopPath(true, &system_desktop_path));
string16 shortcut_name;
- EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist_, false, L"",
+ EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist_, false, string16(),
&shortcut_name));
string16 default_profile_shortcut_name;
@@ -155,15 +172,14 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::CURRENT_USER,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), user_shortcut_path.value(), description, 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(exe_path, user_shortcut_path, description, 0));
EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(
dist_,
ShellUtil::CURRENT_USER,
@@ -174,16 +190,15 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SYSTEM_LEVEL,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), system_shortcut_path.value(), description,
- 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(
+ exe_path, system_shortcut_path, description, 0));
EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(
dist_,
ShellUtil::SYSTEM_LEVEL,
@@ -195,8 +210,8 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SYSTEM_LEVEL,
@@ -205,16 +220,15 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::CURRENT_USER,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), system_shortcut_path.value(), description,
- 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(
+ exe_path, system_shortcut_path, description, 0));
EXPECT_FALSE(file_util::PathExists(user_shortcut_path));
EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(
dist_,
@@ -227,8 +241,8 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::CURRENT_USER,
@@ -237,19 +251,17 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_,
exe_path.value(),
description,
- L"",
- L"",
+ string16(),
+ string16(),
exe_path.value(),
dist_->GetIconIndex(),
ShellUtil::SYSTEM_LEVEL,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), user_shortcut_path.value(), description, 0));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), system_shortcut_path.value(), description,
- 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(exe_path, user_shortcut_path, description, 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(
+ exe_path, system_shortcut_path, description, 0));
EXPECT_TRUE(ShellUtil::RemoveChromeDesktopShortcut(
dist_,
ShellUtil::CURRENT_USER,
@@ -271,10 +283,9 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_->GetIconIndex(),
ShellUtil::CURRENT_USER,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), default_profile_shortcut_path.value(),
- description, 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(
+ exe_path, default_profile_shortcut_path, description, 0));
EXPECT_TRUE(ShellUtil::CreateChromeDesktopShortcut(
dist_,
exe_path.value(),
@@ -285,10 +296,9 @@ TEST_F(ShellUtilTestWithDirAndDist, CreateChromeDesktopShortcutTest) {
dist_->GetIconIndex(),
ShellUtil::CURRENT_USER,
ShellUtil::SHORTCUT_CREATE_ALWAYS));
- EXPECT_EQ(ShellUtil::VERIFY_SHORTCUT_SUCCESS,
- ShellUtil::VerifyChromeShortcut(
- exe_path.value(), second_profile_shortcut_path.value(),
- description, 0));
+ EXPECT_EQ(base::win::VERIFY_SHORTCUT_SUCCESS,
+ VerifyChromeShortcut(
+ exe_path, second_profile_shortcut_path, description, 0));
std::vector<string16> profile_names;
profile_names.push_back(default_profile_shortcut_name);
profile_names.push_back(second_profile_shortcut_name);
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 5f33508..90512dc 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -38,6 +38,10 @@
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_file_dir_job.h"
+#if defined(OS_WIN)
+#include "base/win/shortcut.h"
+#endif
+
namespace net {
class URLRequestFileJob::AsyncResolver
@@ -201,7 +205,7 @@ bool URLRequestFileJob::IsRedirectResponse(GURL* location,
FilePath new_path = file_path_;
bool resolved;
- resolved = file_util::ResolveShortcut(new_path, &new_path, NULL);
+ resolved = base::win::ResolveShortcut(new_path, &new_path, NULL);
// If shortcut is not resolved succesfully, do not redirect.
if (!resolved)
diff --git a/ui/base/dialogs/select_file_dialog_win.cc b/ui/base/dialogs/select_file_dialog_win.cc
index 82c3cda..0fd90ef 100644
--- a/ui/base/dialogs/select_file_dialog_win.cc
+++ b/ui/base/dialogs/select_file_dialog_win.cc
@@ -23,6 +23,7 @@
#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
+#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "grit/ui_strings.h"
#include "ui/base/dialogs/base_shell_dialog_win.h"
@@ -699,7 +700,7 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(const std::wstring& title,
// According to MSDN, win2000 will not resolve shortcuts, so we do it
// ourself.
- file_util::ResolveShortcut(*path, path, NULL);
+ base::win::ResolveShortcut(*path, path, NULL);
}
CoTaskMemFree(list);
}