)'s technique to implement COM interface. Unlikely virtual function calls in a normal COM object using AB, function calls in the COM object of this template version are potentially inlineable thus a certain degree of improved performance is expected at an expense of code bloat as usual in C++ template. (Disclaimer! This is an experimental code snippet.)
#include <iostream>
#include <cassert>
// #include <vld.h>
#include "Unknown2.hpp"
IID const IID_IFoo = { 0xe37b25e4, 0xddf9, 0x4624, { 0x9d, 0xa4, 0xa3, 0x91, 0x2e, 0x99, 0x83, 0x48 } };
IID const IID_IBar = { 0x040b23c2, 0x8790, 0x419e, { 0xa4, 0xe4, 0x9d, 0x6d, 0xdd, 0xa7, 0x4d, 0x39 } };
// --------------------------------------------------------------------------------
class FooBar
: private Interface<IBar, FooBar>
, private Interface<IFoo, FooBar>
{
private:
long volatile m_cRef;
public:
FooBar()
: m_cRef( 0 )
{
}
// IUnknown2
STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject)
{
if(0 == ppvObject)
return E_POINTER;
if(IID_IUnknown == iid)
*ppvObject = Interface<IFoo, FooBar>::get_pointer();
else if(IID_IFoo == iid)
*ppvObject = Interface<IFoo, FooBar>::get_pointer();
else if(IID_IBar == iid)
*ppvObject = Interface<IBar, FooBar>::get_pointer();
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown2 *>( *ppvObject )->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) Release()
{
LONG res = --m_cRef;
if(0 == res)
delete this;
return res;
}
// IFoo
void foofun(int) { std::cout << "void foofun(int)" << std::endl; }
void __stdcall foofun2(int, long) { std::cout << "void foofun2(int, long)" << std::endl; }
// IBar
void barfun(int) { std::cout << "void barfun(int)" << std::endl; }
};
// --------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
FooBar * pfb = new FooBar;
assert( 12 == sizeof( FooBar ) ); // 4 bytes per interface
IUnknown2 * punk = 0;
assert( SUCCEEDED( pfb->QueryInterface( IID_IUnknown, reinterpret_cast<void **>( &punk ) ) ) );
IFoo * pfoo = 0;
assert( SUCCEEDED( punk->QueryInterface( IID_IFoo, reinterpret_cast<void **>( &pfoo ) ) ) );
punk->Release();
pfoo->foofun(1);
pfoo->foofun2(1, 2);
IBar * pbar = 0;
assert( SUCCEEDED( pfoo->QueryInterface( IID_IBar, reinterpret_cast<void **>( &pbar ) ) ) );
pfoo->Release();
pbar->barfun(2);
assert( SUCCEEDED( pbar->QueryInterface( IID_IUnknown, reinterpret_cast<void **>( &punk ) ) ) );
pbar->Release();
// QueryInterface is Symmetric
assert( SUCCEEDED( punk->QueryInterface( IID_IFoo, reinterpret_cast<void **>( &pfoo ) ) ) );
assert( SUCCEEDED( pfoo->QueryInterface( IID_IUnknown, reinterpret_cast<void **>( &punk ) ) ) );
pfoo->Release();
punk->Release();
// QueryInterface is Transitive
assert( SUCCEEDED( punk->QueryInterface( IID_IFoo, reinterpret_cast<void **>( &pfoo ) ) ) );
assert( SUCCEEDED( pfoo->QueryInterface( IID_IBar, reinterpret_cast<void **>( &pbar ) ) ) );
assert( SUCCEEDED( pbar->QueryInterface( IID_IUnknown, reinterpret_cast<void **>( &punk ) ) ) );
pfoo->Release();
pbar->Release();
punk->Release();
// QueryInterface is Reflexive
assert( SUCCEEDED( punk->QueryInterface( IID_IUnknown, reinterpret_cast<void **>( &punk ) ) ) );
punk->Release();
assert( SUCCEEDED( pfoo->QueryInterface( IID_IFoo, reinterpret_cast<void **>( &pfoo ) ) ) );
pfoo->Release();
assert( SUCCEEDED( pbar->QueryInterface( IID_IBar, reinterpret_cast<void **>( &pbar ) ) ) );
pbar->Release();
punk->Release();
// --------------------------------------------------------------------------------
system("PAUSE");
return EXIT_SUCCESS;
}
#if !defined(__UNKNOWN2_HPP__INCLUDED__)
#define __UNKNOWN2_HPP__INCLUDED__
#include <windows.h>
// --------------------------------------------------------------------------------
template<typename T> struct apply { typedef T type; };
// --------------------------------------------------------------------------------
template<typename TIface, typename T>
class Interface : protected TIface
{
protected:
Interface() : TIface( apply<T>() ) { }
public:
TIface * get_pointer() const
{
// Adjust void pointer as a pointer of Interface type first
// then adjust the resultant as a pointer of TIface type again.
return const_cast<TIface *>( static_cast<TIface const *>( static_cast<Interface const *>( this ) ) );
}
};
// --------------------------------------------------------------------------------
class IUnknown2
{
typedef IUnknown2 interface_type;
protected:
void const * vtbl_ptr_;
struct fxn_table
{
HRESULT (*QueryInterface)(void *, REFIID, void **);
ULONG (*AddRef)(void *);
ULONG (*Release)(void *);
fxn_table()
: QueryInterface( 0 )
, AddRef( 0 )
, Release( 0 )
{
}
fxn_table(
HRESULT (*QueryInterface_)(void *, REFIID, void **),
ULONG (*AddRef_)(void *),
ULONG (*Release_)(void *) )
: QueryInterface( QueryInterface_ )
, AddRef( AddRef_ )
, Release( Release_ )
{
}
};
template<typename TIface, typename T> struct interface_stub
{
static HRESULT QueryInterface(void * obj_ptr, REFIID iid, void ** ppvObject)
{
// Adjust void pointer as a pointer of TIface type first
// then adjust the resultant as a pointer of T type again to call the function.
return static_cast<T *>( static_cast<TIface *>(obj_ptr) )->QueryInterface( iid, ppvObject );
}
static ULONG AddRef(void * obj_ptr)
{
return static_cast<T *>( static_cast<TIface *>(obj_ptr) )->AddRef();
}
static ULONG Release(void * obj_ptr)
{
return static_cast<T *>( static_cast<TIface *>(obj_ptr) )->Release();
}
static fxn_table * get_table()
{
static fxn_table static_table(
&QueryInterface,
&AddRef,
&Release );
return &static_table;
}
};
IUnknown2(void const * table_ptr) : vtbl_ptr_( table_ptr )
{
}
public:
template<class T>
IUnknown2(apply<T>) : vtbl_ptr_( interface_stub<interface_type, typename apply<T>::type>::get_table() )
{
}
public:
HRESULT QueryInterface(REFIID iid, void ** ppvObject)
{
return static_cast<fxn_table const *>( vtbl_ptr_ )->QueryInterface( this, iid, ppvObject );
}
ULONG AddRef()
{
return static_cast<fxn_table const *>( vtbl_ptr_ )->AddRef( this );
}
ULONG Release()
{
return static_cast<fxn_table const *>( vtbl_ptr_ )->Release( this );
}
}; // class IUnknown2
// --------------------------------------------------------------------------------
class IFoo : public IUnknown2
{
typedef IFoo interface_type;
typedef IUnknown2 base_interface_type;
typedef base_interface_type::fxn_table base_interface_fxn_table;
template<typename TIface, typename T>
struct rebind_base_interfacel_stub
{
typedef base_interface_type::interface_stub<TIface, T> type;
};
protected:
struct fxn_table : public base_interface_fxn_table
{
void (*foofun)(void *, int);
void (*foofun2)(void *, int, long);
fxn_table()
: base_interface_fxn_table()
, foofun( 0 ), foofun2( 0 )
{
}
fxn_table(base_interface_fxn_table * base_table_ptr
, void (*foofun_)(void *, int)
, void (*foofun2_)(void *, int, long))
: base_interface_fxn_table( *base_table_ptr )
, foofun( foofun_ ), foofun2( foofun2_ )
{
}
};
template<typename TIface, typename T> struct interface_stub : public rebind_base_interfacel_stub<TIface, T>::type
{
static void foofun(void * obj_ptr, int a0)
{
// Adjust void pointer as a pointer of TIface type first
// then adjust the resultant as a pointer of T type again to call the function.
static_cast<T *>( static_cast<TIface *>(obj_ptr) )->foofun( a0 );
}
static void foofun2(void * obj_ptr, int a0, long a1)
{
static_cast<T *>( static_cast<TIface *>(obj_ptr) )->foofun2( a0, a1 );
}
static fxn_table * get_table()
{
static fxn_table static_table(
typename rebind_base_interfacel_stub<TIface, T>::type::get_table(),
&foofun,
&foofun2);
return &static_table;
}
};
IFoo(void const * table_ptr) : base_interface_type( table_ptr )
{
}
public:
template<class T>
IFoo(apply<T>) : base_interface_type( interface_stub<interface_type, typename apply<T>::type>::get_table() )
{
}
void foofun(int a0)
{
static_cast<fxn_table const *>( vtbl_ptr_ )->foofun( this, a0 );
}
void foofun2(int a0, long a1)
{
static_cast<fxn_table const *>( vtbl_ptr_ )->foofun2( this, a0, a1 );
}
}; // class IFoo : public IUnknown2
// --------------------------------------------------------------------------------
class IBar : public IUnknown2
{
typedef IBar interface_type;
typedef IUnknown2 base_interface_type;
typedef base_interface_type::fxn_table base_interface_fxn_table;
template<typename TIface, typename T>
struct rebind_base_interfacel_stub
{
typedef base_interface_type::interface_stub<TIface, T> type;
};
protected:
struct fxn_table : public base_interface_fxn_table
{
void (*barfun)(void *, int);
fxn_table()
: base_interface_fxn_table()
, barfun( 0 )
{
}
fxn_table(base_interface_fxn_table * base_table_ptr, void (*funfun_)(void *, int))
: base_interface_fxn_table( *base_table_ptr )
, barfun( funfun_ )
{
}
};
template<typename TIface, typename T> struct interface_stub : public rebind_base_interfacel_stub<TIface, T>::type
{
static void barfun(void * obj_ptr, int a0)
{
static_cast<T *>( static_cast<TIface *>(obj_ptr) )->barfun( a0 );
}
static fxn_table * get_table()
{
static fxn_table static_table(
typename rebind_base_interfacel_stub<TIface, T>::type::get_table(),
&barfun );
return &static_table;
}
};
IBar(void const * table_ptr) : base_interface_type( table_ptr )
{
}
public:
template<class T>
IBar(apply<T>) : base_interface_type( interface_stub<interface_type, typename apply<T>::type>::get_table() )
{
}
void barfun(int a0)
{
static_cast<fxn_table const *>( vtbl_ptr_ )->barfun( this, a0 );
}
}; // class IBar : public IUnknown2
#endif // #if !defined(__UNKNOWN2_HPP__INCLUDED__)