用C++/WinRT制作敏捷版Windows运行时委托,第4部分

The Old New Thing (Raymond Chen) 工具

摘要

本文讨论在C++/WinRT中实现敏捷的Windows运行时委托,重点介绍使用CoGetContextToken比较上下文令牌以提高效率,而不是比较COM对象。

<p>上一次,我们编写了一个包装委托,<a title="用C++/WinRT制作敏捷版Windows运行时委托,第4部分" href="https://devblogs.microsoft.com/oldnewthing/20260722-00/?p=112552">检查它被调用的上下文是否与其被捕获的上下文匹配</a>。</p> <pre> if (d.try_as&lt;::INoMarshal&gt;()) { return [d = std::forward&lt;Delegate&gt;(d), context = winrt::capture&lt;IContextCallback&gt;(CoGetObjectContext)](auto&amp;&amp;...args) { if (context == winrt::capture&lt;IContextCallback&gt;(CoGetObjectContext)) { d(std::forward&lt;decltype(args)&gt;(args)...); } else { throw winrt::hresult_error(CO_E_NOT_SUPPORTED); } }; } </pre> <p>我们通过比较上下文对象来实现这一点。</p> <p>这会获取当前对象上下文以便与原始上下文进行比较,这意味着内部会调用<code>Add­Ref</code>,然后我们必须显式调用<code>Release</code>。</p> <p>但有一种方法可以在不获取任何对象的情况下完成此操作。</p> <p><code>Co­Get­Context­Token</code>函数会返回一个唯一标识活动上下文对象的整数。然后你可以比较整数,而无需比较COM对象。</p> <p>请注意,上下文必须是活动的。一旦允许上下文析构,该值可能会被重用。(你已经习惯这一点了。进程和线程ID以相同方式工作:只要它们仍在运行或者你通过<code>HANDLE</code>持有对它们的引用,它们就保持唯一。)</p> <p>由于我们通过<code>Co­Get­Object­Context</code>返回的<code>IContext­Callback</code>保持上下文活跃,我们可以将其与上下文令牌配对,以便将来进行更快的检查。</p> <pre><span style="border: solid 1px currentcolor; border-bottom: none;">ULONG_PTR get_context_token() </span> <span style="border: 1px currentcolor; border-style: none solid;">{ </span> <span style="border: 1px currentcolor; border-style: none solid;"> ULONG_PTR token; </span> <span style="border: 1px currentcolor; border-style: none solid;"> winrt::check_hresult(CoGetContextToken(&amp;token));</span> <span style="border: 1px currentcolor; border-style: none solid;"> return token; </span> <span style="border: solid 1px currentcolor; border-top: none;">} </span> if (d.try_as&lt;::INoMarshal&gt;()) { return [d = std::forward&lt;Delegate&gt;(d), context = winrt::capture&lt;IContextCallback&gt;(CoGetObjectContext), <span style="border: solid 1px currentcolor;">token = get_context_token()</span>](auto&amp;&amp;...args) { if (<span style="border: solid 1px currentcolor;">token == get_context_token()</span>) { d(std::forward&lt;decltype(args)&gt;(args)...); } else { throw winrt::hresult_error(CO_E_NOT_SUPPORTED); } }; } </pre> <p>我们完成了吗?</p> <p>当然没有!</p> <p>上面的代码存在一个缺陷。下次继续。</p> <p>这篇<a href="https://devblogs.microsoft.com/oldnewthing/20260723-00/?p=112560">用C++/WinRT制作敏捷版Windows运行时委托,第4部分</a>的文章最初出现在<a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>上。</p>
查看原文
查看缓存全文

缓存时间: 2026/07/24 17:02

# 在 C++/WinRT 中创建敏捷版本的 Windows 运行时委托,第 4 部分 - 旧事新说 来源:https://devblogs.microsoft.com/oldnewthing/20260723-00?p=112560 上次,我们编写了一个包装委托,检查它被调用的上下文是否与它被捕获的上下文匹配(https://devblogs.microsoft.com/oldnewthing/20260722-00/?p=112552)。 `` if (d.try_as<::INoMarshal>()) { return [d = std::forward(d), context = winrt::capture(CoGetObjectContext)](auto&&...args) { if (context == winrt::capture(CoGetObjectContext)) { d(std::forward(args)...); } else { throw winrt::hresult_error(CO_E_NOT_SUPPORTED); } }; } `` 我们通过比较上下文对象来实现这一点。这会获取当前对象上下文以与原始上下文进行比较,这意味着内部会执行一次 `AddRef`,然后我们必须显式地 `Release` 它。但有一种方法可以不必获取任何对象就能做到。 `CoGetContextToken` 函数会返回一个整数,该整数唯一标识一个活动的上下文对象。然后你可以比较整数,而不是比较 COM 对象。注意,上下文必须是活动的。一旦你让上下文析构,该值可能会被重用。(你已经习惯了这一点。进程 ID 和线程 ID 的工作方式类似:只要它们还在运行,或者你通过 `HANDLE` 保留了引用,它们就保持唯一。) 由于我们通过 `CoGetObjectContext` 返回的 `IContextCallback` 保持上下文活动,我们可以将其与上下文令牌配对,以便将来进行更快的检查。 `` ULONG_PTR get_context_token() { ULONG_PTR token; winrt::check_hresult(CoGetContextToken(&token)); return token; } if (d.try_as<::INoMarshal>()) { return [d = std::forward(d), context = winrt::capture(CoGetObjectContext), token = get_context_token()](auto&&...args) { if (token == get_context_token()) { d(std::forward(args)...); } else { throw winrt::hresult_error(CO_E_NOT_SUPPORTED); } }; } `` 我们完成了?当然没有!上面的代码存在一个缺陷。下次继续。 ### 分类 ### 主题 ## 作者 Raymond Chen Raymond 参与 Windows 的演进已有 30 多年。2003 年,他创办了一个名为“旧事新说”的网站,其受欢迎程度远远超出他最疯狂的想象——这一发展至今仍让他感到毛骨悚然。该网站催生了一本书,巧合的是书名也叫《旧事新说》(Addison Wesley, 2007)。他偶尔会出现在 Windows Dev Docs 的 Twitter 账号上,讲述一些不传递有用信息的故事。

相似文章