Я хочу создать WinRT использование компонента C ++ а также WRL (Библиотека шаблонов среды выполнения C ++ Windows) для использования в управляемом коде через вызов статического метода C #.
int sum = Math.FastAdd(5,6);
Реализация, которая не работает для меня, ниже.
Что здесь может быть не так?
импорт "inspectable.idl"; #define COMPONENT_VERSION 1.0 пространство имен WRLNativeComponent { runtimeclass Math; [UUID (EFA9D613-BA8F-4F61-B9E7-C6BE7B7765DD)] [Exclusiveto (WRLNativeComponent.Math)] [Версия (COMPONENT_VERSION)] Интерфейс IMathStatics: IInspectable { HRESULT FastAdd ([in] int a, [in] int b, [out, retval] int * value); } [uuid (650438BA-C401-49E1-8F06-58DCD5A4B685), версия (COMPONENT_VERSION)] Интерфейс IMath: IInspectable { HRESULT InstanceMethod (void); } [статические (WRLNativeComponent.IMathStatics, COMPONENT_VERSION)] [версия (COMPONENT_VERSION), активируемая (COMPONENT_VERSION)] runtimeclass Math { [по умолчанию] интерфейс IMath; } }
#pragma один раз #включают <wrl.h> #include "MyMath_h.h" // сгенерировано из IDL используя пространство имен Microsoft :: WRL; пространство имен WRLNativeComponent { класс Math: общедоступный Microsoft :: WRL :: RuntimeClass, ABI :: WRLNativeComponent :: IMath> { InspectableClass (RuntimeClass_WRLNativeComponent_Math, BaseTrust); общественности: Математика (недействительная) {} Математика (недействительная) {} STDMETHODIMP InstanceMethod () переопределить { возврат S_OK; } }; класс MathStatics: общедоступный Microsoft :: WRL :: ActivationFactory { InspectableClassStatic (InterfaceName_WRLNativeComponent_IMathStatics, BaseTrust); общественности: MathStatics (void) {} ~ MathStatics (void) {} Переопределение STDMETHODIMP FastAdd (_In_ int a, _In_ int b, _Out_ int *) { if (value == nullptr) return E_POINTER; * значение = a + b; возврат S_OK; } }; ActivatableClass (Математика); ActivatableStaticOnlyFactory (MathStatics); }
После компиляции WRLNativeComponent.winmd файл создан. Я могу видеть математический класс с общедоступная статическая FastAdd метод.
Создайте клиент C # для вызова статического метода. Когда звонок сделан, ‘System.InvalidCastException’ брошен Ожидается, что это будет работать правильно.
Класс выполнения может иметь не более одной фабрики активации. Каждое использование одного из Activatable
макросы регистрируют фабрику активации для типа времени выполнения. Поэтому следующий код из вашей библиотеки
ActivatableClass(Math);
ActivatableStaticOnlyFactory(MathStatics);
пытается зарегистрировать две фабрики активации: первая регистрирует простую фабрику активации для Math
class и second регистрирует еще одну простую фабрику активации, которая на самом деле не используется (мы покажем почему).
Поскольку первая простая фабрика активации связана с Math
класс, он возвращается, когда компонент C # пытается вызвать статическую функцию-член. Затем компонент C # пытается привести этот интерфейсный указатель к IMathStatics
интерфейс, который не реализует простая фабрика активации, поэтому приведение не выполняется, и вы получаете InvalidCastException
,
Поскольку для данного класса среды выполнения может быть только одна фабрика активации, ваш MathStatics
класс должен реализовать как IMathStatics
интерфейс статических членов и IActivationFactory
интерфейс, который используется для построения по умолчанию (это необходимо, потому что вы объявили Math
введите в качестве конструктора по умолчанию, используя activatable
атрибут без заводского имени интерфейса).
Ваша фабрика активации должна быть реализована так:
class MathStatics : public ActivationFactory<IMathStatics>
{
InspectableClassStatic(RuntimeClass_WRLNativeComponent_Math, BaseTrust);
public:
MathStatics() {}
~MathStatics() {}
STDMETHODIMP ActivateInstance(_Outptr_result_nullonfailure_ IInspectable** ppvObject) override
{
return MakeAndInitialize<Math>(ppvObject);
}
STDMETHODIMP FastAdd(_In_ int a, _In_ int b, _Out_ int* value) override
{
if (value == nullptr) return E_POINTER;
*value = a + b;
return S_OK;
}
};
ActivatableClassWithFactory(Math, MathStatics);
ActivationFactory
Шаблон базового класса обеспечивает реализацию по умолчанию IActivationFactory
интерфейс. Эта реализация по умолчанию просто возвращает E_NOTIMPL
когда клиент пытается по умолчанию создать экземпляр Math
типа, поэтому нам нужно переопределить эту функцию-член на самом деле построить по умолчанию Math
объект.
Обратите внимание, что при использовании InspectableClassStatic
завершить реализацию IInspectable
для фабрики активации имя класса должно быть именем класса времени выполнения (в этом случае RuntimeClass_WRLNativeComponent_Math
), а не название интерфейса статики. Активация выполняется по имени типа, и именно это имя используется инфраструктурой WRL для поиска фабрики активации для типа времени выполнения, используя его имя.
ActivatableClassWithFactory
используется для регистрации класса времени выполнения в связанной фабрике активации.
Других решений пока нет …