WRLを使用して記述された継承されたWinRTコンポーネントクラス

WinRTの別のコンポーネント/アプリケーションに継承できるクラスを作成するトピックに興味がありました。 C ++ / CX拡張機能を使用すると、別の非シールクラスを継承する場合にのみ、そのようなクラスを作成できます。 それ以外の場合、コンパイルは失敗します。 WRLを使用すると、この制限を回避して、封印されていないクラスを記述できます。

インターフェースの説明


最初に、オブジェクトとファクトリーのインターフェースを記述する必要があります。

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

説明では、いくつかの興味深い詳細に気付くことができます。

このコードに基づいて、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を使用して「継承」クラスを作成する機能を実証することでした。

Source: https://habr.com/ru/post/J248071/


All Articles