microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.72k stars 308 forks source link

Exception when launching appsfeatures-app settings uri with LaunchUriAsync #4460

Open HO-COOH opened 1 month ago

HO-COOH commented 1 month ago

Describe the bug

I need to launch the settings app to the settings of my app. But I got exceptions and nothing was launched. The uri is documented here.

Steps to reproduce the bug

  1. Use this code in App.OnLaunch
    winrt::Windows::System::LauncherOptions options;
    auto name = winrt::Windows::ApplicationModel::Package::Current().Id().FamilyName();
    options.TargetApplicationPackageFamilyName(name);
    winrt::Windows::System::Launcher::LaunchUriAsync(winrt::Windows::Foundation::Uri{L"ms-settings:appsfeatures-app"}, options);

Expected behavior

No response

Screenshots

No response

NuGet package version

Windows App SDK 1.5.3: 1.5.240428000

Packaging type

Packaged (MSIX)

Windows version

Windows 11 version 22H2 (22621, 2022 Update)

IDE

Visual Studio 2022

Additional context

No response

jonwis commented 1 month ago

See https://github.com/MicrosoftDocs/winrt-api/issues/1107 - the docs for Launcher and LauncherOptions don't make this clear enough. The launcher needs a "source window" so it knows where to put the resulting launched app's window.

In an ideal world, we'd update WASDK to include a Microsoft.Windows.System.Launcher whose Launch methods took a WindowId so devs knew it had to be passed along.

HO-COOH commented 1 month ago

@jonwis Can't get it working. Still exceptions at the launch line. Updated code:

    winrt::Windows::System::LauncherOptions options;
    options.TargetApplicationPackageFamilyName(winrt::Windows::ApplicationModel::Package::Current().Id().FamilyName());
    winrt::check_hresult(options.as<::IInitializeWithWindow>()->Initialize(GetHwnd(*this)));  /*Get hwnd of this window*/

    winrt::Windows::System::Launcher::LaunchUriAsync(
        winrt::Windows::Foundation::Uri{ L"ms-settings:appsfeatures-app" },
        options
    );
lhak commented 1 month ago

I tested calling LaunchUriAsync() without any options set and it correctly opens the application specific settings for me. I do no think that TargetApplicationPackageFamilyName is actually the optional parameter that the documentation talks about.

HO-COOH commented 1 month ago

@lhak Now things gets interesting. Directly using Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:appsfeatures-app"));, it will correctly launch to app setting on Windows 11, but on Windows 10, it does not. It opens this page,

image

jonwis commented 1 month ago

Aha, correct. TargetApplicationPackageFamilyName is the application that you want to launch with the launcher. For instance, if AppA knows that their partner team's AppB is the best possible handler of the x-contoso-foo: protocol, and they want to avoid the "Which app do you want to handle this launch?" dialog, AppA would set the family name for AppB as the Target- value.

Is your app packaged, on both Win10 and Win11? Settings uses the identity of the app-that-does-the-launch to navigate to the right settings page.

HO-COOH commented 1 month ago

@jonwis Yes, self-packaging winui3 project on both OS. Also if the TargetApplicationPackageFamilyName is supposed to be used to open another app's settings, it should also able to open itself's settings shouldn't it?

jonwis commented 1 month ago

Packaging as in "has package identity" via an MSIX deployment or sparse packaging after an MSI or other installer? The caller must have package identity (which you appear to, per your sample.)

For TargetApplicationPackageFamilyName - from https://learn.microsoft.com/uwp/api/windows.system.launcheroptions.targetapplicationpackagefamilyname?view=winrt-22621 :

The package family name of the target package that should be used to launch a file or URI. This property is optional.

This property is not specific to Settings. It's a general purpose "I know a specific app - like Visual Studio or Task Manager or Terminal - handles this launch; don't prompt the user to let them pick, and don't guess which one on your own. Launch this one, specifically."

There does not appear to be a general-purpose way to launch another app's settings page. You could ask the other app to add a URI that "auto redirects" to settings.

Gaoyifei1011 commented 1 month ago

Packaging as in "has package identity" via an MSIX deployment or sparse packaging after an MSI or other installer? The caller must have package identity (which you appear to, per your sample.)

For TargetApplicationPackageFamilyName - from https://learn.microsoft.com/uwp/api/windows.system.launcheroptions.targetapplicationpackagefamilyname?view=winrt-22621 :

The package family name of the target package that should be used to launch a file or URI. This property is optional.

This property is not specific to Settings. It's a general purpose "I know a specific app - like Visual Studio or Task Manager or Terminal - handles this launch; don't prompt the user to let them pick, and don't guess which one on your own. Launch this one, specifically."

There does not appear to be a general-purpose way to launch another app's settings page. You could ask the other app to add a URI that "auto redirects" to settings.

So I'm curious to know how the Start menu and web-based search lead to the app's Settings page. Are they using some kind of private api?

castorix commented 4 weeks ago

So I'm curious to know how the Start menu and web-based search lead to the app's Settings page. Are they using some kind of private api?

The Start Menu just calls ShellExecuteEx on the link ("10 - AppsAndFeatures.lnk" on my Windows 10 OS) (which mainly contains "_windows.immersivecontrolpanelcw5n1h2txyewy!microsoft.windows.immersivecontrolpanel" "page=SettingsPageAppsSizes" (Arguments for IApplicationActivationManager) and also "Microsoft.Windows.PCSettings.AppsAndFeatures"

HO-COOH commented 4 weeks ago

@jonwis I was using the "winui3 project (packaged)" template from visual studio, and yes it would be packaged to msix, that has a package family name. That's why it doesn't throw exception on the PackageId.FamilyName() line. I simply want a way to launch settings to my own app that works on Windows 10 & 11, and Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings:appsfeatures-app")); this does not work on Windows 10.

Gaoyifei1011 commented 4 weeks ago

So I'm curious to know how the Start menu and web-based search lead to the app's Settings page. Are they using some kind of private api?

The Start Menu just calls ShellExecuteEx on the link ("10 - AppsAndFeatures.lnk" on my Windows 10 OS) (which mainly contains "_windows.immersivecontrolpanelcw5n1h2txyewy!microsoft.windows.immersivecontrolpanel" "page=SettingsPageAppsSizes" (Arguments for IApplicationActivationManager) and also "Microsoft.Windows.PCSettings.AppsAndFeatures"

Can you write a code example and try to call the relevant API to achieve the corresponding functionality? Thank you very much. I'm talking about the Settings pages that open in these places Start menu image Web search 3E87A503D0C4641873B6D172FEF8DE0A

HO-COOH commented 4 weeks ago

I uploaded a sample to demo everything I tried. There is called with parameter, without parameter, and with other apps' family name as parameter, nothing works on Windows 10 17763.

castorix commented 4 weeks ago

I'm talking about the Settings pages that open in these places

Ah sorry, I thought you were talking about the "Apps & Features" menu item on right-click on Start Menu (which is not associated with an app)

castorix commented 4 weeks ago

I uploaded a sample to demo everything I tried. There is called with parameter, without parameter, and with other apps' family name as parameter, nothing works on Windows 10 17763.

On Windows 10, I must set "_windows.immersivecontrolpanelcw5n1h2txyewy" for TargetApplicationPackageFamilyName if I use options But I don't see what the doc means by "pass an optional parameter of the package family name of the app." (I tried with ValueSet, but failed...) (but it works without that if the application is packaged)