パッケージ サポート フレームワークの使用を開始する
パッケージ サポート フレームワークは、既存のデスクトップ アプリケーションに (コードを変更することなく) 修正を適用して、MSIX コンテナー内で実行できるようにするのに役立つオープン ソース キットです。 パッケージ サポート フレームワークは、アプリケーションで最新のランタイム環境のベスト プラクティスに従うのに役立ちます。
この記事では、パッケージ サポート フレームワークの各コンポーネントについて詳しく説明し、使用するためのステップ バイ ステップ ガイドを提供します。
パッケージ サポート フレームワークの仕組みの概要
パッケージ サポート フレームワークには、1 つの実行可能ファイル、1 つのランタイム マネージャー DLL、およびランタイム修正プログラムのセットが含まれます。
プロセスは次のとおりです。
- アプリケーションに適用する修正プログラムを指定する構成ファイルを作成します。
- パッケージ サポート フレームワーク (PSF) 起動ツールの実行可能ファイルをポイントするようにパッケージを変更します。
ユーザーがアプリケーションを起動すると、パッケージ サポート フレームワーク起動ツールが最初に実行されます。 ランチャーによって構成ファイルが読み取られ、ランタイム修正プログラムとランタイム マネージャー DLL がアプリケーション プロセスに挿入されます。 ランタイム マネージャーは、MSIX、コンテナー内で実行するアプリケーションで必要になったときに修正プログラムを適用します。
手順 1: パッケージ化されたアプリケーションの互換性の問題を特定する
まず、アプリケーションのパッケージを作成します。 次に、そのパッケージをインストールして実行し、動作を観察します。 互換性に関する問題の特定に役立つエラー メッセージが表示されることがあります。 プロセス モニターを使用して問題を識別することもできます。 一般的な問題は、作業ディレクトリとプログラムパスのアクセス許可に関するアプリケーションの前提に関連しています。
プロセス モニターを使用して問題を特定する
プロセス モニターは、アプリによるファイルとレジストリの操作およびその結果を監視するための強力なユーティリティです。 これは、アプリケーションの互換性に関する問題を理解するのに役立ちます。 プロセス モニターを開いた後、フィルター (フィルター > フィルター...) を追加して、アプリケーションの実行可能ファイルからのイベントのみを含めます。
イベントの一覧が表示されます。 これらのイベントの多くについて、[結果] 列に成功の文字が表示されます。
必要に応じて、エラーのみを表示するようにイベントをフィルター処理できます。
ファイル システムへのアクセス エラーが疑われる場合は、System32/SysWOW64 かそのパッケージ ファイル パスの下にある失敗したイベントを検索します。 この際にもフィルターを利用できます。 この一覧の一番下から開始して、上にスクロールします。 この一覧の一番下に表示されるエラーが、一番新しいエラーです。 "アクセスが拒否されました" や "パス/名前が見つかりません" などの文字列を含むエラーに特に注意し、疑わしくないものは無視します。 PSFSample に 2 つの問題があります。 次の図に示されている一覧で、これらの問題を確認できます。
この図に示されている最初の問題では、アプリケーションは "C:\Windows\SysWOW64" パスにある "Config.txt" ファイルからの読み取りに失敗しています。 アプリケーションがそのパスを直接参照しようとすることはほとんどありません。 通常、アプリケーションは相対パスを使用してそのファイルを読み取ろうとします。既定では、"System32/SysWOW64" がそのアプリケーションの作業ディレクトリです。 これは、そのアプリケーションでは、現在の作業ディレクトリがパッケージ内のどこかに設定されるように想定されていることを示しています。 appx の内部を見ると、そのファイルが実行可能ファイルと同じディレクトリに存在することがわかります。
2 つ目の問題は、次の図に示されています。
この問題では、アプリケーションはそのパッケージ パスに .log ファイルを書き込むことができていません。 これは、ファイル リダイレクトの修正が役立つ可能性があることを示しています。
手順 2: ランタイム修正プログラムを検索する
PSF には、ファイル リダイレクトの修正など、すぐに使用できるランタイム修正プログラムが含まれています。
ファイル リダイレクトの修正
ファイル リダイレクトの修正を使用すると、MSIX コンテナーで実行されているアプリケーションからアクセスできないディレクトリ内のデータの書き込みまたは読み取りの試行をリダイレクトできます。
たとえば、アプリケーションがそのアプリケーションの実行可能ファイルと同じディレクトリにあるログ ファイルに書き込みを行う場合は、ファイル リダイレクトの修正を使用して、ローカル アプリ データストアなどの別の場所にそのログ ファイルを作成できます。
コミュニティのランタイム修正プログラム
GitHub ページへのコミュニティ投稿もぜひご確認ください。 他の開発者が同様の問題を既に解決していて、ランタイム修正プログラムを共有している場合があります。
手順 3: ランタイム修正プログラムを適用する
Windows SDK のいくつかの簡単なツールを使用し、次の手順に従うことにより、既存のランタイム修正プログラムを適用できます。
- パッケージ レイアウト フォルダーを作成する
- パッケージ サポート フレームワーク ファイルを取得する
- それらをパッケージに追加する
- パッケージ マニフェストを変更する
- 構成ファイルを作成する
次に、それぞれのタスクについて説明します。
パッケージ レイアウト フォルダーを作成する
.msix (または .appx) ファイルが既にある場合は、そのパッケージのステージング領域として機能するレイアウト フォルダーにその内容をアンパックできます。 この操作は、MakeAppx ツールを使用して、コマンド プロンプトから実行できます。SDK のインストール パスによって、次の場所に Windows 10 PC の makeappx.exe が見つかります。x86: C:\Program Files (x86)\Windows Kits\10\bin\x86\makeappx.exe x64: C:\Program Files (x86)\Windows Kits\10\bin\x64\makeappx.exe
makeappx unpack /p PSFSamplePackage_1.0.60.0_AnyCPU_Debug.msix /d PackageContents
これを実行すると、次のようになります。
.msix (または .appx) ファイルがない場合は、パッケージ フォルダーとファイルを最初から作成できます。
パッケージ サポート フレームワーク ファイルを取得する
スタンドアロン Nuget コマンド ライン ツールを使用するか Visual Studio を使用することにより、PSF Nuget パッケージを取得できます。
コマンド ライン ツールを使用してパッケージを取得する
Nuget コマンド ライン ツールを https://www.nuget.org/downloads からインストールします。 次に、その Nuget コマンド ラインから、次のコマンドを実行します。
nuget install Microsoft.PackageSupportFramework
または、パッケージの拡張子を .zip に変更してファイルを解凍することもできます。 必要なファイルはすべて /bin フォルダーにあります。
Visual Studio を使用してパッケージを取得する
Visual Studio で、ソリューションまたはプロジェクト ノードを右クリックし、[Nuget パッケージの管理] コマンドの 1 つを選択します。 Nuget.org でパッケージを検索する場合は、Microsoft.PackageSupportFramework または PSF を検索します。その後、パッケージをインストールします。
パッケージ サポート フレームワーク ファイルをパッケージに追加する
必要な 32 ビットと 64 ビットの PSF DLL、および実行可能ファイルをパッケージ ディレクトリに追加します。 次の表をガイドとして使用してください。 また、必要な任意のランタイム修正プログラムを含めることもできます。 この例では、ファイル リダイレクト ランタイム修正プログラムが必要になります。
アプリケーション実行可能ファイルが x64 の場合 | アプリケーションの実行可能ファイルが x86 の場合 |
---|---|
PSFLauncher64.exe | PSFLauncher32.exe |
PSFRuntime64.dll | PSFRuntime32.dll |
PSFRunDll64.exe | PSFRunDll32.exe |
これで、パッケージの内容は次のようになります。
パッケージ マニフェストを変更する
パッケージ マニフェストをテキスト エディターで開き、Application
要素の Executable
属性を PSF 起動ツールの実行可能ファイルの名前に設定します。 ターゲット アプリケーションのアーキテクチャがわかっている場合は、PSFLauncher32.exe と PSFLauncher64.exe のうちの適切なバージョンを選択します。 わかっていない場合は、PSFLauncher32.exe がどの場合でも動作します。 次に例を示します。
<Package ...>
...
<Applications>
<Application Id="PSFSample"
Executable="PSFLauncher32.exe"
EntryPoint="Windows.FullTrustApplication">
...
</Application>
</Applications>
</Package>
構成ファイルを作成する
ファイル名 config.json
を作成し、そのファイルをパッケージのルート フォルダーに保存します。 先ほど置き換えた実行可能ファイルを指すように、config.json ファイルの宣言済みアプリ ID を変更します。 プロセス モニターを使用して得た知識を使用して、作業ディレクトリを設定することもできます。また、ファイル リダイレクトの修正を使用して、パッケージ相対 "PSFSampleApp" ディレクトリの下にある .log ファイルに読み取り/書き込みをリダイレクトすることもできます。
{
"applications": [
{
"id": "PSFSample",
"executable": "PSFSampleApp/PSFSample.exe",
"workingDirectory": "PSFSampleApp/"
}
],
"processes": [
{
"executable": "PSFSample",
"fixups": [
{
"dll": "FileRedirectionFixup.dll",
"config": {
"redirectedPaths": {
"packageRelative": [
{
"base": "PSFSampleApp/",
"patterns": [
".*\\.log"
]
}
]
}
}
}
]
}
]
}
次に、config.json スキーマのガイドを示します。
Array | key | Value |
---|---|---|
applications | id | パッケージ マニフェストの Application 要素の Id 属性の値を使用します。 |
applications | executable | 起動する実行可能ファイルへのパッケージ相対パス。 ほとんどの場合、変更する前にパッケージ マニフェスト ファイルからこの値を取得できます。 これは、Application 要素の Executable 属性の値です。 |
applications | workingDirectory | (省略可能) 開始するアプリケーションの作業ディレクトリとして使用するパッケージ相対パス。 この値を設定しない場合、オペレーティング システムはアプリケーションの作業ディレクトリとして System32 ディレクトリを使用します。 |
プロセス | executable | ほとんどの場合、パスとファイル拡張子が削除された上で構成された executable の名前になります。 |
fixups | dll | 読み込む修正プログラム .msix/.appx のパッケージ相対パス。 |
fixups | config | (省略可能) 修正プログラムの dll の動作を制御します。 この値の正確な形式は、各修正プログラムが必要に応じてこの "blob" を解釈できるため、修正プログラムごとに変化します。 |
applications
、processes
、および fixups
キーは配列です。 つまり、config.json ファイルを使用して、複数のアプリケーション、プロセス、および修正プログラムの DLL を指定できます。
アプリをパッケージ化してテストする
次に、パッケージを作成します。
makeappx pack /d PackageContents /p PSFSamplePackageFixup.msix
次に、署名します。
signtool sign /a /v /fd sha256 /f ExportedSigningCertificate.pfx PSFSamplePackageFixup.msix
詳細については、パッケージ署名証明書の作成方法と、SignTool を使用してパッケージに署名する方法に関する記事を参照してください。
PowerShell を使用して、パッケージをインストールします。
Note
最初にパッケージをアンインストールしてください。
powershell Add-AppPackage .\PSFSamplePackageFixup.msix
アプリケーションを実行し、ランタイム修正プログラムが適用された動作を確認します。 必要に応じて、診断とパッケージ化の手順を繰り返します。
パッケージ サポート フレームワークが実行されているかどうかを確認する
ランタイム修正プログラムが実行されているかどうかを確認できます。 これを行うには、タスク マネージャーを開き、[More details]\(詳細\) をクリックします。 パッケージ サポート フレームワークが適用されているアプリを見つけ、アプリの詳細を展開して、詳細を確認します。 これで、パッケージ サポート フレームワークが実行されていることを確認できます。
トレースの修正を使用する
パッケージ アプリケーションの互換性の問題を診断するための別の方法は、トレースの修正を使用することです。 この DLL は PSF に含まれており、アプリの動作について、プロセス モニターとよく似た詳細な診断ビューを提供します。 これは、特に、アプリケーションの互換性の問題を明らかにするように設計されています。 トレースの修正を使用するには、パッケージに DLL を追加し、次のフラグメントを config.json に追加してから、アプリケーションをパッケージ化してインストールします。
{
"dll": "TraceFixup.dll",
"config": {
"traceLevels": {
"filesystem": "allFailures"
}
}
}
既定で、トレースの修正では "想定どおり" と見なされうるエラーは除外されます。 たとえば、アプリケーションは、あるファイルが既に存在するかを確認せずにファイルを無条件で削除しようとして、その結果を無視する場合があります。 その結果、一部の予期しないエラーがフィルター処理で除外される可能性があります。このため、上の例では、filesystem 関数からすべてのエラーを受信することを選択しています。 このようにするのは、Config.txt ファイルから読み取ろうとすると、"ファイルが見つかりません" というメッセージが表示されて失敗することがわかっているためです。 これは、よく見られるエラーで、予期しないエラーとは一般的には見なされません。 通常は、最初は予期しないエラーのみが対象となるようにフィルター処理をし、特定できない問題が依然として存在する場合に、すべてのエラーにフォールバックすることが最適です。
既定で、トレース修正の出力は、アタッチされたデバッガーに送信されます。 この例では、デバッガーをアタッチせず、SysInternals の DebugView プログラムを代わりに使用して出力を表示します。 アプリを実行すると、前述のものと同じエラーを確認でき、同じランタイム修正プログラムが必要であることがわかります。
ランタイム修正プログラムのデバッグ、拡張、作成
Visual Studio を使用することにより、ランタイム修正プログラムのデバッグ、拡張、またはゼロからの作成を行うことができます。 成功するには、次の操作が必要になります。
- パッケージ プロジェクトを追加する
- ランタイム修正プログラムのプロジェクトを追加する
- PSF 起動ツールの実行可能ファイルを起動するプロジェクトを追加する
- パッケージ プロジェクトを構成する
完了すると、ソリューションは次のようになります。
この例の各プロジェクトについて説明します。
プロジェクト | 目的 |
---|---|
DesktopApplicationPackage | このプロジェクトは、Windows アプリケーション パッケージ プロジェクトに基づいており、MSIX パッケージを出力します。 |
Runtimefix | これは、C++ ダイナミック リンク ライブラリ プロジェクトで、ランタイム修正プログラムとして機能する 1 つ以上の置換関数を含んでいます。 |
PSFLauncher | これは、空の C++ プロジェクトです。 このプロジェクトは、パッケージ サポート フレームワークのランタイム再頒布可能ファイルを収集する場所です。 実行可能ファイルが出力されます。 この実行可能ファイルは、ソリューションの起動時に最初に実行されるものです。 |
WinFormsDesktopApplication | このプロジェクトには、デスクトップ アプリケーションのソース コードが含まれています。 |
これらのすべての種類のプロジェクトを含む完全なサンプルについては、PSFSample のページを参照してください。
次に、ソリューションでこれらの各プロジェクトを作成して構成する手順について説明します。
パッケージ ソリューションを作成する
デスクトップ アプリケーション用のソリューションをまだ作成していない場合は、Visual Studio で新しい [空のソリューション] を作成してください。
また、使用しているアプリケーション プロジェクトを追加することもできます。
パッケージ プロジェクトを追加する
Windows アプリケーション パッケージ プロジェクト をまだ持っていない場合は作成し、ソリューションに追加します。
Windows アプリケーション パッケージ プロジェクトの詳細については、Visual Studio を使用したアプリケーションのパッケージ化に関する記事を参照してください。
ソリューション エクスプローラーで、パッケージ プロジェクトを右クリックし、[編集] を選択して、プロジェクト ファイルの一番下に次の内容を追加します。
<Target Name="PSFRemoveSourceProject" AfterTargets="ExpandProjectReferences" BeforeTargets="_ConvertItems">
<ItemGroup>
<FilteredNonWapProjProjectOutput Include="@(_FilteredNonWapProjProjectOutput)">
<SourceProject Condition="'%(_FilteredNonWapProjProjectOutput.SourceProject)'=='<your runtime fix project name goes here>'" />
</FilteredNonWapProjProjectOutput>
<_FilteredNonWapProjProjectOutput Remove="@(_FilteredNonWapProjProjectOutput)" />
<_FilteredNonWapProjProjectOutput Include="@(FilteredNonWapProjProjectOutput)" />
</ItemGroup>
</Target>
ランタイム修正プログラムのプロジェクトを追加する
C++ ダイナミック リンク ライブラリ (DLL) プロジェクトをソリューションに追加します。
そのプロジェクトを右クリックして、[プロパティ] を選択します。
プロパティ ページで、"C++ 言語標準" フィールドを見つけ、そのフィールドの横にあるドロップダウン リストの中の [ISO C++17 標準 (/std:c++17)] オプションを選択します。
そのプロジェクトを右クリックして、コンテキスト メニューの中の [Nuget パッケージの管理] オプションを選択します。 [パッケージ ソース] オプションが [すべて] または [nuget.org] に設定されていることを確認します。
そのフィールドの横にある設定アイコンをクリックします。
PSF* Nuget パッケージを検索し、このプロジェクト用にインストールします。
既存のランタイム修正プログラムをデバッグまたは拡張する場合は、このガイドの「ランタイム修正プログラムを検索する」セクションで説明されているガイダンスを使用して、取得したランタイム修正ファイルを追加します。
新しい修正プログラムを作成する場合は、このプロジェクトにまだ何も追加しないでください。 このプロジェクトに適切なファイルを追加する方法については、このガイドの後半で説明します。 ここでは、ソリューションのセットアップを続行します。
PSF 起動ツールの実行可能ファイルを起動するプロジェクトを追加する
ソリューションに C++ [空のプロジェクト] プロジェクトを追加します。
前のセクションで説明したのと同じガイダンスを使用して、このプロジェクトに PSF Nuget パッケージを追加します。
プロジェクトのプロパティ ページを開き、[全般] 設定ページで、アプリケーションのアーキテクチャに応じて [ターゲット名] プロパティを PSFLauncher32
または PSFLauncher64
に設定します。
ソリューションのランタイム修正プロジェクトへのプロジェクト参照を追加します。
参照を右クリックして、[プロパティ] ウィンドウで次の値を適用します。
プロパティ | 値 |
---|---|
ローカルにコピー | True |
ローカル サテライト アセンブリにコピー | True |
参照アセンブリの出力 | True |
ライブラリ依存関係のリンク | False |
ライブラリ依存関係のリンクの入力 | False |
パッケージ プロジェクトを構成する
パッケージ 化プロジェクトで、[アプリケーション] フォルダーを右クリックし、[参照の追加] を選択します。
PSF 起動ツール プロジェクトとデスクトップ アプリケーション プロジェクトを選択し、[OK] ボタンを選択します。
Note
アプリケーションへのソース コードがない場合は、PSF 起動ツール プロジェクトを選択します。 構成ファイルを作成するときに実行可能ファイルを参照する方法について説明します。
[アプリケーション] ノードで、PSF 起動ツール アプリケーションを右クリックして、[エントリ ポイントに設定] を選択します。
config.json
という名前のファイルをパッケージ プロジェクトに追加し、次の json テキストをコピーしてファイルに貼り付けます。 [パッケージ アクション] プロパティを [ コンテンツ] に 設定します。
{
"applications": [
{
"id": "",
"executable": "",
"workingDirectory": ""
}
],
"processes": [
{
"executable": "",
"fixups": [
{
"dll": "",
"config": {
}
}
]
}
]
}
各キーの値を指定します。 次の表を参考にしてください。
Array | key | Value |
---|---|---|
applications | id | パッケージ マニフェストの Application 要素の Id 属性の値を使用します。 |
applications | executable | 起動する実行可能ファイルへのパッケージ相対パス。 ほとんどの場合、変更する前にパッケージ マニフェスト ファイルからこの値を取得できます。 これは、Application 要素の Executable 属性の値です。 |
applications | workingDirectory | (省略可能) 開始するアプリケーションの作業ディレクトリとして使用するパッケージ相対パス。 この値を設定しない場合、オペレーティング システムはアプリケーションの作業ディレクトリとして System32 ディレクトリを使用します。 |
プロセス | executable | ほとんどの場合、パスとファイル拡張子が削除された上で構成された executable の名前になります。 |
fixups | dll | 読み込む修正プログラムの DLL へのパッケージ相対パス。 |
fixups | config | (省略可能) 修正プログラムの DLL の動作を制御します。 この値の正確な形式は、各修正プログラムが必要に応じてこの "blob" を解釈できるため、修正プログラムごとに変化します。 |
完了すると、config.json
ファイルは次のように表示されます。
{
"applications": [
{
"id": "DesktopApplication",
"executable": "DesktopApplication/WinFormsDesktopApplication.exe",
"workingDirectory": "WinFormsDesktopApplication"
}
],
"processes": [
{
"executable": ".*App.*",
"fixups": [ { "dll": "RuntimeFix.dll" } ]
}
]
}
Note
applications
、processes
、および fixups
キーは配列です。 つまり、config.json ファイルを使用して、複数のアプリケーション、プロセス、および修正プログラムの DLL を指定できます。
ランタイム修正プログラムをデバッグする
Visual Studio で、F5 キーを押してデバッガーを起動します。 最初に PSF 起動ツール アプリケーションが起動し、次にターゲット デスクトップ アプリケーションが起動します。 ターゲット デスクトップ アプリケーションをデバッグするには、[デバッグ] > [>プロセスにアタッチ] を選択 し、アプリケーション プロセスを選択して、デスクトップ アプリケーション プロセスに手動でアタッチする必要があります。 ネイティブ ランタイム修正 DLL を使用した .NET アプリケーションのデバッグを許可するには、マネージド コードの種類とネイティブ コードの種類 (混合モードのデバッグ) を選択します。
この設定が完了すると、デスクトップ アプリケーション コードとランタイム修正プロジェクトのコード行の横にブレーク ポイントを設定できます。 アプリケーションへのソース コードがない場合は、ランタイム修正プロジェクトのコード行の横にのみブレーク ポイントを設定できます。
F5 デバッグでは、.msix/.appx パッケージからインストールするのではなく、パッケージ レイアウト フォルダー パスからルーズ ファイルを展開することでアプリケーションが実行されるため、レイアウト フォルダーには、通常、インストールされているパッケージ フォルダーと同じセキュリティ制限はありません。 そのため、ランタイム修正プログラムを適用する前に、パッケージ パスのアクセス拒否エラーを再現できない可能性があります。
この問題に対処するには、F5 ルーズ ファイルの展開ではなく、.msix / .appx パッケージの展開を使用します。 .msix / .appx パッケージ ファイルを作成するには、前述の説明に従って Windows SDK から MakeAppx ユーティリティを使用します。 または、Visual Studio 内から、アプリケーション プロジェクト ノードを右クリックし、[ストア] -> [アプリ パッケージの作成] を選択します。
Visual Studio を使用する際の別の問題は、デバッガーによって起動される子プロセスにアタッチするための組み込みのサポートが用意されていないことです。 このため、ターゲット アプリケーションのスタートアップ パスでロジックをデバッグすることが難しくなります。これは、起動後に Visual Studio によって手動でアタッチする必要があります。
この問題に対処するには、子プロセスのアタッチをサポートするデバッガーを使用します。 通常、Just-In-Time (JIT) デバッガーをターゲット アプリケーションにアタッチすることはできません。 これは、ほとんどの JIT 技術で、ImageFileExecutionOptions レジストリ キーを介して、ターゲット アプリの代わりのデバッガーを起動することが関係しているためです。 このため、FixupRuntime.dll をターゲット アプリに挿入するために PSFLauncher.exe によって使用される迂回メカニズムの意味がなくなります。 Windows 用デバッグ ツールに含まれていて Windows SDK から取得される WinDbg は、子プロセスのアタッチをサポートしています。 これは、直接 UWP アプリを起動してデバッグすることもサポートしています。
ターゲット アプリケーションのスタートアップを子プロセスとしてデバッグするには、WinDbg
を起動します。
windbg.exe -plmPackage PSFSampleWithFixup_1.0.59.0_x86__7s220nvg1hg3m -plmApp PSFSample
WinDbg
プロンプトで、子のデバッグを有効にし、適切なブレークポイントを設定します。
.childdbg 1
g
(ターゲット アプリケーションが起動してデバッガーに割り込むまで実行)
sxe ld fixup.dll
g
(修正プログラム DLL が読み込まれるまで実行)
bp ...
Note
PLMDebug を使用してデバッガーを起動時にアプリにアタッチすることもできます。これも、Windows 用デバッグ ツールに含まれています。 ただし、WinDbg で提供されている直接サポートよりも使用の仕方が複雑になります。
サポート
ご質問があるでしょうか。 MSIX 技術コミュニティ サイトのパッケージ サポート フレームワークに関する会話スペースでご質問いただけます。