Files
Meg Viar 7dc630a7c8 Bug 2053812 - Add message targeting for Windows users where one-click default is enabled r=omc-reviewers,nrishel,hanna_a,aborondo,hsohaney
Add message system targeting for Windows users where one-click set to default is enabled and functional.

Differential Revision: https://phabricator.services.mozilla.com/D311309
2026-08-06 12:19:05 +00:00

559 lines
22 KiB
Plaintext

/* 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 "imgIContainer.idl"
#include "nsIShellService.idl"
interface nsIFile;
[scriptable, uuid(fb9b59db-5a91-4e67-92b6-35e7d6e6d3fd)]
interface nsIWindowsShellService : nsIShellService
{
/*
* Bit flags for launchSetDefaultAppPicker's aFlags argument. They map 1:1
* onto the flags accepted by the undocumented Windows IOpenWithLauncher COM
* interface's Launch method.
* The mapping below was determined empirically and determines the picker's
* messaging and actions.
*/
// Suppresses the default open-in-selected-app behavior. Remote-controlled
// by Microsoft.
const long OPEN_WITH_SUPPRESS_OPEN = 1 << 2;
// Switches picker messaging to protocol mode ("Select a default handler
// for ___ links").
const long OPEN_WITH_PROTOCOL_MESSAGING = 1 << 3;
// Opens with the selected app just once; does not set a default.
const long OPEN_WITH_OPEN_ONCE = 1 << 6;
// Asks the user to set a default for the given file type or protocol. Messaging is
// ideal on Windows 11 only.
const long OPEN_WITH_SET_HANDLER = 1 << 7;
// Like OPEN_WITH_SET_HANDLER, but with ideal messaging for Windows 10.
const long OPEN_WITH_SET_HANDLER_WIN10 = 1 << 13;
/*
* Creates a new shortcut (.lnk) file. This shortcut will be recorded in
* a new shortcuts log file located in %PROGRAMDATA%\Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38
* that is named after the currently running application and current user, eg:
* Firefox_user123_shortcuts.ini.
*
* For reasons that we haven't been able to pin down, these shortcuts get created with
* extra metadata on them (KnownFolderDataBlock, SpecialFolderDataBlock) that cause
* the Windows ShellLink classes to improperly read their target path with certain
* parameters. This causes any 32-bit programs that read the links (such as our
* installer and uninstaller) to think that 64-bit installs are located in the 32-bit
* Program Files directory.
* See https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/6f2e7920-50a9-459d-bfdd-316e459e87c0/ishelllink-getpath-returns-wrong-folder-for-64-bit-application-when-called-from-32-bit-application
* for some additional discussion of this.
*
* @param aBinary Target file of the shortcut.
* @param aArguments Arguments to set for the shortcut. May be empty.
* @param aDescription The description of the shortcut. The string used here
* shows up as the hover text of the shortcut in Explorer and on the
* Taskbar (if the shortcut is pinned there).
* @param aIconFile The file containing the desired icon for the shortcut. This
* can be the same file as aBinary.
* @param aIconIndex The index of the in aIconFile. Note that this is 0 based index
* that IShellLinkW requires, _not_ a Resource ID that is sometimes used
* for icons.
* @param aAppUserModelId The App User Model ID to set for the shortcut. This will
* affect which icon on the Taskbar the application groups with when first
* launched.
* @param aShortcutFolder The special Windows folder to create the shortcut in. Must be
* either "Programs" or "Desktop".
* @param aShortcutRelativePath The relative path of the shortcut from the shortcut
* folder.
* @return The full native path to the created shortcut.
*
* @throws NS_ERROR_INVALID_ARG if an invalid shortcut folder is passed
* @throws NS_ERROR_FILE_NOT_FOUND if the shortcut file or shortcuts log cannot be
* created or accessed
* @throws NS_ERROR_FAILURE for other types of failures
*/
[implicit_jscontext]
Promise createShortcut(in nsIFile aBinary, in Array<AString> aArguments,
in AString aDescription, in nsIFile aIconFile, in unsigned short aIconIndex,
in AString aAppUserModelId, in AString aShortcutFolder,
in AString aShortcutRelativePath);
/*
* Deletes the provided shortcut path relative to the shortcut folder, and removes it
* from the uninstaller's log file.
*
* @param aShortcutFolder The special Windows folder to create the shortcut in.
* Should be either Desktop or StartMenu.
* @param aShortcutRelativePath The relative path to the shortcut file from the folder.
*
* @throws NS_ERROR_INVALID_ARG if an invalid shortcut folder is passed
*/
[implicit_jscontext]
Promise deleteShortcut(in AString aShortcutFolder, in AString aShortcutRelativePath);
/*
* Searches the %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
* folder and returns an array with the path of all shortcuts with a target matching the
* current Firefox install location. The AUMID isn't required here as we are only looking
* for the currently running binary, whether that's firefox.exe or the private browsing
* proxy executable.
*
* It is possible to return an empty array if no shortcuts are found.
*
* @return An array of paths for all launch on login shortcuts.s
*
* @throws NS_ERROR_ABORT
* if instance cannot be created.
* @throws NS_ERROR_FILE_NOT_FOUND
* if %USERPROFILE%\AppData\Roaming\ cannot be opened.
* @throws NS_ERROR_FAILURE
* if the executable file cannot be found.
* @throws NS_ERROR_FILE_UNRECOGNIZED_PATH
* if the executable file cannot be converted into a string.
*/
Array<AString> getLaunchOnLoginShortcuts();
/*
* Pins the current application to the Windows Start Menu
*
* The APIs used within this function are MSIX only and
* will also not work on MINGW.
*
* @return True if the application was successfully pinned
* to the Start Menu.
*
* @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 Windows API failures
*/
[implicit_jscontext]
Promise pinCurrentAppToStartMenu();
/*
* Whether the current app is among Windows Start Menu pins
*
* @return True if pinned, false otherwise
*
* The APIs used within this function are MSIX only and
* will also not work on MINGW.
*
* @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 Windows API failures
*/
[implicit_jscontext]
Promise isCurrentAppPinnedToStartMenu();
/*
* 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 enableLaunchOnLoginMSIX(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 disableLaunchOnLoginMSIX(in AString aTaskId);
/*
* Status of launch on login enablement.
*/
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,
};
/*
* 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
*/
[implicit_jscontext]
Promise getLaunchOnLoginEnabledMSIX(in AString aTaskId);
/*
* Result for attempts to pin to taskbar.
*/
cenum PinResult : 8 {
// Successfully pinned.
PINNED,
// User or system rejected pin attempt.
REJECTED,
// Result of pin attempt unknown. Examples include when we intentionally
// return before the user choice is known, and when using APIs which don't
// provide means to know the success or failure of the pin attempt.
UNKNOWN,
};
/*
* Pin the current app to the taskbar. If aPrivateBrowsing is true, the
* Private Browsing version of the app (with a different icon and launch
* arguments) will be pinned instead.
*
* This MUST only be used in response to an active request from the user.
*
* If it exists, uses an existing shortcut on the User or Common Start Menu,
* which would have been created by the installer (for All Users or
* Current User). If none can be found, one will be created with the correct
* AUMID in the User Start Menu for proper launching and grouping.
*
* NOTE: It is possible for the shortcut match to fail even when a
* shortcut refers to the current executable, if the paths differ due
* to e.g. symlinks. This should be rare.
*
* This will definitely fail on an OS before Windows 10 build 1809
* (October 2018 Update).
*
* @param aPrivateBrowsing
* Pins private browsing.
* @param aFireAndForget
* Skips waiting for user to confirm or reject pin prompt if present.
*
* @throws NS_ERROR_NOT_SAME_THREAD
* if called off main thread.
* @throws NS_ERROR_NOT_AVAILABLE
* if OS is not at least Windows 10 build 1809, or if creating the
* Taskband Pin object fails
* @throws NS_ERROR_FAILURE
* for unexpected errors
*
* @rejects NS_ERROR_FILE_NOT_FOUND
* if a shortcut matching this app's AUMID and exe path wasn't found
in shell:appsfolder
*
* @returns {Promise<PinResult>} A Promise that resolves to
* nsIWindowsShellService_PinResult if
* successful or rejects with an nserror.
*/
[implicit_jscontext]
Promise pinCurrentAppToTaskbar(in boolean aPrivateBrowsing, [optional] in boolean aFireAndForget);
/*
* Checks if a taskbar pinning API is available.
*
* @throws NS_ERROR_NOT_SAME_THREAD
* if called off main thread
* @throws NS_ERROR_NOT_AVAILABLE
* if pinning APIs are unavailable for use
*/
void canPinToTaskbar();
/*
* Search for the current executable among taskbar pins
*
* NOTE: It is possible for the check to fail even when a taskbar pin refers
* to this executable, if the paths differ due to e.g. symlinks.
* It is also possible for the check to succeed with a shortcut that doesn't
* actually appear on the taskbar.
* These cases should be rare.
*
* @return Promise that always resolves, true if pinned, false otherwise
* @throws NS_ERROR_NOT_SAME_THREAD if not run on the main thread
*
*/
[implicit_jscontext]
Promise isCurrentAppPinnedToTaskbar(in AString aumid);
/*
* Similar to createShortcut except it removes most of the checking in that
* function that ensures we are pinning a Firefox executable instead allowing
* any shortcut to be pinned.
*
* This function should not be called unless it is certain that it's
* necessary given how few checks there are within.
* @param aAppUserModelId
* The aumid to be contained in the .lnk file
* @param aShortcutFolder The special Windows folder to create the shortcut
* in. Must be either "Programs" or "Desktop".
* @param aShortcutRelativePath
* The path to the .lnk file that should be pinned to the taskbar,
* relative to aShortcutFolder.
* @returns {Promise<PinResult>} A Promise that resolves to
* nsIWindowsShellService_PinResult if
* successful or rejects with an nserror.
*/
[implicit_jscontext]
Promise pinShortcutToTaskbar(
in AString aAppUserModelId,
in AString aShortcutFolder,
in AString aShortcutRelativePath
);
/*
* This function is a counterpart to pinShortcutToTaskbar and allows
* the unpinning of any shortcut, including non-Firefox executables,
* without the checks of createShortcut.
*
* This function should not be called unless it is certain that it's
* necessary given how few checks there are within.
* @param aShortcutFolder The special Windows folder that the shortcut
* is in. Must be either "Programs" or "Desktop".
* @param aShortcutRelativePath
* The path to the .lnk file that should be unpinned, relative
* to aShortcutFolder.
* @throws NS_ERROR_FAILURE
* If the COM service could not be initialized
* @throws NS_ERROR_FILE_NOT_FOUND
* If aShortcutPath cannot be found
* @throws NS_ERROR_NOT_AVAILABLE
* If the taskbar pinning service cannot be initialized
* @throws NS_ERROR_FILE_ACCESS_DENIED
* If the taskbar pins cannot be modified
*/
void unpinShortcutFromTaskbar(
in AString aShortcutFolder,
in AString aShortcutRelativePath
);
/*
* Launch the default app picker via the Windows IOpenWithLauncher COM
* interface. The caller picks the target (a file path whose extension
* determines the picker for file-type defaults, or a URL for protocol
* defaults) and the flag bits that drive the picker's messaging and actions.
*
* @param aTarget
* File path or URL.
* @param aFlags
* Flag combination that determines the behavior of the IOpenWithLauncher dialog.
* @throws NS_ERROR_FAILURE
* If IOpenWithLauncher is unavailable or fails.
*/
void launchSetDefaultAppPicker(in AString aTarget, in long aFlags);
/*
* Open the Windows modern settings dialog for choosing default apps
* (ms-settings:defaultapps).
*
* @throws NS_ERROR_FAILURE
* If the settings dialog cannot be launched.
*/
void launchModernSettingsDialogDefaultApps();
/*
* Determine where a given shortcut likely appears in the shell.
*
* Returns one of:
* - "StartMenu" or "StartMenuPrivate", Current User or All Users Start
* Menu, including pins
* - "Desktop" or "DesktopPrivate", Current User or All Users Desktop
* - "Taskbar" or "TaskbarPrivate", Taskbar Pins
* - "" otherwise
*
* If a Private Browsing shortcut was used to launch, the "Private"
* variant of one of the above entries will be returned.
*
* NOTE: This tries to avoid I/O, so paths are compared directly as
* strings, which may not be accurate in all cases. It is intended
* for noncritical telemetry use.
*/
AString classifyShortcut(in AString aPath);
/*
* Determine whether a pinnable shortcut with matching AUMID is present.
*
* @param aAUMID
* AUMID of the shortcut to find.
* @param aPrivateBrowsing
* `true` to have the private browsing suffix added to `aAUMID`.
*
* @returns {Promise<void>} Always resolves with boolean, true if a pinnable
* shortcut exists.
*/
[implicit_jscontext]
Promise hasPinnableShortcut(in AString aAUMID, in boolean aPrivateBrowsing);
/*
* Check if setDefaultBrowserUserChoice() is expected to succeed.
*
* This checks the ProgIDs for this installation, and the hash of the existing
* UserChoice association.
*
* @return true if the check succeeds, false otherwise.
*/
boolean canSetDefaultBrowserUserChoice();
/*
* checkAllProgIDsExist() and checkBrowserUserChoiceHashes() are components
* of canSetDefaultBrowserUserChoice(), broken out for telemetry purposes.
*
* @return true if the check succeeds, false otherwise.
*/
boolean checkAllProgIDsExist();
boolean checkBrowserUserChoiceHashes();
/*
* Check whether the UserChoice Protection Driver (UCPD) service is currently
* running. Running does not imply that it locks the UserChoice keys, as that
* varies by version and is verified by CanRenameUserChoiceAssociationKey().
*
* @return true if the service is running, false otherwise.
*/
boolean isUserChoiceProtectionDriverRunning();
/*
* Check whether a UserChoice write for aAssociation would currently be
* permitted by renaming its association key to a temporary name and back.
*
* @param aAssociation
* Association to probe, either a protocol ("http") or a file
* extension (".pdf").
*
* @return true if the association key was renamed and renamed back, false
* otherwise.
*/
boolean canRenameUserChoiceAssociationKey(in AString aAssociation);
/*
* Retrieves the application-defined, explicit Application User Model ID
* for the current process. This function is only to be used on
* Windows for testing purposes
*
* @return string AUMID
* @throws NS_ERROR_FAILURE when the AUMID cannot be fetched
*/
AString checkCurrentProcessAUMIDForTesting();
/*
* Determines whether or not Firefox is the "Default Handler", i.e.,
* is registered to handle, the given file extension (like ".pdf")
* or protocol (like "https").
*/
boolean isDefaultHandlerFor(in AString aFileExtensionOrProtocol);
/*
* Return the Windows ProgID currently registered to handle the gven
* file extension (like ".pdf") or protocol (like "https").
*
* @return string ProgID, or "" when no association is registered.
* @throws NS_ERROR_FAILURE when the file extension or protocol
* cannot be determined.
*/
AString queryCurrentDefaultHandlerFor(in AString aFileExtensionOrProtocol);
/*
* Update the icons of existing .lnk shortcuts. Loads each shortcut, calls
* IShellLinkW::SetIconLocation, saves it, and notifies the shell so Explorer
* re-reads the icon. Shortcuts that don't exist or cannot be updated are
* ignored.
*
* @param aShortcutPaths
* Absolute paths to the .lnk files to modify.
* @param aIconPath
* Absolute path to the icon source. Either an .ico file or an
* executable/DLL containing icon resources.
* @param aIconResourceId
* Resource ID of the icon within aIconPath to use (e.g.
* IDI_CUSTOM_RETRO when aIconPath is firefox.exe). The icon is
* referenced by resource ID rather than positional index so the
* reference stays valid no matter what order icons are embedded in
* aIconPath. Pass 0 to use the binary's default icon.
*
* @returns {Promise<void, nsresult>} Resolves when one or more shortcut
* is successfully updated, rejects with an nserror if no shortcuts
* were updated or on unrecoverable failure.
*
* @throws NS_ERROR_NOT_SAME_THREAD if not run on the main thread.
* @rejects NS_ERROR_NOT_AVAILABLE when no shortcuts were able to be updated.
* @rejects NS_ERROR_FAILURE for Windows API failures.
*/
[implicit_jscontext]
Promise setShortcutsIcon(in Array<AString> aShortcutPaths,
in AString aIconPath,
in unsigned short aIconResourceId);
/*
* Enumerate the .lnk files for this install across the per-user shortcut
* locations (taskbar pin folder, Desktop, Start Menu Programs) whose AUMID
* matches aAppUserModelId and whose target matches the currently running
* executable.
*
* Common (all-users) locations are not currently scanned: they typically
* require elevation to modify, and changing them would alter the icon that
* other users on the machine see. The intended use is "find every shortcut I
* am allowed to update without prompting."
*
* @param aAppUserModelId
* AUMID identifying this install's shortcuts.
*
* @returns {Promise<Array<AString>>} Resolves with absolute paths to all
* matching shortcuts. May be empty.
*
* @throws NS_ERROR_NOT_SAME_THREAD if not run on the main thread.
* @rejects NS_ERROR_FAILURE on Windows API initialization failure.
*/
[implicit_jscontext]
Promise enumerateInstallShortcuts(in AString aAppUserModelId);
};