首页 > 解决方案 > 如何将返回非 Windows 运行时类型的受保护方法添加到 C++/WinRT 基类

问题描述

我得到了以下 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包含一个受保护的方法,该方法返回的类型无法映射到相应的 Windows 运行时类型。在 C++/CX 中,这不是问题,因为ProtectedMethod根本没有映射。如果我使用我的 Windows 运行时组件ProtectedMethod,则根本不会暴露这就是我想要的。

但是,该方法应该是的成员,BaseClass因为多个其他类SubClass在实现其公共方法时使用该方法。我想出了以下 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 运行时类型。如果我使用任何其他返回类型,则受保护的方法将被映射。但是,在使用该 Windows 运行时组件时它不应该是可见的,当然我不应该更改它的返回类型。

如何使用 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();
  };
}

但是,尝试使用ProtectedMethodinSubClass会导致以下错误:

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>
  {
  };
}

标签: uwpwindows-runtimec++-winrt

解决方案


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

私有/受保护/内部的方法不是 WinRT API 表面的一部分,因此它们不应进入 IDL。

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

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

基类.idl

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

基类.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>
    {
    };
}

子类.idl

import "BaseClass.idl";

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

子类.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>
    {
    };
}

推荐阅读