Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit d504494

Browse files
committed
Bug 1687562 - Part 2: Detect whether Firefox is pinned to the taskbar. r=mhowell
Differential Revision: https://phabricator.services.mozilla.com/D105365
1 parent 1d35ccd commit d504494

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

browser/components/shell/nsIWindowsShellService.idl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,18 @@ interface nsIWindowsShellService : nsISupports
5555
* @throws same as pinCurrentAppToTaskbar()
5656
*/
5757
void checkPinCurrentAppToTaskbar();
58+
59+
/*
60+
* Search for the current executable among taskbar pins, return true if found
61+
*
62+
* NOTE: This method probably shouldn't be used on the main thread, it
63+
* performs blocking disk I/O.
64+
*
65+
* NOTE: It is possible for the check to fail even when a taskbar pin refers
66+
* to this executable, if the paths differ due to e.g. symlinks.
67+
* It is also possible for the check to succeed with a shortcut that doesn't
68+
* actually appear on the taskbar.
69+
* These cases should be rare.
70+
*/
71+
boolean isCurrentAppPinnedToTaskbar();
5872
};

browser/components/shell/nsWindowsShellService.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,98 @@ nsWindowsShellService::CheckPinCurrentAppToTaskbar() {
882882
return PinCurrentAppToTaskbarImpl(/* aCheckOnly */ true);
883883
}
884884

885+
NS_IMETHODIMP
886+
nsWindowsShellService::IsCurrentAppPinnedToTaskbar(/* out */ bool* aIsPinned) {
887+
*aIsPinned = false;
888+
889+
wchar_t exePath[MAXPATHLEN] = {};
890+
if (NS_WARN_IF(NS_FAILED(BinaryPath::GetLong(exePath)))) {
891+
return NS_OK;
892+
}
893+
894+
wchar_t folderChars[MAX_PATH] = {};
895+
HRESULT hr = SHGetFolderPathW(nullptr, CSIDL_APPDATA, nullptr,
896+
SHGFP_TYPE_CURRENT, folderChars);
897+
if (NS_WARN_IF(FAILED(hr))) {
898+
return NS_OK;
899+
}
900+
901+
nsAutoString folder;
902+
folder.Assign(folderChars);
903+
if (NS_WARN_IF(folder.IsEmpty())) {
904+
return NS_OK;
905+
}
906+
if (folder[folder.Length() - 1] != '\\') {
907+
folder.AppendLiteral("\\");
908+
}
909+
folder.AppendLiteral(
910+
"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar");
911+
nsAutoString pattern;
912+
pattern.Assign(folder);
913+
pattern.AppendLiteral("\\*.lnk");
914+
915+
WIN32_FIND_DATAW findData = {};
916+
HANDLE hFindFile = FindFirstFileW(pattern.get(), &findData);
917+
if (hFindFile == INVALID_HANDLE_VALUE) {
918+
Unused << NS_WARN_IF(GetLastError() != ERROR_FILE_NOT_FOUND);
919+
return NS_OK;
920+
}
921+
// Past this point we don't return until the end of the function,
922+
// when FindClose() is called.
923+
924+
// Check all shortcuts until a match is found
925+
do {
926+
nsAutoString fileName;
927+
fileName.Assign(folder);
928+
fileName.AppendLiteral("\\");
929+
fileName.Append(findData.cFileName);
930+
931+
// Create a shell link object for loading the shortcut
932+
RefPtr<IShellLinkW> link;
933+
HRESULT hr =
934+
CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
935+
IID_IShellLinkW, getter_AddRefs(link));
936+
if (NS_WARN_IF(FAILED(hr))) {
937+
continue;
938+
}
939+
940+
// Load
941+
RefPtr<IPersistFile> persist;
942+
hr = link->QueryInterface(IID_IPersistFile, getter_AddRefs(persist));
943+
if (NS_WARN_IF(FAILED(hr))) {
944+
continue;
945+
}
946+
947+
hr = persist->Load(fileName.get(), STGM_READ);
948+
if (NS_WARN_IF(FAILED(hr))) {
949+
continue;
950+
}
951+
952+
// Note: AUMID is not checked, so a pin that does not group properly
953+
// will still count as long as the exe matches.
954+
955+
// Check the exe path
956+
static_assert(MAXPATHLEN == MAX_PATH);
957+
wchar_t storedExePath[MAX_PATH] = {};
958+
// With no flags GetPath gets a long path
959+
hr = link->GetPath(storedExePath, ArrayLength(storedExePath), nullptr, 0);
960+
if (FAILED(hr) || hr == S_FALSE) {
961+
continue;
962+
}
963+
// Case insensitive path comparison
964+
// NOTE: Because this compares the path directly, it is possible to
965+
// have a false negative mismatch.
966+
if (wcsnicmp(storedExePath, exePath, MAXPATHLEN) == 0) {
967+
*aIsPinned = true;
968+
break;
969+
}
970+
} while (FindNextFileW(hFindFile, &findData));
971+
972+
FindClose(hFindFile);
973+
974+
return NS_OK;
975+
}
976+
885977
nsWindowsShellService::nsWindowsShellService() {}
886978

887979
nsWindowsShellService::~nsWindowsShellService() {}

0 commit comments

Comments
 (0)