PinToTaskbar.cpp (4367B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // This file is an NSIS plugin which exports a function that pins a provided 6 // Shortcut to the Windows Taskbar on Windows 10 (1903+) and Windows 11. 7 // This is an adapted version of the Pin to Taskbar code that is used in 8 // Firefox: https://searchfox.org/mozilla-central/rev/4bce7d85ba4796dd03c5dcc7cfe8eee0e4c07b3b/browser/components/shell/nsWindowsShellService.cpp#1178 9 10 #include <objbase.h> 11 #include <shlobj.h> 12 13 #pragma comment(lib, "shlwapi.lib") 14 15 static bool 16 PinShortcutToTaskbar(const wchar_t *shortcutPath) 17 { 18 // This enum is likely only used for Windows telemetry, INT_MAX is chosen to 19 // avoid confusion with existing uses. 20 enum PINNEDLISTMODIFYCALLER { PLMC_INT_MAX = INT_MAX }; 21 22 // The types below, and the idea of using IPinnedList3::Modify, 23 // are thanks to Gee Law <https://geelaw.blog/entries/msedge-pins/> 24 static constexpr GUID CLSID_TaskbandPin = { 25 0x90aa3a4e, 26 0x1cba, 27 0x4233, 28 {0xb8, 0xbb, 0x53, 0x57, 0x73, 0xd4, 0x84, 0x49}}; 29 30 static constexpr GUID IID_IPinnedList3 = { 31 0x0dd79ae2, 32 0xd156, 33 0x45d4, 34 {0x9e, 0xeb, 0x3b, 0x54, 0x97, 0x69, 0xe9, 0x40}}; 35 36 struct IPinnedList3Vtbl; 37 struct IPinnedList3 { 38 IPinnedList3Vtbl* vtbl; 39 }; 40 41 typedef ULONG STDMETHODCALLTYPE ReleaseFunc(IPinnedList3 * that); 42 typedef HRESULT STDMETHODCALLTYPE ModifyFunc( 43 IPinnedList3 * that, PCIDLIST_ABSOLUTE unpin, PCIDLIST_ABSOLUTE pin, 44 PINNEDLISTMODIFYCALLER caller); 45 46 struct IPinnedList3Vtbl { 47 void* QueryInterface; // 0 48 void* AddRef; // 1 49 ReleaseFunc* Release; // 2 50 void* Other[13]; // 3-15 51 ModifyFunc* Modify; // 16 52 }; 53 54 PIDLIST_ABSOLUTE path = nullptr; 55 HRESULT hr = SHParseDisplayName(shortcutPath, nullptr, &path, 0, nullptr); 56 if (FAILED(hr) || !path) { 57 return false; 58 } 59 60 IPinnedList3* pinnedList = nullptr; 61 hr = CoCreateInstance(CLSID_TaskbandPin, nullptr, CLSCTX_INPROC_SERVER, 62 IID_IPinnedList3, (void**)&pinnedList); 63 if (FAILED(hr) || !pinnedList) { 64 return false; 65 } 66 67 hr = pinnedList->vtbl->Modify(pinnedList, nullptr, path, PLMC_INT_MAX); 68 69 pinnedList->vtbl->Release(pinnedList); 70 CoTaskMemFree(path); 71 return true; 72 } 73 74 struct stack_t { 75 stack_t* next; 76 TCHAR text[MAX_PATH]; 77 }; 78 79 /** 80 * Removes an element from the top of the NSIS stack 81 * 82 * @param stacktop A pointer to the top of the stack 83 * @param str The string to pop to 84 * @param len The max length 85 * @return 0 on success 86 */ 87 int 88 popstring(stack_t **stacktop, TCHAR *str, int len) 89 { 90 // Removes the element from the top of the stack and puts it in the buffer 91 stack_t *th; 92 if (!stacktop || !*stacktop) { 93 return 1; 94 } 95 96 th = (*stacktop); 97 lstrcpyn(str, th->text, len); 98 *stacktop = th->next; 99 HeapFree(GetProcessHeap(), 0, th); 100 return 0; 101 } 102 103 /** 104 * Adds an element to the top of the NSIS stack 105 * 106 * @param stacktop A pointer to the top of the stack 107 * @param str The string to push on the stack 108 * @param len The length of the string to push on the stack 109 * @return 0 on success 110 */ 111 void 112 pushstring(stack_t **stacktop, const TCHAR *str, int len) 113 { 114 stack_t *th; 115 if (!stacktop) { 116 return; 117 } 118 th = (stack_t*)HeapAlloc(GetProcessHeap(), 0, sizeof(stack_t) + len); 119 lstrcpyn(th->text, str, len); 120 th->next = *stacktop; 121 *stacktop = th; 122 } 123 124 /** 125 * Pins a provided shortcut to the Taskbar on Windows 10 (1903) and up. 126 * 127 * @param stacktop Pointer to the top of the stack, AKA the first parameter to 128 the plugin call. Should contain the shortcut to pin. 129 * @return 1 if the shortcut was pinned successfully, otherwise 0 130 */ 131 extern "C" void __declspec(dllexport) 132 Pin(HWND, int, TCHAR *, stack_t **stacktop, void *) 133 { 134 wchar_t shortcutPath[MAX_PATH + 1]; 135 bool rv = false; 136 // We're skipping building the C runtime to keep the file size low, so we 137 // can't use a normal string initialization because that would call memset. 138 shortcutPath[0] = L'\0'; 139 popstring(stacktop, shortcutPath, MAX_PATH); 140 141 rv = PinShortcutToTaskbar(shortcutPath); 142 143 pushstring(stacktop, rv ? L"1" : L"0", 2); 144 } 145 146 BOOL APIENTRY 147 DllMain(HMODULE, DWORD, LPVOID) 148 { 149 return TRUE; 150 }