创建一个com组件的对象有多种办法,每种办法得到的都是一个指向获得的特定接口的指针。就向c++的对象一样,每个com组件对象都有自己的一份数据拷贝,但是却共用一份的函数拷贝。因此,对于同一个com组件,创建的每一个对象获得的都应该是指向同一个内存中虚函数表中,那么得到这样的指针以后,我怎么针对特定的对象进行操作呢?或者说,创建一个com对象后,它的this指针放在哪里,我怎么去获得呢?
调试欢乐多
你应该知道只能对接口操作,而不能对对象操作啊。
COM是和语言无关的,没有this这个概念
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwClsContext,
REFIID riid,
LPVOID * ppv
);HRESULT QueryInterface(
LPUNKNOWN ps,
const IID & riid,
void **ppvObj
);
LPVOID * ppv和void **ppvObj 带回了对象指针,所以*ppvObj和ppv大概就是你要的this指针.
这么说,N 个接口指针也是this 的话,N 个接口指针 的值也是相等的,但事实上同一个COM对象不同的接口指针的值是不一样的,所以说接口指针并不是this指针。
| +------->ComObject
+<----+ |
| |
+-------->+
-------------------------------------------------------------------------------
这么说,N 个接口指针也是this 的话,N 个接口指针 的值也是相等的,但事实上同一个COM对象不同的接口指针的值是不一样的,所以说接口指针并不是this指针。
-------------------------------------------------------------------------------你说的这个问题我也同样觉得,这个this指针不应该是接口指针,它应该是对象的所有数据地址的总入口,应该是由操作系统的组件服务程序维护的,调用queryinterface时,用户给入需要的接口名,然后this指针会自动的被传入。
class CA
{
long a;
void A( long e );
void B( long e );
};
上面的类定义实际上如下:
struct s_CA
{
long a;
};
void CA_A( s_CA *this, long e );
void CA_B( s_CA *this, long e );因此:
CA a; // 此时实际为: s_CA a; CA_CA( &a ); // 调用构造函数
a.A( 34 ); // 此时实际如下:CA_A( &a, 34 );因此所谓的this指针就是struct s_CA的一个指针,而所谓的类实例其实就是一个结构的实例。而当出现虚函数时,假设如下:
接口IA为: 接口IB为:
struct IA struct IB
{ {
void A( long e ) = 0; void B( long e ) = 0;
}; };
而CA派生自IA和IB,即实现IA和IB(用ATL的方式),此时s_CA变成如下:
struct s_CA
{
void *pvt_A; // 由于IA所引入的虚函数地址指针,也就是楼主所谓的一份函数拷贝
void *pvt_B; // 由于IB所引入的虚函数地址指针,也就是楼主所谓的一份函数拷贝
long a;
};此时:
CA a;
IA *pA = static_cast< IA* >( &a ); // 此时pA == &a
IB *pB = static_cast< IB* >( &a ); // 此时pB == &a + 4,跳过pvt_A,
// 由static_cast这个指令进行转换的
pA->A( 34 ); // 此时实际为( *pA->pvt_A[0] )( pA, 34 );
pB->B( 34 ); // 此时实际为( *pB->pvt_B[0] )( pB, 34 );
而pA->pvt_A[0]的函数原型为void CA_A( IA *this, long e );
而pB->pvt_B[0]的函数原形为void CA_B( IB *this, long e );因此就有函数CA_A和CA_B,而CA_A的this指针是IA*,CA_B的this指针是IB*,即调用接口函数时传递的this指针就是那个接口的指针,但是数据是怎么传递的呢?即编译器如何知道IA*加上8个字节后就是成员变量a的值?很简单,因为CA_A和CA_B是类CA实现的,因此编译器在编译CA_A时知道此时传进来的this+8就是成员变量a的地址,在CA_B时知道此时传进来的this+4就是成员变量a的地址,因为编译器在编译这两个函数时是知道类CA的定义的,即编译器知道如下:
class CA : public IA, public IB
{
long a;
void A( long e );
void B( long e );
};
所以编译器知道传进来的this到底是个什么类的实例,因而可以表现出通过传递虚函数列表的指针就达到了传递数据成员的现象。
我先前说的有错误,我更正一下:
this指针是指向当前类实例的指针,类实例是一群数据成员的集合,其中包括vtbl指针,通过多继承方法得到的类的类实例,包含它所继承的所有接口的vtbl的指针,我们可以使用static_case<IXXX*>把this指针强制转换为指向对应IXXX接口的vtbl的指针的指针(因为vtbl指针是类实例的数据成员,编译器只需调整this指针加上一个适当的偏移量即可指向它)。很显然我们通过this指针强制转换,从而得到了指向vtbl的指针的指针,也就得到了所谓的借口指针。
另外,类的各个实例将共享相同的vtbl(但各自拥有指向它的指针)和函数实现。
static_cast<interface*>this 强制类型转换来得到,它应该是一个指向该接口虚函数表的指针。如果这样,对于同一个对象,不同的接口指针当然是不一样的,但是对于同一个com组件的不同对象,如果它们查询同样的接口,那么应该要获得同样的指针了?
我认为你走入误区了,在考虑this指针的时候,不应该把它与com联系起来讲,原因有三:
一、this是C++语言的中概念
二、COM规范中并无this的说法
三、在查询COM对象时,只能获知COM对象的接口指针