次の方法で共有


チュートリアル : 拡張性のあるアプリケーションの作成

更新 : 2008 年 7 月

このチュートリアルでは、簡単な電卓機能を実行するアドインのパイプラインを作成する方法を説明します。これは実用的なアプリケーションを作成するシナリオではありません。パイプラインの基本機能を示し、アドインによってホスト向けのサービスを実現する方法を示すものです。

このチュートリアルでは、次のタスクについて説明します。

  • Visual Studio ソリューションの作成

  • ディレクトリ構造の作成

  • コントラクトとビューの生成

  • アドイン側アダプタの作成

  • ホスト側アダプタの作成

  • ホストの作成

  • アドインの作成

  • パイプラインの配置

  • ホスト アプリケーションの実行

このパイプラインでは、シリアル化できる型 (Double および String) のみをホストとアドイン間で受け渡します。複合データ型のコレクションを渡す方法を示す例については、「チュートリアル : アドインとホスト間でのコレクションの受け渡し」を参照してください。

このパイプラインのコントラクトによって、4 種類の算術演算 (加算、減算、乗算、除算) に対応するオブジェクト モデルが定義されます。ホストからアドインに計算の式 (2 + 2 など) が渡され、アドインからホストに結果が返されます。

Version 2 の計算機アドインでは計算機能がより高度になり、バージョン管理機能が備えられています。これについては、「チュートリアル : ホスト変更時の下位互換性の確保」で解説されています。

メモ :

CodePlex の「Managed Extensibility and Add-In Framework」サイトには、その他のサンプル コードや、アドイン パイプラインのビルドに使用するツールのカスタマ テクノロジ プレビューが掲載されています。

前提条件

このチュートリアルを完了するための要件は次のとおりです。

  • Visual Studio.

Visual Studio ソリューションの作成

Visual Studio のソリューションを使用して、パイプライン セグメントのプロジェクトを格納します。

パイプライン ソリューションを作成するには

  1. Visual Studio で、Calc1Contract という名前の新規プロジェクトを作成します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューションに CalculatorV1 という名前を付けます。

パイプライン ディレクトリ構造の作成

アドイン モデルでは、指定したディレクトリ構造内にパイプライン セグメント アセンブリが配置される必要があります。パイプライン構造の詳細については、「パイプライン開発の必要条件」を参照してください。

パイプライン ディレクトリ構造を作成するには

  1. コンピュータ上の任意の位置にアプリケーション フォルダを作成します。

  2. そのフォルダ内に、次の構造を作成します。

    Pipeline
      AddIns
        CalcV1
        CalcV2
      AddInSideAdapters
      AddInViews
      Contracts
      HostSideAdapters
    

    アプリケーション フォルダ内にパイプライン フォルダ構造を配置する必要はありません。ここでは、便宜上、そのようにしているだけです。パイプライン フォルダ構造が別の場所にある場合は、チュートリアルの該当の手順で、コードを変更する方法について説明します。パイプライン ディレクトリの必要条件の詳細については、「パイプライン開発の必要条件」を参照してください。

    メモ :

    このチュートリアルでは、CalcV2 フォルダは使用しません。これは、「チュートリアル : ホスト変更時の下位互換性の確保」のプレースホルダです。

コントラクトとビューの生成

このパイプラインのコントラクト セグメントで ICalc1Contract インターフェイスを定義します。これにより、add、subtract、multiply、および divide という 4 つのメソッドを定義します。

コントラクトを作成するには

  1. CalculatorV1 という名前の Visual Studio ソリューションで、Calc1Contract プロジェクトを開きます。

  2. ソリューション エクスプローラで、次のアセンブリへの参照を Calc1Contract プロジェクトに追加します。

    System.AddIn.Contract.dll

    System.AddIn.dll

  3. ソリューション エクスプローラで、新しいクラス ライブラリ プロジェクトに追加された既定のクラスを除外します。

  4. ソリューション エクスプローラで、インターフェイス テンプレートを使用して、新しい項目をプロジェクトに追加します。[新しい項目の追加] ダイアログ ボックスで、インターフェイスに ICalc1Contract という名前を付けます。

  5. インターフェイス ファイルに、System.AddIn.Contract および System.AddIn.Pipeline への名前空間参照を追加します。

  6. このコントラクト セグメントを完了するには、次のコードを使用します。このインターフェイスには、AddInContractAttribute 属性が必要であることに注意してください。

    Imports System.AddIn.Contract
    Imports System.AddIn.Pipeline
    
    Namespace CalculatorContracts
    
        ' The AddInContractAttribute identifes this pipeline segment as a
        ' contract.
        <AddInContract()> _
        Public Interface ICalc1Contract
            Inherits IContract
    
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    using System.AddIn.Contract;
    using System.AddIn.Pipeline;
    
    namespace CalculatorContracts
    {
        // The AddInContractAttribute identifes this pipeline segment as a 
        // contract.
        [AddInContract]
        public interface ICalc1Contract : IContract
        {
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Multiply(double a, double b);
        double Divide(double a, double b);
        }
    }
    
  7. 必要に応じて、Visual Studio ソリューションをビルドします。最後の手順になるまでソリューションを実行することはできませんが、各手順のたびにソリューションをビルドすることによって、各プロジェクトが正しいことを確認できます。

アドイン ビューと、アドインのホスト ビューは、アドインの最初のバージョンの場合は特に、通常はコードが同じであるため、ビューを同時に簡単に作成できます。この 2 つのビューの相違点は、アドイン ビューには AddInBaseAttribute 属性が必要ですが、アドインのホスト ビューには属性が必要ないということのみです。

アドイン ビューを作成するには

  1. CalculatorV1 ソリューションに Calc1AddInView という名前の新規プロジェクトを追加します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューション エクスプローラで、Calc1AddInView プロジェクトに System.AddIn.dll への参照を追加します。

  3. ソリューション エクスプローラで、新しいクラス ライブラリ プロジェクトに追加された既定のクラスを除外し、インターフェイス テンプレートを使用して新しい項目をプロジェクトに追加します。[新しい項目の追加] ダイアログ ボックスで、インターフェイスに ICalculator という名前を付けます。

  4. インターフェイス ファイルに、System.AddIn.Pipeline への名前空間参照を追加します。

  5. このアドイン ビューを完了するには、次のコードを使用します。このインターフェイスには、AddInBaseAttribute 属性が必要であることに注意してください。

    Imports System.AddIn.Pipeline
    
    Namespace CalcAddInViews
    
        ' The AddInBaseAttribute identifes this interface as the basis for the
        ' add-in view pipeline segment.
        <AddInBaseAttribute()> _
        Public Interface ICalculator
    
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    using System.AddIn.Pipeline;
    
    namespace CalcAddInViews 
    {
        // The AddInBaseAttribute identifes this interface as the basis for
        // the add-in view pipeline segment.
        [AddInBase()]
        public interface ICalculator 
        {
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Multiply(double a, double b);
        double Divide(double a, double b);
        }
    }
    
  6. 必要に応じて、Visual Studio ソリューションをビルドします。

アドインのホスト ビューを作成するには

  1. CalculatorV1 ソリューションに Calc1HVA という名前の新規プロジェクトを追加します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューション エクスプローラで、新しいクラス ライブラリ プロジェクトに追加された既定のクラスを除外し、インターフェイス テンプレートを使用して新しい項目をプロジェクトに追加します。[新しい項目の追加] ダイアログ ボックスで、インターフェイスに ICalculator という名前を付けます。

  3. インターフェイス ファイルで、次のコードを使用して、アドインのホスト ビューを完了します。

    Namespace CalcHVAs
    
        Public Interface ICalculator
            Function Add(ByVal a As Double, ByVal b As Double) As Double
            Function Subtract(ByVal a As Double, ByVal b As Double) As Double
            Function Multiply(ByVal a As Double, ByVal b As Double) As Double
            Function Divide(ByVal a As Double, ByVal b As Double) As Double
        End Interface
    
    End Namespace
    
    namespace CalcHVAs 
    {
        public interface ICalculator 
        {
            double Add(double a, double b);
            double Subtract(double a, double b);
            double Multiply(double a, double b);
            double Divide(double a, double b);
        }
    }
    
  4. 必要に応じて、Visual Studio ソリューションをビルドします。

アドイン側アダプタの作成

このアドイン側アダプタは、ビューからコントラクトへの 1 つのアダプタで構成されます。このパイプライン セグメントにより、アドイン ビューからコントラクトに型が変換されます。

このパイプラインでは、アドインによりホストにサービスが提供され、アドインからホストに型が渡されます。ホストからアドインには型が渡されないため、このパイプラインのアドイン側では、コントラクトからビューへのアダプタは不要です。

アドイン側アダプタを作成するには

  1. CalculatorV1 ソリューションに Calc1AddInSideAdapter という名前の新規プロジェクトを追加します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューション エクスプローラで、次のアセンブリへの参照を Calc1AddInSideAdapter プロジェクトに追加します。

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 隣接するパイプライン セグメントのプロジェクトへのプロジェクト参照を追加します。

    Calc1AddInView

    Calc1Contract

  4. 各プロジェクト参照を選択し、[プロパティ] で、[ローカルにコピーする] を [False] に設定します。Visual Basic で、[プロジェクトのプロパティ] の [参照] タブを使用して、2 つのプロジェクト参照に対応する [ローカルにコピーする] を [False] に設定します。

  5. プロジェクトの既定のクラス名を CalculatorViewToContractAddInSideAdapter に変更します。

  6. クラス ファイルに、System.AddIn.Pipeline への名前空間参照を追加します。

  7. クラス ファイルに、CalcAddInViews および CalculatorContracts という隣接セグメントに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、これらの名前空間参照は Calc1AddInView.CalcAddInViews および Calc1Contract.CalculatorContracts です)。

  8. AddInAdapterAttribute 属性を CalculatorViewToContractAddInSideAdapter クラスに適用して、クラスをアドイン側アダプタとして指定します。

  9. CalculatorViewToContractAddInSideAdapter クラスが ContractBase を継承するようにします。これによって、IContract インターフェイスの既定の実装が提供され、ICalc1Contract というパイプラインのコントラクト インターフェイスが実装されます。

  10. ICalculator を受け取り、これをプライベート フィールドにキャッシュし、基本クラスのコンストラクタを呼び出すパブリック コンストラクタを追加します。

  11. ICalc1Contract のメンバを実装するには、コンストラクタに渡される ICalculator インスタンスの対応するメンバを呼び出し、結果を返します。これによって、ビュー (ICalculator) がコントラクト (ICalc1Contract) に適応します。

    完成したアドイン側アダプタを次のコードに示します。

    Imports System.AddIn.Pipeline
    Imports Calc1AddInView.CalcAddInViews
    Imports Calc1Contract.CalculatorContracts
    
    Namespace CalcAddInSideAdapters
    
        ' The AddInAdapterAttribute identifes this class as the add-in-side 
        ' adapter pipeline segment.
        <AddInAdapter()> _
        Public Class CalculatorViewToContractAddInSideAdapter
            Inherits ContractBase
            Implements ICalc1Contract
    
            Private _view As ICalculator
    
            Public Sub New(ByVal view As ICalculator)
                MyBase.New()
                _view = view
            End Sub
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Add
                Return _view.Add(a, b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Subtract
                Return _view.Subtract(a, b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Multiply
                Return _view.Multiply(a, b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double Implements ICalc1Contract.Divide
                Return _view.Divide(a, b)
            End Function
    
        End Class
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcAddInViews;
    using CalculatorContracts;
    
    namespace CalcAddInSideAdapters 
    {
        // The AddInAdapterAttribute identifes this class as the add-in-side adapter
        // pipeline segment.
        [AddInAdapter()]
        public class CalculatorViewToContractAddInSideAdapter :
            ContractBase, ICalc1Contract 
        {
            private ICalculator _view;
    
            public CalculatorViewToContractAddInSideAdapter(ICalculator view) 
            {
                _view = view;
            }
    
            public virtual double Add(double a, double b) 
            {
                return _view.Add(a, b);
            }
    
            public virtual double Subtract(double a, double b) 
            {
                return _view.Subtract(a, b);
            }
    
            public virtual double Multiply(double a, double b) 
            {
                return _view.Multiply(a, b);
            }
    
            public virtual double Divide(double a, double b) 
            {
                return _view.Divide(a, b);
            }
        }
    }
    
  12. 必要に応じて、Visual Studio ソリューションをビルドします。

ホスト側アダプタの作成

このホスト側アダプタは、コントラクトからビューへの 1 つのアダプタで構成されます。このセグメントにより、コントラクタがアドインのホスト ビューに適応します。

このパイプラインでは、アドインによりホストにサービスが提供され、アドインからホストに型が渡されます。ホストからアドインには型が渡されないため、ビューからコントラクトへのアダプタは不要です。

有効期間の管理を実装するために、ContractHandle オブジェクトを使用してコントラクトに有効期間トークンをアタッチします。有効期間の管理を機能させるためには、このハンドルへの参照を保持する必要があります。トークンを適用した後のプログラミングは不要です。アドイン システムでは使用されなくなったオブジェクトを破棄し、ガベージ コレクションに含められるように設定できるためです。詳細については、「有効期間管理」を参照してください。

ホスト側アダプタを作成するには

  1. CalculatorV1 ソリューションに Calc1HostSideAdapter という名前の新規プロジェクトを追加します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューション エクスプローラで、次のアセンブリへの参照を Calc1HostSideAdapter プロジェクトに追加します。

    System.AddIn.dll

    System.AddIn.Contract.dll

  3. 隣接するセグメントのプロジェクトへのプロジェクト参照を追加します。

    Calc1Contract

    Calc1HVA

  4. 各プロジェクト参照を選択し、[プロパティ] で、[ローカルにコピーする] を [False] に設定します。Visual Basic で、[プロジェクトのプロパティ] の [参照] タブを使用して、2 つのプロジェクト参照に対応する [ローカルにコピーする] を [False] に設定します。

  5. プロジェクトの既定のクラス名を CalculatorContractToViewHostSideAdapter に変更します。

  6. クラス ファイルに、System.AddIn.Pipeline への名前空間参照を追加します。

  7. クラス ファイルに、CalcHVAs および CalculatorContracts という隣接セグメントに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、これらの名前空間参照は Calc1HVA.CalcHVAs および Calc1Contract.CalculatorContracts です)。

  8. HostAdapterAttribute 属性を CalculatorContractToViewHostSideAdapter クラスに適用して、クラスをホスト側アダプタ セグメントとして指定します。

  9. CalculatorContractToViewHostSideAdapter クラスが、Calc1HVAs.ICalculator (Visual Basic では Calc1HVA.CalcHVAs.ICalculator) というアドインのホスト ビューを表すインターフェイスを実装するようにします。

  10. ICalc1Contract というパイプライン コントラクト タイプを受け取るパブリック コンストラクタを追加します。このコンストラクタは、コントラクトへの参照をキャッシュする必要があります。コントラクタの新しい ContractHandle を作成およびキャッシュして、アドインの有効期間を管理する必要もあります。

    重要 :

    有効期間の管理には、ContractHandle が重要です。ContractHandle オブジェクトへの参照を保持していないと、ガベージ コレクションによってオブジェクトが再利用され、プログラムで予期していないタイミングでパイプラインがシャットダウンすることになります。これは、AppDomainUnloadedException のような診断が困難なエラーの原因となる可能性があります。シャットダウンはパイプラインの正常な段階の 1 つであるため、有効期間を管理するコードでこの状態をエラーとして検出する方法はありません。

  11. ICalculator のメンバを実装するには、コンストラクタに渡される ICalc1Contract インスタンスの対応するメンバを呼び出し、結果を返します。これによって、コントラクト (ICalc1Contract) がビュー (ICalculator) に適応します。

    完成したホスト側アダプタを次のコードに示します。

    Imports System.AddIn.Pipeline
    Imports Calc1Contract.CalculatorContracts
    Imports Calc1HVA.CalcHVAs
    
    Namespace CalcHostSideAdapters
    
        ' The HostAdapterAttribute identifes this class as the host-side adapter
        ' pipeline segment.
        <HostAdapterAttribute()> _
        Public Class CalculatorContractToViewHostSideAdapter
            Implements ICalculator
    
            Private _contract As ICalc1Contract
            Private _handle As System.AddIn.Pipeline.ContractHandle
    
            Public Sub New(ByVal contract As ICalc1Contract)
                    MyBase.New()
                _contract = contract
                _handle = New ContractHandle(contract)
            End Sub
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Add
                Return _contract.Add(a, b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Subtract
                Return _contract.Subtract(a, b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Multiply
                Return _contract.Multiply(a, b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Divide
                Return _contract.Divide(a, b)
            End Function
    
        End Class
    
    End Namespace
    
    using System.AddIn.Pipeline;
    using CalcHVAs;
    using CalculatorContracts;
    
    namespace CalcHostSideAdapters 
    {
        // The HostAdapterAttribute identifes this class as the host-side adapter
        // pipeline segment.
        [HostAdapterAttribute()]
        public class CalculatorContractToViewHostSideAdapter : ICalculator 
        {
            private ICalc1Contract _contract;
            private System.AddIn.Pipeline.ContractHandle _handle;
    
            public CalculatorContractToViewHostSideAdapter(ICalc1Contract contract) 
            {
                _contract = contract;
                _handle = new ContractHandle(contract);
            }
    
            public double Add(double a, double b) 
            {
                return _contract.Add(a, b);
            }
    
            public double Subtract(double a, double b) 
            {
                return _contract.Subtract(a, b);
            }
    
            public double Multiply(double a, double b) 
            {
                return _contract.Multiply(a, b);
            }
    
            public double Divide(double a, double b) 
            {
                return _contract.Divide(a, b);
            }
        }
    }
    
  12. 必要に応じて、Visual Studio ソリューションをビルドします。

ホストの作成

ホスト アプリケーションは、アドインのホスト ビューを利用してアドインと対話します。AddInStore クラスと AddInToken クラスを利用したアドイン探索とアクティベーション メソッドを使って、次の処理を実行します。

  • パイプライン情報とアドイン情報のキャッシュを更新する。

  • 指定されたパイプライン ルート ディレクトリで、ICalculator というホスト ビュー タイプのアドインを検索する。

  • 使用するアドインを指定するように促すメッセージを表示する。

  • セキュリティ信頼レベルが指定された新しいアプリケーション ドメインで、選択されたアドインをアクティブにする。

  • RunCalculator カスタム メソッドを実行する。これにより、アドインのホスト ビューの指定に従ってアドインのメソッドが呼び出されます。

ホストを作成するには

  1. CalculatorV1 ソリューションに Calc1Host という名前の新規プロジェクトを追加します。これにコンソール アプリケーション テンプレートを適用します。

  2. ソリューション エクスプローラで、Calc1Host プロジェクトに System.AddIn.dll アセンブリへの参照を追加します。

  3. Calc1HVA プロジェクトへのプロジェクト参照を追加します。プロジェクト参照を選択し、[プロパティ] で、[ローカルにコピーする] を [False] に設定します。Visual Basic で、[プロジェクトのプロパティ] の [参照] タブを使用して、[ローカルにコピーする] を [False] に設定します。

  4. クラス ファイル (Visual Basic ではモジュール) の名前を MathHost1 に変更します。

  5. Visual Basic で、[プロジェクトのプロパティ] ダイアログ ボックスの [アプリケーション] タブを使用して、[スタートアップ オブジェクト] を [Sub Main] に設定します。

  6. クラス ファイルまたはモジュール ファイルに、System.AddIn.Hosting への名前空間参照を追加します。

  7. クラス ファイルまたはモジュール ファイルに、CalcHVAs というアドインのホスト ビューに対応する名前空間参照を追加します (Visual Basic では、Visual Basic プロジェクトで既定の名前空間をオフにしていない限り、この名前空間参照は Calc1HVA.CalcHVAs です)。

  8. ソリューション エクスプローラでソリューションを選択し、[プロジェクト] メニューの [プロパティ] を選択します。ソリューションの [プロパティ ページ] ダイアログ ボックスで、[シングル スタートアップ プロジェクト] をこのホスト アプリケーション プロジェクトに設定します。

  9. クラス ファイルまたはモジュール ファイルで、AddInStore.Update メソッドを使用してキャッシュを更新します。AddInStore.FindAddIn メソッドを使用してトークンのコレクションを取得し、AddInToken.Activate メソッドを使用してアドインをアクティブ化します。

    完成したホスト アプリケーションを次のコードに示します。

    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.AddIn.Hosting
    Imports Calc1HVA.CalcHVAs
    
    Namespace MathHost
    
        Module MathHost1
    
            Sub Main()
                ' Assume that the current directory is the application folder, 
                ' and that it contains the pipeline folder structure.
                Dim addInRoot As String = Environment.CurrentDirectory & "\Pipeline"
    
                ' Update the cache files of the pipeline segments and add-ins.
                Dim warnings() As String = AddInStore.Update(addInRoot)
                For Each warning As String In warnings
                    Console.WriteLine(warning)
                Next
    
                ' Search for add-ins of type ICalculator (the host view of the add-in).
                Dim tokens As System.Collections.ObjectModel.Collection(Of AddInToken) = _
                    AddInStore.FindAddIns(GetType(ICalculator), addinRoot)
    
                ' Ask the user which add-in they would like to use.
                Dim calcToken As AddInToken = ChooseCalculator(tokens)
    
                ' Activate the selected AddInToken in a new application domain 
                ' with the Internet trust level.
                Dim calc As ICalculator = _
                    calcToken.Activate(Of ICalculator)(AddInSecurityLevel.Internet)
    
                ' Run the add-in.
                RunCalculator(calc)
            End Sub
    
            Private Function ChooseCalculator(ByVal tokens As Collection(Of AddInToken)) _
                    As AddInToken
    
                If (tokens.Count = 0) Then
                    Console.WriteLine("No calculators are available")
                    Return Nothing
                End If
    
                Console.WriteLine("Available Calculators: ")
                ' Show the token properties for each token in the AddInToken collection
                ' (tokens), preceded by the add-in number in [] brackets.
                Dim tokNumber As Integer = 1
                For Each tok As AddInToken In tokens
                    Console.WriteLine(vbTab & "[{0}]: {1} - {2}" & _
                            vbLf & vbTab & "{3}" & _
                            vbLf & vbTab & "{4}" & _
                            vbLf & vbTab & "{5} - {6}", _
                            tokNumber.ToString, tok.Name, _
                            tok.AddInFullName, tok.AssemblyName, _
                            tok.Description, tok.Version, tok.Publisher)
                    tokNumber = tokNumber + 1
                Next
                Console.WriteLine("Which calculator do you want to use?")
                Dim line As String = Console.ReadLine
                Dim selection As Integer
                If Int32.TryParse(line, selection) Then
                    If (selection <= tokens.Count) Then
                        Return tokens((selection - 1))
                    End If
                End If
                Console.WriteLine("Invalid selection: {0}. Please choose again.", line)
                Return ChooseCalculator(tokens)
            End Function
    
            Private Sub RunCalculator(ByVal calc As ICalculator)
                If IsNothing(calc) Then
                    'No calculators were found, read a line and exit.
                    Console.ReadLine()
                End If
                Console.WriteLine("Available operations: +, -, *, /")
                Console.WriteLine("Request a calculation , such as: 2 + 2")
                Console.WriteLine("Type 'exit' to exit")
                Dim line As String = Console.ReadLine
    
                While Not line.Equals("exit")
                    ' The Parser class parses the user's input.
                    Try
                        Dim c As Parser = New Parser(line)
                        Select Case (c.action)
                            Case "+"
                                Console.WriteLine(calc.Add(c.a, c.b))
                            Case "-"
                                Console.WriteLine(calc.Subtract(c.a, c.b))
                            Case "*"
                                Console.WriteLine(calc.Multiply(c.a, c.b))
                            Case "/"
                                Console.WriteLine(calc.Divide(c.a, c.b))
                            Case Else
                                Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.action)
                        End Select
                    Catch Ex As System.Exception
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line)
                    End Try
                    line = Console.ReadLine
    
                End While
            End Sub
        End Module
    
        Class Parser
    
            Public partA As Double
            Public partB As Double
            Public action As String
    
            Friend Sub New(ByVal line As String)
                MyBase.New()
                Dim parts() As String = line.Split(" ")
                partA = Double.Parse(parts(0))
                action = parts(1)
                partB = Double.Parse(parts(2))
            End Sub
    
            Public ReadOnly Property A() As Double
                Get
                    Return partA
                End Get
            End Property
    
            Public ReadOnly Property B() As Double
                Get
                    Return partB
                End Get
            End Property
    
            Public ReadOnly Property CalcAction() As String
                Get
                    Return Action
                End Get
            End Property
        End Class
    
    End Namespace
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.AddIn.Hosting;
    using CalcHVAs;
    
    namespace MathHost
    {
        class Program
        {
            static void Main()
            {
                // Assume that the current directory is the application folder, 
                // and that it contains the pipeline folder structure.
                String addInRoot = Environment.CurrentDirectory + "\\Pipeline";
    
                // Update the cache files of the pipeline segments and add-ins.
                string[] warnings = AddInStore.Update(addInRoot);
                foreach (string warning in warnings)
                {
                    Console.WriteLine(warning);
                }
    
                // Search for add-ins of type ICalculator (the host view of the add-in).
                Collection<AddInToken> tokens = 
                    AddInStore.FindAddIns(typeof(ICalculator), addInRoot);
    
                // Ask the user which add-in they would like to use.
                AddInToken calcToken = ChooseCalculator(tokens);
    
                // Activate the selected AddInToken in a new application domain 
                // with the Internet trust level.
                ICalculator calc = 
                    calcToken.Activate<ICalculator>(AddInSecurityLevel.Internet);
    
                // Run the add-in.
                RunCalculator(calc);
            }
    
            private static AddInToken ChooseCalculator(Collection<AddInToken> tokens)
            {
                if (tokens.Count == 0)
                {
                    Console.WriteLine("No calculators are available");
                    return null;
                }
                Console.WriteLine("Available Calculators: ");
                // Show the token properties for each token in the AddInToken collection 
                // (tokens), preceded by the add-in number in [] brackets.
                int tokNumber = 1;
                foreach (AddInToken tok in tokens)
                {
                    Console.WriteLine(String.Format("\t[{0}]: {1} - {2}\n\t{3}\n\t\t {4}\n\t\t {5} - {6}",
                        tokNumber.ToString(),
                        tok.Name,
                        tok.AddInFullName,
                        tok.AssemblyName,
                        tok.Description,
                        tok.Version,
                        tok.Publisher));
                    tokNumber++;
                }
                Console.WriteLine("Which calculator do you want to use?");
                String line = Console.ReadLine();
                int selection;
                if (Int32.TryParse(line, out selection))
                {
                    if (selection <= tokens.Count)
                    {
                        return tokens[selection - 1];
                    }
                }
                Console.WriteLine("Invalid selection: {0}. Please choose again.", line);
                return ChooseCalculator(tokens);
            }
    
            private static void RunCalculator(ICalculator calc)
            {
    
                if (calc == null)
                {
                    //No calculators were found; read a line and exit.
                    Console.ReadLine();
                }
                Console.WriteLine("Available operations: +, -, *, /");
                Console.WriteLine("Request a calculation , such as: 2 + 2");
                Console.WriteLine("Type \"exit\" to exit");
                String line = Console.ReadLine();
                while (!line.Equals("exit"))
                {
                    // The Parser class parses the user's input.
                    try
                    {
                        Parser c = new Parser(line);
                        switch (c.Action)
                        {
                            case "+":
                                Console.WriteLine(calc.Add(c.A, c.B));
                                break;
                            case "-":
                                Console.WriteLine(calc.Subtract(c.A, c.B));
                                break;
                            case "*":
                                Console.WriteLine(calc.Multiply(c.A, c.B));
                                break;
                            case "/":
                                Console.WriteLine(calc.Divide(c.A, c.B));
                                break;
                            default:
                                Console.WriteLine("{0} is an invalid command. Valid commands are +,-,*,/", c.Action);
                                break;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("Invalid command: {0}. Commands must be formated: [number] [operation] [number]", line);
                    }
    
                    line = Console.ReadLine();
                }
            }
        }
    
        internal class Parser
        {
            double a;
            double b;
            string action;
    
            internal Parser(string line)
            {
                string[] parts = line.Split(' ');
                a = double.Parse(parts[0]);
                action = parts[1];
                b = double.Parse(parts[2]);
            }
    
            public double A
            {
                get { return a; }
            }
    
            public double B
            {
                get { return b; }
            }
    
            public string Action
            {
                get { return action; }
            }
        }
    }
    
    メモ :

    このコードでは、アプリケーション フォルダにパイプライン フォルダ構造があると仮定しています。別の場所にある場合は、addInRoot 変数を設定するコード行を変更して、パイプライン ディレクトリ構造へのパスを変数に設定します。

    コードでは、ChooseCalculator メソッドを使用してトークンを一覧し、ユーザーにアドインの選択を求めるメッセージを表示します。RunCalculator メソッドは、ユーザーに単純な数式の入力を要求し、Parser クラスを使用して式を解析し、アドインから返される結果を表示します。

  10. 必要に応じて、Visual Studio ソリューションをビルドします。

アドインの作成

アドインにより、アドイン ビューで指定されたメソッドを実装します。このアドインにより、Add、Subtract、Multiply、および Divide の各処理が実装され、ホストに結果が返されます。

アドインを作成するには

  1. CalculatorV1 ソリューションに AddInCalcV1 という名前の新規プロジェクトを追加します。それにクラス ライブラリ テンプレートを適用します。

  2. ソリューション エクスプローラで、プロジェクトに System.AddIn.dll アセンブリへの参照を追加します。

  3. Calc1AddInView プロジェクトへのプロジェクト参照を追加します。プロジェクト参照を選択し、[プロパティ] で、[ローカルにコピーする] を [False] に設定します。Visual Basic で、[プロジェクトのプロパティ] の [参照] タブを使用して、プロジェクト参照に対応する [ローカルにコピーする] を [False] に設定します。

  4. クラス名を AddInCalcV1 に変更します。

  5. クラス ファイルに、CalcAddInViews (Visual Basic では Calc1AddInView.CalcAddInViews) という、System.AddIn およびアドイン ビュー セグメントへの名前空間参照を追加します。

  6. AddInAttribute 属性を AddInCalcV1 クラスに適用して、クラスをアドインとして指定します。

  7. AddInCalcV1 クラスが、CalcAddInViews.ICalculator (Visual Basic では Calc1AddInView.CalcAddInViews.ICalculator) というアドイン ビューを表すインターフェイスを実装するようにします。

  8. 適切な計算結果を返すことによって、ICalculator のメンバを実装します。

    完成したアドインを次に示します。

    Imports System.AddIn
    Imports Calc1AddInView.CalcAddInViews
    
    Namespace CalcAddIns
    
        ' The AddInAttribute identifies this pipeline segment as an add-in.
        <AddIn("Calculator AddIn", Version:="1.0.0.0")> _
        Public Class AddInCalcV1
            Implements ICalculator
    
            Public Function Add(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Add
                Return (a + b)
            End Function
    
            Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Subtract
                Return (a - b)
            End Function
    
            Public Function Multiply(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Multiply
                Return (a * b)
            End Function
    
            Public Function Divide(ByVal a As Double, ByVal b As Double) As Double _
                    Implements ICalculator.Divide
                Return (a / b)
            End Function
        End Class
    
    End Namespace
    
    using System.Collections.Generic;
    using System.AddIn;
    using CalcAddInViews;
    
    namespace CalcAddIns
    {
        // The AddInAttribute identifies this pipeline segment as an add-in.
        [AddIn("Calculator AddIn",Version="1.0.0.0")]
        public class AddInCalcV1 : ICalculator
        {
            public double Add(double a, double b)
            {
                return a + b;
            }
    
            public double Subtract(double a, double b)
            {
                return a - b;
            }
    
            public double Multiply(double a, double b)
            {
                return a * b;
            }
    
            public double Divide(double a, double b)
            {
                return a / b;
            }
        }
    }
    
  9. 必要に応じて、Visual Studio ソリューションをビルドします。

パイプラインの配置

これで、アドイン セグメントを作成し、必要なパイプライン ディレクトリ構造内に配置する準備ができました。

セグメントをパイプラインに配置するには

  1. ソリューション内の各プロジェクトについて、[プロジェクトのプロパティ] の [ビルド] タブ (Visual Basic では [コンパイル] タブ) を使用して、[出力パス] (Visual Basic では [ビルド出力パス]) の値を設定します。たとえば、アプリケーション フォルダの名前が MyApp の場合、プロジェクトは次のフォルダにビルドされます。

    プロジェクト

    パス

    AddInCalcV1

    MyApp\Pipeline\AddIns\CalcV1

    Calc1AddInSideAdapter

    MyApp\Pipeline\AddInSideAdapters

    Calc1AddInView

    MyApp\Pipeline\AddInViews

    Calc1Contract

    MyApp\Pipeline\Contracts

    Calc1Host

    MyApp

    Calc1HostSideAdapter

    MyApp\Pipeline\HostSideAdapters

    Calc1HVA

    MyApp

    メモ :

    アプリケーション フォルダ以外の場所にパイプライン フォルダ構造を配置した場合は、それに応じて、表内のパスを変更する必要があります。パイプライン ディレクトリの必要条件の詳細については、「パイプライン開発の必要条件」を参照してください。

  2. Visual Studio ソリューションをビルドします。

  3. アプリケーション ディレクトリおよびパイプライン ディレクトリをチェックして、アセンブリが正しいディレクトリにコピーされ、余分なアセンブリが間違ったフォルダにインストールされていないことを確認します。

    メモ :

    AddInCalcV1 プロジェクト内で、Calc1AddInView プロジェクト参照について、[ローカルにコピーする] を [False] に変更しなかった場合、ローダー コンテキストの問題が原因で、アドインを見つけることができません。

    パイプラインへの配置の詳細については、「パイプライン開発の必要条件」を参照してください。

ホスト アプリケーションの実行

これで、ホストを実行し、アドインと対話する準備が整いました。

ホスト アプリケーションを実行するには

  1. コマンド プロンプトで、アプリケーション ディレクトリに移動し、ホスト アプリケーション Calc1Host.exe を実行します。

  2. 対応する型のアドインがすべて検索され、アドインの選択を求めるメッセージが表示されます。使用できるアドインは 1 つのみであるため、「1」を入力します。

  3. 計算の式を入力します。たとえば、「2 + 2」などと入力します。数字と演算子の間には空白が必要です。

  4. 「exit」と入力し、Enter キーを押して、アプリケーションを閉じます。

参照

処理手順

チュートリアル : ホスト変更時の下位互換性の確保

チュートリアル : アドインとホスト間でのコレクションの受け渡し

概念

パイプライン開発の必要条件

コントラクト、ビュー、およびアダプタ

パイプラインの開発

履歴の変更

日付

履歴

理由

2008 年 7 月

テキストの誤記を修正。コントラクトへの参照の保持に関する説明を追加。

カスタマ フィードバック