summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
}