使用 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::vector 和 std::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 的并发和异步操作。