Упаковка и распаковка значений в IInspectable с помощью C++/WinRT

Note

Вы можете упаковывать и распаковывать не только скалярные значения, но и большинство типов массивов (за исключением массивов перечислений) с помощью функций winrt::box_value и winrt::unbox_value . С помощью функции winrt::unbox_value_or можно распаковывать только скалярные значения.

Интерфейс IInspectable — это корневой интерфейс каждого класса среды выполнения в среда выполнения Windows (WinRT). Это аналогичная идея, что IUnknown находится в корне каждого com-интерфейса и класса; и System.Object в корне каждого класса Common Type System .

Другими словами, функция, которая ожидает, что IInspectable может быть передана экземпляру любого класса среды выполнения. Но вы не можете напрямую передать такой функции скалярное значение (например, числовое или текстовое значение), а также массив. Вместо этого скалярное или массивное значение необходимо упаковать в объект класса ссылок. Этот процесс называется упаковкой значения.

Это важно

Вы можете упаковывать и распаковывать любой тип, который вы можете передать в API среда выполнения Windows. Другими словами, тип среда выполнения Windows. Числовые и текстовые значения (строки) и массивы приведены в некоторых примерах выше. Другой пример — это struct, который определяется в IDL. Если вы попытаетесь упаковать обычный C++ struct (то есть не определённый в IDL), компилятор напомнит вам, что можно упаковывать только тип среда выполнения Windows. Класс среды выполнения — это тип среда выполнения Windows, но их, конечно, можно передавать в API среда выполнения Windows без упаковки.

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()));
    ...
}

Чтобы задать свойство содержимого кнопки XAML, вызовите функцию мутатора Button::Content . Чтобы задать свойство содержимого строковым значением, можно использовать этот код.

Button().Content(winrt::box_value(L"Clicked"));

Во-первых, конструктор преобразования hstring преобразует строковый литерал в hstring. Затем вызывается перегрузка winrt::box_value, принимающая hstring.

Примеры распаковки 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. Ниже приведен пример кода.

WINRT_ASSERT — это определение макроса, и оно расширяется до _ASSERTE.

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);

Важные API