Поделиться через


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

Замечание

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

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

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

Это важно

Вы можете упаковать и распаковать любой тип, который вы можете передать в API среды выполнения Windows. Другими словами, тип среды выполнения Windows. Числовые и текстовые значения (строки) и массивы приведены в некоторых примерах выше. Еще одним примером является struct, определяемый в IDL. Если вы попытаетесь обернуть обычный C++ struct (который не определен в IDL), компилятор напомнит вам, что можно обернуть только тип Windows Runtime. Класс среды выполнения является типом среды выполнения 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