2

我想使用C++WRL (Windows 运行时 C++ 模板库)创建一个WinRT组件,以便通过 C# 静态方法调用在托管代码中使用。

int sum = Math.FastAdd(5,6);

对我不起作用的实现如下。
这里有什么问题?

  1. IDL文件中创建一个数学类。它将是托管端静态方法的宿主。使用FastAdd方法创建IMathStatics接口。这个只包含一堆静态方法。使用带有IMathStatics参数的静态属性标记Math类。
    导入“inspectable.idl”;
    #define COMPONENT_VERSION 1.0
    命名空间 WRLNativeComponent
    {
        运行时类数学;
        [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)]
        运行时类数学
        {
            [默认] 接口 IMath;
        }
    }
  1. 创建MathStatics C++ 类。让InspectableClassStatic宏指向IMathStatics字符串标识符。添加ActivatableStaticOnlyFactory宏以指向MathStatics类实现。
    #pragma 一次
    #include <wrl.h>
    #include "MyMath_h.h" // 从 IDL 生成
    使用命名空间 Microsoft::WRL;
    命名空间 WRLNativeComponent {
    数学类:公共 Microsoft::WRL::RuntimeClass,
        ABI::WRLNativeComponent::IMath>
    {
        InspectableClass(RuntimeClass_WRLNativeComponent_Math, BaseTrust);
    上市:
        数学(无效){}
        〜数学(无效){}
        STDMETHODIMP InstanceMethod() 覆盖
        {
            返回 S_OK;
        }
    };
    类 MathStatics : public Microsoft::WRL::ActivationFactory
    {
        InspectableClassStatic(InterfaceName_WRLNativeComponent_IMathStatics, BaseTrust);
    上市:
        数学静态(无效){}
        〜数学(无效){}
        STDMETHODIMP FastAdd(_In_ int a, _In_ int b, _Out_ int* value) 覆盖
        {
            if (value == nullptr) 返回 E_POINTER;
            *值 = a + b;
            返回 S_OK;
        }
    };
    可激活类(数学);
    ActivatableStaticOnlyFactory(MathStatics);
    }
  1. 编译后,将创建WRLNativeComponent.winmd文件。我可以看到具有公共静态 FastAdd方法的Math类。

  2. 构造 C# 客户端以调用静态方法。进行调用时,将引发“System.InvalidCastException” 。这有望正常工作。

4

1 回答 1

4

一个运行时类最多可以有一个激活工厂。每次使用其中一个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用于向关联的激活工厂注册运行时类。

于 2012-09-24T20:23:56.650 回答