1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/test/test_shortcut_win.h" 6 7 #include <windows.h> 8 #include <shlobj.h> 9 #include <propkey.h> 10 11 #include "base/files/file_path.h" 12 #include "base/strings/string16.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/win/scoped_comptr.h" 15 #include "base/win/scoped_propvariant.h" 16 #include "base/win/windows_version.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace base { 20 namespace win { 21 22 namespace { 23 24 // Validates |actual_path|'s LongPathName case-insensitively matches 25 // |expected_path|'s LongPathName. 26 void ValidatePathsAreEqual(const base::FilePath& expected_path, 27 const base::FilePath& actual_path) { 28 wchar_t long_expected_path_chars[MAX_PATH] = {0}; 29 wchar_t long_actual_path_chars[MAX_PATH] = {0}; 30 31 // If |expected_path| is empty confirm immediately that |actual_path| is also 32 // empty. 33 if (expected_path.empty()) { 34 EXPECT_TRUE(actual_path.empty()); 35 return; 36 } 37 38 // Proceed with LongPathName matching which will also confirm the paths exist. 39 EXPECT_NE(0U, ::GetLongPathName( 40 expected_path.value().c_str(), long_expected_path_chars, MAX_PATH)) 41 << "Failed to get LongPathName of " << expected_path.value(); 42 EXPECT_NE(0U, ::GetLongPathName( 43 actual_path.value().c_str(), long_actual_path_chars, MAX_PATH)) 44 << "Failed to get LongPathName of " << actual_path.value(); 45 46 base::FilePath long_expected_path(long_expected_path_chars); 47 base::FilePath long_actual_path(long_actual_path_chars); 48 EXPECT_FALSE(long_expected_path.empty()); 49 EXPECT_FALSE(long_actual_path.empty()); 50 51 EXPECT_EQ(long_expected_path, long_actual_path); 52 } 53 54 } // namespace 55 56 void ValidateShortcut(const base::FilePath& shortcut_path, 57 const ShortcutProperties& properties) { 58 ScopedComPtr<IShellLink> i_shell_link; 59 ScopedComPtr<IPersistFile> i_persist_file; 60 61 wchar_t read_target[MAX_PATH] = {0}; 62 wchar_t read_working_dir[MAX_PATH] = {0}; 63 wchar_t read_arguments[MAX_PATH] = {0}; 64 wchar_t read_description[MAX_PATH] = {0}; 65 wchar_t read_icon[MAX_PATH] = {0}; 66 int read_icon_index = 0; 67 68 HRESULT hr; 69 70 // Initialize the shell interfaces. 71 EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance( 72 CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER))); 73 if (FAILED(hr)) 74 return; 75 76 EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link))); 77 if (FAILED(hr)) 78 return; 79 80 // Load the shortcut. 81 EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load( 82 shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at " 83 << shortcut_path.value(); 84 if (FAILED(hr)) 85 return; 86 87 if (properties.options & ShortcutProperties::PROPERTIES_TARGET) { 88 EXPECT_TRUE(SUCCEEDED( 89 i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH))); 90 ValidatePathsAreEqual(properties.target, base::FilePath(read_target)); 91 } 92 93 if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) { 94 EXPECT_TRUE(SUCCEEDED( 95 i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH))); 96 ValidatePathsAreEqual(properties.working_dir, 97 base::FilePath(read_working_dir)); 98 } 99 100 if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) { 101 EXPECT_TRUE(SUCCEEDED( 102 i_shell_link->GetArguments(read_arguments, MAX_PATH))); 103 EXPECT_EQ(properties.arguments, read_arguments); 104 } 105 106 if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) { 107 EXPECT_TRUE(SUCCEEDED( 108 i_shell_link->GetDescription(read_description, MAX_PATH))); 109 EXPECT_EQ(properties.description, read_description); 110 } 111 112 if (properties.options & ShortcutProperties::PROPERTIES_ICON) { 113 EXPECT_TRUE(SUCCEEDED( 114 i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index))); 115 ValidatePathsAreEqual(properties.icon, base::FilePath(read_icon)); 116 EXPECT_EQ(properties.icon_index, read_icon_index); 117 } 118 119 if (GetVersion() >= VERSION_WIN7) { 120 ScopedComPtr<IPropertyStore> property_store; 121 EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link))); 122 if (FAILED(hr)) 123 return; 124 125 if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) { 126 ScopedPropVariant pv_app_id; 127 EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID, 128 pv_app_id.Receive())); 129 switch (pv_app_id.get().vt) { 130 case VT_EMPTY: 131 EXPECT_TRUE(properties.app_id.empty()); 132 break; 133 case VT_LPWSTR: 134 EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal); 135 break; 136 default: 137 ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt; 138 } 139 } 140 141 if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) { 142 ScopedPropVariant pv_dual_mode; 143 EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode, 144 pv_dual_mode.Receive())); 145 switch (pv_dual_mode.get().vt) { 146 case VT_EMPTY: 147 EXPECT_FALSE(properties.dual_mode); 148 break; 149 case VT_BOOL: 150 EXPECT_EQ(properties.dual_mode, 151 static_cast<bool>(pv_dual_mode.get().boolVal)); 152 break; 153 default: 154 ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt; 155 } 156 } 157 } 158 } 159 160 } // namespace win 161 } // namespace base 162