Making an agile version of a Windows Runtime delegate in C++/WinRT, part 5
cppdashboard.dev/r/2026/08/making-an-agile-version-of-a-windows-runtime-delegate-in-cpp-6This article discusses handling non-marshalable delegates in C++/WinRT, focusing on ensuring proper context during destruction to avoid threading issues. It introduces a custom deleter using std::unique_ptr to manage the lifecycle of delegates safely.
From the article
So far, we have handled the case of a non-marshalable delegate by wrapping it in a delegate that fails with CO_ E_ NOT_ SUPPORTED if used in a manner that would require marshaling.
if (d.try_as<::INoMarshal>()) { return [d, token = get_context_token(), context = winrt::capture<IContextCallback>(CoGetObjectContext)](auto&&...args) { if (token == get_context_token()) { d(std::forward<decltype(args)>(args)...); } else { throw winrt::hresult_error(CO_E_NOT_SUPPORTED); } }; } While we copy and invoke the delegate only from its original context, we still destruct it from a possibly-wrong context.
This is a serious problem not just because the non-agile delegate might not be using thread-safe atomic instructions to manage its reference count, but even worse, if the release drops the reference…
Share this resource