次の方法で共有


WPF Add-Ins の概要

.NET Framework には、開発者がアドイン拡張機能をサポートするアプリケーションを作成するために使用できるアドイン モデルが含まれています。 このアドイン モデルを使用すると、アプリケーション機能と統合して拡張するアドインを作成できます。 一部のシナリオでは、アプリケーションはアドインによって提供されるユーザー インターフェイスも表示する必要があります。このトピックでは、WPF が .NET Framework アドイン モデルを拡張して、これらのシナリオ、その背後にあるアーキテクチャ、その利点、およびその制限を実現する方法について説明します。

[前提条件]

.NET Framework アドイン モデルに関する知識が必要です。 詳細については、「 アドインと機能拡張」を参照してください。

Add-Ins の概要

新しい機能を組み込むためのアプリケーションの再コンパイルと再デプロイの複雑さを回避するために、アプリケーションは、開発者 (ファースト パーティとサード パーティの両方) が、それらを統合する他のアプリケーションを作成できるようにする拡張メカニズムを実装します。 この種の拡張機能をサポートする最も一般的な方法は、アドイン ("アドオン" と "プラグイン" とも呼ばれます) を使用する方法です。 アドインで拡張性を公開する実際のアプリケーションの例を次に示します。

  • Internet Explorer アドオン。

  • Windows Media Player プラグイン。

  • Visual Studio アドイン。

たとえば、Windows Media Player アドイン モデルを使用すると、サード パーティの開発者は、Windows Media Player でネイティブにサポートされていないメディア形式 (DVD、MP3、オーディオ効果、スキンなど) のデコーダーやエンコーダーの作成など、さまざまな方法で Windows Media Player を拡張する "プラグイン" を実装できます。 各アドイン モデルは、アプリケーションに固有の機能を公開するように構築されていますが、すべてのアドイン モデルに共通するエンティティと動作がいくつかあります。

一般的なアドイン拡張ソリューションの 3 つの主要なエンティティは、 コントラクトアドインホスト アプリケーションです。 コントラクトは、アドインとホスト アプリケーションの統合方法を次の 2 つの方法で定義します。

  • アドインは、ホスト アプリケーションによって実装される機能と統合されます。

  • ホスト アプリケーションは、アドインと統合するための機能を公開します。

アドインを使用するには、ホスト アプリケーションでアドインを検索し、実行時に読み込む必要があります。 そのため、アドインをサポートするアプリケーションには、次の追加の責任があります。

  • 検出: ホスト アプリケーションでサポートされているコントラクトに準拠するアドインを検索します。

  • アクティブ化: アドインとの通信の読み込み、実行、および確立。

  • 分離: アプリケーション ドメインまたはプロセスを使用して、アドインの潜在的なセキュリティと実行の問題からアプリケーションを保護する分離境界を確立します。

  • 通信: メソッドを呼び出してデータを渡すことで、アドインとホスト アプリケーションが分離境界を越えて相互に通信できるようにします。

  • 有効期間管理: アプリケーション ドメインとプロセスの読み込みとアンロードをクリーンで予測可能な方法で行います ( 「アプリケーション ドメイン」を参照)。

  • バージョン管理: いずれかの新しいバージョンが作成されたときに、ホスト アプリケーションとアドインが引き続き通信できるようにします。

最終的には、堅牢なアドイン モデルの開発は簡単ではありません。 このため、.NET Framework にはアドイン モデルを構築するためのインフラストラクチャが用意されています。

アドインの詳細については、「アドイン と機能拡張」を参照してください。

.NET Framework Add-In モデルの概要

System.AddIn名前空間にある .NET Framework アドイン モデルには、アドインの拡張性の開発を簡略化するために設計された一連の型が含まれています。 .NET Framework アドイン モデルの基本的な単位は コントラクトであり、ホスト アプリケーションとアドインが相互に通信する方法を定義します。 コントラクトは、コントラクトのホスト アプリケーション固有の ビュー を使用してホスト アプリケーションに公開されます。 同様に、コントラクトのアドイン固有の ビュー がアドインに公開されます。 アダプターは、ホスト アプリケーションとアドインがコントラクトのそれぞれのビュー間で通信できるようにするために使用されます。 コントラクト、ビュー、およびアダプターはセグメントと呼ばれ、関連するセグメントのセットが パイプラインを構成します。 パイプラインは、.NET Framework アドイン モデルが検出、アクティブ化、セキュリティの分離、実行の分離 (アプリケーション ドメインとプロセスの両方を使用)、通信、有効期間管理、およびバージョン管理をサポートする基盤です。

このサポートの合計により、開発者はホスト アプリケーションの機能と統合するアドインを構築できます。 ただし、一部のシナリオでは、アドインによって提供されるユーザー インターフェイスを表示するためにホスト アプリケーションが必要です。.NET Framework の各プレゼンテーション テクノロジには、ユーザー インターフェイスを実装するための独自のモデルがあるため、.NET Framework アドイン モデルは特定のプレゼンテーション テクノロジをサポートしていません。 代わりに、WPF はアドインの UI サポートを使用して .NET Framework アドイン モデルを拡張します。

WPF Add-Ins

WPF と .NET Framework アドイン モデルを組み合わせることで、ホスト アプリケーションでアドインのユーザー インターフェイスを表示する必要があるさまざまなシナリオに対処できます。特に、これらのシナリオは、次の 2 つのプログラミング モデルを使用して WPF によって対処されます。

  1. アドインは UI を返します。 アドインは、コントラクトで定義されているように、メソッド呼び出しを介してホスト アプリケーションに UI を返します。 このシナリオは、次の場合に使用されます。

    • アドインによって返される UI の外観は、動的に生成されたレポートなど、実行時にのみ存在するデータまたは条件に依存します。

    • アドインによって提供されるサービスの UI は、アドインを使用できるホスト アプリケーションの UI とは異なります。

    • アドインは主にホスト アプリケーションのサービスを実行し、UI を使用してホスト アプリケーションに状態を報告します。

  2. アドインは UI です。 アドインは、コントラクトによって定義される UI です。 このシナリオは、次の場合に使用されます。

    • アドインは、広告など、表示される以外のサービスを提供しません。

    • アドインによって提供されるサービスの UI は、電卓やカラー ピッカーなど、そのアドインを使用できるすべてのホスト アプリケーションに共通です。

これらのシナリオでは、ホスト アプリケーションとアドイン アプリケーション ドメインの間で UI オブジェクトを渡すことができる必要があります。 .NET Framework アドイン モデルはリモート処理に依存してアプリケーション ドメイン間の通信を行っているため、それらの間で渡されるオブジェクトはリモート処理可能である必要があります。

リモートテーブル オブジェクトは、次の 1 つ以上を実行するクラスのインスタンスです。

リモート処理可能な .NET Framework オブジェクトの作成の詳細については、「 オブジェクトのリモート処理の作成」を参照してください。

WPF UI の種類はリモート処理できません。 この問題を解決するために、WPF は .NET Framework アドイン モデルを拡張して、アドインによって作成された WPF UI をホスト アプリケーションから表示できるようにします。 このサポートは、INativeHandleContract インターフェイスと、FrameworkElementAdapters クラスによって実装される 2 つの静的メソッド (INativeHandleContractViewToContractAdapter) の 2 種類によって WPF によって提供されます。 大まかに言えば、これらの型とメソッドは次の方法で使用されます。

  1. WPF では、アドインによって提供されるユーザー インターフェイスは、図形、コントロール、ユーザー コントロール、レイアウト パネル、ページなど、 FrameworkElementから直接または間接的に派生するクラスである必要があります。

  2. コントラクトでアドインとホスト アプリケーションの間で UI が渡されることを宣言する場合は必ず、UI を (INativeHandleContractではなく) FrameworkElementとして宣言する必要があります。INativeHandleContractは、分離境界を越えて渡すことができるアドイン UI のリモート可能な表現です。

  3. アドインのアプリケーション ドメインから渡される前に、FrameworkElementINativeHandleContractを呼び出してViewToContractAdapterとしてパッケージ化されます。

  4. ホスト アプリケーションのアプリケーション ドメインに渡された後、INativeHandleContractを呼び出して、FrameworkElementContractToViewAdapterとして再パッケージ化する必要があります。

INativeHandleContractContractToViewAdapter、およびViewToContractAdapterの使用方法は、特定のシナリオによって異なります。 以降のセクションでは、各プログラミング モデルの詳細について説明します。

Add-In ユーザー インターフェイスを返します

アドインが UI をホスト アプリケーションに返すには、次のものが必要です。

  1. ホスト アプリケーション、アドイン、およびパイプラインは、.NET Framework アドインと拡張機能 のドキュメントで説明されているように作成する必要があります。

  2. コントラクトは IContract 実装する必要があり、UI を返すには、コントラクトで INativeHandleContract型の戻り値を持つメソッドを宣言する必要があります。

  3. アドインとホスト アプリケーションの間で渡される UI は、 FrameworkElementから直接または間接的に派生する必要があります。

  4. アドインによって返される UI は、分離境界を越える前に、 FrameworkElement から INativeHandleContract に変換する必要があります。

  5. 返される UI は、分離境界を越えた後、 INativeHandleContract から FrameworkElement に変換する必要があります。

  6. ホスト アプリケーションは、返された FrameworkElementを表示します。

UI を返すアドインを実装する方法を示す例については、「UI を返す Add-In を作成する」を参照してください。

Add-In はユーザー インターフェイスです

アドインが UI の場合は、次のものが必要です。

  1. ホスト アプリケーション、アドイン、およびパイプラインは、.NET Framework アドインと拡張機能 のドキュメントで説明されているように作成する必要があります。

  2. アドインのコントラクト インターフェイスは、 INativeHandleContractを実装する必要があります。

  3. ホスト アプリケーションに渡されるアドインは、直接または間接的に FrameworkElementから派生する必要があります。

  4. 分離境界を越える前に、アドインを FrameworkElement から INativeHandleContract に変換する必要があります。

  5. アドインは、分離境界を越えた後、 INativeHandleContract から FrameworkElement に変換する必要があります。

  6. ホスト アプリケーションは、返された FrameworkElementを表示します。

UI であるアドインを実装する方法を示す例については、「UI である Add-In を作成する」を参照してください。

Add-In から複数の UI を返す

アドインは、多くの場合、ホスト アプリケーションに表示する複数のユーザー インターフェイスを提供します。 たとえば、ホスト アプリケーションにも UI として状態情報を提供する UI であるアドインを考えてみます。 このようなアドインは、 ユーザー インターフェイスを返すAdd-In とユーザー インターフェイス モデルである Add-In の両方の手法の組み合わせを使用して実装できます。

Add-Ins と XAML ブラウザー アプリケーション

これまでの例では、ホスト アプリケーションはインストール済みのスタンドアロン アプリケーションでした。 ただし、XAML ブラウザー アプリケーション (XBAP) では、次の追加のビルドと実装の要件があるにもかかわらず、アドインをホストすることもできます。

  • XBAP アプリケーション マニフェストは、パイプライン (フォルダーとアセンブリ) とアドイン アセンブリを、XBAP と同じフォルダー内のクライアント コンピューター上の ClickOnce アプリケーション キャッシュにダウンロードするように特別に構成する必要があります。

  • アドインを検出して読み込む XBAP コードでは、XBAP の ClickOnce アプリケーション キャッシュをパイプラインおよびアドインの場所として使用する必要があります。

  • XBAP は、アドインが配信元サイトにあるルーズ ファイルを参照する場合、アドインを特別なセキュリティ コンテキストに読み込む必要があります。XBAP によってホストされている場合、アドインはホスト アプリケーションの配信元サイトにあるルース ファイルのみを参照できます。

これらのタスクについては、次のサブセクションで詳しく説明します。

ClickOnce デプロイメントのためのパイプライン構成と Add-In の設定

XBAP は、ClickOnce 配置キャッシュ内の安全なフォルダーにダウンロードされ、実行されます。 XBAP でアドインをホストするには、パイプラインとアドイン アセンブリも安全なフォルダーにダウンロードする必要があります。 これを実現するには、ダウンロード用のパイプライン アセンブリとアドイン アセンブリの両方を含むようにアプリケーション マニフェストを構成する必要があります。 これは Visual Studio で最も簡単に行えますが、Visual Studio がパイプライン アセンブリを検出するには、パイプラインとアドイン アセンブリがホスト XBAP プロジェクトのルート フォルダーにある必要があります。

そのため、最初の手順では、各パイプライン アセンブリとアドイン アセンブリ プロジェクトのビルド出力を設定して、パイプラインとアドイン アセンブリを XBAP プロジェクトのルートにビルドします。 次の表に、ホスト XBAP プロジェクトと同じソリューションとルート フォルダーにあるパイプライン アセンブリ プロジェクトとアドイン アセンブリ プロジェクトのビルド出力パスを示します。

表 1: XBAP によってホストされるパイプライン アセンブリの出力パスをビルドする

パイプライン アセンブリ プロジェクト ビルド出力パス
コントラクト ..\HostXBAP\Contracts\
Add-In 表示 ..\HostXBAP\AddInViews\
追加-In-Sideアダプター ..\HostXBAP\AddInSideAdapters\
Host-Side アダプター ..\HostXBAP\HostSideAdapters\
Add-In ..\HostXBAP\AddIns\WPFAddIn1

次の手順では、次の手順を実行して、パイプライン アセンブリとアドイン アセンブリを Visual Studio の XBAPs コンテンツ ファイルとして指定します。

  1. ソリューション エクスプローラーで各パイプライン フォルダーを右クリックし、[プロジェクトに含める] を選択して、パイプラインとアドイン アセンブリを プロジェクトに含めます

  2. 各パイプライン アセンブリとアドイン アセンブリのビルド アクション[プロパティ] ウィンドウから [コンテンツ] に設定します。

最後の手順では、ダウンロード用のパイプライン アセンブリ ファイルとアドイン アセンブリ ファイルを含むようにアプリケーション マニフェストを構成します。 ファイルは、XBAP アプリケーションが占有する ClickOnce キャッシュ内のフォルダーのルートにあるフォルダーに配置する必要があります。 この構成は、次の手順を実行して Visual Studio で実現できます。

  1. XBAP プロジェクトを右クリックし、[ プロパティ] をクリックし、[ 発行] をクリックして、[ アプリケーション ファイル ] ボタンをクリックします。

  2. [ アプリケーション ファイル ] ダイアログで、各パイプラインとアドイン DLL の 発行状態[含める] (自動) に設定し、各パイプラインとアドイン DLL の ダウンロード グループ(必須) に設定します。

アプリケーション ベースからのパイプラインと Add-In の使用

パイプラインとアドインが ClickOnce 配置用に構成されると、XBAP と同じ ClickOnce キャッシュ フォルダーにダウンロードされます。 XBAP からパイプラインとアドインを使用するには、XBAP コードがアプリケーション ベースからそれらを取得する必要があります。 パイプラインとアドインを使用するための .NET Framework アドイン モデルのさまざまな型とメンバーは、このシナリオに対して特別なサポートを提供します。 まず、パスは ApplicationBase 列挙値によって識別されます。 この値は、次のようなパイプラインを利用するために、関連するアドインメンバーのオーバーロードを組み合わせて使用します。

ホストの起点サイトへのアクセス

アドインが元のサイトのファイルを参照できるようにするには、ホスト アプリケーションと同等のセキュリティ分離を使用してアドインを読み込む必要があります。 このセキュリティ レベルは、 AddInSecurityLevel.Host 列挙値によって識別され、アドインがアクティブになったときに Activate メソッドに渡されます。

WPF Add-In アーキテクチャ

最も高いレベルでは、WPF を使用すると、.NET Framework アドインは、FrameworkElementINativeHandleContract、およびViewToContractAdapterを使用して (ContractToViewAdapterから直接または間接的に派生する) ユーザー インターフェイスを実装できます。 その結果、ホスト アプリケーションから、ホスト アプリケーションの UI から表示される FrameworkElement が返されます。

単純な UI アドイン のシナリオでは、これは開発者のニーズと同じくらい詳細です。 より複雑なシナリオ 、特にレイアウト、リソース、データ バインディングなどの追加の WPF サービスを利用しようとするシナリオでは、その利点と制限事項を理解するために、WPF が UI をサポートして .NET Framework アドイン モデルを拡張する方法に関するより詳細な知識が必要です。

基本的に、WPF はアドインからホスト アプリケーションに UI を渡しません。代わりに、WPF は WPF 相互運用性を使用して UI の Win32 ウィンドウ ハンドルを渡します。 そのため、アドインの UI がホスト アプリケーションに渡されると、次の処理が行われます。

  • アドイン側では、WPF はホスト アプリケーションによって表示される UI のウィンドウ ハンドルを取得します。 ウィンドウ ハンドルは、 HwndSource から派生し、 INativeHandleContractを実装する内部 WPF クラスによってカプセル化されます。 このクラスのインスタンスは ViewToContractAdapter によって返され、アドインのアプリケーション ドメインからホスト アプリケーションのアプリケーション ドメインにマーシャリングされます。

  • ホスト アプリケーション側では、WPF はHwndSourceから派生し、HwndHostを使用する内部 WPF クラスとしてINativeHandleContractを再パッケージ化します。 このクラスのインスタンスは、ホスト アプリケーションに ContractToViewAdapter によって返されます。

HwndHost は、WPF ユーザー インターフェイスからウィンドウ ハンドルによって識別されるユーザー インターフェイスを表示するために存在します。 詳細については、「 WPF と Win32 相互運用」を参照してください。

要約すると、 INativeHandleContractViewToContractAdapter、および ContractToViewAdapter 存在して、WPF UI のウィンドウ ハンドルをアドインからホスト アプリケーションに渡すことができます。このウィンドウ ハンドルは、 HwndHost によってカプセル化され、ホスト アプリケーションの UI が表示されます。

ホスト アプリケーションは HwndHostを取得するため、ホスト アプリケーションは、 ContractToViewAdapter によって返されるオブジェクトをアドインによって実装された型 (たとえば、 UserControl) に変換できません。

その性質上、 HwndHost には、ホスト アプリケーションでの使用方法に影響する特定の制限があります。 ただし、WPF は HwndHost をアドイン シナリオ用のいくつかの機能で拡張します。 これらの利点と制限事項を以下に示します。

WPF Add-In の利点

WPF アドインのユーザー インターフェイスは、 HwndHostから派生した内部クラスを使用してホスト アプリケーションから表示されるため、これらのユーザー インターフェイスは、レイアウト、レンダリング、データ バインディング、スタイル、テンプレート、リソースなどの WPF UI サービスに関する HwndHost の機能によって制約されます。 ただし、WPF は内部 HwndHost サブクラスを拡張し、次のような追加機能を備えます。

  • ホスト アプリケーションの UI とアドインの UI の間のタブ移動。 "アドインは UI です" プログラミング モデルでは、アドインが完全に信頼されているか部分的に信頼されているかに関係なく、 QueryContract をオーバーライドしてタブ処理を有効にするアドイン側アダプターが必要であることに注意してください。

  • ホスト アプリケーション のユーザー インターフェイスから表示されるアドイン ユーザー インターフェイスのアクセシビリティ要件を遵守します。

  • 複数のアプリケーション ドメイン シナリオで WPF アプリケーションを安全に実行できるようにする。

  • アドインがセキュリティ分離 (部分信頼セキュリティ サンドボックス) で実行されるときに、アドイン UI ウィンドウ ハンドルへの不正アクセスを防止します。 ViewToContractAdapterを呼び出すと、次のセキュリティが確保されます。

    • "アドインは UI を返します" プログラミング モデルの場合、分離境界を越えてアドイン UI のウィンドウ ハンドルを渡す唯一の方法は、 ViewToContractAdapterを呼び出すことです。

    • "アドインが UI プログラミングモデルである場合、アドイン側アダプターの QueryContract をオーバーライドし、ホスト側アダプターからの呼び出しと同様に (前の例に示すように) ViewToContractAdapter を呼び出す必要があるほか、アドイン側アダプターの QueryContract 実装をホスト側アダプターから呼び出す必要があります。"

  • 複数のアプリケーション ドメイン実行保護を提供します。 アプリケーション ドメインの制限により、アドイン アプリケーション ドメインでスローされたハンドルされない例外が、分離境界が存在していてもアプリケーション全体をクラッシュさせます。 ただし、WPF と .NET Framework アドイン モデルは、この問題を回避し、アプリケーションの安定性を向上させる簡単な方法を提供します。 UI を表示する WPF アドインは、ホスト アプリケーションが WPF アプリケーションの場合、アプリケーション ドメインが実行されているスレッドの Dispatcher を作成します。 WPF アドインのUnhandledExceptionDispatcher イベントを処理することで、アプリケーション ドメインで発生するすべてのハンドルされない例外を検出できます。 Dispatcher プロパティからCurrentDispatcherを取得できます。

WPF Add-In の制限事項

WPF が HwndSourceHwndHost、ウィンドウ ハンドルによって提供される既定の動作に追加する利点以外に、ホスト アプリケーションから表示されるアドイン ユーザー インターフェイスにも制限があります。

  • ホスト アプリケーションから表示されるアドイン ユーザー インターフェイスは、ホスト アプリケーションのクリッピング動作を考慮しません。

  • 相互運用性シナリオでの 空域 の概念は、アドインにも適用されます ( 「テクノロジリージョンの概要」を参照)。

  • ホスト アプリケーションの UI サービス (リソースの継承、データ バインディング、コマンド実行など) は、アドイン ユーザー インターフェイスでは自動的には使用できません。 これらのサービスをアドインに提供するには、パイプラインを更新する必要があります。

  • アドイン UI を回転、スケーリング、傾斜、またはその他の変換の影響を受けることはできません (「 変換の概要」を参照)。

  • System.Drawing名前空間からの描画操作によってレンダリングされるアドイン ユーザー インターフェイス内のコンテンツには、アルファ ブレンドを含めることができます。 ただし、アドイン UI とそれを含むホスト アプリケーション UI の両方は、100% 不透明である必要があります。つまり、両方の Opacity プロパティを 1 に設定する必要があります。

  • アドイン UI を含むホスト アプリケーションのウィンドウの AllowsTransparency プロパティが true に設定されている場合、アドインは非表示になります。 これは、アドイン UI が 100% 不透明な場合でも当てはまります (つまり、 Opacity プロパティの値は 1 です)。

  • アドイン UI は、同じ最上位ウィンドウ内の他の WPF 要素の上に表示される必要があります。

  • VisualBrushを使用してアドインの UI の一部をレンダリングすることはできません。 代わりに、アドインは生成された UI のスナップショットを取得して、コントラクトで定義されたメソッドを使用してホスト アプリケーションに渡すことができるビットマップを作成できます。

  • アドイン UI の MediaElement からメディア ファイルを再生することはできません。

  • アドイン UI 用に生成されたマウス イベントは、ホスト アプリケーションによって受信も発生もされません。また、ホスト アプリケーション UI の IsMouseOver プロパティの値は false です。

  • アドイン UI のコントロール間でフォーカスが移動すると、 GotFocus イベントと LostFocus イベントはホスト アプリケーションによって受信も発生もされません。

  • アドイン UI を含むホスト アプリケーションの部分は、印刷時に白く表示されます。

  • ホスト アプリケーションが実行を続行する場合、所有者アドインがアンロードされる前に、アドイン UI によって作成されたすべてのディスパッチャー ( Dispatcherを参照) を手動でシャットダウンする必要があります。 コントラクトは、アドインがアンロードされる前にホスト アプリケーションがアドインを通知できるようにするメソッドを実装できるため、アドイン UI でディスパッチャーをシャットダウンできます。

  • アドイン UI が InkCanvas であるか、 InkCanvasが含まれている場合、アドインをアンロードすることはできません。

パフォーマンスの最適化

既定では、複数のアプリケーション ドメインを使用すると、各アプリケーションに必要なさまざまな .NET Framework アセンブリがすべてそのアプリケーションのドメインに読み込まれます。 その結果、新しいアプリケーション ドメインを作成し、その中でアプリケーションを起動するために必要な時間がパフォーマンスに影響する可能性があります。 ただし、.NET Framework には、アセンブリが既に読み込まれている場合にアプリケーション ドメイン間でアセンブリを共有するようにアプリケーションに指示することで、開始時刻を短縮する方法が用意されています。 これを行うには、エントリ ポイント メソッド (LoaderOptimizationAttribute) に適用する必要があるMain属性を使用します。 この場合は、コードのみを使用してアプリケーション定義を実装する必要があります (「 アプリケーション管理の概要」を参照)。

こちらも参照ください