OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "chrome/utility/shell_handler_impl_win.h" |
| 6 |
| 7 #include <shldisp.h> |
| 8 |
| 9 #include "base/files/file_enumerator.h" |
| 10 #include "base/files/file_path.h" |
| 11 #include "base/path_service.h" |
| 12 #include "base/scoped_native_library.h" |
| 13 #include "base/win/scoped_bstr.h" |
| 14 #include "base/win/scoped_com_initializer.h" |
| 15 #include "base/win/scoped_comptr.h" |
| 16 #include "base/win/scoped_variant.h" |
| 17 #include "base/win/shortcut.h" |
| 18 #include "chrome/installer/util/install_util.h" |
| 19 #include "content/public/utility/utility_thread.h" |
| 20 |
| 21 namespace { |
| 22 |
| 23 // This class checks if the current executable is pinned to the taskbar. It also |
| 24 // keeps track of the errors that occurs that prevents it from getting a result. |
| 25 class IsPinnedToTaskbarHelper { |
| 26 public: |
| 27 IsPinnedToTaskbarHelper() = default; |
| 28 |
| 29 // Returns true if the current executable is pinned to the taskbar. |
| 30 bool GetResult(); |
| 31 |
| 32 bool error_occured() { return error_occured_; } |
| 33 |
| 34 private: |
| 35 // Returns the shell resource string identified by |resource_id|, or an empty |
| 36 // string on error. |
| 37 base::string16 LoadShellResourceString(uint32_t resource_id); |
| 38 |
| 39 // Returns true if the "Unpin from taskbar" verb is available for |shortcut|, |
| 40 // which means that the shortcut is pinned to the taskbar. |
| 41 bool ShortcutHasUnpinToTaskbarVerb(const base::FilePath& shortcut); |
| 42 |
| 43 // Returns true if the target parameter of the |shortcut| evaluates to |
| 44 // |program_compare|. |
| 45 bool IsShortcutForProgram(const base::FilePath& shortcut, |
| 46 const InstallUtil::ProgramCompare& program_compare); |
| 47 |
| 48 // Returns true if one of the shortcut inside the given |directory| evaluates |
| 49 // to |program_compare| and is pinned to the taskbar. |
| 50 bool DirectoryContainsPinnedShortcutForProgram( |
| 51 const base::FilePath& directory, |
| 52 const InstallUtil::ProgramCompare& program_compare); |
| 53 |
| 54 bool error_occured_ = false; |
| 55 base::win::ScopedCOMInitializer scoped_com_initializer_; |
| 56 |
| 57 DISALLOW_COPY_AND_ASSIGN(IsPinnedToTaskbarHelper); |
| 58 }; |
| 59 |
| 60 base::string16 IsPinnedToTaskbarHelper::LoadShellResourceString( |
| 61 uint32_t resource_id) { |
| 62 base::ScopedNativeLibrary scoped_native_library(::LoadLibraryEx( |
| 63 FILE_PATH_LITERAL("shell32.dll"), nullptr, LOAD_LIBRARY_AS_DATAFILE)); |
| 64 if (!scoped_native_library.is_valid()) |
| 65 return base::string16(); |
| 66 |
| 67 const wchar_t* resource_ptr = nullptr; |
| 68 int length = ::LoadStringW(scoped_native_library.get(), resource_id, |
| 69 reinterpret_cast<wchar_t*>(&resource_ptr), 0); |
| 70 if (!length || !resource_ptr) |
| 71 return base::string16(); |
| 72 return base::string16(resource_ptr, length); |
| 73 } |
| 74 |
| 75 bool IsPinnedToTaskbarHelper::ShortcutHasUnpinToTaskbarVerb( |
| 76 const base::FilePath& shortcut) { |
| 77 // Found inside shell32.dll's resources. |
| 78 constexpr uint32_t kUnpinFromTaskbarID = 5387; |
| 79 |
| 80 base::string16 verb_name(LoadShellResourceString(kUnpinFromTaskbarID)); |
| 81 if (verb_name.empty()) { |
| 82 error_occured_ = true; |
| 83 return false; |
| 84 } |
| 85 |
| 86 base::win::ScopedComPtr<IShellDispatch> shell_dispatch; |
| 87 HRESULT hresult = |
| 88 shell_dispatch.CreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER); |
| 89 if (FAILED(hresult) || !shell_dispatch) { |
| 90 error_occured_ = true; |
| 91 return false; |
| 92 } |
| 93 |
| 94 base::win::ScopedComPtr<Folder> folder; |
| 95 hresult = shell_dispatch->NameSpace( |
| 96 base::win::ScopedVariant(shortcut.DirName().value().c_str()), |
| 97 folder.Receive()); |
| 98 if (FAILED(hresult) || !folder) { |
| 99 error_occured_ = true; |
| 100 return false; |
| 101 } |
| 102 |
| 103 base::win::ScopedComPtr<FolderItem> item; |
| 104 hresult = folder->ParseName( |
| 105 base::win::ScopedBstr(shortcut.BaseName().value().c_str()), |
| 106 item.Receive()); |
| 107 if (FAILED(hresult) || !item) { |
| 108 error_occured_ = true; |
| 109 return false; |
| 110 } |
| 111 |
| 112 base::win::ScopedComPtr<FolderItemVerbs> verbs; |
| 113 hresult = item->Verbs(verbs.Receive()); |
| 114 if (FAILED(hresult) || !verbs) { |
| 115 error_occured_ = true; |
| 116 return false; |
| 117 } |
| 118 |
| 119 long verb_count = 0; |
| 120 hresult = verbs->get_Count(&verb_count); |
| 121 if (FAILED(hresult)) { |
| 122 error_occured_ = true; |
| 123 return false; |
| 124 } |
| 125 |
| 126 long error_count = 0; |
| 127 for (long i = 0; i < verb_count; ++i) { |
| 128 base::win::ScopedComPtr<FolderItemVerb> verb; |
| 129 hresult = verbs->Item(base::win::ScopedVariant(i, VT_I4), verb.Receive()); |
| 130 if (FAILED(hresult) || !verb) { |
| 131 error_count++; |
| 132 continue; |
| 133 } |
| 134 base::win::ScopedBstr name; |
| 135 hresult = verb->get_Name(name.Receive()); |
| 136 if (FAILED(hresult)) { |
| 137 error_count++; |
| 138 continue; |
| 139 } |
| 140 if (base::StringPiece16(name, name.Length()) == verb_name) |
| 141 return true; |
| 142 } |
| 143 |
| 144 if (error_count == verb_count) |
| 145 error_occured_ = true; |
| 146 |
| 147 return false; |
| 148 } |
| 149 |
| 150 bool IsPinnedToTaskbarHelper::IsShortcutForProgram( |
| 151 const base::FilePath& shortcut, |
| 152 const InstallUtil::ProgramCompare& program_compare) { |
| 153 base::win::ShortcutProperties shortcut_properties; |
| 154 if (!ResolveShortcutProperties( |
| 155 shortcut, base::win::ShortcutProperties::PROPERTIES_TARGET, |
| 156 &shortcut_properties)) { |
| 157 return false; |
| 158 } |
| 159 |
| 160 return program_compare.EvaluatePath(shortcut_properties.target); |
| 161 } |
| 162 |
| 163 bool IsPinnedToTaskbarHelper::DirectoryContainsPinnedShortcutForProgram( |
| 164 const base::FilePath& directory, |
| 165 const InstallUtil::ProgramCompare& program_compare) { |
| 166 base::FileEnumerator shortcut_enum(directory, false, |
| 167 base::FileEnumerator::FILES); |
| 168 for (base::FilePath shortcut = shortcut_enum.Next(); !shortcut.empty(); |
| 169 shortcut = shortcut_enum.Next()) { |
| 170 if (IsShortcutForProgram(shortcut, program_compare) && |
| 171 ShortcutHasUnpinToTaskbarVerb(shortcut)) { |
| 172 return true; |
| 173 } |
| 174 } |
| 175 return false; |
| 176 } |
| 177 |
| 178 bool IsPinnedToTaskbarHelper::GetResult() { |
| 179 base::FilePath current_exe; |
| 180 PathService::Get(base::FILE_EXE, ¤t_exe); |
| 181 |
| 182 InstallUtil::ProgramCompare current_exe_compare(current_exe); |
| 183 // Look into the "Quick Launch\User Pinned\TaskBar" folder. |
| 184 base::FilePath taskbar_pins_dir; |
| 185 PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_pins_dir); |
| 186 if (DirectoryContainsPinnedShortcutForProgram(taskbar_pins_dir, |
| 187 current_exe_compare)) { |
| 188 return true; |
| 189 } |
| 190 |
| 191 // Check all folders in ImplicitAppShortcuts. |
| 192 base::FilePath implicit_app_shortcuts_dir; |
| 193 PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, |
| 194 &implicit_app_shortcuts_dir); |
| 195 base::FileEnumerator directory_enum(implicit_app_shortcuts_dir, false, |
| 196 base::FileEnumerator::DIRECTORIES); |
| 197 for (base::FilePath directory = directory_enum.Next(); !directory.empty(); |
| 198 directory = directory_enum.Next()) { |
| 199 if (DirectoryContainsPinnedShortcutForProgram(directory, |
| 200 current_exe_compare)) { |
| 201 return true; |
| 202 } |
| 203 } |
| 204 return false; |
| 205 } |
| 206 |
| 207 } // namespace |
| 208 |
| 209 // static |
| 210 void ShellHandlerImpl::Create(mojom::ShellHandlerRequest request) { |
| 211 new ShellHandlerImpl(std::move(request)); |
| 212 } |
| 213 |
| 214 ShellHandlerImpl::ShellHandlerImpl(mojom::ShellHandlerRequest request) |
| 215 : binding_(this, std::move(request)) {} |
| 216 |
| 217 ShellHandlerImpl::~ShellHandlerImpl() = default; |
| 218 |
| 219 void ShellHandlerImpl::IsPinnedToTaskbar( |
| 220 const IsPinnedToTaskbarCallback& callback) { |
| 221 IsPinnedToTaskbarHelper helper; |
| 222 bool is_pinned_to_taskbar = helper.GetResult(); |
| 223 callback.Run(!helper.error_occured(), is_pinned_to_taskbar); |
| 224 } |
OLD | NEW |