| Index: base/win/shortcut.cc
|
| diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
|
| index f8b2182b28664224c76ff39321dfcd6d326d5275..57f8e615d1dc5609062fc4a9e84460b434afcfea 100644
|
| --- a/base/win/shortcut.cc
|
| +++ b/base/win/shortcut.cc
|
| @@ -5,13 +5,18 @@
|
| #include "base/win/shortcut.h"
|
|
|
| #include <shellapi.h>
|
| +#include <shldisp.h>
|
| #include <shlobj.h>
|
| #include <propkey.h>
|
|
|
| #include "base/files/file_util.h"
|
| +#include "base/strings/string_util.h"
|
| #include "base/threading/thread_restrictions.h"
|
| +#include "base/win/scoped_bstr.h"
|
| #include "base/win/scoped_comptr.h"
|
| +#include "base/win/scoped_handle.h"
|
| #include "base/win/scoped_propvariant.h"
|
| +#include "base/win/scoped_variant.h"
|
| #include "base/win/win_util.h"
|
| #include "base/win/windows_version.h"
|
|
|
| @@ -20,6 +25,90 @@ namespace win {
|
|
|
| namespace {
|
|
|
| +// String resource IDs in shell32.dll.
|
| +const uint32_t kPinToTaskbarID = 5386;
|
| +const uint32_t kUnpinFromTaskbarID = 5387;
|
| +
|
| +// Traits for a GenericScopedHandle that will free a module on closure.
|
| +struct ModuleTraits {
|
| + typedef HMODULE Handle;
|
| + static Handle NullHandle() { return nullptr; }
|
| + static bool IsHandleValid(Handle module) { return !!module; }
|
| + static bool CloseHandle(Handle module) { return !!::FreeLibrary(module); }
|
| +
|
| + private:
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleTraits);
|
| +};
|
| +
|
| +// An object that will free a module when it goes out of scope.
|
| +using ScopedLibrary = GenericScopedHandle<ModuleTraits, DummyVerifierTraits>;
|
| +
|
| +// Returns the shell resource string identified by |resource_id|, or an empty
|
| +// string on error.
|
| +string16 LoadShellResourceString(uint32_t resource_id) {
|
| + ScopedLibrary shell32(::LoadLibrary(L"shell32.dll"));
|
| + if (!shell32.IsValid())
|
| + return string16();
|
| +
|
| + const wchar_t* resource_ptr = nullptr;
|
| + int length = ::LoadStringW(shell32.Get(), resource_id,
|
| + reinterpret_cast<wchar_t*>(&resource_ptr), 0);
|
| + if (!length || !resource_ptr)
|
| + return string16();
|
| + return string16(resource_ptr, length);
|
| +}
|
| +
|
| +// Uses the shell to perform the verb identified by |resource_id| on |path|.
|
| +bool DoVerbOnFile(uint32_t resource_id, const FilePath& path) {
|
| + string16 verb_name(LoadShellResourceString(resource_id));
|
| + if (verb_name.empty())
|
| + return false;
|
| +
|
| + ScopedComPtr<IShellDispatch> shell_dispatch;
|
| + HRESULT hresult =
|
| + shell_dispatch.CreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER);
|
| + if (FAILED(hresult) || !shell_dispatch.get())
|
| + return false;
|
| +
|
| + ScopedComPtr<Folder> folder;
|
| + hresult = shell_dispatch->NameSpace(
|
| + ScopedVariant(path.DirName().value().c_str()), folder.Receive());
|
| + if (FAILED(hresult) || !folder.get())
|
| + return false;
|
| +
|
| + ScopedComPtr<FolderItem> item;
|
| + hresult = folder->ParseName(ScopedBstr(path.BaseName().value().c_str()),
|
| + item.Receive());
|
| + if (FAILED(hresult) || !item.get())
|
| + return false;
|
| +
|
| + ScopedComPtr<FolderItemVerbs> verbs;
|
| + hresult = item->Verbs(verbs.Receive());
|
| + if (FAILED(hresult) || !verbs.get())
|
| + return false;
|
| +
|
| + long verb_count = 0;
|
| + hresult = verbs->get_Count(&verb_count);
|
| + if (FAILED(hresult))
|
| + return false;
|
| +
|
| + for (long i = 0; i < verb_count; ++i) {
|
| + ScopedComPtr<FolderItemVerb> verb;
|
| + hresult = verbs->Item(ScopedVariant(i, VT_I4), verb.Receive());
|
| + if (FAILED(hresult) || !verb.get())
|
| + continue;
|
| + ScopedBstr name;
|
| + hresult = verb->get_Name(name.Receive());
|
| + if (FAILED(hresult))
|
| + continue;
|
| + if (StringPiece16(name, name.Length()) == verb_name) {
|
| + hresult = verb->DoIt();
|
| + return SUCCEEDED(hresult);
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| // Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
|
| // are already initialized).
|
| // If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
|
| @@ -314,28 +403,24 @@ bool ResolveShortcut(const FilePath& shortcut_path,
|
| return true;
|
| }
|
|
|
| -bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
|
| +bool TaskbarPinShortcutLink(const FilePath& shortcut) {
|
| base::ThreadRestrictions::AssertIOAllowed();
|
|
|
| // "Pin to taskbar" is only supported after Win7.
|
| if (GetVersion() < VERSION_WIN7)
|
| return false;
|
|
|
| - intptr_t result = reinterpret_cast<intptr_t>(
|
| - ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
|
| - return result > 32;
|
| + return DoVerbOnFile(kPinToTaskbarID, shortcut);
|
| }
|
|
|
| -bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
|
| +bool TaskbarUnpinShortcutLink(const FilePath& shortcut) {
|
| base::ThreadRestrictions::AssertIOAllowed();
|
|
|
| // "Unpin from taskbar" is only supported after Win7.
|
| if (GetVersion() < VERSION_WIN7)
|
| return false;
|
|
|
| - intptr_t result = reinterpret_cast<intptr_t>(
|
| - ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
|
| - return result > 32;
|
| + return DoVerbOnFile(kUnpinFromTaskbarID, shortcut);
|
| }
|
|
|
| } // namespace win
|
|
|