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

Примечание.

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

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

Другими словами, функции, которая ожидает 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.

Примеры упаковки значения

Функция доступа LaunchActivatedEventArgs::Arguments возвращаетwinrt::hstring (скалярное значение). Вы можете упаковать это значение hstring и передать его функции, ожидающей IInspectable.

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

Чтобы задать свойство содержимого Button 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