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/win/shortcut.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <propkey.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_propvariant.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/win_util.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are already initialized). 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If any of the above steps fail, both |i_shell_link| and |i_persist_file| will 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be released. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InitializeShortcutInterfaces( 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const wchar_t* shortcut, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IShellLink>* i_shell_link, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPersistFile>* i_persist_file) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->Release(); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_persist_file->Release(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CLSCTX_INPROC_SERVER)) || 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAILED(i_persist_file->QueryFrom(*i_shell_link)) || 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link->Release(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_persist_file->Release(); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ShortcutProperties& properties, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ShortcutOperation operation) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A target is required unless |operation| is SHORTCUT_UPDATE_EXISTING. 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (operation != SHORTCUT_UPDATE_EXISTING && 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch bool shortcut_existed = PathExists(shortcut_path); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Interfaces to the old shortcut when replacing an existing shortcut. 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedComPtr<IShellLink> old_i_shell_link; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedComPtr<IPersistFile> old_i_persist_file; 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Interfaces to the shortcut being created/updated. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IShellLink> i_shell_link; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPersistFile> i_persist_file; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (operation) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHORTCUT_CREATE_ALWAYS: 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHORTCUT_UPDATE_EXISTING: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &i_persist_file); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case SHORTCUT_REPLACE_EXISTING: 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) InitializeShortcutInterfaces(shortcut_path.value().c_str(), 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &old_i_shell_link, &old_i_persist_file); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Confirm |shortcut_path| exists and is a shortcut by verifying 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |old_i_persist_file| was successfully initialized in the call above. If 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // so, initialize the interfaces to begin writing a new shortcut (to 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overwrite the current one if successful). 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (old_i_persist_file.get()) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return false immediately upon failure to initialize shortcut interfaces. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!i_persist_file.get()) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) && 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) && 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAILED(i_shell_link->SetWorkingDirectory( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties.working_dir.value().c_str()))) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) { 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(i_shell_link->SetArguments(properties.arguments.c_str()))) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (old_i_persist_file.get()) { 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wchar_t current_arguments[MAX_PATH] = {0}; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SUCCEEDED(old_i_shell_link->GetArguments(current_arguments, 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MAX_PATH))) { 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) i_shell_link->SetArguments(current_arguments); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) && 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAILED(i_shell_link->SetDescription(properties.description.c_str()))) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((properties.options & ShortcutProperties::PROPERTIES_ICON) && 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(), 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties.icon_index))) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool has_app_id = 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool has_dual_mode = 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((has_app_id || has_dual_mode) && 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetVersion() >= VERSION_WIN7) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPropertyStore> property_store; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get()) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (has_app_id && 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !SetAppIdForPropertyStore(property_store, properties.app_id.c_str())) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (has_dual_mode && 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !SetBooleanValueForPropertyStore(property_store, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PKEY_AppUserModel_IsDualMode, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) properties.dual_mode)) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Release the interfaces to the old shortcut to make sure it doesn't prevent 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // overwriting it if needed. 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) old_i_persist_file.Release(); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) old_i_shell_link.Release(); 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Release the interfaces in case the SHChangeNotify call below depends on 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the operations above being fully completed. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_persist_file.Release(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i_shell_link.Release(); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we successfully created/updated the icon, notify the shell that we have 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // done so. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const bool succeeded = SUCCEEDED(result); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (succeeded) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (shortcut_existed) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(gab): SHCNE_UPDATEITEM might be sufficient here; further testing 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // required. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, shortcut_path.value().c_str(), 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return succeeded; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResolveShortcutProperties(const FilePath& shortcut_path, 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 options, 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ShortcutProperties* properties) { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(options && properties); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ~ShortcutProperties::PROPERTIES_ALL) 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTREACHED() << "Unhandled property is used."; 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IShellLink> i_shell_link; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get pointer to the IShellLink interface. 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CLSCTX_INPROC_SERVER))) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IPersistFile> persist; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Query IShellLink for the IPersistFile interface. 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(persist.QueryFrom(i_shell_link))) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the shell link. 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(persist->Load(shortcut_path.value().c_str(), STGM_READ))) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Reset |properties|. 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->options = 0; 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) wchar_t temp[MAX_PATH]; 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_TARGET) { 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY))) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_target(FilePath(temp)); 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_WORKING_DIR) { 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link->GetWorkingDirectory(temp, MAX_PATH))) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_working_dir(FilePath(temp)); 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_ARGUMENTS) { 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link->GetArguments(temp, MAX_PATH))) 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_arguments(temp); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_DESCRIPTION) { 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Note: description length constrained by MAX_PATH. 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link->GetDescription(temp, MAX_PATH))) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_description(temp); 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_ICON) { 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int temp_index; 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(i_shell_link->GetIconLocation(temp, MAX_PATH, &temp_index))) 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_icon(FilePath(temp), temp_index); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Windows 7+ options, avoiding unnecessary work. 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ((options & ShortcutProperties::PROPERTIES_WIN7) && 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetVersion() >= VERSION_WIN7) { 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedComPtr<IPropertyStore> property_store; 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(property_store.QueryFrom(i_shell_link))) 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_APP_ID) { 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedPropVariant pv_app_id; 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (property_store->GetValue(PKEY_AppUserModel_ID, 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pv_app_id.Receive()) != S_OK) { 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (pv_app_id.get().vt) { 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case VT_EMPTY: 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_app_id(L""); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case VT_LPWSTR: 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_app_id(pv_app_id.get().pwszVal); 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTREACHED() << "Unexpected variant type: " << pv_app_id.get().vt; 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (options & ShortcutProperties::PROPERTIES_DUAL_MODE) { 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedPropVariant pv_dual_mode; 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (property_store->GetValue(PKEY_AppUserModel_IsDualMode, 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pv_dual_mode.Receive()) != S_OK) { 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (pv_dual_mode.get().vt) { 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case VT_EMPTY: 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_dual_mode(false); 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case VT_BOOL: 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) properties->set_dual_mode(pv_dual_mode.get().boolVal == VARIANT_TRUE); 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTREACHED() << "Unexpected variant type: " << pv_dual_mode.get().vt; 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResolveShortcut(const FilePath& shortcut_path, 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FilePath* target_path, 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) string16* args) { 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 options = 0; 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (target_path) 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) options |= ShortcutProperties::PROPERTIES_TARGET; 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (args) 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) options |= ShortcutProperties::PROPERTIES_ARGUMENTS; 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(options); 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ShortcutProperties properties; 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!ResolveShortcutProperties(shortcut_path, options, &properties)) 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (target_path) 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *target_path = properties.target; 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (args) 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *args = properties.arguments; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TaskbarPinShortcutLink(const wchar_t* shortcut) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Pin to taskbar" is only supported after Win7. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetVersion() < VERSION_WIN7) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarpin", shortcut, 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, 0)); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result > 32; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "Unpin from taskbar" is only supported after Win7. 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (GetVersion() < VERSION_WIN7) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int result = reinterpret_cast<int>(ShellExecute(NULL, L"taskbarunpin", 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shortcut, NULL, NULL, 0)); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result > 32; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace win 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace base 334