UWPアプリのウインドウを最前面にもってくる

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

UIのあるwin32アプリのウインドウを最前面に持ってくるのは、win32APIのSetForegroundWindow()というAPIを使えばできていた。

learn.microsoft.com

が、UWPアプリはその方法ではできなかった。

※UWPのアプリは、ApplicationFrameHost.exeというプロセスが、実体のexe(Windowsの設定の場合はSystemSettings.exe)を包んでいる??ために、SystemSettings.exeのハンドルを取ってきてSetForegroundWindow()をしても、前面に出てくれなかった。

また、ApplicationFrameHost.exeのハンドルを取ってきてSetForegroundWindow()をすると、「直前にフォーカスされてたUWPアプリのウインドウ」が最前面にくるという動きをして、狙ったUWPのウインドウを前面に持ってこれなかった。

なんとか、狙ったUWPウインドウを前面に持ってきたい。

やりかた

Launcher.LaunchUriAsync()

AppDiagnosticInfoLaunchAsync()を使う。

learn.microsoft.com

今回は、UWPアプリ=Windowsの設定アプリでやってみた。

Windowsの設定アプリは、

ms-settings:なんとか

で、開きたい設定画面を指定して開くことができる。そのms-settings:を使って、今回は、

  • Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-webcam")) で、カメラ設定画面を開いて、
  • その画面を、app.LaunchAsync()で、前にもってくる

ということをやってみた。

実験コード1(LaunchAsync()で前に出す)

今回、UWPのAPIを使うために、ターゲットをWindowsにして、ターゲットのOSを10.0.22000.0にした。

using System;
using System.Collections.Generic;
using System.Threading;
using Windows.System;
using Windows.System.Diagnostics;

namespace ProcessListUpByUwpApi;

class Program
{
    static async Task Main(string[] args)
    {
        while (true)
        {
            Console.WriteLine("処理スタート");

            await LaunchSettingWindow();
            Console.WriteLine("設定を開きました");

            await BringFront();
            Console.WriteLine("設定を前に持ってきました");

            await Task.Delay(5000);
        }
    }

    static async Task LaunchSettingWindow()
    {
        // https://learn.microsoft.com/ja-jp/windows/uwp/launch-resume/launch-settings-app#calling-launchuriasync
        await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-webcam"));
    }

    static async Task BringFront()
    {
        var uwpApps = await AppDiagnosticInfo.RequestInfoAsync().AsTask();

        if (uwpApps is null)
            return;

        var app = uwpApps.Where(x => x.AppInfo.AppUserModelId == "windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel")
               .FirstOrDefault();

        if (app is null)
            return;

        // https://learn.microsoft.com/ja-jp/uwp/api/windows.system.appdiagnosticinfo.launchasync?view=winrt-26100
        await app.LaunchAsync().AsTask();
    }
}

実験コード2(PowerShellでStart-ProcessでAUMIDを指定して前面に出す)

using System.Diagnostics;
using Windows.System;

namespace ProcessListUpByUwpApi;

class Program
{
    static async Task Main(string[] args)
    {
        while (true)
        {
            await Task.Delay(1000);

            await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-webcam"));

            await Task.Delay(1000);
        }
    }

    static async Task BringFront()
    {
        GetPowerShellCommandReturn("Start-Process shell:AppsFolder\\windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel");
    }

    static string GetPowerShellCommandReturn(string psCommandWithArgs)
    {
        var psInfo = new ProcessStartInfo();

        psInfo.FileName = @"PowerShell.exe";
        psInfo.CreateNoWindow = true;
        psInfo.WindowStyle = ProcessWindowStyle.Hidden;
        psInfo.UseShellExecute = false;
        psInfo.Arguments = psCommandWithArgs;

        psInfo.RedirectStandardOutput = true; // 標準出力をリダイレクト
        psInfo.RedirectStandardError = true;  // 標準エラー出力をリダイレクト

        var p = Process.Start(psInfo);

        string all = p.StandardOutput.ReadToEnd();   // 標準出力の読み取り

        return all;
    }
}

実験コード3(PowerShellでStart-ProcessでURIを叩いて前面に出す)

using System.Diagnostics;
using Windows.System;

namespace ProcessListUpByUwpApi;

class Program
{
    static async Task Main(string[] args)
    {
        while (true)
        {
            await BringFront();

            await Task.Delay(1000);
        }
    }

    static async Task BringFront()
    {
        GetPowerShellCommandReturn("Start-Process ms-settings:privacy-webcam");
    }

    static string GetPowerShellCommandReturn(string psCommandWithArgs)
    {
        var psInfo = new ProcessStartInfo();

        psInfo.FileName = @"PowerShell.exe";
        psInfo.CreateNoWindow = true;
        psInfo.WindowStyle = ProcessWindowStyle.Hidden;
        psInfo.UseShellExecute = false;
        psInfo.Arguments = psCommandWithArgs;

        psInfo.RedirectStandardOutput = true; // 標準出力をリダイレクト
        psInfo.RedirectStandardError = true;  // 標準エラー出力をリダイレクト

        var p = Process.Start(psInfo);

        string all = p.StandardOutput.ReadToEnd();   // 標準出力の読み取り

        return all;
    }
}

備考

Windows 24H2以降、うまく動かない(前面に出てくれない)気がする、、、

Windows 設定アプリの起動

下記に一覧がある。

learn.microsoft.com