インターフェースの説明
最初に、オブジェクトとファクトリーのインターフェースを記述する必要があります。
import "inspectable.idl"; namespace DataBinding { interface INumber; interface INumberOverrides; interface INumberFactory; runtimeclass Number; } namespace DataBinding { [exclusiveto(Number)] [uuid(5b197688-2f57-4d01-92cd-a888f10dcd90)] [version(0x00000001)] interface INumber : IInspectable { [propget] HRESULT Value([out, retval] INT32* value); [propput] HRESULT Value([in] INT32 value); } [exclusiveto(Number)] [uuid(12b0eeee-76ed-47af-8247-610025184b58)] [version(0x00000001)] interface INumberOverrides : IInspectable { HRESULT GetValue([out, retval] INT32* value); } [exclusiveto(Number)] [uuid(29f9bd09-d452-49bf-99f9-59f328103cbd)] [version(0x00000001)] interface INumberFactory : IInspectable { [overload("CreateInstance")] HRESULT CreateInstance0( [in] IInspectable* outer, [out] IInspectable** inner, [out, retval] Number** result); [overload("CreateInstance")] HRESULT CreateInstance1( [in] int value, [in] IInspectable* outer, [out] IInspectable** inner, [out, retval] Number** result); } [composable(DataBinding.INumberFactory, public, 1.0)] [marshaling_behavior(agile)] [threading(both)] [version(0x00000001)] runtimeclass Number { [default] interface INumber; [overridable][version(0x00000001)] interface INumberOverrides; } }
説明では、いくつかの興味深い詳細に気付くことができます。
- 単一のGetValueメソッドを持つINumberOverridesインターフェイスが定義されています。 Numberクラスはこのインターフェイスを実装し、子クラスでオーバーライドできるようにします。
- INumberFactoryのファクトリインターフェイスは、CreateInstance0(...)およびCreateInstance1(...)のインスタンスを作成するための2つのメソッドを定義します。 どちらのメソッドもCreateInstance(...)メソッドのオーバーロードです-このメソッドは* .winmdメタデータファイルで確認できます。 一般に、CreateInstanceメソッドは次の形式に縮小できます。
HRESULT CreateInstance( .... params, // , IInspectable *outer, //, IInspectable **inner, //, ISomeInterface **instance) // , outer inner
- Numberクラスには補助属性があります。
[composable(DataBinding.INumberFactory, public, 1.0)]
このコードに基づいて、MIDLコンパイラは、コードファイルに含める必要があるヘッダーファイルを作成します。
C ++コードでのインターフェイスの実装
次のタスクは、指定されたインターフェイスをコードに実装することです。 MIDLコンパイラは、pattern%(ファイル名)_h.hを使用して* .hファイルを作成するように設定され、/ ns_prefixオプションが指定されました(生成されたコードにABIプレフィックスが追加されます)。 インターフェイスはDataBinding.idlファイルで定義されているため、DataBinding_h.hヘッダーファイルが含まれています。
そのため、インターフェース実装コード:
#include <wrl.h> #include <wrl/wrappers/corewrappers.h> #include "DataBinding_h.h" using ABI::DataBinding::INumber; using ABI::DataBinding::INumberOverrides; using ABI::DataBinding::INumberFactory; using Microsoft::WRL::RuntimeClassFlags; using Microsoft::WRL::RuntimeClassType; using Microsoft::WRL::EventSource; using Microsoft::WRL::Make; using Microsoft::WRL::MakeAndInitialize; using Microsoft::WRL::RuntimeClass; using Microsoft::WRL::ActivationFactory; using Microsoft::WRL::ComPtr; using Microsoft::WRL::Wrappers::HStringReference; class Number : public RuntimeClass < RuntimeClassFlags<RuntimeClassType::WinRt>, INumber, INumberOverrides > { InspectableClass(RuntimeClass_DataBinding_Number, BaseTrust); private: INT32 _value; public: Number() : _value(0) { } Number(INT32 value) : _value(value) { } virtual HRESULT STDMETHODCALLTYPE get_Value(INT32* value) override { *value = _value; return S_OK; } virtual HRESULT STDMETHODCALLTYPE put_Value(INT32 value) override { _value = value; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetValue(INT32* value) override { *value = _value; return S_OK; } }; class NumberFactory : public ActivationFactory < INumberFactory > { InspectableClassStatic(RuntimeClass_DataBinding_Number, BaseTrust); public: virtual HRESULT STDMETHODCALLTYPE CreateInstance0( IInspectable* outer, IInspectable** inner, INumber** result) override { .... } virtual HRESULT STDMETHODCALLTYPE CreateInstance1( INT32 value, IInspectable* outer, IInspectable** inner, INumber** result) override { .... } }; ActivatableClassWithFactory(Number, NumberFactory);
CreateInstance0とCreateInstance1について説明します。 これらのメソッドは「継承」に責任があります。
残念ながら、ドキュメントにはこのタイプのファクトリメソッドの実装に関する推奨事項が見つかりませんでした。 したがって、パラメーターの目的を実験的に調査する必要がありました。
IInspectable* outer, IInspectable** inner, INumber** result
これを行うために、C#で記述されたアプリケーションにコンポーネントを接続しました。 * .winmdメタデータには、封印されていないNumberクラスが定義されています。 まさに私が達成しようとしていたこと。 メソッドの実装方法を理解することだけが残っていました。 このために、次のコードを使用しました。
private class LocalNumber : Number { public LocalNumber() { } public LocalNumber(int value) : base(value) { } } ..... { var items = new List<Number> { new Number(), new Number(1), new LocalNumber(), new LocalNumber(1), }; }
いくつかのデバッグパスの後、ファクトリメソッドの次の実装に行きました。
virtual HRESULT STDMETHODCALLTYPE CreateInstance0( IInspectable* outer, IInspectable** inner, INumber** result) override { auto pnumber = Make<Number>().Detach(); if (nullptr != outer && S_OK != outer->QueryInterface(ABI::DataBinding::IID_INumber, reinterpret_cast<void**>(result))) { *inner = reinterpret_cast<IInspectable*>(pnumber); } else { *result = pnumber; } return S_OK; } virtual HRESULT STDMETHODCALLTYPE CreateInstance1( INT32 value, IInspectable* outer, IInspectable** inner, INumber** result) override { auto pnumber = Make<Number>(value).Detach(); if (nullptr != outer && S_OK != outer->QueryInterface(ABI::DataBinding::IID_INumber, reinterpret_cast<void**>(result))) { *inner = reinterpret_cast<IInspectable*>(pnumber); } else { *result = pnumber; } return S_OK; }
まず、オブジェクトを作成します。 次に、条件を使用して、戻り値を初期化します。 式:
outer->QueryInterface(ABI::DataBinding::IID_INumber, reinterpret_cast<void**>(result))
INumberインターフェイスの実装のためにオブジェクトをポーリングし、結果パラメーターへのポインターが戻り値として渡されます。 実行が成功した場合、次の式を使用して内部パラメーターを初期化します。
*inner = reinterpret_cast<IInspectable*>(pnumber);
それ以外の場合は、単に結果パラメーターを初期化します。
PS
この記事は参照専用です。 主な目標は、WRLを使用して「継承」クラスを作成する機能を実証することでした。