UWPアプリケーションでファイルの拡張子を関連付ける

UWPアプリケーションでファイルの拡張子を関連付ける手順を紹介します。

手順・プログラム例

UWPアプリケーションのプロジェクトを新規作成します。

マニフェストファイルの設定

ソリューションエクスプローラーで "Package.appxmanifest" ファイルをダブルクリックします。 下図のマニフェスト編集画面が表示されます。


編集画面の上部のタブの[宣言]のタブをクリックします。下図の画面に切り替わります。


[使用可能な宣言]のコンボボックスをクリックします。下図のドロップダウンリストが表示されます。 ドロップダウンリストの中の[ファイルの種類の関連付け]の項目をクリックして選択します。


[ファイルの種類の関連付け]が選択された状態でコンボボックス右側の[追加]ボタンをクリックします。


下図の画面に切り替わります。コンボボックスの右側に入力項目が表示されます。


[プロパティ:]のセクションのテキストボックスに入力します。
[表示名:]にはプロパティダイアログで開いた際の[ファイルの種類]に表示されるファイルの名称を入力します。下図の例では"Penguin File"としています。
[ロゴ:]は拡張子に対応したファイルのアイコンを指定できます。
[ヒント:]はエクスプローラーでファイルのアイコンにマウスポインタがおかれた場合に表示されるToolTipsの表示文字列になります。
[名前:]はファイルの名称を設定します。すべて小文字で記述する必要があります。

[サポートされるファイルの種類]の欄に入力します。
[コンテンツの種類:]には、MIME コンテンツの種類(MIME Type)を入力します。
[ファイルの種類:]には関連付ける拡張子名を入力します。拡張子名は先頭にピリオドをつけて入力します。


入力後、プロジェクトを保存します。"Package.appxmanifest" ファイルのコードを表示すると、<uap:Extension Category="windows.fileTypeAssociation"> タグで始まる下記のコードが追加されています。


UI

ウィンドウにはコントロールの配置はしません。大きさのみを調整します。

コードの記述

関連付けしたファイルをダブルクリックしてアプリケーションが起動された際の処理を実装します。
App.xaml.csファイルに OnFileActivated() メソッドを記述します。
App.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;

namespace SimpleFileAssociation
{
  /// <summary>
  /// 既定の Application クラスを補完するアプリケーション固有の動作を提供します。
  /// </summary>
  sealed partial class App : Application
  {
    /// <summary>
    ///単一アプリケーション オブジェクトを初期化します。これは、実行される作成したコードの
    ///最初の行であるため、論理的には main() または WinMain() と等価です。
    /// </summary>
    public App()
    {
      this.InitializeComponent();
      this.Suspending += OnSuspending;
    }

    /// <summary>
    /// アプリケーションがエンド ユーザーによって正常に起動されたときに呼び出されます。他のエントリ ポイントは、
    /// アプリケーションが特定のファイルを開くために起動されたときなどに使用されます。
    /// </summary>
    /// <param name="e">起動の要求とプロセスの詳細を表示します。</param>
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
      Frame rootFrame = Window.Current.Content as Frame;

      // ウィンドウに既にコンテンツが表示されている場合は、アプリケーションの初期化を繰り返さずに、
      // ウィンドウがアクティブであることだけを確認してください
      if (rootFrame == null) {
        // ナビゲーション コンテキストとして動作するフレームを作成し、最初のページに移動します
        rootFrame = new Frame();

        rootFrame.NavigationFailed += OnNavigationFailed;

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) {
          //TODO: 以前中断したアプリケーションから状態を読み込みます
        }

        // フレームを現在のウィンドウに配置します
        Window.Current.Content = rootFrame;
      }

      if (e.PrelaunchActivated == false) {
        if (rootFrame.Content == null) {
          // ナビゲーションの履歴スタックが復元されていない場合、最初のページに移動します。
          // このとき、必要な情報をナビゲーション パラメーターとして渡して、新しいページを
          // 作成します
          rootFrame.Navigate(typeof(MainPage), e.Arguments);
        }
        // 現在のウィンドウがアクティブであることを確認します
        Window.Current.Activate();
      }
    }

    /// <summary>
    /// 特定のページへの移動が失敗したときに呼び出されます
    /// </summary>
    /// <param name="sender">移動に失敗したフレーム</param>
    /// <param name="e">ナビゲーション エラーの詳細</param>
    void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
      throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    /// <summary>
    /// アプリケーションの実行が中断されたときに呼び出されます。
    /// アプリケーションが終了されるか、メモリの内容がそのままで再開されるかに
    /// かかわらず、アプリケーションの状態が保存されます。
    /// </summary>
    /// <param name="sender">中断要求の送信元。</param>
    /// <param name="e">中断要求の詳細。</param>
    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
      var deferral = e.SuspendingOperation.GetDeferral();
      //TODO: アプリケーションの状態を保存してバックグラウンドの動作があれば停止します
      deferral.Complete();
    }

    protected async override void OnFileActivated(FileActivatedEventArgs e)
    {
      MessageDialog md = new MessageDialog(e.Files.Count.ToString());
      await md.ShowAsync();

      if (0 < e.Files.Count) {
        MessageDialog md2 = new MessageDialog(e.Files[0].Name + ":"+ e.Files[0].Path);
        await md2.ShowAsync();
      }
    }
  }
}

コードの解説

関連付けしたファイルをダブルクリックすると、このアプリケーションが起動します。 関連付けされた、ファイルのダブルクリックでアプリケーションが実行された場合には、OnFileActivated() メソッドが呼び出されます。
ダブルクリックしたファイルはOnFileActivatedメソッドの引数の FileActivatedEventArgs オブジェクトの Files プロパティに設定されます。 最初のメッセージダイアログで、FileActivatedEventArgsオブジェクトのFilesプロパティの個数を表示します。
Filesプロパティの個数の個数が0以上であれば、最初のFiles要素のファイル名と、ファイルパスを次のメッセージダイアログで表示します。
    protected async override void OnFileActivated(FileActivatedEventArgs e)
    {
      MessageDialog md = new MessageDialog(e.Files.Count.ToString());
      await md.ShowAsync();

      if (0 < e.Files.Count) {
        MessageDialog md2 = new MessageDialog(e.Files[0].Name + ":"+ e.Files[0].Path);
        await md2.ShowAsync();
      }
    }

なお、UWPでのメッセージダイアログの表示についてはこちらの記事を参照してください。

アプリケーションの配置

アプリケーションを一度デバッグ実行してインストールされた状態にします。
起動すると下図のスプラッシュ画面が表示されます。


その後、メインウィンドウが表示されます。
メインウィンドウの表示を確認後、ウィンドウを閉じます。

ファイルの作成

プログラムを一度実行すると、拡張子が関連付けされた状態になります。マニフェストファイルで設定した .mypenguin 拡張子のファイルを作成します。 テキストファイルを作成して、拡張子を .txt から .mypenguin に変更します。
ファイルを作成すると、アイコンの画像がマニフェストファイルで設定したイメージに変わることが確認できます。


作成したファイルのプロパティを確認します。[ファイルの種類:]の説明がマニフェストファイルで設定した "Penguin File" になっています。


ファイルのアイコンの上にマウスポインタを乗せると、「ぺんぎんファイル」のツールチップも表示されます。

プログラムの実行

作成した、test.mypenguin ファイルをダブルクリックします。先ほど作成したアプリケーションが起動します。最初にメッセージダイアログが表示され、1 の文字列が表示されます。OnFileActivatedメソッドが呼び出され、FileActivatedEventArgsオブジェクトのFilesプロパティの個数が1であることがわかります。
メッセージダイアログの[閉じる]ボタンをクリックします。


2つ目のメッセージダイアログでダブルクリックしたファイルの名前とファイル名のフルパスが表示されます。 ファイル名は test.mypenguin の表示になっており、あっています。 フルパス名もデスクトップのパスになっており、こちらもあっています。
[閉じる]ボタンをクリックします。


UWPアプリケーションのメインウィンドウが表示されます。


UWPアプリケーションで拡張子を関連付けできました。 また、関連付けした拡張子のファイルをクリックしてアプリケーションを起動した際の、実行元のファイル名を取得することもできました。

補足:拡張子関連付けの解除

アプリケーションをアンインストールすると、拡張子関連付けの設定は自動で削除されます。
\HKEY_CLASSES_ROOT\.mypenguin \HKEY_CLASSES_ROOT\.mypenguin\OpenWithProgifs のキーは残りますが、内部のアプリケーションに関係する値(AppXk3m5negpgm7nq0p8em35fppwy9j59nt5)は削除されます。 \HKEY_CLASSES_ROOT\AppXk3m5negpgm7nq0p8em35fppwy9j59nt5のキーはキーごと削除されます。

レジストリはどうなっているか

上記のプログラムで拡張子の関連付けができましたが、レジストリがどのような設定になっているのかを確認します。
下記の通りレジストリの設定は複雑になっているため、基本的にはレジストリエディタでの修正ではなく、プログラムに処理を任せたほうが良さそうです。

拡張子名(.mypenguin)のキー

拡張子のキー \HKEY_CLASSES_ROOT\.mypenguin を確認します。キーの規定の値は設定されていません。


子キーに OpenWithProgids キーが作成されており、値の名称に App で始まる値が設定されています。


エクスプローラーの拡張子設定 \HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.mypenguin にも キーが作成されています。子キーにOpenWithListキーが作成されています。



OpenWithProgidsのApp*キー

\HKEY_CLASSES_ROOT\.mypenguin¥OpenWithProgids キーの値、今回の例では、AppXk3m5negpgm7nq0p8em35fppwy9j59nt5 の値でレジストリを検索します。\HKEY_CLASSES_ROOT\AppXk3m5negpgm7nq0p8em35fppwy9j59nt5 キーが存在することが確認できます。


子要素に Application DefaultIcon Shell のキーが存在しています。





パッケージIDのキー名

ファイルをダブルクリックした際にアプリケーションが起動される設定があるか確認します。 今回デバッグした、UWPのアプリケーションが配置されているアプリケーションのパスでレジストリを検索します。
(今回の例では、C:\storage\Develop Repository\iPentecDemo\UwpFileAssociation\SimpleFileAssociation\bin\x86\Debug\AppX)

\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38 のキーに配置ディレクトリパスの記述があります。





\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38
\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38


同様の設定が、以下のキーにも作成されます。
\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38

\HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38


\HKEY_USERS\S-1-5-21-3120619235-2779843880-2524708837-1001\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38


\HKEY_USERS\S-1-5-21-3120619235-2779843880-2524708837-1001_Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\Repository\Packages\ba197666-726c-4005-8288-4859ec105580_1.0.0.0_x86__ay6g4qsbgxw38

プログラムの resources.pri のパスがキー名

以下のキーにもアプリケーション配置ディレクトリのパスが保存されています。
\HKEY_CURRENT_USER\Software\Classes\Local Settings\MrtCache\C:%5Cstorage%5CDevelop Repository%5CiPentecDemo%5CUwpFileAssociation%5CSimpleFileAssociation%5Cbin%5Cx86%5CDebug%5CAppX%5Cresources.pri\1d7d223a7150686\485bc990

\HKEY_CLASSES_ROOT\Local Settings\MrtCache\C:%5Cstorage%5CDevelop Repository%5CiPentecDemo%5CUwpFileAssociation%5CSimpleFileAssociation%5Cbin%5Cx86%5CDebug%5CAppX%5Cresources.pri\1d7d223a7150686\485bc990


\HKEY_USERS\S-1-5-21-3120619235-2779843880-2524708837-1001_Classes\Local Settings\MrtCache\C:%5Cstorage%5CDevelop Repository%5CiPentecDemo%5CUwpFileAssociation%5CSimpleFileAssociation%5Cbin%5Cx86%5CDebug%5CAppX%5Cresources.pri\1d7d223a7150686\485bc990

その他のキー

\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Compatibility Assistant\Store


\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModel\StateRepository\Cache\Package\Data\c7c

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2021-11-05
iPentec all rights reserverd.