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.
<p>Last time, we <a title="Making an agile version of a Windows Runtime delegate in C++/WinRT, part 2" href="https://devblogs.microsoft.com/oldnewthing/20260721-00/?p=112550"> made a small but significant optimization to making an agile version of a Windows Runtime delegate</a>. But there’s another case we missed.</p>
<p>That case is an object that implements the <code>INoMarshal</code> interface, which means “Do not marshal this object.” For these objects, the <code>RoGetAgileReference</code> function fails to create an agile reference and returns <code>CO_<wbr />E_<wbr />NOT_<wbr />SUPPORTED</code>. This function is what powers the <code>agile_<wbr />ref</code> class, so if you ask for an <code>agile_<wbr />ref</code> to an object that refuses to be marshaled, you get an <code>CO_<wbr />E_<wbr />NOT_<wbr />SUPPORTED</code> exception.</p>
<p>The catch is that this error is produced at the creation of the agile reference. If in practice all your uses of the agile reference are from the original context, you never actually needed to marshal the object, but too bad, you get the error anyway.</p>
<p>So let’s teach our agile delegate wrapper about delegates that deny marshalability: If the wrapper is invoked on the same context that the original delegate belongs to, then everything is fine. But if you try to invoke the wrapper from another context, then you get the <code>CO_<wbr />E_<wbr />NOT_<wbr />SUPPORTED</code> exception.</p>
<p>Here’s our first try. (Foreshadowing: Since I call this a “first try”, that suggests we’re going to have a second try.)</p>
<pre>// Don't use this yet - read to the end of the series
template<typename Delegate>
Delegate make_agile_delegate(Delegate const& d)
{
if (d.try_as<::IAgileObject>()) {
return d;
}
<span style="border: solid 1px currentcolor; border-bottom: none;">if (d.try_as<::INoMarshal>()) { </span>
<span style="border: 1px currentcolor; border-style: none solid;"> return [d, context = winrt::capture<IContextCallback>(CoGetObjectContext)](auto&&...args) {</span>
<span style="border: 1px currentcolor; border-style: none solid;"> if (context == winrt::capture<IContextCallback>(CoGetObjectContext)) { </span>
<span style="border: 1px currentcolor; border-style: none solid;"> d(std::forward<decltype(args)>(args)...); </span>
<span style="border: 1px currentcolor; border-style: none solid;"> } else { </span>
<span style="border: 1px currentcolor; border-style: none solid;"> throw winrt::hresult_error(CO_E_NOT_SUPPORTED); </span>
<span style="border: 1px currentcolor; border-style: none solid;"> } </span>
<span style="border: 1px currentcolor; border-style: none solid;"> }; </span>
<span style="border: solid 1px currentcolor; border-top: none;">} </span>
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
</pre>
<p>If the object has the <code>INoMarshal</code> marker interface, then we capture the original context into our wrapper delegate. At invoke time, the wrapper checks whether the invoke context equals the captured context. If so, then all is good, and we call the original delegate. Otherwise, we throw the exception that <code>RoGetAgileReference</code> uses to say “Sorry, I can’t marshal this object.”</p>
<p>If we take a universal reference to the <code>Delegate</code>, we gain the ability to <code>std::move()</code> out of the inbound delegate if it is an rvalue reference.</p>
<pre>template<typename Delegate>
<span style="border: solid 1px currentcolor;">std::remove_reference_t<Delegate></span> make_agile_delegate(Delegate&& d)
{
if (d.try_as<::IAgileObject>()) {
return d;
}
if (d.try_as<::INoMarshal>()) {
return [<span style="border: solid 1px currentcolor;">d = std::forward<Delegate>(d)</span>,
context = winrt::capture<IContextCallback>(CoGetObjectContext)](auto&&...args) {
if (context == winrt::capture<IContextCallback>(CoGetObjectContext)) {
d(std::forward<decltype(args)>(args)...);
} else {
throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
}
};
}
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
</pre>
<p>Next time, we’ll look at a small optimization we can make to this implementation to reduce the amount of work needed to check the context at invoke time.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260722-00/?p=112552">Making an agile version of a Windows Runtime delegate in C++/WinRT, part 3</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
# Making an agile version of a Windows Runtime delegate in C++/WinRT, part 3 - The Old New Thing
Source: [https://devblogs.microsoft.com/oldnewthing/20260722-00?p=112552](https://devblogs.microsoft.com/oldnewthing/20260722-00?p=112552)
Last time, we[made a small but significant optimization to making an agile version of a Windows Runtime delegate](https://devblogs.microsoft.com/oldnewthing/20260721-00/?p=112550)\. But there’s another case we missed\.
That case is an object that implements the`INoMarshal`interface, which means “Do not marshal this object\.” For these objects, the`RoGetAgileReference`function fails to create an agile reference and returns`CO\_E\_NOT\_SUPPORTED`\. This function is what powers the`agile\_ref`class, so if you ask for an`agile\_ref`to an object that refuses to be marshaled, you get an`CO\_E\_NOT\_SUPPORTED`exception\.
The catch is that this error is produced at the creation of the agile reference\. If in practice all your uses of the agile reference are from the original context, you never actually needed to marshal the object, but too bad, you get the error anyway\.
So let’s teach our agile delegate wrapper about delegates that deny marshalability: If the wrapper is invoked on the same context that the original delegate belongs to, then everything is fine\. But if you try to invoke the wrapper from another context, then you get the`CO\_E\_NOT\_SUPPORTED`exception\.
Here’s our first try\. \(Foreshadowing: Since I call this a “first try”, that suggests we’re going to have a second try\.\)
```
// Don't use this yet - read to the end of the series
template<typename Delegate>
Delegate make_agile_delegate(Delegate const& d)
{
if (d.try_as<::IAgileObject>()) {
return d;
}
if (d.try_as<::INoMarshal>()) {
return [d, context = winrt::capture<IContextCallback>(CoGetObjectContext)](auto&&...args) {
if (context == winrt::capture<IContextCallback>(CoGetObjectContext)) {
d(std::forward<decltype(args)>(args)...);
} else {
throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
}
};
}
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
```
If the object has the`INoMarshal`marker interface, then we capture the original context into our wrapper delegate\. At invoke time, the wrapper checks whether the invoke context equals the captured context\. If so, then all is good, and we call the original delegate\. Otherwise, we throw the exception that`RoGetAgileReference`uses to say “Sorry, I can’t marshal this object\.”
If we take a universal reference to the`Delegate`, we gain the ability to`std::move\(\)`out of the inbound delegate if it is an rvalue reference\.
```
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 [d = std::forward<Delegate>(d),
context = winrt::capture<IContextCallback>(CoGetObjectContext)](auto&&...args) {
if (context == winrt::capture<IContextCallback>(CoGetObjectContext)) {
d(std::forward<decltype(args)>(args)...);
} else {
throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
}
};
}
return [agile = winrt::agile_ref(d)](auto&&...args) {
return agile.get()(std::forward<decltype(args)>(args)...);
};
}
```
Next time, we’ll look at a small optimization we can make to this implementation to reduce the amount of work needed to check the context at invoke 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 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 article explains how to create an agile version of a Windows Runtime delegate in C++/WinRT by wrapping the delegate in an agile_ref, with a promise of more details in part 2.
This article continues a series on implementing agile delegates in C++/WinRT, addressing the issue of destructing non-agile delegates in the correct context using a custom deleter and IContextCallback.
This article discusses implementing an agile Windows Runtime delegate in C++/WinRT, focusing on using CoGetContextToken to compare context tokens for efficiency instead of comparing COM objects.
The article discusses a fix for exception safety in C++/WinRT when creating an agile delegate, addressing the issue of unspecified lambda capture construction order to prevent reference leaks.