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 void ValidatePathsAreEqual(const base::FilePath& expected_path, 23 const base::FilePath& actual_path) { 24 wchar_t long_expected_path_chars[MAX_PATH] = {0}; 25 wchar_t long_actual_path_chars[MAX_PATH] = {0}; 26 27 // If |expected_path| is empty confirm immediately that |actual_path| is also 28 // empty. 29 if (expected_path.empty()) { 30 EXPECT_TRUE(actual_path.empty()); 31 return; 32 } 33 34 // Proceed with LongPathName matching which will also confirm the paths exist. 35 EXPECT_NE(0U, ::GetLongPathName( 36 expected_path.value().c_str(), long_expected_path_chars, MAX_PATH)) 37 << "Failed to get LongPathName of " << expected_path.value(); 38 EXPECT_NE(0U, ::GetLongPathName( 39 actual_path.value().c_str(), long_actual_path_chars, MAX_PATH)) 40 << "Failed to get LongPathName of " << actual_path.value(); 41 42 base::FilePath long_expected_path(long_expected_path_chars); 43 base::FilePath long_actual_path(long_actual_path_chars); 44 EXPECT_FALSE(long_expected_path.empty()); 45 EXPECT_FALSE(long_actual_path.empty()); 46 47 EXPECT_EQ(long_expected_path, long_actual_path); 48 } 49 50 void ValidateShortcut(const base::FilePath& shortcut_path, 51 const ShortcutProperties& properties) { 52 ScopedComPtr<IShellLink> i_shell_link; 53 ScopedComPtr<IPersistFile> i_persist_file; 54 55 wchar_t read_target[MAX_PATH] = {0}; 56 wchar_t read_working_dir[MAX_PATH] = {0}; 57 wchar_t read_arguments[MAX_PATH] = {0}; 58 wchar_t read_description[MAX_PATH] = {0}; 59 wchar_t read_icon[MAX_PATH] = {0}; 60 int read_icon_index = 0; 61 62 HRESULT hr; 63 64 // Initialize the shell interfaces. 65 EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance( 66 CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER))); 67 if (FAILED(hr)) 68 return; 69 70 EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link))); 71 if (FAILED(hr)) 72 return; 73 74 // Load the shortcut. 75 EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load( 76 shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at " 77 << shortcut_path.value(); 78 if (FAILED(hr)) 79 return; 80 81 if (properties.options & ShortcutProperties::PROPERTIES_TARGET) { 82 EXPECT_TRUE(SUCCEEDED( 83 i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH))); 84 ValidatePathsAreEqual(properties.target, base::FilePath(read_target)); 85 } 86 87 if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) { 88 EXPECT_TRUE(SUCCEEDED( 89 i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH))); 90 ValidatePathsAreEqual(properties.working_dir, 91 base::FilePath(read_working_dir)); 92 } 93 94 if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) { 95 EXPECT_TRUE(SUCCEEDED( 96 i_shell_link->GetArguments(read_arguments, MAX_PATH))); 97 EXPECT_EQ(properties.arguments, read_arguments); 98 } 99 100 if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) { 101 EXPECT_TRUE(SUCCEEDED( 102 i_shell_link->GetDescription(read_description, MAX_PATH))); 103 EXPECT_EQ(properties.description, read_description); 104 } 105 106 if (properties.options & ShortcutProperties::PROPERTIES_ICON) { 107 EXPECT_TRUE(SUCCEEDED( 108 i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index))); 109 ValidatePathsAreEqual(properties.icon, base::FilePath(read_icon)); 110 EXPECT_EQ(properties.icon_index, read_icon_index); 111 } 112 113 if (GetVersion() >= VERSION_WIN7) { 114 ScopedComPtr<IPropertyStore> property_store; 115 EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link))); 116 if (FAILED(hr)) 117 return; 118 119 if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) { 120 ScopedPropVariant pv_app_id; 121 EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID, 122 pv_app_id.Receive())); 123 switch (pv_app_id.get().vt) { 124 case VT_EMPTY: 125 EXPECT_TRUE(properties.app_id.empty()); 126 break; 127 case VT_LPWSTR: 128 EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal); 129 break; 130 default: 131 ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt; 132 } 133 } 134 135 if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) { 136 ScopedPropVariant pv_dual_mode; 137 EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode, 138 pv_dual_mode.Receive())); 139 switch (pv_dual_mode.get().vt) { 140 case VT_EMPTY: 141 EXPECT_FALSE(properties.dual_mode); 142 break; 143 case VT_BOOL: 144 EXPECT_EQ(properties.dual_mode, 145 static_cast<bool>(pv_dual_mode.get().boolVal)); 146 break; 147 default: 148 ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt; 149 } 150 } 151 } 152 } 153 154 } // namespace win 155 } // namespace base 156