diff options
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); } |