在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第 9 部分

The Old New Thing (Raymond Chen) 新闻

摘要

Raymond Chen 继续他的系列文章,讨论在 C++/WinRT 中创建敏捷版 Windows Runtime 委托,并比较 C++/WinRT、C++/CX 和 WRL 如何处理不可封送委托和敏捷引用创建。

<p>我们在尝试用 C++/WinRT 创建 Windows Runtime 委托的敏捷版本时,有一半以上的时间都在处理 <a title="在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第 8 部分" href="https://devblogs.microsoft.com/oldnewthing/20260729-00/?p=112570">声明不可封送性的委托</a> 这种情况。但这到底有多大影响呢?</p><p>我考察了 Windows Runtime 的三个主要 C++ 实现:C++/WinRT、C++/CX 和 WRL。</p><p>C++/WinRT 实现<a href="https://github.com/microsoft/cppwinrt/blob/55f1b452aca069d6ac7eaad3e05cc1058fc39d27/strings/base_delegate.h#L88">对 <code>IAgileObject</code> 进行了优化</a>,但对于非敏捷对象,<a href="https://github.com/microsoft/cppwinrt/blob/55f1b452aca069d6ac7eaad3e05cc1058fc39d27/strings/base_delegate.h#L95">它会直接使用 <code>agile_<wbr />ref</code></a>,而不检查 <code>INoMarshal</code>。这意味着,声明不可封送性的委托在用作事件处理程序时,C++/WinRT 将始终拒绝它。</p><p>C++/CX 实现<a href="https://github.com/ojdkbuild/tools_toolchain_vs2013e/blob/a6cea36c2e52a571864986ee2957fbd91d6f4ce8/VC/include/agile.h#L207">在从不同单元使用包装器时,会延迟创建对原始委托的敏捷引用</a>。如果原始委托不可封送,这意味着只有在以需要可封送委托的方式使用包装器时,才会产生 <code>CO_<wbr />E_<wbr />NOTSUPPORTED</code>。</p><p>WRL 实现没有对 <code>IAgileObject</code> 进行优化,尽管<a href="https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/winrt/wrl/event.h#L278">它提到这是一种可能的优化</a>。它总是急切地创建敏捷引用,这意味着如果原始委托不可封送,则无法将其添加到敏捷事件源。</p><p>好了,下面用表格来总结一下。</p><table class="cp3" style="border-collapse: collapse;" border="1" cellspacing="0" cellpadding="3"><tbody><tr><th rowspan="2">事件源</th><th rowspan="2">C++/WinRT</th><th rowspan="2">C++/CX</th><th colspan="2">WRL</th><th rowspan="2">我们的版本</th></tr><tr><th>单线程</th><th>多线程</th></tr><tr><td>优化敏捷委托</td><td>是</td><td>是</td><td>不适用</td><td>否</td><td>是</td></tr><tr><td>避免包装敏捷委托</td><td>是</td><td>否</td><td>从不包装</td><td>否</td><td>是</td></tr><tr><td>敏捷引用创建</td><td>急切</td><td>延迟</td><td>从不</td><td>急切</td><td>急切</td></tr><tr><td>不可封送委托</td><td>拒绝</td><td>允许(以非敏捷方式<br />使用)</td><td>允许(始终<br />以非敏捷方式使用)</td><td>拒绝</td><td>允许(以非敏捷方式<br />使用)</td></tr></tbody></table><p>现在,也许你认为我们太努力了。(也许确实如此。)在这种情况下,你可以移除对任何你认为不需要的情况的支持。</p><p><a href="https://devblogs.microsoft.com/oldnewthing/20260730-00/?p=112573">在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第 9 部分</a>一文首发于 <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>。</p>
查看原文
查看缓存全文

缓存时间: 2026/07/31 06:26

# 在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第 9 部分 - The Old New Thing 来源:https://devblogs.microsoft.com/oldnewthing/20260730-00?p=112573 2026年7月30日 0 条反应 我们花在尝试用 C++/WinRT 创建 Windows Runtime 委托的敏捷版本上的时间,有一半以上都用在了处理声明不可封送性的委托上(链接)。但这到底有多重要呢? 我考察了 Windows Runtime 的三种主要 C++ 实现:C++/WinRT、C++/CX 和 WRL。 C++/WinRT 实现针对 `IAgileObject` 有一个优化(链接),但对于非敏捷对象,它直接使用 `agile_ref`(链接),而不检查 `INoMarshal`。这意味着,声明不可封送性的委托在用作事件处理程序时,总是会被 C++/WinRT 拒绝。 C++/CX 实现会在包装器从不同单元使用时延迟创建对原始委托的敏捷引用(链接)。如果原始委托不可封送,则意味着只有在需要可封送委托的方式下使用包装器时,才会产生 `CO_E_NOTSUPPORTED`。 WRL 实现没有针对 `IAgileObject` 的优化,尽管它提到这是一种可能的优化(链接)。它总是立即创建敏捷引用,这意味着如果原始委托不可封送,则无法将其添加到敏捷事件源。 好了,让我们用表格来总结一下。 | 事件源 | C++/WinRT | C++/CX | WRL | 我们的版本(单线程) | 我们的版本(多线程) | |---|---|---|---|---|---| | 优化敏捷委托 | 是 | 是 | 不适用 | 否 | 是 | | 避免包装敏捷委托 | 是 | 否 | 从不包装 | 否 | 是 | | 敏捷引用创建 | 即时 | 延迟 | 从不 | 即时 | 即时 | | 不可封送委托 | 被拒绝 | 如果以非敏捷方式使用则允许 | 允许(始终以非敏捷方式使用) | 被拒绝 | 如果以非敏捷方式使用则允许 | 现在,也许你会觉得我们工作得太辛苦了。(也许确实如此。)在这种情况下,你可以移除对自己不需要的任意情况的支持。 ### 分类 ### 主题 ## 作者 Raymond Chen Raymond 参与 Windows 的演进已有 30 多年。2003 年,他创办了一个名为 The Old New Thing 的网站,其受欢迎程度远超他最疯狂的想象,这一发展至今仍让他感到不寒而栗。该网站还催生了一本书,巧合的是,书名也叫 The Old New Thing(Addison Wesley 2007)。他偶尔会出现在 Windows Dev Docs Twitter 账号上,讲一些毫无有用信息的故事。 ## 阅读下一篇 ## 保持关注 当新文章发布时收到通知。 关注此博客 - https://twitter.com/ChenCravat - YouTube(https://www.youtube.com/playlist?list=PLlrxD0HtieHge3_8Dm48C0Ns61I6bHThc) - https://github.com/oldnewthing - https://devblogs.microsoft.com/oldnewthing/feed/

相似文章