标准 C++ 数据类型和 C++/WinRT

使用 C++/WinRT,可以使用标准 C++ 数据类型调用Windows 运行时 API,包括一些 C++ 标准库数据类型。 可以将标准字符串传递给 API(请参阅 C++/WinRT 中的字符串处理),可以将初始值设定项列表和标准容器传递给需要语义等效集合的 API。

另请参阅 将参数传递到 ABI 边界

标准初始化器列表

初始值设定项列表(std::initializer_list)是 C++ 标准库构造。 调用某些Windows 运行时构造函数和方法时,可以使用初始值设定项列表。 例如,你可以用一个 DataWriter::WriteBytes 来调用它。

#include <winrt/Windows.Storage.Streams.h>

using namespace winrt::Windows::Storage::Streams;

int main()
{
    winrt::init_apartment();

    InMemoryRandomAccessStream stream;
    DataWriter dataWriter{stream};
    dataWriter.WriteBytes({ 99, 98, 97 }); // the initializer list is converted to a winrt::array_view before being passed to WriteBytes.
}

制作这项工作涉及两个部分。 首先, DataWriter::WriteBytes 方法采用 winrt::array_view 类型的参数。

void WriteBytes(winrt::array_view<uint8_t const> value) const

winrt::array_view 是一种自定义 C++/WinRT 类型,可安全地表示连续的一系列值(它是在 C++/WinRT 基库中定义的,即 %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h)。

其次, winrt::array_view 具有初始值设定项列表构造函数。

template <typename T> winrt::array_view(std::initializer_list<T> value) noexcept

在许多情况下,可以选择是否在编程中注意 winrt::array_view 。 如果你选择去关注它,那么如果将来 C++ 标准库中出现了对应的类型,你就不需要修改任何代码。

可以将初始化列表传递给接受集合参数的 Windows 运行时 API。 以 StorageItemContentProperties::RetrievePropertiesAsync 为例。

IAsyncOperation<IMap<winrt::hstring, IInspectable>> StorageItemContentProperties::RetrievePropertiesAsync(IIterable<winrt::hstring> propertiesToRetrieve) const;

可以使用这样的初始值设定项列表调用该 API。

IAsyncAction retrieve_properties_async(StorageFile const storageFile)
{
    auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync({ L"System.ItemUrl" }) };
}

这里有两个因素。 首先,被调用者从初始化器列表构造一个 std::vector(该被调用者是异步的,因此它能够并且必须拥有该对象)。 其次,C++/WinRT 以透明方式(且不引入副本)将 std::vector 绑定为Windows 运行时集合参数。

标准数组和向量

winrt::array_view 还具有 std::vectorstd::array 的转换构造函数。

template <typename C, size_type N> winrt::array_view(std::array<C, N>& value) noexcept
template <typename C> winrt::array_view(std::vector<C>& vectorValue) noexcept

因此,可以改用 std::vector 调用 DataWriter::WriteBytes

std::vector<byte> theVector{ 99, 98, 97 };
dataWriter.WriteBytes(theVector); // theVector is converted to a winrt::array_view before being passed to WriteBytes.

或者使用 std::array

std::array<byte, 3> theArray{ 99, 98, 97 };
dataWriter.WriteBytes(theArray); // theArray is converted to a winrt::array_view before being passed to WriteBytes.

C++/WinRT 将 std::vector 绑定为Windows 运行时集合参数。 因此,可以传递 std::vector<winrt::hstring>,并将它转换为 winrt::hstring 的相应Windows 运行时集合。 如果被调用方是异步的,需要记住一个额外的细节。 由于该情况的实现细节,你需要提供一个右值,因此必须提供该向量的副本或将其移动。 在下面的代码示例中,我们将向量所有权移到异步被调用方接受的参数类型的对象(然后我们小心在移动后不要再次访问 vecH )。 如果想要详细了解右值,请参阅 值类别及其引用

IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<winrt::hstring> vecH)
{
	auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecH)) };
}

但是,在需要 Windows 运行时 集合的地方,不能传递 std::vector<std::wstring>。 这是因为,在转换为 std::wstring 的相应Windows 运行时集合后,C++ 语言不会强制该集合的类型参数(s)。 因此,下面的代码示例不会编译(解决方案是改为传递 std::vector<winrt::hstring> ,如上所示)。

IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<std::wstring> vecW)
{
    auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecW)) }; // error! Can't convert from vector of wstring to async_iterable of hstring.
}

原始数组和指针范围

请注意,未来 C++ 标准库中可能会出现一种等效类型;如果你愿意或者有此需要,也可以直接使用 winrt::array_view

winrt::array_view 具有可从原始数组以及由 T*(指向元素类型的指针)组成的范围进行转换的构造函数。

using namespace winrt;
...
byte theRawArray[]{ 99, 98, 97 };
array_view<byte const> fromRawArray{ theRawArray };
dataWriter.WriteBytes(fromRawArray); // the winrt::array_view is passed to WriteBytes.

array_view<byte const> fromRange{ theArray.data(), theArray.data() + 2 }; // just the first two elements.
dataWriter.WriteBytes(fromRange); // the winrt::array_view is passed to WriteBytes.

winrt::array_view 函数和运算符

winrt::array_view 实现一系列构造函数、运算符、函数和迭代器。 winrt::array_view 是一个范围对象,因此你可以将它用于基于范围的 for,或者与 std::for_each 一起使用。

有关更多示例和信息,请参阅 winrt::array_view API 参考主题。

IVector<T> 和标准迭代构造

SyndicationFeed.Items 是一个Windows 运行时 API 的示例,它返回 IVector<T> 类型的集合(投影到 C++/WinRT 中作为 winrt::Windows::Foundation::Collections::IVector<T>)。 可以将此类型用于标准的迭代结构中,例如基于范围的 for

// main.cpp
#include "pch.h"
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>

using namespace winrt;
using namespace Windows::Web::Syndication;

void PrintFeed(SyndicationFeed const& syndicationFeed)
{
    for (SyndicationItem const& syndicationItem : syndicationFeed.Items())
    {
        std::wcout << syndicationItem.Title().Text().c_str() << std::endl;
    }
}

使用异步 Windows 运行时 API 的 C++ 协程

调用异步Windows 运行时 API 时,可以继续使用并行模式库(PPL)。 但是,在许多情况下,C++ 协同例程为与异步对象交互提供了高效且更易于编码的成语。 有关详细信息和代码示例,请参阅 使用 C++/WinRT 的并发和异步操作

重要 API