Bug 1895744 - Implemented WRL StartupTask for MSIX launch on login r=nrishel
Differential Revision: https://phabricator.services.mozilla.com/D209718
This commit is contained in:
@@ -75,6 +75,93 @@ interface nsIWindowsShellService : nsISupports
|
||||
|
||||
Array<AString> getLaunchOnLoginShortcuts();
|
||||
|
||||
/*
|
||||
* Disables the startup task corresponding to the provided taskId
|
||||
* to launch upon OS login. The startup task is declared
|
||||
* within the App Manifest.
|
||||
*
|
||||
* If the task was previously disabled by the user this function
|
||||
* will not re-enable it.
|
||||
*
|
||||
* The APIs used within this function are MSIX only and
|
||||
* will also not work on MINGW.
|
||||
*
|
||||
* @param aTaskId Target taskId to enable
|
||||
*
|
||||
* @return True if the application was successfully set up to
|
||||
* launch on OS login.
|
||||
*
|
||||
* @throws NS_ERROR_NOT_AVAILABLE
|
||||
* If used on a non-MSIX build
|
||||
* @throws NS_ERROR_NOT_IMPLEMENTED
|
||||
* If used on a MinGW build
|
||||
* @throws NS_ERROR_NOT_SAME_THREAD
|
||||
* If called off main thread
|
||||
* @throws NS_ERROR_FAILURE
|
||||
* For other types of failures
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
Promise enableLaunchOnLoginMSIXAsync(in AString aTaskId);
|
||||
|
||||
/*
|
||||
* Disables the startup task corresponding to the provided taskId
|
||||
* to launch upon OS login. The startup task is declared
|
||||
* within the App Manifest.
|
||||
*
|
||||
* The APIs used within this function are MSIX only and
|
||||
* will also not work on MINGW.
|
||||
*
|
||||
* @param aTaskId Target taskId to disable
|
||||
*
|
||||
* @return True if the application was successfully disabled from
|
||||
* launching on OS login.
|
||||
*
|
||||
* @throws NS_ERROR_NOT_AVAILABLE
|
||||
* If used on a non-MSIX build
|
||||
* @throws NS_ERROR_NOT_IMPLEMENTED
|
||||
* If used on a MinGW build
|
||||
* @throws NS_ERROR_NOT_SAME_THREAD
|
||||
* If called off main thread
|
||||
* @throws NS_ERROR_FAILURE
|
||||
* For other types of failures
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
Promise disableLaunchOnLoginMSIXAsync(in AString aTaskId);
|
||||
|
||||
/*
|
||||
* Determines if the startup task corresponding to the provided taskId to
|
||||
* launch upon OS login is enabled. The startup task is declared
|
||||
* within the App Manifest. The APIs used within this function are MSIX
|
||||
* only and will also not work on MINGW.
|
||||
*
|
||||
* If the user has disabled the application from launching on login, it
|
||||
* cannot be re-enabled by the application.
|
||||
*
|
||||
* @param aTaskId Target taskId to check status of
|
||||
*
|
||||
* @return 0/1/2/3 if the application's OS launch on login is
|
||||
disabled in settings / disabled / enabled / enabled by policy
|
||||
*
|
||||
* @throws NS_ERROR_NOT_AVAILABLE
|
||||
* If used on a non-MSIX build
|
||||
* @throws NS_ERROR_NOT_IMPLEMENTED
|
||||
* If used on a MinGW build
|
||||
* @throws NS_ERROR_NOT_SAME_THREAD
|
||||
* If called off main thread
|
||||
* @throws NS_ERROR_FAILURE
|
||||
* For other types of failures
|
||||
*/
|
||||
|
||||
cenum LaunchOnLoginEnabledEnumerator : 8 {
|
||||
LAUNCH_ON_LOGIN_DISABLED_BY_SETTINGS = 0,
|
||||
LAUNCH_ON_LOGIN_DISABLED = 1,
|
||||
LAUNCH_ON_LOGIN_ENABLED = 2,
|
||||
LAUNCH_ON_LOGIN_ENABLED_BY_POLICY = 3,
|
||||
};
|
||||
|
||||
[implicit_jscontext]
|
||||
Promise getLaunchOnLoginEnabledMSIXAsync(in AString aTaskId);
|
||||
|
||||
/*
|
||||
* Pin the current app to the taskbar. If aPrivateBrowsing is true, the
|
||||
* Private Browsing version of the app (with a different icon and launch
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsIWindowsRegKey.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@@ -54,6 +55,14 @@ PSSTDAPI PropVariantToString(REFPROPVARIANT propvar, PWSTR psz, UINT cch);
|
||||
# define UNLEN 256
|
||||
#else
|
||||
# include <Lmcons.h> // For UNLEN
|
||||
# include <wrl.h>
|
||||
# include <windows.applicationmodel.activation.h>
|
||||
# include <windows.foundation.h>
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::ApplicationModel;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
#endif
|
||||
|
||||
#include <comutil.h>
|
||||
@@ -1907,6 +1916,310 @@ nsWindowsShellService::IsCurrentAppPinnedToTaskbarAsync(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifndef __MINGW32__
|
||||
# define RESOLVE_AND_RETURN(HOLDER, RESOLVE, RETURN) \
|
||||
NS_DispatchToMainThread( \
|
||||
NS_NewRunnableFunction(__func__, [promiseHolder = HOLDER] { \
|
||||
promiseHolder.get()->get()->MaybeResolve(RESOLVE); \
|
||||
})); \
|
||||
return RETURN
|
||||
|
||||
# define REJECT_AND_RETURN(HOLDER, REJECT, RETURN) \
|
||||
NS_DispatchToMainThread( \
|
||||
NS_NewRunnableFunction(__func__, [promiseHolder = HOLDER] { \
|
||||
promiseHolder.get()->get()->MaybeReject(REJECT); \
|
||||
})); \
|
||||
return RETURN
|
||||
|
||||
static void EnableLaunchOnLoginMSIXAsyncImpl(
|
||||
const nsString& capturedTaskId,
|
||||
const RefPtr<nsMainThreadPtrHolder<dom::Promise>> promiseHolder) {
|
||||
ComPtr<IStartupTaskStatics> startupTaskStatics;
|
||||
HRESULT hr = GetActivationFactory(
|
||||
HStringReference(RuntimeClass_Windows_ApplicationModel_StartupTask).Get(),
|
||||
&startupTaskStatics);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
ComPtr<IAsyncOperation<StartupTask*>> getTaskOperation = nullptr;
|
||||
hr = startupTaskStatics->GetAsync(
|
||||
HStringReference(capturedTaskId.get()).Get(), &getTaskOperation);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
auto getTaskCallback =
|
||||
Callback<IAsyncOperationCompletedHandler<StartupTask*>>(
|
||||
[promiseHolder](IAsyncOperation<StartupTask*>* operation,
|
||||
AsyncStatus status) -> HRESULT {
|
||||
if (status != AsyncStatus::Completed) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
ComPtr<IStartupTask> startupTask;
|
||||
HRESULT hr = operation->GetResults(&startupTask);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
ComPtr<IAsyncOperation<StartupTaskState>> enableOperation;
|
||||
hr = startupTask->RequestEnableAsync(&enableOperation);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
// Set another callback for enabling the startup task
|
||||
auto enableHandler =
|
||||
Callback<IAsyncOperationCompletedHandler<StartupTaskState>>(
|
||||
[promiseHolder](
|
||||
IAsyncOperation<StartupTaskState>* operation,
|
||||
AsyncStatus status) -> HRESULT {
|
||||
StartupTaskState resultState;
|
||||
HRESULT hr = operation->GetResults(&resultState);
|
||||
if (SUCCEEDED(hr) && status == AsyncStatus::Completed) {
|
||||
RESOLVE_AND_RETURN(promiseHolder, true, S_OK);
|
||||
}
|
||||
RESOLVE_AND_RETURN(promiseHolder, false, S_OK);
|
||||
});
|
||||
hr = enableOperation->put_Completed(enableHandler.Get());
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, hr);
|
||||
}
|
||||
return hr;
|
||||
});
|
||||
hr = getTaskOperation->put_Completed(getTaskCallback.Get());
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
}
|
||||
|
||||
static void DisableLaunchOnLoginMSIXAsyncImpl(
|
||||
const nsString& capturedTaskId,
|
||||
const RefPtr<nsMainThreadPtrHolder<dom::Promise>> promiseHolder) {
|
||||
ComPtr<IStartupTaskStatics> startupTaskStatics;
|
||||
HRESULT hr = GetActivationFactory(
|
||||
HStringReference(RuntimeClass_Windows_ApplicationModel_StartupTask).Get(),
|
||||
&startupTaskStatics);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
ComPtr<IAsyncOperation<StartupTask*>> getTaskOperation = nullptr;
|
||||
hr = startupTaskStatics->GetAsync(
|
||||
HStringReference(capturedTaskId.get()).Get(), &getTaskOperation);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
auto getTaskCallback =
|
||||
Callback<IAsyncOperationCompletedHandler<StartupTask*>>(
|
||||
[promiseHolder](IAsyncOperation<StartupTask*>* operation,
|
||||
AsyncStatus status) -> HRESULT {
|
||||
if (status != AsyncStatus::Completed) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
ComPtr<IStartupTask> startupTask;
|
||||
HRESULT hr = operation->GetResults(&startupTask);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
hr = startupTask->Disable();
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
RESOLVE_AND_RETURN(promiseHolder, true, S_OK);
|
||||
});
|
||||
hr = getTaskOperation->put_Completed(getTaskCallback.Get());
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
}
|
||||
|
||||
static void GetLaunchOnLoginEnabledMSIXAsyncImpl(
|
||||
const nsString& capturedTaskId,
|
||||
const RefPtr<nsMainThreadPtrHolder<dom::Promise>> promiseHolder) {
|
||||
ComPtr<IStartupTaskStatics> startupTaskStatics;
|
||||
HRESULT hr = GetActivationFactory(
|
||||
HStringReference(RuntimeClass_Windows_ApplicationModel_StartupTask).Get(),
|
||||
&startupTaskStatics);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
ComPtr<IAsyncOperation<StartupTask*>> getTaskOperation = nullptr;
|
||||
hr = startupTaskStatics->GetAsync(
|
||||
HStringReference(capturedTaskId.get()).Get(), &getTaskOperation);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
auto getTaskCallback =
|
||||
Callback<IAsyncOperationCompletedHandler<StartupTask*>>(
|
||||
[promiseHolder](IAsyncOperation<StartupTask*>* operation,
|
||||
AsyncStatus status) -> HRESULT {
|
||||
if (status != AsyncStatus::Completed) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
ComPtr<IStartupTask> startupTask;
|
||||
HRESULT hr = operation->GetResults(&startupTask);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
StartupTaskState state;
|
||||
hr = startupTask->get_State(&state);
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, E_FAIL);
|
||||
}
|
||||
switch (state) {
|
||||
case StartupTaskState_EnabledByPolicy:
|
||||
RESOLVE_AND_RETURN(
|
||||
promiseHolder,
|
||||
nsIWindowsShellService::LaunchOnLoginEnabledEnumerator::
|
||||
LAUNCH_ON_LOGIN_ENABLED_BY_POLICY,
|
||||
S_OK);
|
||||
break;
|
||||
case StartupTaskState_Enabled:
|
||||
RESOLVE_AND_RETURN(
|
||||
promiseHolder,
|
||||
nsIWindowsShellService::LaunchOnLoginEnabledEnumerator::
|
||||
LAUNCH_ON_LOGIN_ENABLED,
|
||||
S_OK);
|
||||
break;
|
||||
case StartupTaskState_DisabledByUser:
|
||||
case StartupTaskState_DisabledByPolicy:
|
||||
RESOLVE_AND_RETURN(
|
||||
promiseHolder,
|
||||
nsIWindowsShellService::LaunchOnLoginEnabledEnumerator::
|
||||
LAUNCH_ON_LOGIN_DISABLED_BY_SETTINGS,
|
||||
S_OK);
|
||||
break;
|
||||
default:
|
||||
RESOLVE_AND_RETURN(
|
||||
promiseHolder,
|
||||
nsIWindowsShellService::LaunchOnLoginEnabledEnumerator::
|
||||
LAUNCH_ON_LOGIN_DISABLED,
|
||||
S_OK);
|
||||
}
|
||||
});
|
||||
hr = getTaskOperation->put_Completed(getTaskCallback.Get());
|
||||
if (FAILED(hr)) {
|
||||
REJECT_AND_RETURN(promiseHolder, NS_ERROR_FAILURE, /* void */);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::EnableLaunchOnLoginMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
if (!widget::WinUtils::HasPackageIdentity()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
ErrorResult rv;
|
||||
RefPtr<dom::Promise> promise =
|
||||
dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
|
||||
if (MOZ_UNLIKELY(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// A holder to pass the promise through the background task and back to
|
||||
// the main thread when finished.
|
||||
auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
|
||||
"EnableLaunchOnLoginMSIXAsync promise", promise);
|
||||
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"EnableLaunchOnLoginMSIXAsync",
|
||||
[taskId = nsString(aTaskId), promiseHolder] {
|
||||
EnableLaunchOnLoginMSIXAsyncImpl(taskId, promiseHolder);
|
||||
}));
|
||||
|
||||
promise.forget(aPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::DisableLaunchOnLoginMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
if (!widget::WinUtils::HasPackageIdentity()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
ErrorResult rv;
|
||||
RefPtr<dom::Promise> promise =
|
||||
dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
|
||||
if (MOZ_UNLIKELY(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// A holder to pass the promise through the background task and back to
|
||||
// the main thread when finished.
|
||||
auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
|
||||
"DisableLaunchOnLoginMSIXAsync promise", promise);
|
||||
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"DisableLaunchOnLoginMSIXAsync",
|
||||
[taskId = nsString(aTaskId), promiseHolder] {
|
||||
DisableLaunchOnLoginMSIXAsyncImpl(taskId, promiseHolder);
|
||||
}));
|
||||
|
||||
promise.forget(aPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetLaunchOnLoginEnabledMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
if (!widget::WinUtils::HasPackageIdentity()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_NOT_SAME_THREAD;
|
||||
}
|
||||
ErrorResult rv;
|
||||
RefPtr<dom::Promise> promise =
|
||||
dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
|
||||
if (MOZ_UNLIKELY(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// A holder to pass the promise through the background task and back to
|
||||
// the main thread when finished.
|
||||
auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
|
||||
"GetLaunchOnLoginEnabledMSIXAsync promise", promise);
|
||||
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"GetLaunchOnLoginEnabledMSIXAsync",
|
||||
[taskId = nsString(aTaskId), promiseHolder] {
|
||||
GetLaunchOnLoginEnabledMSIXAsyncImpl(taskId, promiseHolder);
|
||||
}));
|
||||
|
||||
promise.forget(aPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
#else
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::EnableLaunchOnLoginMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::DisableLaunchOnLoginMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetLaunchOnLoginEnabledMSIXAsync(
|
||||
const nsAString& aTaskId, JSContext* aCx,
|
||||
/* out */ dom::Promise** aPromise) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::ClassifyShortcut(const nsAString& aPath,
|
||||
nsAString& aResult) {
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
|
||||
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
|
||||
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
|
||||
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap uap2 uap3 uap10 rescap">
|
||||
IgnorableNamespaces="uap uap2 uap3 uap5 uap10 rescap">
|
||||
|
||||
<Identity Name="@APPX_IDENTITY@" Publisher="@APPX_PUBLISHER@" Version="@APPX_VERSION@" ProcessorArchitecture="@APPX_ARCH@" />
|
||||
<Properties>
|
||||
@@ -102,6 +103,16 @@
|
||||
</com:SurrogateServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<uap5:Extension
|
||||
Category="windows.startupTask"
|
||||
Executable="VFS\ProgramFiles\@APPX_INSTDIR@\@MOZ_APP_NAME@.exe"
|
||||
EntryPoint="Windows.FullTrustApplication"
|
||||
uap10:Parameters="-os-autostart">
|
||||
<uap5:StartupTask
|
||||
TaskId="LaunchOnLogin"
|
||||
Enabled="false"
|
||||
DisplayName="@MOZ_APP_DISPLAYNAME@" />
|
||||
</uap5:Extension>
|
||||
<desktop:Extension Category="windows.toastNotificationActivation">
|
||||
<desktop:ToastNotificationActivation ToastActivatorCLSID="@MOZ_INOTIFICATIONACTIVATION_CLSID@" />
|
||||
</desktop:Extension>
|
||||
|
||||
Reference in New Issue
Block a user