mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 16:22:00 +00:00
Bug 1879975 - Adding in logging for taskbar debugging r=nrishel,mpohle
Differential Revision: https://phabricator.services.mozilla.com/D206554
This commit is contained in:
parent
e85366d893
commit
9057cbea60
@ -9,6 +9,12 @@
|
||||
*/
|
||||
#include "Windows11LimitedAccessFeatures.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
static mozilla::LazyLogModule sLog("Windows11LimitedAccessFeatures");
|
||||
|
||||
#define LAF_LOG(level, msg, ...) MOZ_LOG(sLog, level, (msg, ##__VA_ARGS__))
|
||||
|
||||
// MINGW32 is not supported for these features
|
||||
// Fall back function defined in the #else
|
||||
#ifndef __MINGW32__
|
||||
@ -30,11 +36,7 @@ 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;
|
||||
};
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* To unlock features, we need a feature identifier, a token, and an
|
||||
@ -95,26 +97,36 @@ struct LimitedAccessFeatureInfo {
|
||||
* Windows 11 will then work.
|
||||
*
|
||||
*/
|
||||
|
||||
struct LimitedAccessFeatureInfo {
|
||||
const char* debugName;
|
||||
const WCHAR* feature;
|
||||
const WCHAR* token;
|
||||
const WCHAR* attestation;
|
||||
};
|
||||
|
||||
static LimitedAccessFeatureInfo limitedAccessFeatureInfo[] = {{
|
||||
// Win11LimitedAccessFeatureType::Taskbar
|
||||
"Win11LimitedAccessFeatureType::Taskbar",
|
||||
MOZ_WINDOWS_TASKBAR_PINNING_API_FEATURE,
|
||||
MOZ_WINDOWS_TASKBAR_PINNING_API_KEY,
|
||||
MOZ_WINDOWS_TASKBAR_PINNING_API_ATTRIBUTION,
|
||||
}};
|
||||
|
||||
static_assert(mozilla::ArrayLength(limitedAccessFeatureInfo) ==
|
||||
kWin11LimitedAccessFeatureTypeCount);
|
||||
|
||||
/**
|
||||
Implementation of the Win11LimitedAccessFeaturesInterface.
|
||||
*/
|
||||
class Win11LimitedAccessFeatures : public Win11LimitedAccessFeaturesInterface {
|
||||
public:
|
||||
using AtomicState = mozilla::Atomic<int, mozilla::SequentiallyConsistent>;
|
||||
using AtomicState = Atomic<int, SequentiallyConsistent>;
|
||||
|
||||
mozilla::Result<bool, HRESULT> Unlock(
|
||||
Win11LimitedAccessFeatureType feature) override;
|
||||
Result<bool, HRESULT> Unlock(Win11LimitedAccessFeatureType feature) override;
|
||||
|
||||
private:
|
||||
AtomicState& GetState(Win11LimitedAccessFeatureType feature);
|
||||
mozilla::Result<bool, HRESULT> UnlockImplementation(
|
||||
Result<bool, HRESULT> UnlockImplementation(
|
||||
Win11LimitedAccessFeatureType feature);
|
||||
|
||||
/**
|
||||
@ -145,12 +157,20 @@ CreateWin11LimitedAccessFeaturesInterface() {
|
||||
return result;
|
||||
}
|
||||
|
||||
mozilla::Result<bool, HRESULT> Win11LimitedAccessFeatures::Unlock(
|
||||
Result<bool, HRESULT> Win11LimitedAccessFeatures::Unlock(
|
||||
Win11LimitedAccessFeatureType feature) {
|
||||
AtomicState& atomicState = GetState(feature);
|
||||
|
||||
const auto& lafInfo = limitedAccessFeatureInfo[static_cast<int>(feature)];
|
||||
|
||||
LAF_LOG(
|
||||
LogLevel::Debug, "Limited Access Feature Info for %s. Feature %S, %S, %S",
|
||||
lafInfo.debugName, lafInfo.feature, lafInfo.token, lafInfo.attestation);
|
||||
|
||||
int state = atomicState;
|
||||
if (state != Uninitialized) {
|
||||
LAF_LOG(LogLevel::Debug, "%s already initialized! State = %s",
|
||||
lafInfo.debugName, (state == Unlocked) ? "true" : "false");
|
||||
return (state == Unlocked);
|
||||
}
|
||||
|
||||
@ -177,6 +197,8 @@ Win11LimitedAccessFeatures::AtomicState& Win11LimitedAccessFeatures::GetState(
|
||||
return mTaskbarState;
|
||||
|
||||
default:
|
||||
LAF_LOG(LogLevel::Debug, "Missing feature type for %d",
|
||||
static_cast<int>(feature));
|
||||
MOZ_ASSERT(false,
|
||||
"Unhandled feature type! Add a new atomic state variable, add "
|
||||
"that entry to the switch statement above, and add the proper "
|
||||
@ -185,11 +207,13 @@ Win11LimitedAccessFeatures::AtomicState& Win11LimitedAccessFeatures::GetState(
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::Result<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
|
||||
Result<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
|
||||
Win11LimitedAccessFeatureType feature) {
|
||||
ComPtr<ILimitedAccessFeaturesStatics> limitedAccessFeatures;
|
||||
ComPtr<ILimitedAccessFeatureRequestResult> limitedAccessFeaturesResult;
|
||||
|
||||
const auto& lafInfo = limitedAccessFeatureInfo[static_cast<int>(feature)];
|
||||
|
||||
HRESULT hr = RoGetActivationFactory(
|
||||
HStringReference(
|
||||
RuntimeClass_Windows_ApplicationModel_LimitedAccessFeatures)
|
||||
@ -197,29 +221,35 @@ mozilla::Result<bool, HRESULT> Win11LimitedAccessFeatures::UnlockImplementation(
|
||||
IID_ILimitedAccessFeaturesStatics, &limitedAccessFeatures);
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
return mozilla::Err(hr);
|
||||
LAF_LOG(LogLevel::Debug, "%s activation error. HRESULT = 0x%lx",
|
||||
lafInfo.debugName, hr);
|
||||
return 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);
|
||||
LAF_LOG(LogLevel::Debug, "%s unlock error. HRESULT = 0x%lx",
|
||||
lafInfo.debugName, hr);
|
||||
return Err(hr);
|
||||
}
|
||||
|
||||
LimitedAccessFeatureStatus status;
|
||||
hr = limitedAccessFeaturesResult->get_Status(&status);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
return mozilla::Err(hr);
|
||||
LAF_LOG(LogLevel::Debug, "%s get status error. HRESULT = 0x%lx",
|
||||
lafInfo.debugName, hr);
|
||||
return Err(hr);
|
||||
}
|
||||
|
||||
int state = Unlocked;
|
||||
if ((status != LimitedAccessFeatureStatus_Available) &&
|
||||
(status != LimitedAccessFeatureStatus_AvailableWithoutToken)) {
|
||||
LAF_LOG(LogLevel::Debug, "%s not available. HRESULT = 0x%lx",
|
||||
lafInfo.debugName, hr);
|
||||
state = Locked;
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,10 @@
|
||||
#include "mozilla/ResultVariant.h"
|
||||
#include <winerror.h>
|
||||
#include <windows.h> // for HRESULT
|
||||
#include "mozilla/DefineEnum.h"
|
||||
#include <winerror.h>
|
||||
|
||||
enum class Win11LimitedAccessFeatureType {
|
||||
Taskbar,
|
||||
};
|
||||
MOZ_DEFINE_ENUM_CLASS(Win11LimitedAccessFeatureType, (Taskbar));
|
||||
|
||||
/**
|
||||
* Class to manage unlocking limited access features on Windows 11.
|
||||
|
@ -14,6 +14,13 @@
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ResultVariant.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
static mozilla::LazyLogModule sLog("Windows11TaskbarPinning");
|
||||
|
||||
#define TASKBAR_PINNING_LOG(level, msg, ...) \
|
||||
MOZ_LOG(sLog, level, (msg, ##__VA_ARGS__))
|
||||
|
||||
#ifndef __MINGW32__ // WinRT headers not yet supported by MinGW
|
||||
|
||||
# include <wrl.h>
|
||||
@ -24,6 +31,8 @@
|
||||
# include <windows.foundation.h>
|
||||
# include <windows.ui.shell.h>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* The Win32 SetEvent and WaitForSingleObject functions take HANDLE parameters
|
||||
* which are typedefs of void*. When using nsAutoHandle, that means if you
|
||||
@ -54,30 +63,40 @@ using namespace ABI::Windows::UI::Shell;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::ApplicationModel;
|
||||
|
||||
static mozilla::Result<ComPtr<ITaskbarManager>, HRESULT> InitializeTaskbar() {
|
||||
static Result<ComPtr<ITaskbarManager>, HRESULT> InitializeTaskbar() {
|
||||
ComPtr<IInspectable> taskbarStaticsInspectable;
|
||||
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug, "Initializing taskbar");
|
||||
|
||||
HRESULT hr = RoGetActivationFactory(
|
||||
HStringReference(RuntimeClass_Windows_UI_Shell_TaskbarManager).Get(),
|
||||
IID_ITaskbarManagerStatics, &taskbarStaticsInspectable);
|
||||
if (FAILED(hr)) {
|
||||
return mozilla::Err(hr);
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug,
|
||||
"Taskbar: Failed to activate. HRESULT = 0x%lx", hr);
|
||||
return Err(hr);
|
||||
}
|
||||
|
||||
ComPtr<ITaskbarManagerStatics> taskbarStatics;
|
||||
|
||||
hr = taskbarStaticsInspectable.As(&taskbarStatics);
|
||||
if (FAILED(hr)) {
|
||||
return mozilla::Err(hr);
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug, "Failed statistics. HRESULT = 0x%lx",
|
||||
hr);
|
||||
return Err(hr);
|
||||
}
|
||||
|
||||
ComPtr<ITaskbarManager> taskbarManager;
|
||||
|
||||
hr = taskbarStatics->GetDefault(&taskbarManager);
|
||||
if (FAILED(hr)) {
|
||||
return mozilla::Err(hr);
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug,
|
||||
"Error getting TaskbarManager. HRESULT = 0x%lx", hr);
|
||||
return Err(hr);
|
||||
}
|
||||
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug,
|
||||
"TaskbarManager retrieved successfully!");
|
||||
return taskbarManager;
|
||||
}
|
||||
|
||||
@ -95,10 +114,16 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
|
||||
auto result =
|
||||
limitedAccessFeatures->Unlock(Win11LimitedAccessFeatureType::Taskbar);
|
||||
if (result.isErr()) {
|
||||
return {result.unwrapErr(), Win11PinToTaskBarResultStatus::NotSupported};
|
||||
auto hr = result.unwrapErr();
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug,
|
||||
"Taskbar unlock: Error. HRESULT = 0x%lx", hr);
|
||||
return {hr, Win11PinToTaskBarResultStatus::NotSupported};
|
||||
}
|
||||
|
||||
if (result.unwrap() == false) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar unlock: failed. Not supported on this version of Windows.");
|
||||
return {S_OK, Win11PinToTaskBarResultStatus::NotSupported};
|
||||
}
|
||||
}
|
||||
@ -130,17 +155,38 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
|
||||
boolean supported;
|
||||
hr = taskbar->get_IsSupported(&supported);
|
||||
if (FAILED(hr) || !supported) {
|
||||
if (FAILED(hr)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: error checking if supported. HRESULT = 0x%lx", hr);
|
||||
} else {
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: not supported.");
|
||||
}
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::NotSupported);
|
||||
}
|
||||
|
||||
if (aCheckOnly) {
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug, "Taskbar: check succeeded.");
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
|
||||
}
|
||||
|
||||
boolean isAllowed = false;
|
||||
hr = taskbar->get_IsPinningAllowed(&isAllowed);
|
||||
if (FAILED(hr) || !isAllowed) {
|
||||
if (FAILED(hr)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: error checking if pinning is allowed. HRESULT = "
|
||||
"0x%lx",
|
||||
hr);
|
||||
} else {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: is pinning allowed error or isn't allowed right now. "
|
||||
"It's not clear when it will be allowed. Possibly after a "
|
||||
"reboot.");
|
||||
}
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::NotCurrentlyAllowed);
|
||||
}
|
||||
@ -148,6 +194,11 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
|
||||
ComPtr<IAsyncOperation<bool>> isPinnedOperation = nullptr;
|
||||
hr = taskbar->IsCurrentAppPinnedAsync(&isPinnedOperation);
|
||||
if (FAILED(hr)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: is current app pinned operation failed. HRESULT = "
|
||||
"0x%lx",
|
||||
hr);
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
@ -157,84 +208,117 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
|
||||
// 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;
|
||||
};
|
||||
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);
|
||||
}
|
||||
bool asyncOpSucceeded = status == AsyncStatus::Completed;
|
||||
if (!asyncOpSucceeded) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: is pinned operation failed to complete.");
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
unsigned char isCurrentAppPinned = false;
|
||||
hr = asyncInfo->GetResults(&isCurrentAppPinned);
|
||||
unsigned char isCurrentAppPinned = false;
|
||||
hr = asyncInfo->GetResults(&isCurrentAppPinned);
|
||||
if (FAILED(hr)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: is current app pinned check failed. HRESULT = 0x%lx",
|
||||
hr);
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
if (isCurrentAppPinned) {
|
||||
TASKBAR_PINNING_LOG(LogLevel::Debug,
|
||||
"Taskbar: current app is already pinned.");
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::AlreadyPinned);
|
||||
}
|
||||
|
||||
ComPtr<IAsyncOperation<bool>> requestPinOperation = nullptr;
|
||||
hr = taskbar->RequestPinCurrentAppAsync(&requestPinOperation);
|
||||
if (FAILED(hr)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin current app operation creation failed. "
|
||||
"HRESULT = 0x%lx",
|
||||
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) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin current app operation did not "
|
||||
"complete.");
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
unsigned char successfullyPinned = 0;
|
||||
hr = asyncInfo->GetResults(&successfullyPinned);
|
||||
if (FAILED(hr) || !successfullyPinned) {
|
||||
if (FAILED(hr)) {
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::Failed);
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin current app operation failed to pin "
|
||||
"due to error. HRESULT = 0x%lx",
|
||||
hr);
|
||||
} else {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin current app operation failed to pin");
|
||||
}
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
if (isCurrentAppPinned) {
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::AlreadyPinned);
|
||||
}
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin current app operation succeeded");
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Success);
|
||||
});
|
||||
|
||||
ComPtr<IAsyncOperation<bool>> requestPinOperation = nullptr;
|
||||
hr = taskbar->RequestPinCurrentAppAsync(&requestPinOperation);
|
||||
if (FAILED(hr)) {
|
||||
return CompletedOperations(
|
||||
Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
HRESULT pinOperationHR =
|
||||
requestPinOperation->put_Completed(pinAppCallback.Get());
|
||||
if (FAILED(pinOperationHR)) {
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: request pin operation failed when setting completion "
|
||||
"callback. HRESULT = 0x%lx",
|
||||
hr);
|
||||
hr = pinOperationHR;
|
||||
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;
|
||||
});
|
||||
// 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;
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Debug,
|
||||
"Taskbar: is pinned operation failed when setting completion "
|
||||
"callback. HRESULT = 0x%lx",
|
||||
hr);
|
||||
return CompletedOperations(Win11PinToTaskBarResultStatus::Failed);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user