Raymond Chen continues his series on creating a fake agile wrapper in COM, explaining how to move non-marshalable objects by forwarding references into the force_marshal wrapper and discussing C++/WinRT deduction guides.
<p>Last time, we successfully <a title="Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 3" href="https://devblogs.microsoft.com/oldnewthing/20260805-00/?p=112591"> our plan to use the global interface table to hold created a fake agile wrapper that is technically agile, even though it isn’t useful outside its home apartment</a>. I noted that there are opportunities for fine-tuning.</p>
<p>One thing we can do is move the non-marshalable COM object rather than copying it. This means forwarding the reference all the way into the <code>force_<wbr />marshal</code> wrapper.</p>
<pre>template<typename Smart>
struct force_marshal :
winrt::implements<force_marshal<Smart>, IUnknown, winrt::non_agile>
{
<span style="border: solid 1px currentcolor; border-bottom: none;">template<typename Arg> </span>
<span style="border: solid 1px currentcolor; border-top: none;">force_marshal(Arg&& arg) : m_p(std::forward<Arg>(arg)) {}</span>
Smart m_p;
};
</pre>
<p>The <code>force_<wbr />marshal<Smart></code> now takes anything and forwards it into the smart pointer. This means that if the inbound parameter is an rvalue reference to a smart pointer, the COM reference is moved into the <code>force_<wbr />marshal<Smart></code> object rather than copied.</p>
<p>Now it’s a matter of plumbing this reference all the way down.</p>
<pre>template<typename T>
struct fake_agile_ref
{
⟦ ... ⟧
<span style="border: solid 1px currentcolor;">template<typename Arg></span>
fake_agile_ref(<span style="border: solid 1px currentcolor;">Arg&&</span> p) : m_raw(winrt::get_abi(p))
{
if (m_raw) {
m_context = winrt::capture<IContextCallback>(CoGetObjectContext);
m_token = get_context_token();
m_git = winrt::create_instance<IGlobalInterfaceTable>(CLSID_StdGlobalInterfaceTable);
winrt::check_hresult(m_git->RegisterInterfaceInGlobal(
winrt::make<force_marshal<Smart>>(<span style="border: solid 1px currentcolor;">std::forward<Arg>(p)</span>).get(),
__uuidof(IUnknown), &m_cookie));
}
}
⟦ ... ⟧
};
template<typename Delegate>
std::remove_reference_t<Delegate> make_agile_delegate(Delegate&& d)
{
if (d.try_as<::IAgileObject>()) {
return d;
}
if (d.try_as<::INoMarshal>()) {
return [agile = fake_agile_ref(<span style="border: solid 1px currentcolor;">std::forward<Delegate>(d)</span>](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
</pre>
<p>Note that we didn’t have to update the deduction guides for <code>fake_<wbr />agile_<wbr />ref</code> to add forwarding support. Deduction guides are matched against the constructor invocation to determine which template specialization to use, but they are not used for actually invoking the constructor. That happens by matching against the constructors themselves. So if somebody tries to create a <code>fake_<wbr />agile_<wbr />ref</code> from an rvalue reference, the deduction guide for <code>const&</code> steers class template argument deduction (CTAD) toward the correct specialization, and then when the compiler actually looks for a constructor, it finds the one that takes an rvalue reference.</p>
<p>Remember how I complained that we couldn’t use <code>std::<wbr />unique_ptr</code> to avoid a lot of boilerplate in <code>fake_<wbr />agile_<wbr />ref</code> to manage the fact that cookies cannot be copied?</p>
<p>Yeah, so maybe I lied.</p>
<p>We’ll look at it next time.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260806-00/?p=112595">Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 4</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
# Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 4 - The Old New Thing
Source: [https://devblogs.microsoft.com/oldnewthing/20260806-00?p=112595](https://devblogs.microsoft.com/oldnewthing/20260806-00?p=112595)
Last time, we successfully[our plan to use the global interface table to hold created a fake agile wrapper that is technically agile, even though it isn’t useful outside its home apartment](https://devblogs.microsoft.com/oldnewthing/20260805-00/?p=112591)\. I noted that there are opportunities for fine\-tuning\.
One thing we can do is move the non\-marshalable COM object rather than copying it\. This means forwarding the reference all the way into the`force\_marshal`wrapper\.
```
template<typename Smart>
struct force_marshal :
winrt::implements<force_marshal<Smart>, IUnknown, winrt::non_agile>
{
template<typename Arg>
force_marshal(Arg&& arg) : m_p(std::forward<Arg>(arg)) {}
Smart m_p;
};
```
The`force\_marshal<Smart\>`now takes anything and forwards it into the smart pointer\. This means that if the inbound parameter is an rvalue reference to a smart pointer, the COM reference is moved into the`force\_marshal<Smart\>`object rather than copied\.
Now it’s a matter of plumbing this reference all the way down\.
```
template<typename T>
struct fake_agile_ref
{
⟦ ... ⟧
template<typename Arg>
fake_agile_ref(Arg&& p) : m_raw(winrt::get_abi(p))
{
if (m_raw) {
m_context = winrt::capture<IContextCallback>(CoGetObjectContext);
m_token = get_context_token();
m_git = winrt::create_instance<IGlobalInterfaceTable>(CLSID_StdGlobalInterfaceTable);
winrt::check_hresult(m_git->RegisterInterfaceInGlobal(
winrt::make<force_marshal<Smart>>(std::forward<Arg>(p)).get(),
__uuidof(IUnknown), &m_cookie));
}
}
⟦ ... ⟧
};
template<typename Delegate>
std::remove_reference_t<Delegate> make_agile_delegate(Delegate&& d)
{
if (d.try_as<::IAgileObject>()) {
return d;
}
if (d.try_as<::INoMarshal>()) {
return [agile = fake_agile_ref(std::forward<Delegate>(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
```
Note that we didn’t have to update the deduction guides for`fake\_agile\_ref`to add forwarding support\. Deduction guides are matched against the constructor invocation to determine which template specialization to use, but they are not used for actually invoking the constructor\. That happens by matching against the constructors themselves\. So if somebody tries to create a`fake\_agile\_ref`from an rvalue reference, the deduction guide for`const&`steers class template argument deduction \(CTAD\) toward the correct specialization, and then when the compiler actually looks for a constructor, it finds the one that takes an rvalue reference\.
Remember how I complained that we couldn’t use`std::unique\_ptr`to avoid a lot of boilerplate in`fake\_agile\_ref`to manage the fact that cookies cannot be copied?
Yeah, so maybe I lied\.
We’ll look at it next time\.
### Category
### Topics
## Author

Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.
Raymond Chen continues his series on creating a fake agile wrapper for non-marshalable COM objects by wrapping them in a marshalable object, enabling registration in the global interface table while preserving undefined-behavior-free failures in other apartments.
Raymond Chen describes a technique for creating a fake agile wrapper in COM that uses the Global Interface Table to automatically release an object when its source apartment shuts down, addressing a problem with context callback failures.
Raymond Chen explains how to use std::unique_ptr to manage a registration cookie in a fake agile wrapper, discussing integer-to-pointer round-tripping and the wil::unique_any alternative.
Raymond Chen continues his series on building an agile Windows Runtime delegate in C++/WinRT, comparing how C++/WinRT, C++/CX, and WRL handle non-marshalable delegates and agile reference creation.
This blog post discusses handling Windows Runtime delegates that implement the INoMarshal interface in C++/WinRT, providing an agile delegate wrapper that checks the calling context to avoid marshaling errors.