一个com对象可以实现多个接口,利用每一个接口的QueryInterface可以取得另一个接口。
com对象如果实现了好几个接口,那么这个com对象的有几个虚函数表,虚函数表里是什么内容。
QueryInterface的能找到其他接口的实现原理是什么?谢谢!

解决方案 »

  1.   

    QueryInterface()如果是返回同一个类提供的接口的话就直接返回该类或某个基类的指针,
    当然,也有可能是返回其它对象的指针。
      

  2.   

    建议看<COM技术内幕>第三章,讲的很容易懂,对你的理解很有帮助
      

  3.   

    switch (iid)
    {
    case IID_xxx:
    ....
    case IID_yyy:
    ...
    }
      

  4.   

    呵呵,黑盒子
    输入一个GUID
    输出一个Interface有一个虚函数表吧,具体可以看看《com技术内幕》或者《com本质论》
    可以理解为“多重继承的类对象向其父类做类型转换”
      

  5.   

    接口QueryInterface()函数只是虚函数,实际是由接口实现类(派生类)实现的这个函数,不同的id对应转换成相应的接口
      

  6.   

    其实就是要解释C++的多重继承和虚拟函数:一个COM类可能继承了多个接口.
    class CA : public IA,public IB{
    }如果我有一个指针CA* pCA;
    那么我可以做一些转换:
    static_cast<IA*>pCA,这会得到CA中IA的那部分.
    static_cast<IB*>pCA会得到CA中IB那部分.
    QueryIntyerface用的就是(一般情况下)这样的方法,当请求的是IA接口时,返回static_cast<IA*>this,当请求的是IB接口时,返回static_cast<IB*>this
    刚才说的是一般情况下,但是对于VC下编写COM,我们用的一般是ATL,不是这种继承方式,可以叫做"组合"的方式:class CA:basexxx{
       interface IA{}
      interface IB{}
    }
    这种方式的query很方便,只是查找IA或者IB在CA中的位置偏移.
      

  7.   

    MFC的CCmdTarget类是用子对象来实现接口的,查询时返回相应对象的接口指针。参考MSDN文章TN038
      

  8.   

    kevin_wang(砸锅卖铁)你说的对,就是解释C++的多重继承和虚拟函数:
    我知道,
    static_cast<IA*>pCA,这会得到CA中IA的那部分.
    static_cast<IB*>pCA会得到CA中IB那部分.但是我想知道他们的内存模型,实现对象里是总共一个虚函数表还是一个接口一个虚函数表,如何关联?
      

  9.   

    QueryInterface的某种可能实现:HRESULT CMyObject::QueryInterface(const IID& iid, void** ppv)
    {
      if (iid == IID_IUnknown)
      {
        *ppv = (IMyInterface *)this;
       ((IMyInterface *)(*ppv))->AddRef();
      }
      else if (iid == IID_IMyInterface)
      {
        *ppv = (IMyInterface *)this;
        ((IMyInterface *)(*ppv))->AddRef();
      }
      else if (iid == IID_Another)
      {
        *ppv = (IAnother *)this;
        ((IAnother *)(*ppv))->AddRef();
      }
      else
      {
        *ppv = NULL;
        return E_NOINTERFACE;
      }
      return S_OK;
    }
      

  10.   

    我是这样理解的,不知道对不对实现对象中对于每一个接口都有一个指向该接口vtable的vptr。
    根据传入的IID不同,通过static_cast<IA*>this返回对应的vptr。
    static_cast应该是在编译期就完成的吧。不过还有个问题就是,一般queryInterface都是通过一个接口调用的,接口的指针
    应该就是该接口的vptr的指针吧。按楼上的代码,queryInterface都是通过实现类的this
    指针得到接口指针,那么通过接口指针调用queryInterface时,这个this指针怎么得到呢?
      

  11.   

    是不是编译器编译时会保存各个接口的vprt相对this的偏移,然后在编译IA.queryInterface(IID_B,IB)时,就会根据偏移和IA的vtable得到IB的vtable。而对于程序的运行期并不知道并不知道这些vtable的偏移,只管执行指定内存的代码,是这样吧。
      

  12.   

    一、若是以多重继承的方式实现接口,那么实现接口的对象内存模型如下:
    class IUnkown{
    public:
    virtual void QueryInterface()=0;}
    class driver1:public IUnknown{
    public:
    virtual void f1()=0;}
    class driver2:public IUnknown{
    public:
    virtual void f2()=0;}
    class mostdrive:public drive1,drive2 {
    public:
    virtual void QueryInterface() {cout<<"QueryInterface"<<endl;}
    virtual void f1() {cout<<"f1()"<<endl;}
    virtual void f2() {cout<<"f2()"<<endl;}
    }调试过程:
    mostdrive有两个:_vtble1,_vtble2 ,因drive1只含一个vptr值,所以this向后调整4个字节所指的值就是_vtble2。1、mostdrive::mostdrive调用drive1::drive1调用IUnkown::IUnkown,
    _vtble1的初值为0x0046f0e8
    mostdrive::mostdrive调用drive1::drive1
    _vtble1的值第一次调整为0x0046f0d0
    mostdrive::mostdrive
    _vtble1的值第二次调整为0x0046f084,
    C++伪码:((*(IUnknown *)((*(drive1 *)(obj)))))._vfptr2、mostdrive::mostdrive调用drive2::drive2调用IUnkown::IUnkown
    _vtble1的初值为0x0046f0e8
    mostdrive::mostdrive调用drive1::drive1
    _vtble2的值第一次调整为0x0046f0dc
    mostdrive::mostdrive
    _vtble2的值第二次调整为0x0046f078
    C++伪码:((*(IUnknown *)((*(drive2 *)(obj)))))._vfptr关于QueryInterface调用:1、若_vtble1[0]表示QueryInterface,它函数指针是0x0040110e2、若_vtble2[0]表示QueryInterface,它函数指针是0x004012d5,但是经过thunk处理,最终调用0x0040110e二、若是MFC的CCmdTarget类以子对象来实现接口的,查询时返回相应对象的接口指针,它的对象内存模型如下: