UWPアプリから外部のexeファイルを実行する【UWP】

UWPアプリではセキュリティの関係でそのアプリ以外の領域へのアクセスに制限が加えられています。そのため今まで通りUWPアプリから他のexeファイルを呼び出すことはできません。しかし、UWPアプリの機能だけでは足りず、どうしてもWin32アプリやPython・Javaなどの他の言語で作ったコンポーネントを連携させたい場合もあるかもしれません。そのために、UWPではDesktop Bridgeという仕組みでUWPアプリと外部のexeファイルとを連携させることが可能になっています。

UWPアプリでexeファイルを実行しようとすると…

従来のWin32アプリからはProcessクラスのStartメソッドを用いることで外部のプログラムを実行可能でした。例えばアプリ上からメモ帳を起動する場合は次のようになります。

Process.Start(@"C:\Windows\notepad.exe");

では、これはUWPアプリでも使えるのでしょうか?

試しにVisual Studioで新規のUWPアプリのプロジェクトを作成して、次のようなコードを書きます。

MainPage.xaml
<Page ...(中略)... >
    <StackPanel>
        <Button Content="アプリ起動" Click="Button_Click"/>
        <TextBlock x:Name="txtBlock"/>
    </StackPanel>
</Page>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            var process = Process.Start(@"C:\Windows\notepad.exe");
            txtBlock.Text = process.ToString();
        }
        catch(Exception ex)
        {
            txtBlock.Text = ex.ToString();
        }
    }
}

「アプリ起動」ボタンを押すとメモ帳が起動するというUWPアプリです。

このコードは問題なくコンパイルされ一見UWPアプリでも従来通り外部のアプリを起動できそうに思えます。しかし実際に「アプリ起動」ボタンをクリックしてみると次のようなエラーが表示されて実行できません。

「System.PlatformNotSupportedException」という例外から分かる通り、UWPアプリから外部アプリを起動することはサポートされていないのです。このことはProcessクラスのStartメソッドのAPIドキュメントでも以下のように適用対象からUWPが除外されていることからも分かります。

Startメソッドの適用対象

そうはいっても例えばデータ解析や画像解析、AIの機能はPythonで構築したり、あるいは部分的にJavaでコーディングしたりと、それぞれの言語の得意分野を組み合わせてUWPアプリを構築したいという場合もあるかも知れません。

そのために用意されているのが次に解説するDesktop Bridgeです。

Desktop Bridgeとは?

Desktop BridgeはWin32アプリや.NETアプリを.appxパッケージとしてラッピングすることでUWPアプリ化する方法です。exeファイルの実行コードに手を加える必要はなく、.appxパッケージにexeファイルを同梱して、AppxManifest.xmlを正しく設定するだけでできます。

Desktop Bridgeの用途としては次のようなものが挙げられます。

  • すでにあるexeファイルをUWPアプリ化する
  • UWPのみでは使えない機能を入れる

それでは、既存のWin32アプリをUWPアプリ化することで他のUWPアプリと連携し、UWPアプリのみでは使えない機能を入れる方法を試してみましょう。

Desktop Bridgeを使ってみる

ここでは例として、UWPアプリからWPFで作成したWin32のWindowsアプリを起動するプログラムを作ってみましょう。以下のサイトにDesktop Bridgeを使った連携の仕方が詳しく解説されているので、ここではそれを参考にさせていただきました。

まず、新規の「Windowsアプリケーションパッケージプロジェクト」を「AppLauncher」というプロジェクト名で作成し、次の2つのプロジェクトを追加します。

  • 空白のアプリ(ユニバーサルWindows)
    • ここでは「UWPApp」とします
  • WPFアプリケーション
    • ここでは「WPFApp」とします

AppLauncherプロジェクトのアプリケーションを右クリックして、「参照の追加」から先ほど作成した以下の2つのプロジェクトを追加しておきます。

  • UWPApp
  • WPFApp

さらに、追加して表示されたUWPAppを右クリックしてエントリポイントに設定しておきましょう。これでAppLauncherを実行すると、まずUWPAppが起動されるようになります。

続いて、AppLauncherプロジェクトのPackage.appxmanifestを右クリックして、コードの表示からコードを表示させ、以下のハイライト部分を追加します。

<?xml version="1.0" encoding="utf-8"?>

<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  IgnorableNamespaces="uap rescap">

  ......省略......

  <Applications>
    <Application Id="App"
      Executable="$targetnametoken$.exe"
      EntryPoint="$targetentrypoint$">
      <uap:VisualElements
        DisplayName="AppLauncher"
        Description="AppLauncher"
        BackgroundColor="transparent"
        Square150x150Logo="Images\Square150x150Logo.png"
        Square44x44Logo="Images\Square44x44Logo.png">
        <uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
        <uap:SplashScreen Image="Images\SplashScreen.png" />
      </uap:VisualElements>
      <Extensions>
        <desktop:Extension Category="windows.fullTrustProcess" Executable="WPFApp\WPFApp.exe" />
      </Extensions>
    </Application>
  </Applications>

  ......省略......

</Package>


UWPアプリから外部プログラムを起動するための処理はFullTrustProcessLauncherクラスを用いますが、これはデスクトップデバイスファミリーでのみしか使えないので、デフォルトでは無効になっています。これを有効化するにはUWPAppプロジェクトの参照の追加から「Windows Desktop Extenshons for the UWP」のチェックを入れる必要があります。

これでUWPAppからWPFAppを実行するための準備が終わりました。あとは、それぞれの処理を書いていくだけです。ここではUWPAppに配置したボタンをクリックすることでWPFAppが起動するようにするので、UWPAppのXAML上でボタンを配置し、そのイベントハンドラーを次のようにします。

MainPage.xaml.cs (UWPApp)
using Windows.ApplicationModel;
    ...(略)...

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
    }
}

UWPアプリからはFullTrustProcessLauncherクラスのLaunchFullTrustProcessForCurrentAppAsyncメソッドを用いることで、Package.appxmanifestにあらかじめ登録したWin32アプリを起動することができます。それではWin32アプリとしてWPFアプリケーションをUWPアプリから起動してみましょう。なお、実行するときは、「Any CPU」ではなくて x86 か x64 にして起動する必要があります。

これでUWPAppからWPFAppが起動できたことが分かります。

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)