File: taskbar_util.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (167 lines) | stat: -rw-r--r-- 5,925 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/installer/util/taskbar_util.h"

#include <objbase.h>

#include <shellapi.h>
#include <shlobj.h>
#include <wrl/client.h>

#include "base/files/file_path.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "chrome/install_static/install_util.h"

namespace {

enum class PinnedListModifyCaller { kExplorer = 4 };

constexpr GUID CLSID_TaskbandPin = {
    0x90aa3a4e,
    0x1cba,
    0x4233,
    {0xb8, 0xbb, 0x53, 0x57, 0x73, 0xd4, 0x84, 0x49}};

constexpr wchar_t kInstallerPinned[] = L"InstallerPinned";

// Set by tests to control whether or not pinning to taskbar is allowed.
CanPinToTaskBarDelegateFunctionPtr g_can_pin_to_taskbar;

// Undocumented COM interface for manipulating taskbar pinned list.
class __declspec(uuid("0DD79AE2-D156-45D4-9EEB-3B549769E940")) IPinnedList3
    : public IUnknown {
 public:
  virtual HRESULT STDMETHODCALLTYPE EnumObjects() = 0;
  virtual HRESULT STDMETHODCALLTYPE GetPinnableInfo() = 0;
  virtual HRESULT STDMETHODCALLTYPE IsPinnable() = 0;
  virtual HRESULT STDMETHODCALLTYPE Resolve() = 0;
  virtual HRESULT STDMETHODCALLTYPE LegacyModify() = 0;
  virtual HRESULT STDMETHODCALLTYPE GetChangeCount() = 0;
  virtual HRESULT STDMETHODCALLTYPE IsPinned(PCIDLIST_ABSOLUTE) = 0;
  virtual HRESULT STDMETHODCALLTYPE GetPinnedItem() = 0;
  virtual HRESULT STDMETHODCALLTYPE GetAppIDForPinnedItem() = 0;
  virtual HRESULT STDMETHODCALLTYPE ItemChangeNotify() = 0;
  virtual HRESULT STDMETHODCALLTYPE UpdateForRemovedItemsAsNecessary() = 0;
  virtual HRESULT STDMETHODCALLTYPE PinShellLink() = 0;
  virtual HRESULT STDMETHODCALLTYPE GetPinnedItemForAppID() = 0;
  virtual HRESULT STDMETHODCALLTYPE Modify(PCIDLIST_ABSOLUTE unpin,
                                           PCIDLIST_ABSOLUTE pin,
                                           PinnedListModifyCaller caller) = 0;
};

// ScopedPIDLFromPath class, and the idea of using IPinnedList3::Modify,
// are thanks to Gee Law <https://geelaw.blog/entries/msedge-pins/>
class ScopedPIDLFromPath {
 public:
  explicit ScopedPIDLFromPath(PCWSTR path)
      : p_id_list_(ILCreateFromPath(path)) {}
  ~ScopedPIDLFromPath() {
    if (p_id_list_)
      ILFree(p_id_list_);
  }
  PIDLIST_ABSOLUTE Get() const { return p_id_list_; }

 private:
  PIDLIST_ABSOLUTE const p_id_list_;
};

// Returns the taskbar pinned list if successful, an empty ComPtr otherwise.
Microsoft::WRL::ComPtr<IPinnedList3> GetTaskbarPinnedList() {
  if (base::win::GetVersion() < base::win::Version::WIN10_RS5)
    return nullptr;

  Microsoft::WRL::ComPtr<IPinnedList3> pinned_list;
  if (FAILED(CoCreateInstance(CLSID_TaskbandPin, nullptr, CLSCTX_INPROC_SERVER,
                              IID_PPV_ARGS(&pinned_list)))) {
    return nullptr;
  }

  return pinned_list;
}

// Use IPinnedList3 to pin shortcut to taskbar on WIN10_RS5 and above.
// Returns true if pinning was successful.
// static
bool PinShortcutWithIPinnedList3(const base::FilePath& shortcut) {
  Microsoft::WRL::ComPtr<IPinnedList3> pinned_list = GetTaskbarPinnedList();
  if (!pinned_list)
    return false;

  ScopedPIDLFromPath item_id_list(shortcut.value().data());
  HRESULT hr = pinned_list->Modify(nullptr, item_id_list.Get(),
                                   PinnedListModifyCaller::kExplorer);
  return SUCCEEDED(hr);
}

// Use IPinnedList3 to unpin shortcut to taskbar on WIN10_RS5 and above.
// Returns true if unpinning was successful.
// static
bool UnpinShortcutWithIPinnedList3(const base::FilePath& shortcut) {
  Microsoft::WRL::ComPtr<IPinnedList3> pinned_list = GetTaskbarPinnedList();
  if (!pinned_list)
    return false;

  ScopedPIDLFromPath item_id_list(shortcut.value().data());
  HRESULT hr = pinned_list->Modify(item_id_list.Get(), nullptr,
                                   PinnedListModifyCaller::kExplorer);
  return SUCCEEDED(hr);
}

}  // namespace

bool CanPinShortcutToTaskbar() {
  // "Pin to taskbar" isn't directly supported in Windows 10, but WIN10_RS5 has
  // some undocumented interfaces to do pinning.
  return base::win::GetVersion() >= base::win::Version::WIN10_RS5;
}

bool PinShortcutToTaskbar(const base::FilePath& shortcut) {
  if (g_can_pin_to_taskbar && !(*g_can_pin_to_taskbar)()) {
    return false;
  }
  return PinShortcutWithIPinnedList3(shortcut);
}

bool UnpinShortcutFromTaskbar(const base::FilePath& shortcut) {
  return UnpinShortcutWithIPinnedList3(shortcut);
}

std::optional<bool> IsShortcutPinnedToTaskbar(const base::FilePath& shortcut) {
  Microsoft::WRL::ComPtr<IPinnedList3> pinned_list = GetTaskbarPinnedList();
  if (!pinned_list.Get())
    return std::nullopt;

  ScopedPIDLFromPath item_id_list(shortcut.value().data());
  HRESULT hr = pinned_list->IsPinned(item_id_list.Get());
  // S_OK means `shortcut` is pinned, S_FALSE means it's not pinned.
  return SUCCEEDED(hr) ? std::optional<bool>(hr == S_OK) : std::nullopt;
}

void SetCanPinToTaskbarDelegate(CanPinToTaskBarDelegateFunctionPtr delegate) {
  g_can_pin_to_taskbar = delegate;
}

bool SetInstallerPinnedChromeToTaskbar(bool installed) {
  base::win::RegKey key;
  if (key.Create(HKEY_CURRENT_USER, install_static::GetRegistryPath().c_str(),
                 KEY_SET_VALUE) == ERROR_SUCCESS) {
    return key.WriteValue(kInstallerPinned, installed ? 1 : 0) == ERROR_SUCCESS;
  }
  return false;
}

std::optional<bool> GetInstallerPinnedChromeToTaskbar() {
  base::win::RegKey key;
  if (key.Open(HKEY_CURRENT_USER, install_static::GetRegistryPath().c_str(),
               KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
    DWORD installer_pinned = 0;
    LONG result = key.ReadValueDW(kInstallerPinned, &installer_pinned);
    if (result == ERROR_SUCCESS)
      return installer_pinned != 0;
  }
  return std::nullopt;
}