[MS] Making an agile version of a Windows Runtime delegate in C++/WinRT, part 4 - devamazonaws.blogspot.com

Last time, we wrote a wrapper delegate that checked whether the context it was being invoked from matched the context it was captured from.

    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);
            }
        };
    }

We did this by comparing context objects.

This obtains the current object context in order to compare it with the original one, and that means an internal Add­Ref, and then we have to explicitly Release it.

But there's a way to do this without having to obtain any objects.

The Co­Get­Context­Token function gives you an integer that uniquely identifies a live context object. You can then compare integers instead of having to compare COM objects.

Note that the context must be live. Once you allow the context to destruct, the value might be reused. (You're already used to this. Process and thread IDs work the same way: They remain unique as long as they are running or you still have a reference to them by a HANDLE.)

Since we are keeping the context alive by the IContext­Callback returned by Co­Get­Object­Context, we can pair that with a context token to make for faster checks in the future.

ULONG_PTR get_context_token()                       
{                                                   
    ULONG_PTR token;                                
    winrt::check_hresult(CoGetContextToken(&token));
    return token;                                   
}                                                   

    if (d.try_as<::INoMarshal>()) {
        return [d = std::forward<Delegate>(d),
                context = winrt::capture<IContextCallback>(CoGetObjectContext),
                token = get_context_token()](auto&&...args) {
            if (token == get_context_token()) {
                d(std::forward<decltype(args)>(args)...);
            } else {
                throw winrt::hresult_error(CO_E_NOT_SUPPORTED);
            }
        };
    }

Are we done?

Of course not!

There's a flaw in the above code. More next time.


Post Updated on July 23, 2026 at 03:00PM
Thanks for reading
from devamazonaws.blogspot.com

Comments

Popular posts from this blog

[MS] Pulling a single item from a C++ parameter pack by its index, remarks - devamazonaws.blogspot.com

[MS] Boosting Azure DevOps Security with GHAS Code Scanning - devamazonaws.blogspot.com

[MS] How can I check that all the changes in a git branch have been cherry-picked or rebased into its upstream branch? - devamazonaws.blogspot.com