OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/win/shortcut.h" | 5 #include "base/win/shortcut.h" |
6 | 6 |
7 #include <shellapi.h> | 7 #include <shellapi.h> |
| 8 #include <shldisp.h> |
8 #include <shlobj.h> | 9 #include <shlobj.h> |
9 #include <propkey.h> | 10 #include <propkey.h> |
10 | 11 |
11 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/strings/string_util.h" |
12 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
| 15 #include "base/win/scoped_bstr.h" |
13 #include "base/win/scoped_comptr.h" | 16 #include "base/win/scoped_comptr.h" |
| 17 #include "base/win/scoped_handle.h" |
14 #include "base/win/scoped_propvariant.h" | 18 #include "base/win/scoped_propvariant.h" |
| 19 #include "base/win/scoped_variant.h" |
15 #include "base/win/win_util.h" | 20 #include "base/win/win_util.h" |
16 #include "base/win/windows_version.h" | 21 #include "base/win/windows_version.h" |
17 | 22 |
18 namespace base { | 23 namespace base { |
19 namespace win { | 24 namespace win { |
20 | 25 |
21 namespace { | 26 namespace { |
22 | 27 |
| 28 // String resource IDs in shell32.dll. |
| 29 const uint32_t kPinToTaskbarID = 5386; |
| 30 const uint32_t kUnpinFromTaskbarID = 5387; |
| 31 |
| 32 // Traits for a GenericScopedHandle that will free a module on closure. |
| 33 struct ModuleTraits { |
| 34 typedef HMODULE Handle; |
| 35 static Handle NullHandle() { return nullptr; } |
| 36 static bool IsHandleValid(Handle module) { return !!module; } |
| 37 static bool CloseHandle(Handle module) { return !!::FreeLibrary(module); } |
| 38 |
| 39 private: |
| 40 DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleTraits); |
| 41 }; |
| 42 |
| 43 // An object that will free a module when it goes out of scope. |
| 44 using ScopedLibrary = GenericScopedHandle<ModuleTraits, DummyVerifierTraits>; |
| 45 |
| 46 // Returns the shell resource string identified by |resource_id|, or an empty |
| 47 // string on error. |
| 48 string16 LoadShellResourceString(uint32_t resource_id) { |
| 49 ScopedLibrary shell32(::LoadLibrary(L"shell32.dll")); |
| 50 if (!shell32.IsValid()) |
| 51 return string16(); |
| 52 |
| 53 const wchar_t* resource_ptr = nullptr; |
| 54 int length = ::LoadStringW(shell32.Get(), resource_id, |
| 55 reinterpret_cast<wchar_t*>(&resource_ptr), 0); |
| 56 if (!length || !resource_ptr) |
| 57 return string16(); |
| 58 return string16(resource_ptr, length); |
| 59 } |
| 60 |
| 61 // Uses the shell to perform the verb identified by |resource_id| on |path|. |
| 62 bool DoVerbOnFile(uint32_t resource_id, const FilePath& path) { |
| 63 string16 verb_name(LoadShellResourceString(resource_id)); |
| 64 if (verb_name.empty()) |
| 65 return false; |
| 66 |
| 67 ScopedComPtr<IShellDispatch> shell_dispatch; |
| 68 HRESULT hresult = |
| 69 shell_dispatch.CreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER); |
| 70 if (FAILED(hresult) || !shell_dispatch.get()) |
| 71 return false; |
| 72 |
| 73 ScopedComPtr<Folder> folder; |
| 74 hresult = shell_dispatch->NameSpace( |
| 75 ScopedVariant(path.DirName().value().c_str()), folder.Receive()); |
| 76 if (FAILED(hresult) || !folder.get()) |
| 77 return false; |
| 78 |
| 79 ScopedComPtr<FolderItem> item; |
| 80 hresult = folder->ParseName(ScopedBstr(path.BaseName().value().c_str()), |
| 81 item.Receive()); |
| 82 if (FAILED(hresult) || !item.get()) |
| 83 return false; |
| 84 |
| 85 ScopedComPtr<FolderItemVerbs> verbs; |
| 86 hresult = item->Verbs(verbs.Receive()); |
| 87 if (FAILED(hresult) || !verbs.get()) |
| 88 return false; |
| 89 |
| 90 long verb_count = 0; |
| 91 hresult = verbs->get_Count(&verb_count); |
| 92 if (FAILED(hresult)) |
| 93 return false; |
| 94 |
| 95 for (long i = 0; i < verb_count; ++i) { |
| 96 ScopedComPtr<FolderItemVerb> verb; |
| 97 hresult = verbs->Item(ScopedVariant(i, VT_I4), verb.Receive()); |
| 98 if (FAILED(hresult) || !verb.get()) |
| 99 continue; |
| 100 ScopedBstr name; |
| 101 hresult = verb->get_Name(name.Receive()); |
| 102 if (FAILED(hresult)) |
| 103 continue; |
| 104 if (StringPiece16(name, name.Length()) == verb_name) { |
| 105 hresult = verb->DoIt(); |
| 106 return SUCCEEDED(hresult); |
| 107 } |
| 108 } |
| 109 return false; |
| 110 } |
| 111 |
23 // Initializes |i_shell_link| and |i_persist_file| (releasing them first if they | 112 // Initializes |i_shell_link| and |i_persist_file| (releasing them first if they |
24 // are already initialized). | 113 // are already initialized). |
25 // If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|. | 114 // If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|. |
26 // If any of the above steps fail, both |i_shell_link| and |i_persist_file| will | 115 // If any of the above steps fail, both |i_shell_link| and |i_persist_file| will |
27 // be released. | 116 // be released. |
28 void InitializeShortcutInterfaces( | 117 void InitializeShortcutInterfaces( |
29 const wchar_t* shortcut, | 118 const wchar_t* shortcut, |
30 ScopedComPtr<IShellLink>* i_shell_link, | 119 ScopedComPtr<IShellLink>* i_shell_link, |
31 ScopedComPtr<IPersistFile>* i_persist_file) { | 120 ScopedComPtr<IPersistFile>* i_persist_file) { |
32 i_shell_link->Release(); | 121 i_shell_link->Release(); |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 if (!ResolveShortcutProperties(shortcut_path, options, &properties)) | 396 if (!ResolveShortcutProperties(shortcut_path, options, &properties)) |
308 return false; | 397 return false; |
309 | 398 |
310 if (target_path) | 399 if (target_path) |
311 *target_path = properties.target; | 400 *target_path = properties.target; |
312 if (args) | 401 if (args) |
313 *args = properties.arguments; | 402 *args = properties.arguments; |
314 return true; | 403 return true; |
315 } | 404 } |
316 | 405 |
317 bool TaskbarPinShortcutLink(const wchar_t* shortcut) { | 406 bool TaskbarPinShortcutLink(const FilePath& shortcut) { |
318 base::ThreadRestrictions::AssertIOAllowed(); | 407 base::ThreadRestrictions::AssertIOAllowed(); |
319 | 408 |
320 // "Pin to taskbar" is only supported after Win7. | 409 // "Pin to taskbar" is only supported after Win7. |
321 if (GetVersion() < VERSION_WIN7) | 410 if (GetVersion() < VERSION_WIN7) |
322 return false; | 411 return false; |
323 | 412 |
324 intptr_t result = reinterpret_cast<intptr_t>( | 413 return DoVerbOnFile(kPinToTaskbarID, shortcut); |
325 ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0)); | |
326 return result > 32; | |
327 } | 414 } |
328 | 415 |
329 bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) { | 416 bool TaskbarUnpinShortcutLink(const FilePath& shortcut) { |
330 base::ThreadRestrictions::AssertIOAllowed(); | 417 base::ThreadRestrictions::AssertIOAllowed(); |
331 | 418 |
332 // "Unpin from taskbar" is only supported after Win7. | 419 // "Unpin from taskbar" is only supported after Win7. |
333 if (GetVersion() < VERSION_WIN7) | 420 if (GetVersion() < VERSION_WIN7) |
334 return false; | 421 return false; |
335 | 422 |
336 intptr_t result = reinterpret_cast<intptr_t>( | 423 return DoVerbOnFile(kUnpinFromTaskbarID, shortcut); |
337 ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0)); | |
338 return result > 32; | |
339 } | 424 } |
340 | 425 |
341 } // namespace win | 426 } // namespace win |
342 } // namespace base | 427 } // namespace base |
OLD | NEW |