我想使用 C ++ 和WRL(Windows运行时C ++模板库)创建 WinRT 组件,以便通过C#静态方法在托管代码中使用调用
int sum = Math.FastAdd(5,6);
对我不起作用的实施如下:
这里有什么不妥?
import "inspectable.idl"; #define COMPONENT_VERSION 1.0 namespace WRLNativeComponent { runtimeclass Math; [uuid(EFA9D613-BA8F-4F61-B9E7-C6BE7B7765DD)] [exclusiveto(WRLNativeComponent.Math)] [version(COMPONENT_VERSION)] interface IMathStatics : IInspectable { HRESULT FastAdd([in] int a, [in] int b, [out, retval] int* value); } [uuid(650438BA-C401-49E1-8F06-58DCD5A4B685), version(COMPONENT_VERSION)] interface IMath : IInspectable { HRESULT InstanceMethod(void); } [static(WRLNativeComponent.IMathStatics, COMPONENT_VERSION)] [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)] runtimeclass Math { [default] interface IMath; } }
#pragma once #include <wrl.h> #include "MyMath_h.h" // generated from IDL using namespace Microsoft::WRL; namespace WRLNativeComponent { class Math : public Microsoft::WRL::RuntimeClass, ABI::WRLNativeComponent::IMath> { InspectableClass(RuntimeClass_WRLNativeComponent_Math, BaseTrust); public: Math(void) {} ~Math(void) {} STDMETHODIMP InstanceMethod() override { return S_OK; } }; class MathStatics : public Microsoft::WRL::ActivationFactory { InspectableClassStatic(InterfaceName_WRLNativeComponent_IMathStatics, BaseTrust); public: MathStatics(void) {} ~MathStatics(void) {} STDMETHODIMP FastAdd(_In_ int a, _In_ int b, _Out_ int* value) override { if (value == nullptr) return E_POINTER; *value = a + b; return S_OK; } }; ActivatableClass(Math); ActivatableStaticOnlyFactory(MathStatics); }
编译完成后,将创建 WRLNativeComponent.winmd 文件。我可以使用 public static FastAdd 方法查看 Math 类。
构造C#客户端以调用静态方法。进行调用时,抛出'System.InvalidCastException'。预计这将正常工作。
答案 0 :(得分:3)
运行时类最多可以有一个激活工厂。每次使用其中一个Activatable
宏都会为运行时类型注册激活工厂。因此,您的库中的以下代码
ActivatableClass(Math);
ActivatableStaticOnlyFactory(MathStatics);
尝试注册两个激活工厂:第一个为Math
类注册一个简单的激活工厂,第二个注册另一个实际上不可用的简单激活工厂(我们将在此刻看到原因)。
因为第一个简单激活工厂与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
用于注册具有关联激活工厂的运行时类。