次の方法で共有


Windows ランタイム コンポーネントでイベントを生成する

Note

C++/WinRT Windows ランタイム コンポーネントでイベントを生成する方法について詳しくは、「C++/WinRT でのイベントの作成」をご覧ください。

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

  • (オプション 1) Windows.UI.Core.CoreDispatcher でイベントを生成し、JavaScript のスレッド コンテキストにマーシャリングします。 通常はこれが最適なオプションですが、一部のシナリオでは最速のパフォーマンスが得られない場合があります。
  • (オプション 2) Windows.Foundation.EventHandler<オブジェクト> を使用します (ただし、イベントの型に関する情報が失われます)。 オプション 1 を実行できない場合、または十分なパフォーマンスが得られない場合、型情報が失われても問題がなければ、これが次善の策です。 C# Windows ランタイム コンポーネントを作成している場合、Windows.Foundation.EventHandler<オブジェクト> 型は使用できません代わりに、その型が System.EventHandler に投影されるため、それを代わりに使用する必要があります。
  • (オプション 3)コンポーネントの独自のプロキシとスタブを作成します。 このオプションは実装するのが最も困難ですが、型情報が保持され、要求の厳しいシナリオではオプション 1 と比較してパフォーマンスが向上する可能性があります。

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

背景

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

Windows API のほとんどのオブジェクトはアジャイルであるか、プロキシとスタブが組み込まれています。 ただし、Windows.Foundation.TypedEventHandler<TSender, TResult> などのジェネリックな型は、型引数を指定するまでは完全な型ではないため、プロキシとスタブを作成できません。 プロキシやスタブの不足が問題になるのは JavaScript クライアントだけですが、コンポーネントを JavaScript や C++ または .NET 言語から使用できるようにする場合は、次の 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> を使用しますが、型情報は失われます

Note

C# Windows ランタイム コンポーネントを作成している場合、Windows.Foundation.EventHandler<オブジェクト> 型は使用できません代わりに、その型が System.EventHandler に投影されるため、それを代わりに使用する必要があります。

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

この例では、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++ を使用してプロキシとスタブの DLL を作成し、JavaScript が非同期操作でコンポーネントによって発生する Windows.Foundation.TypedEventHandler<TSender、TResult> イベントを使用できるようにする方法について説明します。 (C++ または Visual Basic を使用してコンポーネントを作成することもできます。プロキシとスタブの作成に関連する手順は同じです)。このチュートリアルは、Windows ランタイムインプロセス コンポーネント サンプル (C++/CX) の作成に基づいており、その目的を説明するのに役立ちます。

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

  • ここでは、2 つの基本的なWindows ランタイム クラスを作成します。 1 つのクラスでは、Windows.Foundation.TypedEventHandler<TSender, TResult> 型のイベントを公開し、もう 1 つのクラスは、TValue の引数として JavaScript に返される型です。 これらのクラスは、後の手順を完了するまで JavaScript と通信できません。
  • このアプリは、メイン クラス オブジェクトをアクティブ化し、メソッドを呼び出し、Windows ランタイム コンポーネントによって発生するイベントを処理します。
  • これらは、プロキシ クラスとスタブ クラスを生成するツールで必要です。
  • 次に、IDL ファイルを使用して、プロキシとスタブの C ソース コードを生成します。
  • COM ランタイムが見つけられるようにプロキシ スタブ オブジェクトを登録し、アプリ プロジェクトでプロキシ スタブ DLL を参照します。

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

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

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

ソリューション エクスプローラーで、ソリューションのショートカット メニューを開き、Properties を選択します。 Property Pages ダイアログ ボックスで、左側のウィンドウで Configuration プロパティを選択し、ダイアログ ボックスの上部にある ConfigurationDebug に設定し、Platform を x86、x64、または ARM に設定します。 [OK] を選択します。

重要 プラットフォーム = 後でソリューションに追加するネイティブ コードの Win32 DLL では無効であるため、任意の CPU は機能しません。

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

.cs ファイルで、Windows.Foundation 名前空間の using ディレクティブを追加して、TypedEventHandler をスコープに取り込みます。

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

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

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

        }
        public interface IToast
        {
            String ToastType { get; }
        }

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

次に、これらのインターフェイスを実装し、後でプログラミングする 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);
                    }
                });
           }
        }

前のコードでは、トーストを作成し、スレッド プールの作業項目を起動して通知を発生させます。 IDE では、非同期呼び出しに await キーワードを適用することが推奨される場合がありますが、このメソッドは操作の結果に依存する作業を行わないので、この場合は必要ありません。

上記のコードの非同期呼び出しでは、ThreadPool.RunAsync を使用して、バックグラウンド スレッドでイベントを発生させる簡単な方法を示しています。 次の例に示すように、この特定のメソッドを記述できます。.NET タスク スケジューラは自動的に async/await 呼び出しを UI スレッドにマーシャリングするため、正常に動作します。  

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

プロジェクトを今すぐビルドすると、正常にビルドされます。

JavaScript アプリをプログラミングするには

これで、JavaScript アプリにボタンを追加して、トーストを作成するために定義したクラスを使用できるようになりました。 これを行う前に、先ほど作成した ToasterComponent プロジェクトへの参照を追加する必要があります。 ソリューション エクスプローラーで、ToasterApplication プロジェクトのショートカット メニューを開き、[追加] > [参照] を選択して、[新しい参照の追加] を選択します。 [参照の追加] ダイアログ ボックスの左側のウィンドウの [ソリューション] でコンポーネント プロジェクトを選択し、中央のウィンドウで [ToasterComponent] を選択します。 [OK] を選択します。

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

default.js ファイルの最後に、コンポーネントを呼び出して呼び出す関数を格納する名前空間を追加します。 名前空間には、トーストを作成するための関数と、トースト完了イベントを処理する関数の 2 つがあります。 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 in this case event is a
           // Toast class, with a toastType string.
           var toastType = event.toastType;

           document.getElementById('toastOutput').innerHTML = "<p>Made " + toastType + " toast</p>";
        },
    });

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 のプロパティ] を選択します。 Debugger の種類Managed Only に変更。 もう一度メニュー バーで、[デバッグ] > [例外] を選択して、[Common Language Runtime Exceptions] (共通言語ランタイムの例外) を選択します。

次に、アプリを実行し、トーストの作成ボタンをクリックします。 デバッガーは無効なキャスト例外をキャッチします。 メッセージからは明らかではありませんが、そのインターフェイスにプロキシがないため、この例外が発生しています。

missing proxy

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

コンポーネントのインターフェイス (C# および他の .NET 言語) の GUID を生成するには

メニュー バーで、[ツール] > [GUID の作成] を選択します。 ダイアログ ボックスで 5 を選択します。 [Guid("xxxxxxxx-xxxx...xxxx")] を選択します。 [新しい GUID] ボタンを選択し、[コピー] ボタンを選択します。

guid generator tool

インターフェイス定義に戻り、次の例に示すように、IToaster インターフェイスの直前に新しい GUID を貼り付けます。 (この例では GUID を使用しないでください。すべての一意のインターフェイスには、独自の GUID が必要です)。

[Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
        public interface IToaster...

System.Runtime.InteropServices 名前空間の using ディレクティブを追加します。

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

コンポーネントのインターフェイスの GUID を生成するには (C++)

メニュー バーで、[ツール] > [GUID の作成] を選択します。 ダイアログ ボックスで 3 を選択します。 static const 構造体 GUID = {...}。 [新しい GUID] ボタンを選択し、[コピー] ボタンを選択します。

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 } };

GuidAttribute をスコープに取り込むには、Windows.Foundation.Metadata の using ディレクティブを追加します。

次の例に示すように、const GUID を GuidAttribute に手動で変換します。 中かっこは角かっことかっこに置き換えられ、末尾のセミコロンは削除されます。

// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
    [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
    public interface IToaster
    {...

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

インターフェイスに一意の ID が設定されたので、.winmd ファイルを winmdidl コマンド ライン ツールにフィードして IDL ファイルを作成し、その IDL ファイルを MIDL コマンド ライン ツールにフィードすることで、プロキシとスタブの C ソース コードを生成できます。 次の手順に示すように、ビルド後のイベントを作成する場合は、Visual Studio でこれを行います。

プロキシとスタブのソース コードを生成するには

ビルド後のカスタム イベントを追加するには、ソリューション エクスプローラーで、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 に変更します。

.winmd ファイルが変更されるたびに IDL ファイルが再生成されるようにするには、 ビルド後イベントの実行に変更します。ビルドによってプロジェクトの出力が更新されるときに [ビルド イベント] プロパティ ページは次のようになります。 ビルド イベント

ソリューションをリビルドして IDL を生成してコンパイルします。

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

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

必要なファイルが完成したら、コンパイルして DLL (C++ ファイル) を生成できます。 これを可能な限り簡単にするには、プロキシの構築をサポートする新しいプロジェクトを追加します。 ToasterApplication ソリューションのショートカット メニューを開き、[追加] > [新しいプロジェクト] を選択します。 [新しいプロジェクト] ダイアログ ボックスの左側のウィンドウで、[Windows > ユニバーサル Windows > Visual C++] を展開し中央のウィンドウで [DLL (UWP アプリ)]を選択します。 (これは C++ Windows ランタイム コンポーネント プロジェクトではないことに注意してください)。プロジェクトに [プロキシ] という名前を付け、OK ボタンを選択します。 これらのファイルは、C# クラスで何かが変更されると、ビルド後のイベントによって更新されます。

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

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

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

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

ここでプロジェクトをビルドすると、失敗します。 このプロジェクトを正しくコンパイルするには、プロジェクトのコンパイル方法とリンク方法を変更する必要があります。 ソリューション エクスプローラーで、プロキシ プロジェクトのショートカット メニューを開き、Properties を選択します。 プロパティ ページを次のように変更します。

左側のペインで [C/C++] > [プリプロセッサ] を選択します。右側のペインで [プリプロセッサの定義] を選択して下矢印ボタンを選択し、[編集] を選択します。 ボックスに次の定義を追加します。

WIN32;_WINDOWS

[C/C++] > [プリコンパイル済みヘッダー] の下で、[プリコンパイル済みヘッダー][プリコンパイル済みヘッダーを使用しない] に変更し、[適用] ボタンを選択します。

[リンカー] > [全般] の下で、[インポート ライブラリの無視][はい] に変更し、[適用] ボタンを選択します。

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

rpcrt4.lib;runtimeobject.lib

これらのライブラリをリスト行に直接貼り付けないでください。 Edit ボックスを使用して、Visual Studio の MSBuild で適切な追加の依存関係が維持されるようにします。

これらの変更を行ったら、[プロパティ ページ] ダイアログ ボックスの [OK] ボタンを選択します。

次に、ToasterComponent プロジェクトに依存します。 これにより、プロキシ プロジェクトがビルドされる前にトースターがビルドされるようになります。 これは、トースター プロジェクトがプロキシをビルドするファイルの生成を担当するためです。

プロキシ プロジェクトのショートカット メニューを開き、[プロジェクトの依存関係] を選択します。 プロキシ プロジェクトが ToasterComponent プロジェクトに依存していることを示すチェック ボックスをオンにして、Visual Studio で正しい順序でビルドされるようにします。

Visual Studio のメニュー バーで [ビルド] > [ソリューションのリビルド] を選択して、ソリューションが正しくビルドされることを確認します。

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

ToasterApplication プロジェクトで、package.appxmanifest のショートカット メニューを開き、 Open With を選択します。 [ファイルを開く] ダイアログ ボックスで、[XML テキスト エディター] を選択しOK ボタンを選択します。 windows.activatableClass.proxyStub 拡張機能の登録を提供し、プロキシの GUID に基づく XML を貼り付けます。 .appxmanifest ファイルで使用する GUID を見つけるには、ToasterComponent_i.c. 次の例のようなエントリを検索します。 また、IToast、IToaster、および 3 番目のインターフェイスの定義にも注目してください。これは、トースターとトーストの 2 つのパラメーターを持つ型指定されたイベント ハンドラーです。 これは、トースター クラスで定義されているイベントと一致します。 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 に貼り付けて、再フォーマットします。 マニフェスト エントリは次の例のようになりますが、ここでも、独自の 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 ノードをパッケージ ノードの直接の子として貼り付け、たとえば[リソース] ノードのピアを貼り付けます。

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

  • ProxyStub ClassId は、ToasterComponent_i.c ファイルの最初の GUID に設定されます。 classId には、このファイルで定義されている最初の GUID を使用します。 (これは、ITypedEventHandler2 の GUID と同じ場合があります)。
  • パスは、プロキシ バイナリのパッケージ相対パスです。 (このチュートリアルでは、proxies.dllは ToasterApplication.winmd と同じフォルダーにあります)。
  • GUID は正しい形式です。 (これは間違って取得するのは簡単です)。)
  • マニフェスト内のインターフェイス ID は、ToasterComponent_i.c ファイル内の IID と一致します。
  • インターフェイス名はマニフェスト内で一意です。 これらはシステムによって使用されないため、値を選択できます。 定義したインターフェイスと明確に一致するインターフェイス名を選択することをお勧めします。 生成されたインターフェイスの場合、名前は生成されたインターフェイスを示す必要があります。 ToasterComponent_i.c ファイルを使用すると、インターフェイス名の生成に役立ちます。

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

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