从子 COM 对象获取父 COM 对象

mar*_*pic 1 c com directx winapi direct3d12

ID3D12GraphicsCommandList接口由继承ID3D12CommandList。那么,如果我有一个ID3D12GraphicsCommandList对象,我如何获得相应的ID3D12CommandList对象?

  1. 排版会起作用吗?
    ID3D12GraphicsCommandList *gcl = ...;
    ID3D12CommandList *cl = (ID3D12CommandList*)gcl;
Run Code Online (Sandbox Code Playgroud)
  1. QueryInterface 会工作吗?
    ID3D12GraphicsCommandList *gcl = ...;
    ID3D12CommandList *cl;
    HRESULT result = ID3D12GraphicsCommandList_QueryInterface(gcl,
                                                              &IID_ID3D12CommandList,
                                                              (void**)&cl);
Run Code Online (Sandbox Code Playgroud)
  1. 我需要做其他事情吗?

谢谢。

IIn*_*ble 5

  1. 排版会起作用吗?

不,不是在 C 中。通过接口指针请求不同的接口可能需要调整指针。在这些情况下,简单地将指向一个接口的指针重新解释为指向另一个接口的指针会中断(请参阅下文以获得更深入的探索)。

在 C++ 中,这可以通过提供用户定义的转换函数来实现,尽管它非常脆弱,并且可以以微妙和不那么微妙的方式惊人地中断。

  1. QueryInterface 会工作吗?

是的。这是通过接口指针请求不同接口的正确方法。您提供的代码是正确的。

  1. 我需要做其他事情吗?

不,不是真的,只要您遵循 COM 规则。一个细节经常被忽视:成功调用QueryInterface增加了接口上的引用计数,因此您将不得不Release调用从调用返回的每个接口QueryInterface


为什么投射不安全

因此,如果IDerived继承 fromIBase那么为什么不是明显的选择,从IDerived*to 转换的指针IBase*有效?TL;DR 是,因为 COM 不提供使其有效的保证。

COM 的要求极其简约。事实上

COM 的唯一语言要求是代码是用一种可以创建指针结构的语言生成的,并且可以显式或隐式地通过指针调用函数。

这允许使用多种编程语言来实现 COM 接口。另一方面,COM 在ABI如何映射到语言级构造方面提供很少的保证。对于接口继承尤其如此:

COM 中的继承并不意味着代码重用。

的实现IDerived可以选择重用IBase的实现,或者提供自己的实现。它还允许对IBase的接口的调用根据调用它的接口(IDerivedIBase)具有不同的行为。这很灵活,但有一个缺陷,即不能保证通过指针转换来导航界面层次结构。

但还有更多!COM还有一个规则这是十分容易理解的,但经常被忽视:

从 COM 客户端的角度来看,始终为每个接口完成引用计数。客户永远不应该假设一个对象对所有接口使用相同的计数器

同样,这为实现提供了很大的灵活性,但需要客户端精心管理他们的接口指针。QueryInterface是实现用来跟踪未完成的接口引用的工具。强制转换指针避开了这一关键的管理任务,创造了一个机会来结束引用计数为零的接口指针。

这些是规则和派生的保证在起作用。现在,实际上,指针强制转换会出人意料地经常出现。因此,如果您是一名开发人员,在正确的代码和尚未失败的代码之间没有太大区别,那么请务必继续并指向您心中的喜悦。

如果,另一方面,你是一个开发人员是骄傲地交付,凭借的是正确的工作软件,然后QueryInterface始终需要浏览一个实现的接口表面。


好的,但 DirectX 实际上并不使用 COM!

真的。DirectX 使用 COM 的一个小子集,通常称为Nano-COM。虽然大部分 COM 不适用,但 COM 的 ABI 方面适用。由于此答案仅讨论 ABI 方面,因此它同样适用于 COM 和 DirectX。

请参阅Microsoft 文档

  • @RbMm 您似乎对 API 和 ABI 感到困惑。`I2` 将支持 `I1` API,但可能不兼容 ABI(因此存在问题)。如果是这样,那么类型转换将不起作用。现在,当前的 MSVC 工具链有可能以 ABI 兼容的方式实现它,但问题是关于 COM 的,而不是它的一个特定实现。 (2认同)