在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第 9 部分
摘要
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/
相似文章
在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,第一部分
本文介绍如何通过将委托包装在 agile_ref 中来在 C++/WinRT 中创建 Windows Runtime 委托的敏捷版本,并承诺在第二部分中提供更多细节。
在C++/WinRT中创建Windows Runtime委托的敏捷版本,第8部分
本文讨论了在C++/WinRT中创建敏捷委托时修复异常安全性问题,解决了未指定lambda捕获构造顺序导致的引用泄漏。
在C++/WinRT中创建Windows运行时代理的敏捷版本,第3部分
这篇博客文章讨论了在C++/WinRT中处理实现INoMarshal接口的Windows运行时代理,提供了一个敏捷的代理包装器,通过检查调用上下文来避免封送错误。
在 C++/WinRT 中制作 Windows Runtime 委托的敏捷版本,第5部分
本文继续系列文章,介绍如何在 C++/WinRT 中实现敏捷委托,解决在正确上下文中销毁非敏捷委托的问题,方法是使用自定义删除器和 IContextCallback。
在C++/WinRT中创建敏捷版的Windows Runtime委托,第6部分
系列文章第6部分:在C++/WinRT中创建敏捷的Windows Runtime委托,修复std::unique_ptr自定义删除器构造函数可能引发的异常问题。