Code:
#include <objbase.h> /* CB3.C */
#include <stdio.h>
const IID IID_IX = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}};
const IID IID_IY = {0x20000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09}};
typedef HRESULT (__stdcall* PFNQUERYINTERFACE) (size_t, const IID*, void**); //For Calling QueryInterface()
typedef ULONG (__stdcall* PFNADDREF) (size_t); //For Calling AddRef()
typedef ULONG (__stdcall* PFNRELEASE) (size_t); //For Calling Release()
typedef void (__stdcall* PIFN) (size_t,int); //For Calling Interface Functions
typedef struct // IX
{
struct IXVTbl* lpIXVTbl;
}IX;
struct IXVTbl // Here is where pointers to interface functions are installed into VTable, which
{ // could be described alterenately as an 'array of function pointers'.
HRESULT (__stdcall* QueryInterface) (IX*, const IID*, void**);
ULONG (__stdcall* AddRef) (IX* );
ULONG (__stdcall* Release) (IX* );
HRESULT (__stdcall* Fx1) (IX*, int );
HRESULT (__stdcall* Fx2) (IX*, int );
};
typedef struct //IY
{
struct IYVTbl* lpIYVTbl;
}IY;
struct IYVTbl
{
HRESULT (__stdcall* QueryInterface) (IY*,const IID* , void**);
ULONG (__stdcall* AddRef) (IY* );
ULONG (__stdcall* Release) (IY* );
HRESULT (__stdcall* Fy1) (IY*, int );
HRESULT (__stdcall* Fy2) (IY*, int );
};
typedef struct IXVTbl IXVTbl;
typedef struct IYVTbl IYVTbl;
typedef struct //CB // CB is actually, what we would term in C++, an object.
{
IXVTbl* lpIXVTbl;
IYVTbl* lpIYVTbl;
long m_cRef;
}CB;
HRESULT __stdcall IX_QueryInterface(IX* This, const IID* iid, void** ppv)
{
*ppv=0;
if(!memcmp(iid,&IID_IUnknown,16))
{
printf("IX_QueryInterface() For IUnknown!\n");
*ppv=This;
}
if(!memcmp(iid,&IID_IX,16))
{
printf("IX_QueryInterface() For IX! - This=%u\t*This=%u\n",This,*This);
//printf("IX_QueryInterface() For IX!\n");
*ppv=This;
}
if(!memcmp(iid,&IID_IY,16))
{
size_t* pInt = NULL;
IY* pIY = NULL;
pInt =(size_t*)This;
pIY = (IY*)pInt;
pIY++;
pInt=(size_t*)pIY;
printf("IX_QueryInterface() For IY! - This=%u\tpIY=%u\n",This,pIY);
*ppv=(void**)pInt[0];
}
if(*ppv)
{
//This->lpIXVTbl->AddRef(This);
return S_OK;
}
return(E_NOINTERFACE);
}
HRESULT __stdcall IY_QueryInterface(IY* This, const IID* iid, void** ppv)
{
*ppv=0;
if(!memcmp(iid,&IID_IUnknown,16))
{
printf("IY_QueryInterface() For IUnknown!\n");
*ppv=This;
}
if(!memcmp(iid,&IID_IY,16))
{
printf("IY_QueryInterface() For IY!\n");
*ppv=This;
}
if(!memcmp(iid,&IID_IX,16))
{
size_t* pInt=NULL;
IX* pIX=NULL;
pInt=(size_t*)This;
pIX=(IX*)pInt;
pIX--;
pInt=(size_t*)pIX;
printf("IY_QueryInterface() For IX! - This=%u\tpIX=%u\n",This,pIX);
*ppv=(void**)pInt[0];
}
if(*ppv)
{
//This->lpIYVTbl->AddRef(This);
return S_OK;
}
return(E_NOINTERFACE);
}
ULONG __stdcall IX_AddRef(IX* This)
{
CB* pCB=NULL;
pCB=(CB*)This;
pCB->m_cRef++;
printf("Called IX_AddRef() - pCB->m_cRef = %u\n",pCB->m_cRef);
return pCB->m_cRef;
}
ULONG __stdcall IY_AddRef(IY* This)
{
CB* pCB=NULL;
pCB=(CB*)This;
pCB->m_cRef++;
printf("Called IY_AddRef() - pCB->m_cRef = %u\n",pCB->m_cRef);
return pCB->m_cRef;
}
ULONG __stdcall IX_Release(IX* This)
{
CB* pCB=NULL;
pCB=(CB*)This;
pCB->m_cRef--;
printf("Called IX_Release() - pCB->m_cRef = %u\n",pCB->m_cRef);
return pCB->m_cRef;
}
ULONG __stdcall IY_Release(IY* This)
{
CB* pCB=NULL;
pCB=(CB*)This;
pCB->m_cRef--;
printf("Called IY_Release() - pCB->m_cRef = %u\n",pCB->m_cRef);
return pCB->m_cRef;
}
HRESULT __stdcall Fx1(IX* This,int iNum)
{
printf("Called Fx1() : iNum = %u\n",iNum);
return S_OK;
}
HRESULT __stdcall Fx2(IX* This,int iNum)
{
printf("Called Fx2() : iNum = %u\n",iNum);
return S_OK;
}
HRESULT __stdcall Fy1(IY* This,int iNum)
{
printf("Called Fy1() : iNum = %u\n",iNum);
return S_OK;
}
HRESULT __stdcall Fy2(IY* This,int iNum)
{
printf("Called Fy2() : iNum = %u\n",iNum);
return S_OK;
}
static IXVTbl ixVTable=
{
IX_QueryInterface,
IX_AddRef,
IX_Release,
Fx1,
Fx2
};
static IYVTbl iyVTable=
{
IY_QueryInterface,
IY_AddRef,
IY_Release,
Fy1,
Fy2
};
int main(void)
{
PFNQUERYINTERFACE ptrQueryInterface = NULL;
PFNADDREF ptrAddRef = NULL;
PFNRELEASE ptrRelease = NULL;
PIFN pIFn = NULL;
size_t* pVTbl = NULL;
size_t* VTbl = NULL;
void* pIUnk = NULL;
CB* pCB = NULL;
IX* pIX = NULL;
IY* pIY = NULL;
IX* pIX1 = NULL;
IY* pIY1 = NULL;
HRESULT hr = 0;
size_t i = 0;
printf("sizeof(CB) = %u\n",sizeof(CB));
pCB=(CB*)malloc(sizeof(CB));
if(pCB)
{
pCB->lpIXVTbl=&ixVTable;
pCB->lpIYVTbl=&iyVTable;
printf("pCB = %u\n",pCB);
printf("pCB->lpIXVTbl = %u\n",pCB->lpIXVTbl);
printf("pCB->lpIYVTbl = %u\n",pCB->lpIYVTbl);
pCB->lpIXVTbl->QueryInterface((IX*)&pCB->lpIXVTbl,&IID_IY,&pIY1);
pCB->lpIXVTbl->Fx1(pIX,1);
pCB->lpIXVTbl->Fx2(pIX,1);
pCB->lpIYVTbl->Fy1(pIY,2);
pCB->lpIYVTbl->Fy2(pIY,2);
pVTbl=(size_t*)pCB;
printf("\n");
printf("&pVTbl[i]\t&VTbl[j]\t\tVTbl[j]\t\t\tpFn()\n");
printf("==================================================================================================================================\n");
for(i=0; i<2; i++)
{
VTbl=(size_t*)pVTbl[i]; //Call...
printf("%u\t\t%u\t\t%u\t\t",&pVTbl[i],&VTbl[0],VTbl[0]);
ptrQueryInterface=(PFNQUERYINTERFACE)VTbl[0]; //QueryInterface()
if(i==0)
ptrQueryInterface((size_t)&pVTbl[i],&IID_IX,&pIUnk);
else
ptrQueryInterface((size_t)&pVTbl[i],&IID_IY,&pIUnk);
printf("%u\t\t%u\t\t%u\t\t",&pVTbl[i],&VTbl[1],VTbl[1]);
ptrAddRef=(PFNADDREF)VTbl[1]; //AddRef()
ptrAddRef((int)&pVTbl[i]);
printf("%u\t\t%u\t\t%u\t\t",&pVTbl[i],&VTbl[2],VTbl[2]);
ptrRelease=(PFNRELEASE)VTbl[2]; //Release()
ptrRelease((int)&pVTbl[i]);
printf("%u\t\t%u\t\t%u\t\t",&pVTbl[i],&VTbl[3],VTbl[3]);
pIFn=(PIFN)VTbl[3]; //Fx1() / Fy1()
pIFn((int)&pVTbl[i],i);
printf("%u\t\t%u\t\t%u\t\t",&pVTbl[i],&VTbl[4],VTbl[4]);
pIFn=(PIFN)VTbl[4]; //Fx2() / Fy2()
pIFn((int)&pVTbl[i],i);
printf("\n");
}
free(pCB);
}
return 0;
}
After the code is the output from my run, which shows the addresses of everything involved in the object. Note this is Microsoft code. It should work with Mingw, but it uses Microsoft specific headers. I built with VC9 from Visual Studio 2008, which is actually VC15 if one believes the compiler version. Its a 64 bit build. Should build x86 though.