C++/WinRT教程(第二篇)基础类型的使用

目录

前言

字符串

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

通过 C++/WinRT 将值装箱到 IInspectable

取消值装箱的示例

取消 IInspectable 装箱的示例

确定装箱值的类型


前言

本文是系列教程的第二篇,推荐新手从第一篇开始阅读体验更佳。本文是根据官方教程整理的更精简版本的教程,并优化了部分翻译问题。

C++/WinRT教程(第一篇)-CSDN博客

字符串

利用 C++/WinRT,你可以使用 C++ 标准库宽字符串类型(如 std::wstring)调用 Windows 运行时 API(注:不要使用窄字符串类型,例如 std::string)。 C++/WinRT 使用 winrt::hstring 自定义字符串类型(在 C++/WinRT 基础库 %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h 中定义) 如果你要自己定义 API,则很可能需要了解 hstring。 winrt::hstring 利用 std::wstring_view 提供了可转换性,以实现 std::basic_string_view 应有的互操作性。

hstring 具有可用且无需关注的转换构造函数。 下面是一个代码示例,展示了如何从宽字符串参数、从宽字符串视图和从 std::wstring 创建 Uri。

#include <winrt/Windows.Foundation.h>
#include <string_view>

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    using namespace std::literals;

    winrt::init_apartment();

    // You can make a Uri from a wide string literal.
    Uri contosoUri{ L"http://www.contoso.com" };

    // Or from a wide string view.
    Uri contosoSVUri{ L"http://www.contoso.com"sv };

    // Or from a std::wstring.
    std::wstring wideString{ L"http://www.adventure-works.com" };
    Uri awUri{ wideString };
}

常用的属性访问器 Uri::Domain 也返回hstring类型 。

public:
    winrt::hstring Domain();

同时由于 hstring 的 std::wstring_view 的转换运算符,返回值可以自动转换。示例:

// Access a property of type hstring, via a conversion operator to a standard type.
std::wstring domainWstring{ contosoUri.Domain() }; // L"contoso.com"
domainWstring = awUri.Domain(); // L"adventure-works.com"

// Or, you can choose to keep the hstring unconverted.
hstring domainHstring{ contosoUri.Domain() }; // L"contoso.com"
domainHstring = awUri.Domain(); // L"adventure-works.com"

你可以使用 hstring::c_str function 函数从 hstring 获取标准宽字符串(正如你可以从 std::wstring 获取一样)。

#include <iostream>
std::wcout << tostringHstring.c_str() << std::endl;

hstring 是一个范围,因此你可以将其与基于范围的 for 或与 std::for_each 一起使用。 它还提供了一个比较运算符,用于自然、高效地与它在 C++ 标准库中的对应项进行比较。

很多 C++ 库使用了 std::string,并且仅与 UTF-8 文本配合。 winrt::to_stringwinrt::to_hstring 等方法可以用于来回转换。

WINRT_ASSERT 是宏定义,扩展到 _ASSERTE。功能是调试模式进行值比较。

winrt::hstring w{ L"Hello, World!" };

std::string c = winrt::to_string(w);
WINRT_ASSERT(c == "Hello, World!");

w = winrt::to_hstring(c);
WINRT_ASSERT(w == L"Hello, World!");

你可能会注意到有些代码在逻辑上应该接受 winrt::hstring 的 C++/WinRT 输入参数,但是实际上需要 winrt::param::hstring。

param 命名空间包含一组类型,专用于优化输入参数以自然地绑定到 C++ 标准库类型,以及避免副本和其他低效率现象。 你不应直接使用这些类型。 如果你要对自己的函数使用优化,则应使用 std::wstring_view。 另请参阅将参数传递到 ABI 边界

用于字符串格式化的一个选择是 std::wostringstream

#include <sstream>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.Xaml.Input.h>
...
void MainPage::OnPointerPressed(winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e)
{
    winrt::Windows::Foundation::Point const point{ e.GetCurrentPoint(nullptr).Position() };
    std::wostringstream wostringstream;
    wostringstream << L"Pointer pressed at (" << point.X << L"," << point.Y << L")" << std::endl;
    ::OutputDebugString(wostringstream.str().c_str());
}

这个示例可以格式化的输出调试信息。

可以将值传递给设置函数,以这种方式设置属性。例如:

// 正确
myTextBlock.Text(L"Hello!");
// 错误
myTextBlock.Text() = L"Hello!";

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

初始值列表 (std::initializer_list) 是 C++ 标准库构造。例如:可以使用初始值列表来调用 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 类型的参数。然后使用winrt::array_view 初始值列表构造函数。

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

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

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.

通过 C++/WinRT 将值装箱到 IInspectable

WinRT 不仅可对标量值进行装箱和取消装箱,而可使用 winrt::box_value 和 winrt::unbox_value 函数对大多数类型的数组进行这类操作(枚举数组除外) 。 但是只能使用 winrt::unbox_value_or 函数对标量值取消装箱。

向任何运行时类的实例传递需要 IInspectable 的函数。 但是你无法将标量值(如数值或文本值)直接传递到此类函数,也不能直接传递数组。 相反,标量或数组值需要封装到引用类对象内。 该封装过程称为对值进行装箱

不管将什么类型传递给 Windows 运行时 API,都可以对该类型进行装箱和取消装箱操作。

C++/WinRT 提供了 winrt::box_value 函数,该函数采用标量或数组值,并将装箱的值返回到 IInspectable中 。 对于取消 IInspectable 装箱并返回到标量或数组值,提供 winrt::unbox_value 函数 。 对于取消 IInspectable 装箱并返回到标量值,还提供 winrt::unbox_value_or 函数 。

取消值装箱的示例

LaunchActivatedEventArgs::Arguments 访问器函数返回 winrt::hstring,这是一个标量值。 我们可以将该 hstring 值进行装箱并将其传递到需要 IInspectable 的函数,如下所示。

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    ...
    rootFrame.Navigate(winrt::xaml_typename<BlankApp1::MainPage>(), winrt::box_value(e.Arguments()));
    ...
}

取消 IInspectable 装箱的示例

在自己的需要 IInspectable 的函数中,可以使用 winrt::unbox_value 取消装箱,也可以使用 winrt::unbox_value_or 通过默认值取消装箱。 还可以使用 try_as 取消装箱到 std::optional。

void Unbox(winrt::Windows::Foundation::IInspectable const& object)
{
    hstring hstringValue = unbox_value<hstring>(object); // Throws if object is not a boxed string.
    hstringValue = unbox_value_or<hstring>(object, L"Default"); // Returns L"Default" if object is not a boxed string.
    float floatValue = unbox_value_or<float>(object, 0.f); // Returns 0.0 if object is not a boxed float.
    std::optional<int> optionalInt = object.try_as<int>(); // Returns std::nullopt if object is not a boxed int.
}

确定装箱值的类型

如果收到装箱值但不确定它所包含的类型(需要知道类型以便取消装箱),可以查询装箱值的 IPropertyValue 接口,然后对其调用 Type。 下面是代码示例。

float pi = 3.14f;
auto piInspectable = winrt::box_value(pi);
auto piPropertyValue = piInspectable.as<winrt::Windows::Foundation::IPropertyValue>();
WINRT_ASSERT(piPropertyValue.Type() == winrt::Windows::Foundation::PropertyType::Single);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值