将 COM 接口转换为它继承的接口 [英] Casting COM interface to interface from which it inherits

查看:34
本文介绍了将 COM 接口转换为它继承的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 让我们有 I1 接口和 I2 继承自 I1 ( struct I2 : public I1 {..}> 在 c++ 符号中)
  • 让我们拥有指向I2接口的指针:I2* p2;
  • 我们需要获取指向 I1 接口的指针.
  • let we have I1 interface and I2 inherited from I1 ( struct I2 : public I1 {..} in c++ notation)
  • let we have pointer to I2 interface: I2* p2;
  • we need get pointer to I1 interface.

问题:

I1* p1 = p2;
// use p1

在没有任何假设、实现细节等的情况下,语义总是有效的.我们不需要在这里调用 QueryInterface(即 p2->QueryInterface(IID_PPV_ARGS(&p1) )

always valid by semantic without any assumption, implementations details etc. and we not need call QueryInterface here (ie p2->QueryInterface(IID_PPV_ARGS(&p1) )

(从 c++ 语法我们甚至不需要在 I1* p1 = p2; 中使用显式转换,在 c 中需要cast I1* p1 = (I1*)p2; 但这不是语言层问题)

(from c++ syntax we even not need use explicit cast in I1* p1 = p2; here, in c need cast I1* p1 = (I1*)p2; but this is not language layer question)

或者更具体的例子.假设某个函数需要指向 I1 接口的指针(void fn(I1*)),但我们有指向 I2* p2 的指针.我们可以按原样调用/传递 fn(p2)(根据 c++ 正式规则这是正确的 - 我们可以将指向派生类的指针传递给基指针)

or even more concrete example. say some function require pointer to I1 interface ( void fn(I1*)), but we have pointer to I2* p2. can we call/pass fn(p2) as is ( from c++ formal rules this is correct - we can pass pointer to derived class in place base pointer)

我认为,这是显而易见的,但因为存在另一个意见 -我只是想听听争论

my opinion that yes, and this is obvious, but because exist another opinion - I just wonder to hear the arguments

那么为什么这个演员可以?

so why is this cast ok?

  1. 我们可以使用 p2 指针从 I2 调用任何方法吗?是的
  2. I1 的任何方法也是 I2 的方法吗?是的,因为 I2 继承自 I1
  3. 12我们可以使用p2调用I1的任何方法指针
  1. we can call any method from I2 by using p2 pointer? yes
  2. any method of I1 was method of I2 too ? yes, because I2 inherit from I1
  3. from 1 and 2 we can call any method of I1 by using p2 pointer

这就够了.这里根本没有任何假设.通过使用 p2 指针(没有任何二进制修改),我们可以调用 I1 接口的任何方法.因此,这也是指向 I1 接口的有效指针

and this is enough. here no any assumption at all. by using p2 pointer as is (without any binary modification) we can call any methods of I1 interface. as result this is valid pointer to I1 interface too

可能,然后说下

I1* p1 = p2; // p1 == p2 on binary level, because COM interface have single vtable pointer
p1->func(..);// let func is  some method of I1 interface
p2->func(..);// will be the exactly same binary code as p1->func(..)

so p1->func(..) 当且仅当 p2->func(..) 正确时正确.但是 p2->func(..) 是正确的

so p1->func(..) correct when and only when, p2->func(..) is correct. but p2->func(..) is correct

有人可以说这有什么问题吗?是否存在隐藏假设?是否可以提供错误的示例?

can somebody say what's wrong here? are exist hidden assumption? are possible provide example when this is wrong?

一些附加说明

注意#1:

请不要混淆 caste I2I1 与 cast I1I2.这个转换是错误的,需要调用 QueryInterface

please not confuse caste I2 to I1 with cast I1 to I2. this cast is wrong and require call to QueryInterface

I1* p1;
I2* p2;
p2 = static_cast<I2*>(p1);            // wrong !!
p1->QueryInterface(IID_PPV_ARGS(&p2)) // ok

为什么?让存在接口 I3 也继承自 I1,但 I3 不继承自 I2I2 不是继承自 I3并且某些对象同时实现了 I2I3(作为结果和 I1)这意味着该对象包含最少 2 个不同的 vtable 指针 - 一个指向 I2,一个指向 I3当我们查询到I1接口时,QueryInterface可以返回

why? let exist interface I3 which is also inherit from I1, but I3 not inherit from I2 and I2 not inherit from I3 and some object implement both I2 and I3 (as result and I1) this mean that object containing how minimum 2 different vtable pointers - one to I2 and one to I3 when we query to I1 interface, QueryInterface can return

static_cast<I1*>(static_cast<I2*>(this)) // pointer to I1 via I2 vtable

但是可以返回

static_cast<I1*>(static_cast<I3*>(this)) // pointer to I1 via I3 vtable

如果 p1 指向 I2 vtable cast 可以,但是如果 p1 指向 I3 vtable - 会是错误的结果 - p1 在这种情况下不是指向 I2 的有效指针但再次 - 关于另一个转换的问题.所以这一切都与问题无关.

if p1 point I2 vtable cast will be ok, but if p1 point to I3 vtable - will be wrong result - p1 not valid pointer to I2 in this case but again - question about another conversion. so all this unrelated to question.

注意#2

但是在 p2->QueryInterface(IID_PPV_ARGS(&p1)) 之后我们可以得到另一个二进制指针 p1 ( p1 != p2> 在二进制级别)?

but after p2->QueryInterface(IID_PPV_ARGS(&p1)) we can got another binary pointer p1 ( p1 != p2 on binary level) ?

是的,可以!与之前的注释相同 - 如果对象继承 I2I3(两者都继承自 I1 但不是相互继承)在 p2->QueryInterface(IID_PPV_ARGS(&p1)) 调用的结果中可以返回或

yes, can! the same as in previous note - if object inherit I2 and I3 (both it inherit from I1 but not from each other) in result of p2->QueryInterface(IID_PPV_ARGS(&p1)) call can be returned or

static_cast<I1*>(static_cast<I2*>(this)) // in this case will be p2 == p1

static_cast<I1*>(static_cast<I3*>(this)) // in this case will be p2 != p1

所以如果 QueryInterface 可以返回不同的二进制指针到 I1(不等于原始的 p2) - 哪个是正确的?这是关于 p1 = p2;投错了吗?.两个指针都正确,可以用于I1接口的调用方法.

so if QueryInterface can return different binary pointer to I1 (not equal to original p2) - which one is correct? this say about p1 = p2; cast wrong ? no. the both pointers is correct and can be used for call methods of I1 interface.

很多人可能会说 - 等等,但这怎么可能?

many may be say here - wait, but how this can be?

如果我们打电话p1->func(..)p2->func(..)p1 != p2 func() 会用不同的指针调用,但只有一个可以正确?

if we call p1->func(..) and p2->func(..) and p1 != p2 the func() will be called with different pointers, but only one can be correct?

这里的错误 - 我们有 2 个不同的 func() - 如果 p1 != p2 p1->func 可以是 != p2->funcfunc 这里不是具体的函数地址.但是这个地址取自 vtable 到 p1p2 的那个点.因为p1 != p2 - 这里将使用不同 vtables,并且这个vtables 中不同 指针.在这个 vtables 之一中,adjustor thunk(可能在两者中)调整传入的p1(或p2)指针,然后跳转到real";func 实现

error here - that we have 2 different func() - in case p1 != p2 the p1->func can be != p2->func func here not concrete function address. but this address taken from vtable to which point p1 or p2. because p1 != p2 - here different vtables will be used and different pointers in this vtables. how minimum in one of this vtables will be adjustor thunk (possible in both) which adjust incoming p1 (or p2) pointer and then jump to "real" func implementation

再次 - 两个指针(p1 = p2p2->QueryInterface(IID_PPV_ARGS(&p1)) )正确在这里,两者都可以使用

so again - both pointers (p1 = p2 and p2->QueryInterface(IID_PPV_ARGS(&p1)) ) is correct here and both can be used

注意#3:

请不要混淆实现一个或多个 com 接口的 COM Interfaceobject.来自 接口指针和接口

please not confuse COM Interface and object which implement one or more com interfaces. from Interface Pointers and Interfaces

接口实现的实例实际上是一个指向指向方法的指针数组 - 即引用的函数表到接口中指定的所有方法的实现.

An instance of an interface implementation is actually a pointer to an array of pointers to methods - that is, a function table that refers to an implementation of all of the methods specified in the interface.

还看什么是一个 COM 接口?

我不问转换指针到对象,它实现(继承)接口指向这个接口的指针.我只询问接口指针转换.

i not ask about convert pointer to object which implement (inherit) interface to pointer to this interface. i ask only about interface pointer conversion.

来自 c/c++ 声明的接口 - 这是指针大小的对象 - 包含指向方法指针数组的单个指针

interface from c/c++ declaration - this is pointer size object - containing single pointer to array of pointers to methods

interface IXxx
{
    CONST_VTBL struct IXxxVtbl *lpVtbl;
};

例如

class I3 : public I1, I2
{
    // new methods
};

这里I3不是接口,而是实现I1I2接口的对象.

here I3 not interface, but object which implement I1 and I2 interfaces.

注意#4界面布局未知"- 这不是真的.界面的布局始终是已知的并明确定义的.对象的布局,其实现接口未知.但这是不同的事情 - 我不假设任何对象布局.再次为什么示例与

note#4 "layout of interface is unknown" - this is not true. layout of interface is always known and explicit defined. layout of object, which implement interface is unknown. but this is different things - i not assume any layout of object. again why example with

class I3 : public I1, I2
{
    // new methods
};

错了.

这里的二进制指针指向 I3 无效指针I2(需要调整)尽管 I3 继承自 <代码>I2.但是com接口不能这样定义.我说下一个如果com接口I2继承自I1接口——指向I2的指针也总是指向I1的有效指针. 这是来自 接口定义

here binary pointer to I3 not valid pointer to I2 (require adjustment) despite I3 inherit from I2. but com interface can not be such defined. i say next if com interface I2 inherit from I1 interface - pointer to I2 is always valid pointer to I1 too. this is from interface definition

只能再重复一遍例子

I1* p1 = p2;
p1->func(..);
p2->func(..);

p1 将是与 p2 相同的二进制值 - 这是由于特定的接口定义.结果 p1->func(..);p2->func(..); 产生相同的二进制代码.如果 p1->func(..); 会出错 - p2->func(..); 也会出错.但是 p2->func(..); 是正确的定义

p1 will be the same binary value as p2 here - this is due specific interfaces definitions. as result p1->func(..); and p2->func(..); produce the same binary code. if p1->func(..); will be wrong - p2->func(..); will be wrong too. but p2->func(..); is correct by definiton

推荐答案

如果您有多重继承,这在 COM 对象中很常见,您不能只使用简单的重新解释转换 - 它并不总是有效,即使在只是 C++ 术语.

If you have multiple inheritance, which is quite common for COM objects, you can't just use simple reinterpret casting - it doesn't always work, even in just C++ terms.

考虑:

class I3 : public I1, I2
{
    // new methods
};

如果您尝试在 I3 指针上调用 I1 方法,它可能会起作用.但是要调用 I2 方法,必须调整指针,使其具有与 I2 指针相同的布局.

If you try to call I1 methods on an I3 pointer, it will probably work. But to call I2 methods the pointer has to be adjusted so it will have the same layout as an I2 pointer.

这篇关于将 COM 接口转换为它继承的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆