【问题标题】:Creating WinRT component with static methods in C++ / WRL在 C++ / WRL 中使用静态方法创建 WinRT 组件
【发布时间】:2012-09-15 19:29:36
【问题描述】:

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

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

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

  1. IDL 文件中创建一个 Math 类。它将是托管端静态方法的宿主。使用 FastAdd 方法创建 IMathStatics 接口。这个只包含一堆静态方法。使用 IMathStatics 的参数标记具有 static 属性的 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 #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 文件。我可以看到带有 public static FastAdd 方法的 Math 类。

  2. 构造 C# 客户端以调用静态方法。进行调用时,会抛出 'System.InvalidCastException'。这应该可以正常工作。

【问题讨论】:

    标签: c++ windows-runtime idl wrl


    【解决方案1】:

    一个运行时类最多可以有一个激活工厂。每次使用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 基础结构使用此名称来查找使用其名称的运行时类型的激活工厂。

    ActivatableClassWithFactory 用于向关联的激活工厂注册运行时类。

    【讨论】:

      猜你喜欢
      • 2012-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      相关资源
      最近更新 更多