Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 4 - The Old New Thing
Skip to main content
Dev Blogs
AI
All .NET posts
.NET MAUI<br>ASP.NET Core<br>Blazor<br>Entity Framework
C++<br>C#<br>F#<br>TypeScript
NuGet<br>Servicing<br>.NET Blog in Chinese
Microsoft for Developers<br>Agent Framework<br>Develop from the cloud<br>Xcode<br>ISE Developer<br>TypeScript<br>PowerShell<br>Python<br>Java<br>Java Blog in Chinese<br>Go<br>Microsoft Edge Dev<br>Microsoft 365 Developer<br>Microsoft Entra Identity Developer<br>Microsoft Entra PowerShell
Visual Studio<br>Visual Studio Code<br>Aspire
All things Azure<br>Azure SDK<br>Azure VM Runtime Team<br>Microsoft Azure<br>Azure Cosmos DB<br>Azure DocumentDB<br>Azure Data Studio<br>Azure SQL<br>DevOps<br>DirectX<br>Microsoft Foundry<br>Power Platform
OData<br>Unified Data Model (IDEAs)
Windows Command Line<br>#ifdef Windows<br>Inside MSIX<br>MIDI and music<br>React Native<br>The Old New Thing<br>Windows Developer
Raymond Chen
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. 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<br>struct force_marshal :<br>winrt::implements, IUnknown, winrt::non_agile><br>template<br>force_marshal(Arg&& arg) : m_p(std::forward(arg)) {}<br>Smart m_p;<br>};
The force_marshal 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 object rather than copied.
Now it’s a matter of plumbing this reference all the way down.
template<br>struct fake_agile_ref<br>⟦ ... ⟧
template<br>fake_agile_ref(Arg&& p) : m_raw(winrt::get_abi(p))<br>if (m_raw) {<br>m_context = winrt::capture(CoGetObjectContext);<br>m_token = get_context_token();<br>m_git = winrt::create_instance(CLSID_StdGlobalInterfaceTable);<br>winrt::check_hresult(m_git->RegisterInterfaceInGlobal(<br>winrt::make>(std::forward(p)).get(),<br>__uuidof(IUnknown), &m_cookie));
⟦ ... ⟧<br>};
template<br>std::remove_reference_t make_agile_delegate(Delegate&& d)<br>if (d.try_as()) {<br>return d;
if (d.try_as()) {<br>return [agile = fake_agile_ref(std::forward(d)](auto&&...args) {<br>return agile.get()(std::forward(args)...);<br>};
return [agile = winrt::agile_ref(d)](auto&&...args) {<br>return agile.get()(std::forward(args)...);<br>};
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<br>Old New Thing
Topics<br>Code
Share
Author
Raymond Chen
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.
0 comments
Be the first to start the discussion.
Leave a commentCancel reply<br>Sign in
Code of Conduct
Read next
August 7, 2026
Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5
Raymond Chen
Stay informed
Get notified when new posts are published.
Email *
Country/Region *<br>Select...United StatesAfghanistanÅland IslandsAlbaniaAlgeriaAmerican SamoaAndorraAngolaAnguillaAntarcticaAntigua and BarbudaArgentinaArmeniaArubaAustraliaAustriaAzerbaijanBahamasBahrainBangladeshBarbadosBelarusBelgiumBelizeBeninBermudaBhutanBoliviaBonaireBosnia and HerzegovinaBotswanaBouvet IslandBrazilBritish Indian Ocean TerritoryBritish Virgin IslandsBruneiBulgariaBurkina FasoBurundiCabo VerdeCambodiaCameroonCanadaCayman IslandsCentral African RepublicChadChileChinaChristmas IslandCocos (Keeling) IslandsColombiaComorosCongoCongo (DRC)Cook IslandsCosta RicaCôte dIvoireCroatiaCuraçaoCyprusCzechiaDenmarkDjiboutiDominicaDominican RepublicEcuadorEgyptEl SalvadorEquatorial GuineaEritreaEstoniaEswatiniEthiopiaFalkland IslandsFaroe...