Last time, we smuggled an arbitrary C++ value inside an IInspectable but noted the lack of safety. So let's add some safety.To ensure that the object is in-process, you can declare the interface as "local", meaning that the interface is for use only within a single process, and the MIDL compiler will not generate proxies for it. Even easier is just defining the interface manually, without involving the MIDL compiler at all.structDECLSPEC_UUID("⟦some guid⟧")IValueAsInspectable : ::IUnknown{};The trick here is that manually defining the interface lets us put C++ stuff inside it.template struct ValueAsInspectable;structDECLSPEC_UUID("⟦some guid⟧")IValueAsInspectable : ::IUnknown{ std::type_info const* type; template T& get_value() { if (*type != typeid(T)) { throw std::bad_cast(); } return static_cast(this) ->value; }};templatestruct ValueAsInspectable : winrt::implements{ T value; template ValueAsInspectable(Args&&... args) : value{ std::forward(args)... } { this->>type = std::addressof(typeid(T)); }};The IValueAsInspectable has a COM interface ID, so it can be queried for. But once you get it, you can call the C++ method get_value(). That method first validates that you are using the matching T, throwing a bad_cast exception if not. If you pass that test, then it returns a reference to the value hiding inside.And for convenience, we can add these helpers. The first two we have seen already:templatewinrt::Windows::Foundation::IInspectable MakeValueAsInspectable(Args&&... args){ return winrt::make( std::forward(args)...);}templatewinrt::Windows::Foundation::IInspectable MakeValueAsInspectable(T&& arg){ return winrt::make>( std::forward(arg));}Next are functions for extracting the value from an object that we believe to be a ValueAsInspectable.templateT& ValueRefFromInspectable( winrt::Windows::Foundation::IInspectable const& arg){ return arg.as()-> get_value();}templateT CopyValueFromInspectable( winrt::Windows::Foundation::IInspectable const& arg){ return ValueRefFromInspectable(arg);}templateT MoveValueFromInspectable( winrt::Windows::Foundation::IInspectable && arg){ return std::move(ValueRefFromInspectable(arg));}The basic function is ValueRefFromInspectable which produces an lvalue reference from an inspectable that we assume represents a ValueAsInspectable. (If we're wrong, it throws a bad_cast exception.) Building on that are two functions which either copy or move the value out of the ValueAsInspectable.I gave the function that returns an lvalue name that emphasizes that you get a reference from the inspectable, hoping to prevent people from getting a reference to an expiring inspectable:// Code in italics is wrong// Don't do this.auto& value = ValueRefFromInspectablt( co_await DoSomethingAsync());Note also that if you modify the value reference or move the value out of the inpectable, this affects the underlying object, which means that other people that have a reference to the same inspectable will see the object change state.void MutateTheWidget(winrt::Windows::Foundation::IInspectable obj){ auto& widget = ValueRefFromInspectable(obj); ⟦ do something that modifies the widget ⟧}winrt::fire_and_forget Sample(){ auto obj = co_await DoSomethingAsync(); MutateTheWidget(obj); auto& widget = ValueRefFromInspectable(obj); // this code sees that the widget has been mutated}But really, if you need a coroutine that produces a non-Windows Runtime type, then use a non-Windows Runtime coroutine library. I'm personally partial to wil::task (and its COM-aware buddy wil::com_task), seeing as I wrote it.