IQI 指针的说明
1. 宏INHERIT_IQI()意思
2. INHERIT_IQI(IQI)表示定义了如下函数指针
3. AEEINTERFACE_DEFINE 表示如下
其实就是如下的东东:
那么如上的IQIVtbl 就是IQI的虚表指针,因为这个结构体中就是包含了三个函数指针成员。其他什么都没有。
4. 最后一个宏,
这个要一段一段的分析,(void *)p 是去掉指针类型偏移,避免后面运算和转型造成偏移错误。
然后将这个指针转换成指向虚表指针的指针,然后再对其解引用,将P 所指向空间最前面4个字节拿出来,作为虚表指针。
我们在看
可以看到IWidget的虚表中,有一个INHERIT_IHandler, 这个是什么呢?
5. INHERIT_IHandler 说明
哈哈,很明显,说明了IWidgetVtbl 这个结构体中前面三个成员是
并且紧跟着 handleEvent, 和 SetHandler 两个函数,然后才是widget 自己函数。
那么只要给IWidget 的结构的对象,我们可以IQI 强制指向它,然后直接调用addRef 和
Release 那么一定不会出错,因为结构体排列是一样的。
所以就可以IWidget_Release 和 IQI Release 是一样的。
为了验证这个问题,我写了一个Demo,就说用来说明这个问题。
// acd.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
typedef unsigned UUIDX;
typedef unsigned uint32;
struct IQI
{
virtual uint32 __cdecl AddRef() = 0;
virtual uint32 __cdecl Release() = 0;
virtual int __cdecl QueryInterface(UUIDX idReq, void **ppo) = 0;
};
struct IWidget : public IQI
{
virtual uint32 __cdecl SetBackColor() = 0;
};
struct IQIVtbl
{
uint32 (__cdecl*AddRef)(IQI*);
uint32 (__cdecl*Release)(IQI*);
int (__cdecl*QueryInterface)(IQI *, UUIDX, void **);
};
struct IWidgetVtbl
{
uint32 (__cdecl*AddRef)(IWidget*);
uint32 (__cdecl*Release)(IWidget*);
int (__cdecl*QueryInterface)(IWidget *, UUIDX, void **);
uint32 (__cdecl*SetBackColor)(IWidget *Phis);
};
struct C_Widget : public IWidget
{
C_Widget():m_nRef(0)
{
m_pInt = new int;
}
virtual ~C_Widget( )
{
delete m_pInt;
}
virtual uint32 __cdecl AddRef()
{
printf("current refcount = %d\n", m_nRef);
++m_nRef;
return m_nRef;
}
virtual uint32 __cdecl Release()
{
uint32 uTemp = 0;
if ( (uTemp = --m_nRef) == 0 )
{
delete this;
}
printf("Release refcount is %d\n", uTemp );
return uTemp;
}
virtual int __cdecl QueryInterface(UUIDX idReq, void **ppo)
{
printf("Enter QueryInterface\n");
if ( idReq == 1 )
{
this->AddRef();
*ppo = this;
return 0;
}
return -1;
}
virtual uint32 __cdecl SetBackColor()
{
printf("test in OK\n");
*m_pInt = 9;
return 0;
}
private:
uint32 m_nRef;
int *m_pInt;
};
//#define AEEGETPVTBL(p,iname) (*((AEEVTBL(iname) **)((void *)p)))
#define TELGETPVTBL(p,iname) (*(( iname**)((void *)p))) /// 替代实现
void Shell_CreateInstance(void **pObject)
{
C_Widget *pWidgetImp = new C_Widget;
pWidgetImp->AddRef();
*pObject = pWidgetImp;
}
void IAny_Release(IQI *pObject)
{
IQIVtbl *pIQI = TELGETPVTBL(pObject, IQIVtbl);
pIQI->Release(pObject);
}
uint32 __cdecl SetBackColorHook(IWidget *Phis)
{
printf("I am in hook function\n");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
size_t uSize = sizeof(IQI);
C_Widget *pWidgetImp = NULL;
Shell_CreateInstance( (void**)&pWidgetImp );
IQIVtbl *pIQI = TELGETPVTBL(pWidgetImp, IQIVtbl);
IWidgetVtbl *pWidget = TELGETPVTBL(pWidgetImp, IWidgetVtbl);
DWORD *pWord = (DWORD*)pWidget;
pIQI->AddRef(pWidgetImp);
pWidget->AddRef(pWidgetImp);
pWidget->Release(pWidgetImp);
pIQI->Release(pWidgetImp);
void *pV = 0;
pWidgetImp->QueryInterface(1, &pV);
pWidget->QueryInterface(pWidgetImp, 1, &pV);
pIQI->Release(pWidgetImp);
pIQI->Release(pWidgetImp);
DWORD dwSize = 0;
BOOL bRet = VirtualProtect(&(pWidget->SetBackColor), 4, PAGE_EXECUTE_READWRITE, &dwSize);
pWidget->SetBackColor = SetBackColorHook;
pWidget->SetBackColor( pWidgetImp );
IAny_Release( pWidgetImp );
C_Widget *pSend = new C_Widget;
pSend->SetBackColor();
return 0;
}
点击打开链接