我想使用C++和WRL(Windows运行时C++模板库)创建一个WinRT组件,以便通过C#静态方法调用在托管代码中使用。
int sum = Math.FastAdd(5,6);
下面是对我不起作用的实现
这里可能出了什么问题?
- 在IDL文件中创建Math类。它将是托管端静态方法的主机。使用FastAdd方法创建IMathStatics接口。这个只是包含了一堆静态方法。使用static属性和IMathStatics参数标记Math类
import"inspectable.idl";#定义COMPONENT_VERSION 1.0命名空间WRLNativeComponent{runtimeclass数学;[uuid(EFA9D613-BA8F-4F61-B9E7-C6BE7B7765DD)][排他否决权(WRLNativeComponent.Math)][版本(COMPONENT_version)]接口IMathStatics:IInspectable{HRESULT FastAdd([in]int a,[in]intb,[out,retval]int*value);}[uuid(650438BA-C401-49E1-8F06-58DCD5A4B685),版本(COMPONENT_version)]接口IMath:IInspectable{HRESULT InstanceMethod(void);}[静态(WRLNativeComponent.IMathStatics,COMPONENT_VERSION)][版本(COMPONENT_version),可激活(COMPONNT_version运行时类数学{[默认]接口IMath;}}
- 创建MathStaticsC++类。让InspectableClassStatic宏指向IMathStatics字符串标识符。添加ActivatableStaticOnlyFactory宏以指向MathStatics类实现
#pragma一次#包括<wrl.h>#include IDL生成的"MyMath_h.h"//使用命名空间Microsoft::WRL;命名空间WRLNativeComponent{class数学:public Microsoft::WRL::RuntimeClass,ABI::WRLNativeComponent::IMath>{InspectableClass(RuntimeClass_WRLNativeComponent_Math,BaseTrust);公共:数学(void){}~数学(void){}STDMETHODIMP InstanceMethod()重写{返回S_OK;}};class MathStatics:public Microsoft::WRL::ActivationFactory{InspectableClassStatic(接口名称_WRLNativeComponent_IMathStatics,BaseTrust);公共:MathStatics(void){}~数理统计(void){}STDMETHODIMP FastAdd(_In_inta,_In_intb,_Out_int*值)覆盖{if(value==nullptr)返回E_POINTER;*值=a+b;返回S_OK;}};ActivatableClass(数学);ActivatableStaticOnlyFactory(MathStatics);}
编译后,将创建WRLNativeComponent.winmd文件。我可以使用公共静态FastAdd方法看到Math类。
构造C#客户端来调用静态方法。进行呼叫时,系统。引发InvalidCastException">。这有望正常工作。
一个运行时类最多可以有一个激活工厂。每次使用一个Activatable
宏都会为运行时类型注册一个激活工厂。因此,以下代码来自您的库
ActivatableClass(Math);
ActivatableStaticOnlyFactory(MathStatics);
尝试注册两个激活工厂:第一个为Math
类注册一个简单的激活工厂,第二个注册另一个实际上不可用的简单激活工厂(我们稍后会看到原因)。
因为第一个简单激活工厂与Math
类相关联,所以当C#组件尝试调用静态成员函数时,它会被返回。然后,C#组件尝试将此接口指针强制转换为IMathStatics
接口,而简单激活工厂没有实现该接口,因此强制转换失败,您将获得InvalidCastException
。
由于给定的运行时类只能有一个激活工厂,因此MathStatics
类需要同时实现IMathStatics
静态成员接口和用于默认构造的IActivationFactory
接口(这是必需的,因为您使用没有工厂接口名称的activatable
属性将Math
类型声明为默认可构造类型)。
你的激活工厂需要这样实现:
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
接口的默认实现。当客户端尝试默认构造Math
类型的实例时,此默认实现只返回E_NOTIMPL
,因此我们需要重写此成员函数,以实际默认构造一个Math
对象。
请注意,当使用InspectableClassStatic
为激活工厂完成IInspectable
的实现时,类名应该是运行时类的名称(在本例中为RuntimeClass_WRLNativeComponent_Math
),而不是静态接口的名称。激活是按类型名称执行的,WRL基础结构正是使用这个名称来查找激活工厂,以查找使用其名称的运行时类型。
CCD_ 19用于向关联的激活工厂注册运行时类。