如何将返回非 Windows 运行时类型的受保护方法添加到 C++/WinRT 基础 class

How to add protected methods returning non-Windows Runtime types to a C++/WinRT base class

我获得了以下按预期工作的 C++/CX 代码,但想将其转换为 C++/WinRT 代码:

namespace My.Custom.Stuff
{
  [Windows::Foundation::Metadata::WebHostHidden]
  public ref class BaseClass : public Windows::UI::Xaml::Controls::SwapChainPanel
  {
  public:
    BaseClass();
    void PublicMethod();

  protected:
    static ::DirectX::XMFLOAT3 ProtectedMethod();
  };
}


namespace My.Custom.Stuff
{
  [Windows::Foundation::Metadata::WebHostHidden]
  public ref class SubClass sealed : public BaseClass
  {
  public:
    SubClass();
    void UseProtectedMethod()
    {
      ::DirectX::XMFLOAT3 value = ProtectedMethod()
      // ...
    }
  };
}

但是,我遇到的问题如下:BaseClass 包含一个受保护的方法,该方法 return 是一种类型,无法映射到相应的 Windows 运行时类型。在 C++/CX 中,这不是问题,因为 ProtectedMethod 根本没有映射。如果我使用我的 Windows 运行时组件 ProtectedMethod 根本不会暴露,这就是我想要的。

但是,该方法应该是 BaseClass 的成员,因为 SubClass 等多个其他 类 在实现其 public 方法时使用该方法。我提出了以下 C++/WinRT MIDL 代码:

namespace My.Custom.Stuff
{
  unsealed runtimeclass BaseClass : Windows.UI.Xaml.Controls.SwapChainPanel
  {
    BaseClass();
    void PublicMethod();

    // This does not work
    protected DirectX.XMFLOAT3 RgbFromBrush(IInspectable brush);
  }
}



import "BaseClass.idl";


namespace My.Custom.Stuff
{
  runtimeclass SubClass : BaseClass
  {
    SubClass();
    void UseProtectedMethod();
  }
}

问题是,如果我这样定义 ProtectedMethod,它将无法工作,因为 ::DirectX::XMFLOAT3 不是 Windows 运行时类型。如果我使用任何其他 return 类型,受保护的方法就会被映射。但是,在使用那个 Windows 运行时组件时它不应该是可见的,当然我不应该更改它的 return 类型。

如何使用 C++/WinRT 实现我使用 C++/CX 所做的事情?

编辑

编译 MIDL 代码会产生如下结果:

#include "BaseClass.g.h"


namespace winrt::My::Custom::Stuff::implementation
{
  struct BaseClass : BaseClassT<BaseClass>
  {
    BaseClass() = default;
    // ...
  };
}


namespace winrt::My::Custom::Stuff::factory_implementation
{
  struct BaseClass : BaseClassT<BaseClass, implementation::BaseClass>
  {
  };
}

我认为可以简单地添加如下受保护的方法:

namespace winrt::My::Custom::Stuff::implementation
{
  struct BaseClass : BaseClassT<BaseClass>
  {
    BaseClass() = default;

  protected:
    static ::DirectX::XMFLOAT3 ProtectedMethod();
  };
}

但是,尝试在 SubClass 中使用 ProtectedMethod 会导致以下错误:

error C2039: 'ProtectedMethod': is not a member of 'winrt::My::Custom::Stuff::BaseClass'

以下是我的使用方法:

#include "SubClass.g.h"


namespace winrt::My::Custom::Stuff::implementation
{
  struct SubClass : SubClassT<SubClass>
  {
    SubClass() = default;
    void UseProtectedMethod()
    {
      ::DirectX::XMFLOAT3 value = ProtectedMethod();
    }
  };
}


namespace winrt::My::Custom::Stuff::factory_implementation
{
  struct SubClass : SubClassT<SubClass, implementation::SubClass>
  {
  };
}

从 C++/CX 转换为 C++/WinRT 时,只有 public 方法应该进入您的 IDL 文件,因为这些是构成 WinRT API 表面的唯一方法。

private/protected/internal 的方法不是 WinRT API 表面的一部分,因此它们不应进入 IDL。

您发布的使用代码不应编译,因为您对 implementation::SubClass 的 C++ 定义缺少模板参数。由于 IDL/WinRT 定义有 SubClassBaseClass 派生,您需要将 BaseClass 的实现类型提供给 SubClassT,并且如果您检查cppwinrt 生成的“SubClass.h”,您会看到这种情况发生。一旦您正确声明了 SubClass 的实现,您将可以访问 BaseClass.

上的受保护方法

我刚刚尝试成功,它看起来像这样:

BaseClass.idl

namespace RuntimeComponent1
{
    [default_interface]
    unsealed runtimeclass BaseClass
    {
        BaseClass();
        void PublicMethod();
    }
}

BaseClass.h

#pragma once
#include "BaseClass.g.h"

struct non_winrt_type
{

};

namespace winrt::RuntimeComponent1::implementation
{
    struct BaseClass : BaseClassT<BaseClass>
    {
        BaseClass() = default;
        void PublicMethod() {}

    protected:
        non_winrt_type ProtectedMethod()
        {
            return {};
        }
    };
}
namespace winrt::RuntimeComponent1::factory_implementation
{
    struct BaseClass : BaseClassT<BaseClass, implementation::BaseClass>
    {
    };
}

SubClass.idl

import "BaseClass.idl";

namespace RuntimeComponent1
{
    [default_interface]
    runtimeclass SubClass : BaseClass
    {
        SubClass();
        void UseProtectedMethod();
    }
}

SubClass.h

#pragma once
#include "SubClass.g.h"
#include "BaseClass.h"

namespace winrt::RuntimeComponent1::implementation
{
    // Notice how BaseClass is used here.
    // This was copied directly from the generated boilerplate SubClass.h
    struct SubClass : SubClassT<SubClass, RuntimeComponent1::implementation::BaseClass>
    {
        SubClass() = default;

        void UseProtectedMethod()
        {
            auto result = ProtectedMethod();
        }
    };
}
namespace winrt::RuntimeComponent1::factory_implementation
{
    struct SubClass : SubClassT<SubClass, implementation::SubClass>
    {
    };
}