Article

Making an agile version of a Windows Runtime delegate in C++/WinRT, part 5

The Old New Thing ·The Old New Thing ·Published 2026-07-24 ·5 min read

This 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


Discovered 2026-08-02 Source The Old New Thing Archive 2026-08 →