使用C ++ / WRL中的静态方法创建WinRT组件

时间:2012-09-24 10:38:48

标签: c++ windows-runtime idl wrl

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

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

对我不起作用的实施如下:
这里有什么不妥?

  1. IDL 文件中,创建 Math 类。它将是托管端静态方法的主机。使用 FastAdd 方法创建 IMathStatics 接口。这个只包含一堆静态方法。使用参数 IMathStatics 静态 属性标记 Math 类。
  2. 
        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;
            }
        }
    
    1. 创建 MathStatics C ++类。让 InspectableClassStatic 宏指向 IMathStatics 字符串标识符。添加 ActivatableStaticOnlyFactory 宏指向 MathStatics 类实现。
    2. 
          #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);
          }
      
      1. 编译完成后,将创建 WRLNativeComponent.winmd 文件。我可以使用 public static FastAdd 方法查看 Math 类。

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

1 个答案:

答案 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用于注册具有关联激活工厂的运行时类。