次の方法で共有


Windows ランタイム コンポーネントでのイベントの発生

Windows ランタイム コンポーネントによってバックグラウンド スレッド (ワーカー スレッド) 内でユーザー定義のデリゲート型のイベントが発生し、JavaScript がこのイベントを受け取れるようにするには、以下の方法のいずれかで実装や発生を行うことができます。

  1. (オプション 1) CoreDispatcher を通じてイベントを発生させ、そのイベントを JavaScript のスレッド コンテキストにマーシャリングします。 通常、これは最善のオプションですが、シナリオによっては最も高速なパフォーマンスを達成できない可能性があります。

  2. (オプション 2) Windows.Foundation.EventHandler<オブジェクト> を使用します (ただし、イベントの型に関する情報を失います)。 オプション 1 が実行可能ではない場合や、パフォーマンスが十分でない場合に、型に関する情報を失ってもかまわない状況では、これが 2 番目のオプションになります。

  3. (オプション 3) コンポーネントに対して独自のプロキシとスタブ COM オブジェクトを作成します。 このオプションは、実装が最も困難ですが、型情報を保持し、また要求が高いシナリオではオプション 1 と比べてパフォーマンスが向上する可能性があります。

これらのオプションをいずれも使用せずに、バックグラウンド スレッドで単純にイベントを発生させる場合、JavaScript クライアントは、そのイベントを受け取りません。

背景

どの言語を使用して作成するかにかかわりなく、すべての Windows のランタイム コンポーネントとアプリケーションは基本的には COM オブジェクトです。 Windows API では、ほとんどのコンポーネントは、バックグラウンド スレッドおよび UI スレッドにあるオブジェクトと同様に通信することができるアジャイル COM オブジェクトです。 COM オブジェクトをアジャイルにすることができない場合は、UI スレッドとバックグラウンド スレッドの境界にまたがって他の COM オブジェクトと通信するために、プロキシおよびスタブと呼ばれるヘルパー オブジェクトが必要です (COM の用語では、この通信をスレッド アパートメント間の通信と呼びます)。

Windows API のオブジェクトのほとんどは、アジャイルであるか、プロキシとスタブを埋め込んでいます。 ただし、Windows.Foundation.TypedEventHandler<TSender, TResult> のようなジェネリック型は、型引数を指定するまでは完全な型ではないため、それらに対してプロキシとスタブを作成することはできません。 プロキシやスタブが存在しないことが問題になるのは、JavaScript クライアントのみです。それでも、開発するコンポーネントを、C++ または .NET 言語と同様に JavaScript でも使用可能にすることを希望する場合は、次の 3 種類のオプションのいずれかを使用する必要があります。

(オプション 1) CoreDispatcher を通じたイベントの発生

Windows.UI.Core.CoreDispatcher を使用して、任意のユーザー定義デリゲート型のイベントを送信することができ、その結果、JavaScript はそれらのイベントを受け取ることができます。 どのオプションを使用すればよいか不明な場合、最初にこのオプションを試してください。 イベントの発生からイベント処理までの待機時間が問題になる場合、他のオプションのいずれかを試してください。

次の例は、CoreDispatcher を使用して、厳密に型指定したイベントを発生させる方法を示します。 型引数が Toast であり、Object ではないことに注意してください。


public event EventHandler<Toast> ToastCompletedEvent;
private void OnToastCompleted(Toast args)
{
    var completedEvent = ToastCompletedEvent;
    if (completedEvent != null)
    {
        completedEvent(this, args);
    }
}

public void MakeToastWithDispatcher(string message)
{
    Toast toast = new Toast(message);
    // Assume you have a CoreDispatcher at class scope.
    // Initialize it here, then use it from the background thread.
    var window = Windows.UI.Core.CoreWindow.GetForCurrentThread();
    m_dispatcher = window.Dispatcher;

    Task.Run( () =>
    {
        if (ToastCompletedEvent != null)
        {
            m_dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            new DispatchedHandler(() =>
            {
                this.OnToastCompleted(toast);
            })); // end m_dispatcher.RunAsync
         }
     }); // end Task.Run
}

(オプション 2) EventHandler<Object> を使用します。ただし、型の情報が失われます。

バックグラウンド スレッドからイベントを送信するもう 1 つの方法は、イベントの型として Windows.Foundation.EventHandler<Object> を使用することです。 Windows は、ジェネリック型に対してこの具体的なインスタンス化を実行し、このジェネリック型にプロキシとスタブを提供します。 欠点は、イベント引数と送信元に関する型情報が失われることです。 C++ と .NET クライアントは、イベントを受信したときに、ドキュメントを通じて、どの型へのキャスト バックを行うかを判断する必要があります。 JavaScript クライアントでは、元の型情報を把握するは必要ありません。 これらは、メタデータ内にある引数の名前に基づいて、引数のプロパティを識別します。

C# 内で Windows.Foundation.EventHandler<Object> を使用する方法を次の例に示します。

public sealed Class1
{
// Declare the event
public event EventHandler<Object> ToastCompletedEvent;

    // Raise the event
    public async void MakeToast(string message)
    {
        Toast toast = new Toast(message);
        // Fire the event from a background thread to allow this thread to continue 
        Task.Run(() =>
        {
            if (ToastCompletedEvent != null)
            {
                OnToastCompleted(toast);
            }
        });
    }

    private void OnToastCompleted(Toast args)
    {
        var completedEvent = ToastCompletedEvent;
        if (completedEvent != null)
        {
            completedEvent(this, args);
        }
    }
}

次のように、JavaScript 側でこのイベントを利用します。

toastCompletedEventHandler: function (event) {
        
        var toastType = event.toast.toastType; 
        document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
    },

(オプション 3) 独自のプロキシとスタブを作成します。

型情報をすべて保持するユーザー定義のイベント型を使用して、パフォーマンス向上の可能性を高めるには、独自のプロキシ オブジェクトとスタブ オブジェクトを作成し、アプリケーションのパッケージに埋め込む必要があります。 通常、このオプションを使用する必要があるのは、他の 2 つのオプションがいずれも適切ではないまれなケースのみです。 また、このオプションが他の 2 つのオプションより優れたパフォーマンスを実現するという保証はありません。 実際のパフォーマンスは多くの要因によって異なります。 アプリケーションの実際のパフォーマンスを測定し、イベントが実際にボトルネックになっているかどうかを確認するには、Visual Studio プロファイラーまたは他のプロファイリング ツールを使用します。

ここからは、C# を使用して基本的な Windows ランタイム コンポーネントを作成する方法と、C++ を使用して、非同期操作の際にコンポーネントによって発生した Windows.Foundation.TypedEventHandler<TSender、TResult> イベントを JavaScript で利用できるようにするプロキシおよびスタブに対応する DLL を作成する方法を示します (C++ または Visual Basic を使用してコンポーネントを作成することもできます。 プロキシとスタブの作成に関連する手順は同じです)。このチュートリアルは、Creating a Windows Runtime in-process component sample (C++/CX) (Windows ランタイムのインプロセス コンポーネント サンプルの作成 (C++/CX)) に基づいており、その目的について説明するのに役立ちます。

このチュートリアルは、次の 3 つのパートで構成されています。

  1. Windows ランタイム コンポーネントの作成: ここでは、2 つの基本的な Windows ランタイム クラスを作成します。 1 つのクラスは Windows.Foundation.TypedEventHandler<TSender, TResult> 型のイベントを公開し、もう 1 つのクラスは TValue に対応する引数として JavaScript に返される型です。 残りの手順を完了するまでは、これらのクラスは JavaScript と通信できません。

  2. JavaScript アプリケーションのプログラミング: このアプリケーションはメイン クラス オブジェクトをアクティブにし、メソッドを呼び出し、Windows ランタイム コンポーネントによって発生したイベントを処理します。

  3. コンポーネントのインターフェイス用の GUID の生成: これらは、プロキシ クラスとスタブ クラスを生成するツールで必要とされるものです。

  4. コンポーネント用の IDL ファイルの生成: その後、プロキシやスタブに対応する C ソース コードを生成するための IDL ファイルを使用します。

  5. プロキシとスタブ コードのコンパイルによる DLL の生成

  6. プロキシ スタブ DLL の登録および使用: プロキシ スタブ DLL を登録します。その結果、COM ランタイムがこれらを見つけ、アプリケーション プロジェクト内でそのプロキシ スタブ DLL を参照することができます。

Windows ランタイム コンポーネントを作成するには

  1. Visual Studio のメニュー バーで、[ファイル]、>[新しいプロジェクト] の順にクリックします。 [新しいプロジェクト] ダイアログ ボックスで、[JavaScript]、>[Windows ストア] の順に展開し、[空のアプリケーション] をクリックします。 プロジェクトに ToasterApplication という名前を付け、[OK] をクリックします。

  2. ソリューションに、C# の Windows ランタイム コンポーネントを追加します。ソリューション エクスプローラー で、ソリューションのショートカット メニューを開き、[追加]、>[新しいプロジェクト] の順にクリックします。 [Visual C#]、>[Windows ストア] の順に展開し、[Windows ランタイム コンポーネント] をクリックします。 プロジェクトに ToasterComponent という名前を付け、[OK] をクリックします。 ToasterComponent は、後で作成するコンポーネントのルート名前空間になります。

    ソリューション エクスプローラー で、ソリューションのショートカット メニューを開き、[プロパティ] をクリックします。 [プロパティ ページ] ダイアログ ボックスで、左ペインの [構成プロパティ] をクリックし、その後、ダイアログ ボックス上部で、[構成][デバッグ] に設定し、[プラットフォーム][x86][x64]、または [ARM] に設定します。 [OK] をクリックします。

    重要

    [プラットフォーム][Any CPU] に設定する方法は、後でソリューションに追加する予定のネイティブ コード Win32 DLL にとって無効であるため、機能しません。

  3. ソリューション エクスプローラーで、プロジェクトの名前に一致するように、class1.cs を ToasterComponent.cs という名前に変更します。 Visual Studio により、新しいファイル名に合わせてファイル内のクラス名が自動的に変更されます。

  4. この .cs ファイルで、TypedEventHandler がスコープ内に入るように、Windows.Foundation 名前空間に対応する using ディレクティブを追加します。

  5. プロキシとスタブが必要な場合は、コンポーネントでインターフェイスを使用してそのパブリック メンバーを公開する必要があります。 ToasterComponent.cs では、トースター用のインターフェイス、およびトースターが生成するトースト用のもう 1 つのインターフェイスを定義します。

    注意

    C# では、この手順は省略できます。代わりに、最初に 1 つのクラスを作成し、次にそのクラスのショートカット メニューを開き、[リファクター][インターフェイスの抽出] の順にクリックします。生成されたコード内で、インターフェイスに対してパブリック アクセシビリティを手動で付与します。

    public interface IToaster
        {
            void MakeToast(String message);
            event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
    
        }
        public interface IToast
        {
            String ToastType { get; }
        }
    

    IToast インターフェイスには、トーストの型を記述する目的で取得できる文字列があります。 IToaster インターフェイスには、トーストを作成するメソッド、およびトーストが作成されたことを示すイベントがあります。 このイベントは、トーストの特定の部分 (つまり、型) を返すため、型指定されたイベントとも呼びます。

  6. 次に、これらのインターフェイスを実装するクラスが必要です。後でプログラミングする JavaScript アプリケーションからアクセスできるように、これらのクラスをパブリックにし、シールすることになります。

    public sealed class Toast : IToast
        {
            private string _toastType;
    
            public string ToastType
            {
                get
                {
                    return _toastType;
                }
            }
            internal Toast(String toastType)
            {
                _toastType = toastType;
            }
    
        }
        public sealed class Toaster : IToaster
        {
            public event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
    
            private void OnToastCompleted(Toast args)
            {
                var completedEvent = ToastCompletedEvent;
                if (completedEvent != null)
                {
                    completedEvent(this, args);
                }
            }
    
            public void MakeToast(string message)
            {
                Toast toast = new Toast(message);
                // Fire the event from a thread-pool thread to enable this thread to continue 
                Windows.System.Threading.ThreadPool.RunAsync(
                (IAsyncAction action) =>
                {
                    if (ToastCompletedEvent != null)
                    {
                        OnToastCompleted(toast);
                    }
                });
            }
        }
    

    前述のコードでは、トーストを作成し、その後、スレッド プールの作業項目を起動して通知を生成します。 非同期呼び出しに対して await キーワードを適用するように IDE から推奨される可能性もありますが、この場合はメソッドが操作結果に依存する処理を何も行わないため、そのキーワードは必要ありません。

    重要

    前述のコード内の非同期呼び出しは、バックグラウンド スレッドでイベントを発生させる簡単な方法を示すのみの目的で ThreadPool.RunAsync を使用します。次の例に示す方法で、この特定のメソッドを記述することもできます。その場合、.NET のタスク スケジューラが UI スレッドに対する async/await のコールバックを自動的にマーシャリングするため、次のメソッドも適切に機能します。

    public async void MakeToast(string message)
    {
        Toast toast = new Toast(message)
        await Task.Delay(new Random().Next(1000));
        OnToastCompleted(toast);
    }
    

    プロジェクトを今すぐビルドする場合、クリーン ビルドする必要があります。

JavaScript アプリケーションをプログラミングするには

  1. 今度は、定義したばかりのクラスを使用して JavaScript アプリケーションがトーストを作成できるように、ボタンを追加できます。 この作業を行う前に、作成したばかりの ToasterComponent プロジェクトへの参照を追加する必要があります。 ソリューション エクスプローラーで、ToasterApplication プロジェクトのショートカット メニューを開き、[追加][参照] をクリックして、[新しい参照の追加] を選択します。 [参照の追加] ダイアログ ボックスで、左ペインで [ソリューション] の下にあるコンポーネント プロジェクトをクリックし、次に中央のペインで ToasterComponent をクリックします。 [OK] をクリックします。

  2. ソリューション エクスプローラーで、ToasterApplication プロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトに設定] をクリックします。

  3. default.js ファイルの最後に、コンポーネントを呼び出す関数、およびそのコンポーネントからコールバックされる関数を含む名前空間を追加します。 この名前空間に 2 つの関数を含めます。1 つはトーストを作成し、もう 1 つはトースト完成イベントを処理します。 makeToast の実装では、トースター オブジェクトを作成し、イベント ハンドラーを登録し、トーストを作成します。 その結果、次に示すように、イベント ハンドラーが実行する作業はそれほど多くありません。

    WinJS.Namespace.define("ToasterApplication", {
            makeToast: function () {
    
                var toaster = new ToasterComponent.Toaster();
            //toaster.addEventListener("ontoastcompletedevent", ToasterApplication.toastCompletedEventHandler);
            toaster.ontoastcompletedevent = ToasterApplication.toastCompletedEventHandler;
            toaster.makeToast("Peanut Butter");
    
            },
    
            toastCompletedEventHandler: function (event) {
                // The sender of the event (the delegate’s first type parameter)
                // is mapped to event.target. The second argument of the delegate
                // is contained in event, which means event in this case is a 
                // Toast class, with a toastType string.
                var toastType = event.toastType;
    
                document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
            },
    
        }); 
    
  4. makeToast 関数をボタンにフックする必要があります。 default.html を更新し、ボタンとトースト作成結果を出力するためにある程度のスペースを含めます。

    <body>
        <h1>Click the button to make toast</h1>
        <button onclick="ToasterApplication.makeToast()">Make Toast!</button>
        <div id="toasterOutput">
            <p>No Toast Yet...</p>
        </div>
    </body>
    

    仮に TypedEventHandler を使用していない場合でも、この時点でローカル コンピューターでアプリケーションを実行し、このボタンをクリックしてトーストを作成することができます。 ただし、アプリケーション内では何も発生しません。 なぜそのような結果になるかを確認するために、ToastCompletedEvent を発生させるマネージ コードをデバッグしてみましょう。 プロジェクトを停止し、次に、メニュー バーの [デバッグ]、>[ToasterApplication のプロパティ] の順にクリックします。 [デバッガーの種類][マネージのみ] に変更します。 もう一度メニュー バーを使用し、[デバッグ][例外] の順にクリックし、その後、[Common Language Runtime Exceptions] をクリックします。

    ここでアプリケーションを実行し、トースト作成ボタンをクリックします。 デバッガーは、無効なキャスト例外をキャッチします。 このメッセージを見るだけでは明白ではありませんが、インターフェイスに対応するプロキシが存在しないことが原因で、この例外が生成されています。

    プロキシがないことを示すデバッガーのエラー ウィンドウ

コンポーネントに対応するプロキシとスタブを作成する最初の手順は、一意の ID、つまり GUID をインターフェイスに追加することです。 ただし、使用する GUID の形式は、C#、Visual Basic、.NET の別の言語、または C++ のどれを使用してコーディングを行っているかによって異なります。

コンポーネントのインターフェイスに対応する GUID を生成するには

  • C#、Visual Basic、または .NET の他の言語の場合:

    1. メニュー バーの [ツール][GUID の作成] の順にクリックします。 ダイアログ ボックスで、[5. [Guid(“xxxxxxxx-xxxx...xxxx)]] をクリックします。 [新規 GUID] をクリックし、次に [コピー] をクリックします。

    2. インターフェイス定義に戻り、その後、次の例に示すように、IToaster インターフェイスの直前に新しい GUID を貼り付けます (この例の GUID を使用しないでください。 あらゆる一意のインターフェイスごとに、独自の GUID が必要です)。

      [Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
          public interface IToaster...
      
    3. System.Runtime.InteropServices 名前空間に対応する using ディレクティブを追加します。

    4. IToast インターフェイスに対して、これらの手順を繰り返します。

  • C++ の場合:

    1. メニュー バーの [ツール][GUID の作成] の順にクリックします。 ダイアログ ボックスで、[3. static const struct GUID = {...}] をクリックします。 [新規 GUID] をクリックし、次に [コピー] をクリックします。

      Visual Studio 内の GUID ジェネレーター

    2. IToaster インターフェイス定義の直前に GUID を貼り付けます。 貼り付けた後、GUID は次の例のようになります (この例の GUID を使用しないでください。 あらゆる一意のインターフェイスごとに、独自の GUID が必要です)。

      // {F8D30778-9EAF-409C-BCCD-C8B24442B09B}
          static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };
      
    3. Windows.Foundation.Metadata に対応する using ディレクティブを追加し、GuidAttribute スコープ内に入るようにします。

    4. 今度は、const GUID を GuidAttribute に手動で変換します。その結果、次の例に示すように書式設定されます。 中かっこを角かっこおよびかっこに置換し、最後のセミコロンを削除することに注意してください。

      // {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
          [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
          public interface IToaster
          {...
      
    5. IToast インターフェイスに対して、これらの手順を繰り返します。

これで、インターフェイスが一意の ID を持つようになったため、winmdidl コマンド ライン ツールに .winmd ファイルを指定することで IDL ファイルを作成し、次に MIDL コマンド ライン ツールに IDL ファイルを指定することでプロキシおよびスタブに対応する C ソース コードを生成することができます。 次の手順に示すように、ビルド後のイベントを作成すると、Visual Studio によってこの作業が実行されます。

プロキシおよびスタブに対応するソース コードを生成するには

  1. ソリューション エクスプローラーでカスタムのビルド後のイベントを追加するには、ToasterComponent プロジェクトのショートカット メニューを開き、[プロパティ] をクリックします。 プロパティ ページの左ペインで [ビルド イベント] をクリックし、次に [ビルド後の編集] をクリックします。 ビルド後のコマンド ラインに次のコマンドを追加します (winmdidl ツールが見つかるように、環境変数を設定するバッチ ファイルを最初に呼び出す必要があります)。

    call "$(DevEnvDir)..\..\vc\vcvarsall.bat" $(PlatformName)
    winmdidl /outdir:output "$(TargetPath)"
    midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(ProjectDir)$(TargetName)_i.c" /env win32 /h "$(ProjectDir)$(TargetName).h" /winmd "Output\$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(ProjectDir)dlldata.c" /proxy "$(ProjectDir)$(TargetName)_p.c" "Output\$(TargetName).idl"
    
    
    

    重要

    ARM または x64 プロジェクトの構成では、MIDL の /env パラメーターを x64 または arm32 に変更します。

  2. .winmd ファイルに変更を加えるたびに IDL ファイルが確実に再生成されるようにするには、[ビルド後イベントの実行][ビルドがプロジェクト出力を更新したとき] に変更します。

    [ビルド イベント] プロパティ ページは次のようになります。

    Visual Studio のプロパティ ページのビルド後のステップ

  3. IDL を生成およびコンパイルするために、ソリューションをリビルドします。

    ToasterComponent プロジェクト ディレクトリ内で ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c、および dlldata.c を検索することにより、MIDL がソリューションを正しくコンパイルすることを確認できます。

プロキシとスタブ コードをコンパイルして DLL を生成するには

  1. ここまでで必要なファイルが揃ったため、それらのファイルをコンパイルし、C++ ファイルである DLL を生成することができます。 できるだけ作業を簡単にするために、プロキシのビルドをサポートする新しいプロジェクトを追加します。 ToasterApplication ソリューションのショートカット メニューを開き、[追加][新しいプロジェクト] の順にクリックします。 [新しいプロジェクト] ダイアログ ボックスで、左ペインの [Visual C++][Windows ストア] の順に展開し、次に中央のペインで [DLL (Windows ストア アプリ)] をクリックします (これは C++ の Windows ランタイム コンポーネント プロジェクトではないことに注意してください)。プロジェクトに Proxies という名前を付け、[OK] をクリックします。 C# のクラス内で何か変更が生じた場合、これらのファイルはビルド後イベントによって更新されます。

  2. 既定では、Proxies プロジェクトは、ヘッダーである .h ファイルと C++ の .cpp ファイルを生成します。 DLL は、MIDL によって生成されたファイルからビルドされるため、これらの .h ファイルと .cpp ファイルは必須ではありません。 ソリューション エクスプローラー で、ソリューションのショートカット メニューを開き、[削除] をクリックし、削除してよいことを確認します。

  3. この時点でプロジェクトが空であるため、MIDL で生成されたファイルを再度追加できます。 Proxies プロジェクトのショートカット メニューを開き、[追加][既存の項目] の順にクリックします。 ダイアログ ボックスで、ToasterComponent プロジェクト ディレクトリに移動し、ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c、および dlldata.c の各ファイルを選択します。 [追加] をクリックします。

  4. Proxies プロジェクト内で、dlldata.c で記述されている DLL のエクスポートを定義する .def ファイルを作成します。 プロジェクトのショートカット メニューを開き、[追加][新しい項目] の 順にクリックします。 ダイアログ ボックスの左ペインで [コード] をクリックし、次に中央のペインで [モジュール定義ファイル] をクリックします。 ファイルに proxies.def という名前を付け、[追加] をクリックします。 この .def ファイルを開き、dlldata.c で定義されている EXPORTS を含むように変更を加えます。

    EXPORTS
        DllCanUnloadNow         PRIVATE
        DllGetClassObject       PRIVATE
    
  5. プロジェクトを今すぐビルドすると、ビルドに失敗します。 このプロジェクトを正しくコンパイルするには、プロジェクトのコンパイルおよびリンクの方法を変更する必要があります。 ソリューション エクスプローラーで、Proxies プロジェクトのショートカット メニューを開き、[プロパティ] をクリックします。 プロパティ ページを次のように変更します。

    • 左ペインで、[C/C++][プリプロセッサ] の順にクリックし、次に右のペインで [プリプロセッサの定義] をクリックし、下向きの矢印ボタンをクリックし、[編集] をクリックします。 ボックス内でこれらの定義を追加します。

      WIN32;_WINDOWS
      
    • [C/C++][プリコンパイル済みヘッダー] の下で、[プリコンパイル済みヘッダー][プリコンパイル済みヘッダーを使用しない] に変更し、[適用] をクリックします。

    • [リンカー][全般] の下で、[インポート ライブラリの無視][はい] に変更し、[適用] をクリックします。

    • [リンカー][入力] の下で、[追加の依存ファイル] をクリックし、下向きの矢印をクリックし、[編集] をクリックします。 次のテキストをボックスに追加します。

      rpcrt4.lib;runtimeobject.lib
      

      これらの lib を list 行に直接直接貼り付けないでください。 Visual Studio が追加の依存関係を確実に正しく維持できるように、[編集] ボックスを使用してください。

    これらの変更を加えた後、[プロパティ ページ] ダイアログ ボックスの [OK] をクリックします。

  6. 次に、ToasterComponent プロジェクトに関する依存関係を設定します。この結果、プロキシ プロジェクトをビルドする前に、確実にトースターがビルドされるようになります。 Toaster プロジェクトには、プロキシをビルドするためのファイルを生成する役割があるため、この設定が必要です。

    Proxies プロジェクトのショートカット メニューを開き、[プロジェクトの依存関係] をクリックします。 Proxies プロジェクトが ToasterComponent プロジェクトに依存していることを示すようにチェック ボックスをオンにします。その結果、Visual Studio はこれらを確実に正しい順序でビルドするようになります。

  7. Visual Studio のメニュー バーで [ビルド][リビルド] の順にクリックし、ソリューションが正しくビルドされることを確認します。

プロキシとスタブを登録するには

  1. ToasterApplication プロジェクトで、package.appxmanifest のショートカット メニューを開き、[ファイルを開くアプリケーションの選択] をクリックします。 [ファイルを開くアプリケーションの選択] ダイアログ ボックスで、[XML テキスト エディター] をクリックし、[OK] をクリックします。 ここでは、windows.activatableClass.proxyStub 拡張機能の登録を行ういくつかの XML を貼り付けます。この XML は、プロキシ内の GUID に基づいています。 .appxmanifest ファイル内で使用する GUID を見つけるには、ToasterComponent_i.c を開きます。 次の例に似たエントリを見つけます。 また IToastIToaster の定義と、3 番目のインターフェイスに注目します。このインターフェイスは型指定されたイベント ハンドラーであり、Toaster および Toast という 2 つのパラメーターを使用します。 これは Toaster クラスで定義されたイベントに対応します。 IToast および IToaster に対応する GUID が、C# ファイル内のインターフェイスに対して定義されている GUID と一致することを確認します。 型指定されたイベント ハンドラーのインターフェイスは自動生成されたため、このインターフェイスに対応する GUID も自動生成されました。

    MIDL_DEFINE_GUID(IID, IID___FITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast,0x1ecafeff,0x1ee1,0x504a,0x9a,0xf5,0xa6,0x8c,0x6f,0xb2,0xb4,0x7d);
    
    
    MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToast,0xF8D30778,0x9EAF,0x409C,0xBC,0xCD,0xC8,0xB2,0x44,0x42,0xB0,0x9B);
    
    
    MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToaster,0xE976784C,0xAADE,0x4EA4,0xA4,0xC0,0xB0,0xC2,0xFD,0x13,0x07,0xC3);
    

    ここで、GUID をクリップボードにコピーし、追加したノード内にある package.appxmanifest の中にそれらを貼り付け、Extensions という名前を付け、書式を再設定します。 マニフェスト エントリは次の例のようになります。ただし、ここでも、独自の GUID を使用してください。 XML 内にある ClassId の GUID が ITypedEventHandler2 と同じであることに注意してください。 この GUID は、ToasterComponent_i.c でリストされた最初の GUID であることが原因です。 ここで使用する GUID では大文字と小文字が区別されません。 IToast および IToaster に対応する GUID の書式を手動で再設定する代わりに、インターフェイス定義に戻り、正しい形式の GuidAttribute 値を取得することができます。 C++ では、正しい形式の GUID がコメント内にあります。 いずれの場合も、ClassId とイベント ハンドラーの両方に使用される GUID の形式を手動で再設定する必要があります。

    <Extensions> <!—Use your own GUIDs!!!-->
        <Extension Category="windows.activatableClass.proxyStub">
          <ProxyStub ClassId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d">
            <Path>Proxies.dll</Path>
            <Interface Name="IToast" InterfaceId="F8D30778-9EAF-409C-BCCD-C8B24442B09B"/>
            <Interface Name="IToaster"  InterfaceId="E976784C-AADE-4EA4-A4C0-B0C2FD1307C3"/>  
            <Interface Name="ITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast" InterfaceId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d"/>
          </ProxyStub>      
        </Extension>
      </Extensions>
    

    Extensions XML ノードを、Package ノードの直接の子、および Resources ノードなどのピアとして貼り付けます。

  2. 先に進む前に、次のことを確認することが重要です。

    • ProxyStub ClassId は、ToasterComponent_i.c ファイル内にある最初の GUID に設定されています。 classId に対して、このファイルで定義されている最初の GUID を使用します (これは ITypedEventHandler2 に対応する GUID と同じになる可能性があります)。

    • Path は、プロキシ バイナリのパッケージの相対パスです (このチュートリアルでは、proxies.dll は ToasterApplication.winmd と同じフォルダーにあります)。

    • GUID は正しい形式になっています (間違いやすいところです)。

    • マニフェスト内にあるインターフェイスの IDは、ToasterComponent_i.c ファイル内の IID と一致しています。

    • インターフェイス名は、マニフェスト内で一意になっています。 これらの名前がシステムによって使用されることはないため、値を選択することもできます。 定義したインターフェイスに明確に一致するインターフェイス名を選択することをお勧めします。 生成されたインターフェイスの場合、名前は、生成されたインターフェイスを表すものになります。 インターフェイス名の生成を容易にするために、ToasterComponent_i.c ファイルを使用することができます。

  3. ソリューションを今すぐ実行しようとすると、proxies.dll がペイロードの一部ではないことを示すエラーが発生します。 ToasterApplication プロジェクト内にある [参照] フォルダーのショートカット メニューを開き、[参照の追加] をクリックします。 Proxies プロジェクトの隣にあるチェック ボックスをオンにします。 また ToasterComponent の隣にあるチェック ボックスもオンになっていることを確認します。 [OK] をクリックします。

    これで、プロジェクトがビルドされます。 プロジェクトを実行し、トーストを作成できることを確認します。