// Our IBase sub-object of IMultInterface. We have chosen IBase to be the base object.
#include <windows.h>
#include <objbase.h>
#include <stddef.h>
#include "IMultInterface2.h"
static DWORD OutstandingObjects;
static DWORD LockCount;
// Our IBase object ////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE IBase_QueryInterface(IBase *this, REFIID vTableGuid, void **ppv)
{
// Because we have an ISub1 sub-object, we must return a pointer to that ISub1
// sub-object if an app asks for it here. (ie, The app is allowed to call our IBase's
// QueryInterface to obtain the ISub1 sub-object). And because we embedded that ISub1
// sub-object right inside of our IMultInterface, we can get it using pointer arithmetic
if (IsEqualIID(vTableGuid, &IID_ISub1))
this = (IBase *)((unsigned char *)this + offsetof(IMultInterface, sub1));
// Because we have an ISub2 sub-object for our IMultInterface, we must return a
// pointer to that ISub2 sub-object if an app asks for it here. But we didn't
// embed our ISub2 sub-object right inside of our IMultInterface. Instead,
// we put a pointer to it in IMultInterface, and we're allocating it here (ie, we
// allocate it when the app finally asks for it)
else if (IsEqualIID(vTableGuid, &IID_ISub2))
{
register IMultInterface *myObj;
// Because our IBase is the base object, "this" is effectively pointing to our
// IMultInterface too
myObj = (IMultInterface *)this;
// If we've already allocated the ISub2, then our IMultInterface->speakerOut
// member points to it. We just need to return this object
if (!myObj->sub2 &&
// We didn't allocate the ISub2 yet. Let's do so now, and save
// the pointer in our IMultInterface->sub2 member
!(myObj->sub2 = allocISub2(this)))
{
// We had a problem allocating/initializing our ISub2. The only reason
// that allocISub2() fails is due to a memory error, so we'll return
// E_OUTOFMEMORY. If there are other possible failures, we should redefine
// allocISub2() to be passed a pointer to a HRESULT variable, and then
// return whatever HRESULT is generated
return(E_OUTOFMEMORY);
}
this = (IBase *)(myObj->sub2);
}
else if (!IsEqualIID(vTableGuid, &IID_IUnknown) && !IsEqualIID(vTableGuid, &IID_IBase) && !IsEqualIID(vTableGuid, &IID_IMultInterface))
{
*ppv = 0;
return(E_NOINTERFACE);
}
*ppv = this;
this->lpVtbl->AddRef(this);
return(NOERROR);
}
ULONG STDMETHODCALLTYPE IBase_AddRef(IBase *this)
{
return(++((IMultInterface *)this)->count);
}
ULONG STDMETHODCALLTYPE IBase_Release(IBase *this)
{
// NOTE: This count includes all outstanding references not only to this
// IBase base object, but also all outstanding references to other sub-objects.
// In other words, we won't be GlobalFree'ing this IMultInterface
// until all of its sub-objects are also Release'ed
if (--((IMultInterface *)this)->count == 0)
{
#ifndef ISub2_NOPERSISTDATA
if (((IMultInterface *)this)->sub2) GlobalFree(((IMultInterface *)this)->sub2);
#endif
GlobalFree(this);
InterlockedDecrement(&OutstandingObjects);
return(0);
}
return(((IMultInterface *)this)->count);
}
static HRESULT STDMETHODCALLTYPE Sum(IBase *this, long value1, long value2, long *sum)
{
// Add the 2 values and return the sum
*sum = value1 + value2;
return(NOERROR);
}
static const IBaseVtbl IBase_Vtbl = {IBase_QueryInterface,
IBase_AddRef,
IBase_Release,
Sum};
// The IClassFactory object ///////////////////////////////////////////////////////
static IClassFactory MyIClassFactoryObj;
static ULONG STDMETHODCALLTYPE classAddRef(IClassFactory *this)
{
InterlockedIncrement(&OutstandingObjects);
return(1);
}
static HRESULT STDMETHODCALLTYPE classQueryInterface(IClassFactory *this, REFIID factoryGuid, void **ppv)
{
if (IsEqualIID(factoryGuid, &IID_IUnknown) || IsEqualIID(factoryGuid, &IID_IClassFactory))
{
this->lpVtbl->AddRef(this);
*ppv = this;
return(NOERROR);
}
*ppv = 0;
return(E_NOINTERFACE);
}
static ULONG STDMETHODCALLTYPE classRelease(IClassFactory *this)
{
return(InterlockedDecrement(&OutstandingObjects));
}
static HRESULT STDMETHODCALLTYPE classCreateInstance(IClassFactory *this, IUnknown *punkOuter, REFIID vTableGuid, void **objHandle)
{
HRESULT hr;
register IMultInterface *thisobj;
*objHandle = 0;
if (punkOuter)
hr = CLASS_E_NOAGGREGATION;
else
{
if (!(thisobj = (IMultInterface *)GlobalAlloc(GMEM_FIXED, sizeof(IMultInterface))))
hr = E_OUTOFMEMORY;
else
{
thisobj->base.lpVtbl = (IBaseVtbl *)&IBase_Vtbl;
// Because we've embedded this IMultInterface's ISub1 sub-object
// directly inside of our IMultInterface, we have that sub-object
// available right now. So, we may as well initialize it now
initISub1(thisobj);
// Zero out the pointer to ISub2 sub-object. It doesn't exist yet
thisobj->sub2 = 0;
// We're returning the base (IBase) object to the app, so AddRef() it
thisobj->count = 1;
// Fill in the pointer to IMultInterface's base object, and AddRef it
hr = IBase_Vtbl.QueryInterface((IBase *)thisobj, vTableGuid, objHandle);
IBase_Vtbl.Release((IBase *)thisobj);
if (!hr) InterlockedIncrement(&OutstandingObjects);
}
}
return(hr);
}
static HRESULT STDMETHODCALLTYPE classLockServer(IClassFactory *this, BOOL flock)
{
if (flock) InterlockedIncrement(&LockCount);
else InterlockedDecrement(&LockCount);
return(NOERROR);
}
static const IClassFactoryVtbl IClassFactory_Vtbl = {classQueryInterface,
classAddRef,
classRelease,
classCreateInstance,
classLockServer};
// Miscellaneous functions ///////////////////////////////////////////////////////
HRESULT PASCAL DllGetClassObject(REFCLSID objGuid, REFIID factoryGuid, void **factoryHandle)
{
register HRESULT hr;
if (IsEqualCLSID(objGuid, &CLSID_IMultInterface))
hr = classQueryInterface(&MyIClassFactoryObj, factoryGuid, factoryHandle);
else
{
*factoryHandle = 0;
hr = CLASS_E_CLASSNOTAVAILABLE;
}
return(hr);
}
HRESULT PASCAL DllCanUnloadNow(void)
{
return((OutstandingObjects | LockCount) ? S_FALSE : S_OK);
}
BOOL WINAPI DllMain(HINSTANCE instance, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
OutstandingObjects = LockCount = 0;
MyIClassFactoryObj.lpVtbl = (IClassFactoryVtbl *)&IClassFactory_Vtbl;
DisableThreadLibraryCalls(instance);
}
}
return(1);
}