15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/test/test_shortcut_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <propkey.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_propvariant.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Validates |actual_path|'s LongPathName case-insensitively matches 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |expected_path|'s LongPathName. 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ValidatePathsAreEqual(const base::FilePath& expected_path, 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::FilePath& actual_path) { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t long_expected_path_chars[MAX_PATH] = {0}; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t long_actual_path_chars[MAX_PATH] = {0}; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If |expected_path| is empty confirm immediately that |actual_path| is also 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // empty. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (expected_path.empty()) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(actual_path.empty()); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Proceed with LongPathName matching which will also confirm the paths exist. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_NE(0U, ::GetLongPathName( 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_path.value().c_str(), long_expected_path_chars, MAX_PATH)) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to get LongPathName of " << expected_path.value(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_NE(0U, ::GetLongPathName( 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual_path.value().c_str(), long_actual_path_chars, MAX_PATH)) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to get LongPathName of " << actual_path.value(); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath long_expected_path(long_expected_path_chars); 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath long_actual_path(long_actual_path_chars); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(long_expected_path.empty()); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(long_actual_path.empty()); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(long_expected_path, long_actual_path); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ValidateShortcut(const base::FilePath& shortcut_path, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ShortcutProperties& properties) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IShellLink> i_shell_link; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPersistFile> i_persist_file; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t read_target[MAX_PATH] = {0}; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t read_working_dir[MAX_PATH] = {0}; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t read_arguments[MAX_PATH] = {0}; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t read_description[MAX_PATH] = {0}; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wchar_t read_icon[MAX_PATH] = {0}; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int read_icon_index = 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize the shell interfaces. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance( 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER))); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link))); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the shortcut. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load( 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at " 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << shortcut_path.value(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_TARGET) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED( 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH))); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ValidatePathsAreEqual(properties.target, base::FilePath(read_target)); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED( 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH))); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ValidatePathsAreEqual(properties.working_dir, 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath(read_working_dir)); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED( 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->GetArguments(read_arguments, MAX_PATH))); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(properties.arguments, read_arguments); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED( 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->GetDescription(read_description, MAX_PATH))); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(properties.description, read_description); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_ICON) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED( 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index))); 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ValidatePathsAreEqual(properties.icon, base::FilePath(read_icon)); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(properties.icon_index, read_icon_index); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetVersion() >= VERSION_WIN7) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPropertyStore> property_store; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link))); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) { 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedPropVariant pv_app_id; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pv_app_id.Receive())); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (pv_app_id.get().vt) { 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_EMPTY: 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(properties.app_id.empty()); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_LPWSTR: 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal); 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt; 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedPropVariant pv_dual_mode; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode, 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pv_dual_mode.Receive())); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (pv_dual_mode.get().vt) { 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_EMPTY: 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(properties.dual_mode); 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case VT_BOOL: 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_EQ(properties.dual_mode, 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<bool>(pv_dual_mode.get().boolVal)); 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace win 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 162