Bug 1879975 - Newer versions of Windows disable pinning to the taskbar using older methods r=mpohle,bhearsum,nrishel

This is adding in the new Windows 11 only version of taskbar pinning. For the new pinning to work, we need to use limited access feature tokens. Those are going to be made private and aren't included with this change.
This change will compile, and will work if built against the correct limited access feature tokens, as specified in developer local machine config files, but for every other build, the new taskbar pinning won't work and will fall back to the old methods.
I will implement the try / release building machines using the secret limited access feature tokens in a follow-up diff.

Differential Revision: https://phabricator.services.mozilla.com/D205004
This commit is contained in:
Michael Hughes 2024-04-10 21:17:20 +00:00
parent d08324b576
commit dbbbed9603
8 changed files with 640 additions and 4 deletions

View File

@ -0,0 +1,237 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This file exists so that LaunchModernSettingsDialogDefaultApps can be called
* without linking to libxul.
*/
#include "Windows11LimitedAccessFeatures.h"
// MINGW32 is not supported for these features
// Fall back function defined in the #else
#ifndef __MINGW32__
# include "nsString.h"
# include "nsWindowsHelpers.h"
# include "mozilla/Atomics.h"
# include <wrl.h>
# include <inspectable.h>
# include <roapi.h>
# include <windows.services.store.h>
# include <windows.foundation.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::ApplicationModel;
struct LimitedAccessFeatureInfo {
const WCHAR* feature;
const WCHAR* token;
const WCHAR* attestation;
};
/**
* To unlock features, we need a feature identifier, a token, and an
* attestation string. The token is generated by Microsoft and must
* match the publisher id Microsoft thinks we have.
*
* To get a token, find the right microsoft email address by doing
* a search on the web for the feature you want unlocked and reach
* out to the right people at Microsoft.
*
* The token is generated from Microsoft.
* The jumbled code in the attestation string is a publisher id and
* must match the code in the resources / .rc file for the identity
* looking like this:
*
* Identity LimitedAccessFeature {{ L"MozillaFirefox_pcsmm0jrprpb2" }}
*
* That is injected into our build in create_rc.py and is necessary
* to unlock the taskbar pinning feature / APIs from an unpackaged
* build.
*
* Note that we keep our tokens secret. They are stored on our secrets
* cluster and picked up by our continuous build machines
* when they build and are injected below via define.
*
* For the taskbar, MOZ_WINDOWS_TASKBAR_PINNING_API_KEY is registered
* in the moz.build file for this, driven by the build environment config.
*
* The matching value in the build environment config is declared in two
* places:
* 1) in toolkit/moz.configure, which registers that it exists but doesn't
* set it's value
* 2) in win32, win64 and win64-aarch/common-opt files, which tell the
* system where to get the files from, via:
*
* ac_add_options
--with-windows-taskbar-pinning-api-keyfile=${APIKEYDIR}/windows-laf-tokens.data
*
* The file with the data is pulled down by the build infrastructure and
* only by the build infrastructure. To see all of the places where that
* data is used by the CI system, do a searchfox for windows-laf-tokens.data.
* In order to unlock a feature locally, if you know the product name
* and token, you can store it in a file with the following format.
*
* PRODUCT_NAME TOKEN
*
* And that's it. No white space before, no white space or newlines or comments
after.
* Assuming you stored the above in
browser/branding/nightly/windows-taskbar-pinning-api.key,
* then you can add a line like this to your mozconfig file:
*
* ac_add_options
--with-windows-taskbar-pinning-api-keyfile=@TOPSRCDIR@/browser/branding/nightly/windows-taskbar-pinning-api.key
*
* And then when you recompile and run, the taskbar-pinning apis for
* Windows 11 will then work.
*
*/
static LimitedAccessFeatureInfo limitedAccessFeatureInfo[] = {{
// Win11LimitedAccessFeatureType::Taskbar
MOZ_WINDOWS_TASKBAR_PINNING_API_FEATURE,
MOZ_WINDOWS_TASKBAR_PINNING_API_KEY,
MOZ_WINDOWS_TASKBAR_PINNING_API_ATTRIBUTION,
}};
/**
Implementation of the Win11LimitedAccessFeaturesInterface.
*/
class Win11LimitedAccessFeatures : public Win11LimitedAccessFeaturesInterface {
public:
using AtomicState = mozilla::Atomic<int, mozilla::SequentiallyConsistent>;
mozilla::Result<bool, HRESULT> Unlock(
Win11LimitedAccessFeatureType feature) override;
private:
AtomicState& GetState(Win11LimitedAccessFeatureType feature);
mozilla::Result<bool, HRESULT> UnlockImplementation(
Win11LimitedAccessFeatureType feature);
/**
* Store the state as an atomic so that it can be safely accessed from
* different threads.
*/
static AtomicState mTaskbarState;
static AtomicState mDefaultState;
enum State {
Uninitialized,
Locked,
Unlocked,
};
};
Win11LimitedAccessFeatures::AtomicState
Win11LimitedAccessFeatures::mTaskbarState(
Win11LimitedAccessFeatures::Uninitialized);
Win11LimitedAccessFeatures::AtomicState
Win11LimitedAccessFeatures::mDefaultState(
Win11LimitedAccessFeatures::Uninitialized);
RefPtr<Win11LimitedAccessFeaturesInterface>
CreateWin11LimitedAccessFeaturesInterface() {
RefPtr<Win11LimitedAccessFeaturesInterface> result(
new Win11LimitedAccessFeatures());
return result;
}
mozilla::Result<bool, HRESULT> Win11LimitedAccessFeatures::Unlock(
Win11LimitedAccessFeatureType feature) {
AtomicState& atomicState = GetState(feature);
int state = atomicState;
if (state != Uninitialized) {
return (state == Unlocked);
}
// If multiple threads read the state at the same time, and it's unitialized,
// both threads will unlock the feature. This situation is unlikely, but even
// if it happens, it's not a problem.
auto result = UnlockImplementation(feature);
int newState = Locked;
if (!result.isErr() && result.unwrap()) {
newState = Unlocked;
}
atomicState = newState;
return result;
}
Win11LimitedAccessFeatures::AtomicState& Win11LimitedAccessFeatures::GetState(
Win11LimitedAccessFeatureType feature) {
switch (feature) {
case Win11LimitedAccessFeatureType::Taskbar:
return mTaskbarState;
default:
MOZ_ASSERT(false,
"Unhandled feature type! Add a new atomic state variable, add "
"that entry to the switch statement above, and add the proper "
"entries for the feature and the token.");
return mDefaultState;
}
}
mozilla::Result<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
Win11LimitedAccessFeatureType feature) {
ComPtr<ILimitedAccessFeaturesStatics> limitedAccessFeatures;
ComPtr<ILimitedAccessFeatureRequestResult> limitedAccessFeaturesResult;
HRESULT hr = RoGetActivationFactory(
HStringReference(
RuntimeClass_Windows_ApplicationModel_LimitedAccessFeatures)
.Get(),
IID_ILimitedAccessFeaturesStatics, &limitedAccessFeatures);
if (!SUCCEEDED(hr)) {
return mozilla::Err(hr);
}
const auto& lafInfo = limitedAccessFeatureInfo[static_cast<int>(feature)];
hr = limitedAccessFeatures->TryUnlockFeature(
HStringReference(lafInfo.feature).Get(),
HStringReference(lafInfo.token).Get(),
HStringReference(lafInfo.attestation).Get(),
&limitedAccessFeaturesResult);
if (!SUCCEEDED(hr)) {
return mozilla::Err(hr);
}
LimitedAccessFeatureStatus status;
hr = limitedAccessFeaturesResult->get_Status(&status);
if (!SUCCEEDED(hr)) {
return mozilla::Err(hr);
}
int state = Unlocked;
if ((status != LimitedAccessFeatureStatus_Available) &&
(status != LimitedAccessFeatureStatus_AvailableWithoutToken)) {
state = Locked;
}
return (state == Unlocked);
}
#else // MINGW32 implementation
RefPtr<Win11LimitedAccessFeaturesInterface>
CreateWin11LimitedAccessFeaturesInterface() {
RefPtr<Win11LimitedAccessFeaturesInterface> result;
return result;
}
#endif

View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SHELL_WINDOWS11LIMITEDACCESSFEATURES_H__
#define SHELL_WINDOWS11LIMITEDACCESSFEATURES_H__
#include "nsISupportsImpl.h"
#include "mozilla/Result.h"
#include "mozilla/ResultVariant.h"
#include <winerror.h>
enum class Win11LimitedAccessFeatureType {
Taskbar,
};
/**
* Class to manage unlocking limited access features on Windows 11.
* Unless stubbing for testing purposes, create objects of this
* class with CreateWin11LimitedAccessFeaturesInterface.
*
* Windows 11 requires certain features to be unlocked in order to work
* (for instance, the Win11 Taskbar pinning APIs). Call Unlock()
* to unlock them. Generally, results will be cached in atomic variables
* and future calls to Unlock will be as long as it takes
* to fetch an atomic variable.
*/
class Win11LimitedAccessFeaturesInterface {
public:
/**
* Unlocks the limited access features, if possible.
*
* Returns an error code on error, true on successful unlock,
* false on unlock failed (but with no error).
*/
virtual mozilla::Result<bool, HRESULT> Unlock(
Win11LimitedAccessFeatureType feature) = 0;
/**
* Reference counting and cycle collection.
*/
NS_INLINE_DECL_REFCOUNTING(Win11LimitedAccessFeaturesInterface)
protected:
virtual ~Win11LimitedAccessFeaturesInterface() {}
};
RefPtr<Win11LimitedAccessFeaturesInterface>
CreateWin11LimitedAccessFeaturesInterface();
#endif // SHELL_WINDOWS11LIMITEDACCESSFEATURES_H__

View File

@ -0,0 +1,260 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Windows11TaskbarPinning.h"
#include "Windows11LimitedAccessFeatures.h"
#include "nsWindowsHelpers.h"
#include "MainThreadUtils.h"
#include "nsThreadUtils.h"
#include <strsafe.h>
#include "mozilla/Result.h"
#include "mozilla/ResultVariant.h"
#ifndef __MINGW32__ // WinRT headers not yet supported by MinGW
# include <wrl.h>
# include <inspectable.h>
# include <roapi.h>
# include <windows.services.store.h>
# include <windows.foundation.h>
# include <windows.ui.shell.h>
/**
* The Win32 SetEvent and WaitForSingleObject functions take HANDLE parameters
* which are typedefs of void*. When using nsAutoHandle, that means if you
* forget to call .get() first, everything still compiles and then doesn't work
* at runtime. For instance, calling SetEvent(mEvent) below would compile but
* not work at runtime and the waits would block forever.
* To ensure this isn't an issue, we wrap the event in a custom class here
* with the simple methods that we want on an event.
*/
class EventWrapper {
public:
EventWrapper() : mEvent(CreateEventW(nullptr, true, false, nullptr)) {}
void Set() { SetEvent(mEvent.get()); }
void Reset() { ResetEvent(mEvent.get()); }
void Wait() { WaitForSingleObject(mEvent.get(), INFINITE); }
private:
nsAutoHandle mEvent;
};
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows;
using namespace ABI::Windows::UI::Shell;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::ApplicationModel;
static mozilla::Result<ComPtr<ITaskbarManager>, HRESULT> InitializeTaskbar() {
ComPtr<IInspectable> taskbarStaticsInspectable;
HRESULT hr = RoGetActivationFactory(
HStringReference(RuntimeClass_Windows_UI_Shell_TaskbarManager).Get(),
IID_ITaskbarManagerStatics, &taskbarStaticsInspectable);
if (FAILED(hr)) {
return mozilla::Err(hr);
}
ComPtr<ITaskbarManagerStatics> taskbarStatics;
hr = taskbarStaticsInspectable.As(&taskbarStatics);
if (FAILED(hr)) {
return mozilla::Err(hr);
}
ComPtr<ITaskbarManager> taskbarManager;
hr = taskbarStatics->GetDefault(&taskbarManager);
if (FAILED(hr)) {
return mozilla::Err(hr);
}
return taskbarManager;
}
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
MOZ_DIAGNOSTIC_ASSERT(!NS_IsMainThread(),
"PinCurrentAppToTaskbarWin11 should be called off main "
"thread only. It blocks, waiting on things to execute "
"asynchronously on the main thread.");
{
RefPtr<Win11LimitedAccessFeaturesInterface> limitedAccessFeatures =
CreateWin11LimitedAccessFeaturesInterface();
auto result =
limitedAccessFeatures->Unlock(Win11LimitedAccessFeatureType::Taskbar);
if (result.isErr()) {
return {result.unwrapErr(), Win11PinToTaskBarResultStatus::NotSupported};
}
if (result.unwrap() == false) {
return {S_OK, Win11PinToTaskBarResultStatus::NotSupported};
}
}
HRESULT hr;
Win11PinToTaskBarResultStatus resultStatus =
Win11PinToTaskBarResultStatus::NotSupported;
EventWrapper event;
// Everything related to the taskbar and pinning must be done on the main /
// user interface thread or Windows will cause them to fail.
NS_DispatchToMainThread(NS_NewRunnableFunction(
"PinCurrentAppToTaskbarWin11", [&event, &hr, &resultStatus, aCheckOnly] {
auto CompletedOperations =
[&event, &resultStatus](Win11PinToTaskBarResultStatus status) {
resultStatus = status;
event.Set();
};
auto result = InitializeTaskbar();
if (result.isErr()) {
hr = result.unwrapErr();
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
ComPtr<ITaskbarManager> taskbar = result.unwrap();
boolean supported;
hr = taskbar->get_IsSupported(&supported);
if (FAILED(hr) || !supported) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotSupported);
}
if (aCheckOnly) {
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
}
boolean isAllowed = false;
hr = taskbar->get_IsPinningAllowed(&isAllowed);
if (FAILED(hr) || !isAllowed) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::NotCurrentlyAllowed);
}
ComPtr<IAsyncOperation<bool>> isPinnedOperation = nullptr;
hr = taskbar->IsCurrentAppPinnedAsync(&isPinnedOperation);
if (FAILED(hr)) {
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// Copy the taskbar; don't use it as a reference.
// With the async calls, it's not guaranteed to still be valid
// if sent as a reference.
// resultStatus and event are not defined on the main thread and will
// be alive until the async functions complete, so they can be used as
// references.
auto isPinnedCallback = Callback<IAsyncOperationCompletedHandler<bool>>(
[taskbar, &event, &resultStatus, &hr](
IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) mutable -> HRESULT {
auto CompletedOperations =
[&event, &resultStatus](
Win11PinToTaskBarResultStatus status) -> HRESULT {
resultStatus = status;
event.Set();
return S_OK;
};
bool asyncOpSucceeded = status == AsyncStatus::Completed;
if (!asyncOpSucceeded) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
unsigned char isCurrentAppPinned = false;
hr = asyncInfo->GetResults(&isCurrentAppPinned);
if (FAILED(hr)) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
if (isCurrentAppPinned) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::AlreadyPinned);
}
ComPtr<IAsyncOperation<bool>> requestPinOperation = nullptr;
hr = taskbar->RequestPinCurrentAppAsync(&requestPinOperation);
if (FAILED(hr)) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
auto pinAppCallback =
Callback<IAsyncOperationCompletedHandler<bool>>(
[CompletedOperations, &hr](
IAsyncOperation<bool>* asyncInfo,
AsyncStatus status) -> HRESULT {
bool asyncOpSucceeded =
status == AsyncStatus::Completed;
if (!asyncOpSucceeded) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
unsigned char successfullyPinned = 0;
hr = asyncInfo->GetResults(&successfullyPinned);
if (FAILED(hr) || !successfullyPinned) {
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
return CompletedOperations(
Win11PinToTaskBarResultStatus::Success);
});
HRESULT pinOperationHR =
requestPinOperation->put_Completed(pinAppCallback.Get());
if (FAILED(pinOperationHR)) {
hr = pinOperationHR;
return CompletedOperations(
Win11PinToTaskBarResultStatus::Failed);
}
// DO NOT SET event HERE. It will be set in the pin operation
// callback As in, operations are not completed, so don't call
// CompletedOperations
return S_OK;
});
HRESULT isPinnedOperationHR =
isPinnedOperation->put_Completed(isPinnedCallback.Get());
if (FAILED(isPinnedOperationHR)) {
hr = isPinnedOperationHR;
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
}
// DO NOT SET event HERE. It will be set in the is pin operation
// callback As in, operations are not completed, so don't call
// CompletedOperations
}));
// block until the pinning is completed on the main thread
event.Wait();
return {hr, resultStatus};
}
#else // MINGW32 implementation below
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
return {S_OK, Win11PinToTaskBarResultStatus::NotSupported};
}
#endif // #ifndef __MINGW32__ // WinRT headers not yet supported by MinGW

View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This file exists to keep the Windows 11 Taskbar Pinning API
* related code as self-contained as possible.
*/
#ifndef SHELL_WINDOWS11TASKBARPINNING_H__
#define SHELL_WINDOWS11TASKBARPINNING_H__
#include "nsString.h"
#include <wrl.h>
enum class Win11PinToTaskBarResultStatus {
Failed,
NotCurrentlyAllowed,
AlreadyPinned,
Success,
NotSupported,
};
struct Win11PinToTaskBarResult {
HRESULT errorCode;
Win11PinToTaskBarResultStatus result;
};
Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
bool aCheckOnly, const nsAString& aAppUserModelId,
nsAutoString aShortcutPath);
#endif // SHELL_WINDOWS11TASKBARPINNING_H__

View File

@ -50,6 +50,8 @@ elif CONFIG["OS_ARCH"] == "WINNT":
]
SOURCES += [
"nsWindowsShellService.cpp",
"Windows11LimitedAccessFeatures.cpp",
"Windows11TaskbarPinning.cpp",
"WindowsDefaultBrowser.cpp",
"WindowsUserChoice.cpp",
]
@ -82,6 +84,25 @@ for var in (
):
DEFINES[var] = '"%s"' % CONFIG[var]
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
apiKey = "MOZ_WINDOWS_TASKBAR_PINNING_API_KEY"
DEFINES[apiKey] = 'L"%s"' % (
CONFIG[apiKey] or "MOZ_WINDOWS_TASKBAR_PINNING_API_KEY_UNDEFINED"
)
# Inject these other values here as well, to keep all of the data together
# but also to construct the attribution key on the fly
# at compile time instead of at runtime.
windows_feature = "com.microsoft.windows.taskbar.pin"
publisher_id = "pcsmm0jrprpb2"
DEFINES["MOZ_WINDOWS_TASKBAR_PINNING_API_FEATURE"] = 'L"%s"' % windows_feature
DEFINES["MOZ_WINDOWS_TASKBAR_PINNING_API_ATTRIBUTION"] = (
'L"%s has registered their use of %s with Microsoft and agrees to the terms of use."'
% (publisher_id, windows_feature)
)
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]

View File

@ -39,6 +39,7 @@
#include "nsIXULAppInfo.h"
#include "nsINIParser.h"
#include "nsNativeAppSupportWin.h"
#include "Windows11TaskbarPinning.h"
#include <windows.h>
#include <shellapi.h>
@ -1626,7 +1627,7 @@ nsWindowsShellService::GetTaskbarTabPins(nsTArray<nsString>& aShortcutPaths) {
static nsresult PinCurrentAppToTaskbarWin10(bool aCheckOnly,
const nsAString& aAppUserModelId,
nsAutoString aShortcutPath) {
const nsAString& aShortcutPath) {
// The behavior here is identical if we're only checking or if we try to pin
// but the app is already pinned so we update the variable accordingly.
if (!aCheckOnly) {
@ -1695,6 +1696,28 @@ static nsresult PinCurrentAppToTaskbarImpl(
}
}
auto pinWithWin11TaskbarAPIResults =
PinCurrentAppToTaskbarWin11(aCheckOnly, aAppUserModelId, shortcutPath);
switch (pinWithWin11TaskbarAPIResults.result) {
case Win11PinToTaskBarResultStatus::NotSupported:
// Fall through to the win 10 mechanism
break;
case Win11PinToTaskBarResultStatus::Success:
case Win11PinToTaskBarResultStatus::AlreadyPinned:
return NS_OK;
case Win11PinToTaskBarResultStatus::NotCurrentlyAllowed:
case Win11PinToTaskBarResultStatus::Failed:
// return NS_ERROR_FAILURE;
// Fall through to the old mechanism for now
// In future, we should be sending telemetry for when
// an error occurs or for when pinning is not allowed
// with the Win 11 APIs.
break;
}
return PinCurrentAppToTaskbarWin10(aCheckOnly, aAppUserModelId, shortcutPath);
}
@ -1720,7 +1743,7 @@ static nsresult PinCurrentAppToTaskbarAsyncImpl(bool aCheckOnly,
}
nsAutoString aumid;
if (NS_WARN_IF(!mozilla::widget::WinTaskbar::GenerateAppUserModelID(
if (NS_WARN_IF(!mozilla::widget::WinTaskbar::GetAppUserModelID(
aumid, aPrivateBrowsing))) {
return NS_ERROR_FAILURE;
}

View File

@ -26,6 +26,8 @@ TEMPLATE = """
{include}
Identity LimitedAccessFeature {{ L"{lafidentity}_pcsmm0jrprpb2" }}
/////////////////////////////////////////////////////////////////////////////
//
@ -112,8 +114,8 @@ def split_and_normalize_version(version, len):
def has_manifest(module_rc, manifest_id):
for line in module_rc.splitlines():
line = line.split(None, 2)
for lineFromInput in module_rc.splitlines():
line = lineFromInput.split(None, 2)
if len(line) < 2:
continue
id, what, *rest = line
@ -167,8 +169,13 @@ def generate_module_rc(binary="", rcinclude=None):
else:
include = ""
lafidentity = buildconfig.substs.get(
"MOZ_WINDOWS_TASKBAR_PINNING_API_CLIENTID", "LAF_ID_UNDEFINED"
)
data = TEMPLATE.format(
include=include,
lafidentity=lafidentity,
fileversion=overrides.get("WIN32_MODULE_FILEVERSION", milestone_winversion),
productversion=overrides.get(
"WIN32_MODULE_PRODUCTVERSION", milestone_winversion

View File

@ -1051,6 +1051,8 @@ id_and_secret_keyfile("Leanplum SDK")
simple_keyfile("Pocket API")
id_and_secret_keyfile("Windows Taskbar Pinning API")
# WebRender Debugger integration
# ==============================================================