Boxing and unboxing scalar values to IInspectable with C++/WinRT

The IInspectable interface is the root interface of every runtime class in the Windows Runtime (WinRT). This is an analogous idea to IUnknown being at the root of every COM interface and class; and System.Object being at the root of every Common Type System class.

In other words, a function that expects IInspectable can be passed an instance of any runtime class. But you can't directly pass a scalar value, such as a numeric or text value, to such a function. Instead, a scalar value needs to be wrapped inside a reference class object. That wrapping process is known as boxing the value.

C++/WinRT provides the winrt::box_value function, which takes a scalar value and returns the value boxed into an IInspectable. For unboxing an IInspectable back into a scalar value, there are the winrt::unbox_value and winrt::unbox_value_or functions.

Examples of boxing a value

The LaunchActivatedEventArgs::Arguments accessor function returns a winrt::hstring, which is a scalar value. We can box that hstring value and pass it to a function that expects IInspectable like this.

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

To set the content property of a XAML Button, you call the Button::Content mutator function. To set the content property to a string value, you can use this code.

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

First, the hstring conversion constructor converts the string literal into an hstring. Then the overload of winrt::box_value that takes an hstring is invoked.

Examples of unboxing an IInspectable

In your own functions that expect IInspectable, you can use winrt::unbox_value to unbox, and you can use winrt::unbox_value_or to unbox with a default value.

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.
}

Determine the type of a boxed value

If you receive a boxed value and you're unsure what type it contains (you need to know its type in order to unbox it), then you can query the boxed value for its IPropertyValue interface, and then call Type on that. Here's a code example.

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

Important APIs