/* Copyright (c) Microsoft Corporation. All rights reserved. */ #include <mmlite.h> #include <tchar.h> #include <mmmacros.h> #include <base/cobdesc.h> extern const struct CUnknown_ClassDesc CUnknown_ClassDesc; /* IUnknown::<this> points to v-table * pDC (pointer of Def Cob) converts interface ptr to implementation. * iDC (interface of DC) converts implementation ptr to interface ptr. * dDC (interface to descriptor) */ #define pCUnknown(_i_) ((struct CUnknown *)(_i_)) #define iCUnknown(_p_) ((PIUNKNOWN)(_p_)) #define dCUnknown(_i_) (((struct CUnknownVtbl *)(((BYTE*)(_i_)->v) - offsetof(struct CUnknownVtbl, v)))->classd); static SCODE MCT CUnknownQueryInterface(PIUNKNOWN iThis, REFIID Iid, void **ppObj) { UINT i; const struct _ClassDesc *classd = dCUnknown(iThis); for (i = 0; i < classd->Count; i++) { if (UuidCmp(Iid, classd->iface[i].Iid)) { PIUNKNOWN pUnk; pUnk = (PIUNKNOWN) ((ADDRESS) iThis + classd->iface[i].Offset); pUnk->v->AddRef(pUnk); *ppObj = (void*) pUnk; return S_OK; } } return E_NO_INTERFACE; } static UINT MCT CUnknownAddRef(PIUNKNOWN iThis) { struct CUnknown *This = pCUnknown(iThis); return AtomicInc(&This->RefCnt); } static UINT MCT CUnknownRelease(PIUNKNOWN iThis) { struct CUnknown *This = pCUnknown(iThis); UINT RefCnt = AtomicDec(&This->RefCnt); if ((RefCnt & ~REFCNT_STATIC) == 0) { const struct _ClassDesc *classd = dCUnknown(iThis); if (classd->Destroy) classd->Destroy(iThis); } return RefCnt; } static const struct CUnknownVtbl CUnknownVtable = { (struct _ClassDesc *) &CUnknown_ClassDesc, { __VTABLE_COMPATIBILITY_FILLER_INITIALIZER CUnknownQueryInterface, CUnknownAddRef, CUnknownRelease } }; #define C_QI(_off_) \ static SCODE MCT CUnknown_ ## _off_ ## _QueryInterface(PIUNKNOWN iThis, REFIID iid, void **ppObj) \ { \ iThis = (PIUNKNOWN) ((ADDRESS) iThis - _off_); \ return CUnknownQueryInterface(iThis, iid, ppObj); \ } #define C_ADDREF(_off_) \ static UINT MCT CUnknown_ ## _off_ ## _AddRef(PIUNKNOWN iThis) \ { \ iThis = (PIUNKNOWN) ((ADDRESS) iThis - _off_); \ return CUnknownAddRef(iThis); \ } #define C_RELEASE(_off_) \ static UINT MCT CUnknown_ ## _off_ ## _Release(PIUNKNOWN iThis) \ { \ iThis = (PIUNKNOWN) ((ADDRESS) iThis - _off_); \ return CUnknownRelease(iThis); \ } #define C_VTAB(_off_) static const struct CUnknownVtbl CUnknown_ ## _off_ ## _Vtable = { \ (struct _ClassDesc *) &CUnknown_ClassDesc, \ { \ __VTABLE_COMPATIBILITY_FILLER_INITIALIZER \ \ CUnknown_ ## _off_ ## _QueryInterface, \ CUnknown_ ## _off_ ## _AddRef, \ CUnknown_ ## _off_ ## _Release \ } \ }; #define C_DEFINE(_ix_) \ C_QI(_ix_) \ C_ADDREF(_ix_) \ C_RELEASE(_ix_) \ C_VTAB(_ix_) C_DEFINE(8) C_DEFINE(12) C_DEFINE(16) C_DEFINE(20) C_DEFINE(24) C_DEFINE(28) C_DEFINE(32) PTR MCT CUnknownInit(const struct _ClassDesc *classd, /*optional*/ struct CUnknown *This) { /* Fill in v-tables and RefCnt */ UINT i; if (!This) { PIHEAP pHeap = CurrentHeap(); This = (struct CUnknown *) pHeap->v->Alloc(pHeap, HEAP_ZERO_MEMORY, classd->Size, 0); if (!This) return NULL; } /* Works when object inherits CUnknown (RefCnt is second item, other * v-tables follow later) */ This->RefCnt = 1; for (i = 0; i < classd->Count; i++) { *(ADDRESS**) ((ADDRESS) This + classd->iface[i].Offset) = (ADDRESS*) classd->iface[i].v; } return This; } static SCODE MCT CUnknownDestroy(PIUNKNOWN iThis) { struct CUnknown *This = pCUnknown(iThis); PIHEAP pHeap = CurrentHeap(); /* Do not free if marked static */ if (This->RefCnt & REFCNT_STATIC) return S_OK; return pHeap->v->Free(pHeap, 0, iThis); } const CLASSDESC(CUnknown, 8) = { _T("CUnknown"), &IID_IUnknown, NULL, NULL, CUnknownDestroy, sizeof(struct CUnknown), 8, { {(struct IUnknownVtbl *) &CUnknownVtable.v, &IID_IUnknown, 3, 0}, {(struct IUnknownVtbl *) &CUnknown_8_Vtable.v, &IID_IUnknown, 3, 8}, {(struct IUnknownVtbl *) &CUnknown_12_Vtable.v, &IID_IUnknown, 3, 12}, {(struct IUnknownVtbl *) &CUnknown_16_Vtable.v, &IID_IUnknown, 3, 16}, {(struct IUnknownVtbl *) &CUnknown_20_Vtable.v, &IID_IUnknown, 3, 20}, {(struct IUnknownVtbl *) &CUnknown_24_Vtable.v, &IID_IUnknown, 3, 24}, {(struct IUnknownVtbl *) &CUnknown_28_Vtable.v, &IID_IUnknown, 3, 28}, {(struct IUnknownVtbl *) &CUnknown_32_Vtable.v, &IID_IUnknown, 3, 32} } }; /* Def COB Object */ typedef struct _DefCob *PDEFCOB; #define pDefCob(_i_) ((PDEFCOB)(_i_)) #define iDefCob(_p_) ((PIUNKNOWN)(_p_)) static SCODE DefCobDestroy(PIUNKNOWN iThis) { PDEFCOB This = pDefCob(iThis); struct _CobDesc *cobd = This->cobd; struct _ClassDesc *classd; SCODE sc; UINT i; PIHEAP pHeap = CurrentHeap(); /* If the COB has a private destructor call it first. * It is presumed not to deallocate. */ //if (cobd->mainclass && cobd->mainclass->Destroy) // cobd->mainclass->Destroy(iThis); /* Unregister registered classes before terminating */ for (i = 0; i < cobd->Count; i++) { classd = cobd->Classes[i]; if (classd->ClassName) { sc = BaseRegisterClass(NULL, 0, classd->ClassName, NULL); /* Ignore any error */ } } /* And give CRT a chance to clean up */ // CrtInit(DLL_PROCESS_DETACH); /* Do not free if marked static */ if (This->super.RefCnt & REFCNT_STATIC) return S_OK; return pHeap->v->Free(pHeap, 0, This); } const CLASSDESC(DefCob,7); static const struct CUnknownVtbl DefCobVtable = { (struct _ClassDesc *) &DefCob_ClassDesc, { __VTABLE_COMPATIBILITY_FILLER_INITIALIZER CUnknownQueryInterface, CUnknownAddRef, CUnknownRelease } }; const struct DefCob_ClassDesc DefCob_ClassDesc = { _T("DefCob"), &IID_IUnknown, _T("CUnknown"), &IID_IUnknown, DefCobDestroy, sizeof(struct _DefCob), 7, { {(struct IUnknownVtbl *) &DefCobVtable.v, &IID_IUnknown, 3, 0}, {(struct IUnknownVtbl *) &CUnknown_12_Vtable.v, &IID_IUnknown, 3, 12}, {(struct IUnknownVtbl *) &CUnknown_16_Vtable.v, &IID_IUnknown, 3, 16}, {(struct IUnknownVtbl *) &CUnknown_20_Vtable.v, &IID_IUnknown, 3, 20}, {(struct IUnknownVtbl *) &CUnknown_24_Vtable.v, &IID_IUnknown, 3, 24}, {(struct IUnknownVtbl *) &CUnknown_28_Vtable.v, &IID_IUnknown, 3, 28}, {(struct IUnknownVtbl *) &CUnknown_32_Vtable.v, &IID_IUnknown, 3, 32} } }; COBDESC(Builtin,2) = { _T("builtin"), 2, { (struct _ClassDesc *) &CUnknown_ClassDesc, (struct _ClassDesc *) &DefCob_ClassDesc } }; PIUNKNOWN GenericCobInit(PTR Descriptor, /*optional*/ struct _DefCob *CobObjArg) { METHOD_DECLARE_NOTHIS(classreg.c, GenericCobInit); struct _CobDesc *cobd = Descriptor; struct _ClassDesc *classd; struct _DefCob *CobObj = CobObjArg; UINT i, j, k; sc = S_OK; for (i = 0; i < cobd->Count; i++) { classd = cobd->Classes[i]; if (classd->SuperClass) { /* Deal with v-table starting from QI so as to account for any pre-fillers */ sc = BaseInheritClass((ADDRESS*) &classd->iface[0].v->QueryInterface, classd->SuperClass, classd->SuperId); CHECKSC("BaseInheritClass"); /* Inherit other v-tables. XXX only CUnknown */ for (j = 1; j < classd->Count; j++) { ADDRESS * VTable = (ADDRESS*) &classd->iface[j].v->QueryInterface; /* Lookup the right v-table in a loop */ ADDRESS * StoredV = NULL; UINT off = classd->iface[j].Offset; for (k = 0; k < CUnknown_ClassDesc.Count; k++) { if (CUnknown_ClassDesc.iface[k].Offset == off) StoredV = (ADDRESS*) &CUnknown_ClassDesc.iface[k].v->QueryInterface; } CHECKSETSC(StoredV, E_INVALID_PARAMETER, "CUnknow0n inheritance botched"); for (k = 0; k < 3; k++) if (VTable[k] == 0) { VTable[k] = StoredV[k]; } } /* When we know the size of the COB, we'll use the correct size */ if (!CobObj && !_tcscmp(classd->SuperClass, _T("DefCob"))) { PIHEAP pHeap = CurrentHeap(); CobObj = (struct _DefCob *) pHeap->v->Alloc(pHeap, HEAP_ZERO_MEMORY, classd->Size, 0); CHECKSETSC(CobObj, E_NOT_ENOUGH_MEMORY, "Alloc cob object"); } } if (classd->ClassName) { sc = BaseRegisterClass((ADDRESS*) &classd->iface[0].v->QueryInterface, classd->iface[0].MethodCount, classd->ClassName, classd->ClassId); CHECKSC("BaseRegisterClass"); } } if (CobObj) { CUnknownInit(cobd->Classes[0], &CobObj->super); //CobObj->super.v = (void*) cobd->Classes[0]->iface[0].v; /* If an object was given, do not automatically Free it. */ if (CobObjArg) CobObj->super.RefCnt |= REFCNT_STATIC; /* Save state so that we can undo the registrations */ CobObj->cobd = cobd; } METHOD_CLEANUP; if (FAILED(sc)) { RELEASE(iDefCob(CobObj)); CobObj = NULL; /* XXX Unregister everything that was registered */ } return iDefCob(CobObj); } /* Class Registry */ static PINAMERANGES ClassNR = NULL; PUBLIC SCODE MCT BaseInitializeClassRegistry (void) { SCODE sc; PINAMESPACE ns = CurrentNameSpace(); PIUNKNOWN pUnk; /* Create subdir. */ sc = ns->v->Bind(ns, _T("vtables"), NAME_SPACE_CREATE, &pUnk); if (FAILED(sc)) return sc; sc = pUnk->v->QueryInterface(pUnk, &IID_INameRanges, (void *) &ClassNR); pUnk->v->Release(pUnk); if (FAILED(sc)) return sc; pUnk = GenericCobInit((struct _CobDesc *) &Builtin_CobDesc, NULL); return sc; } void BaseDeleteClassRegistry (void) { ClassNR->v->Release(ClassNR); } PUBLIC SCODE MCT BaseRegisterClass ( const ADDRESS * VTable, UINT MethodCount, const _TCHAR * ClassName, REFIID Iid) { /* Hack: register ClassNR as the object as it cannot be NULL * but we don't have a real object. */ if (VTable) { return ClassNR->v->RegisterRange(ClassNR, ClassName, (PIUNKNOWN) ClassNR, NAME_SPACE_CREATE, (ADDRESS) VTable, MethodCount * sizeof(ADDRESS), Iid); } else { return ClassNR->v->Unregister(ClassNR, ClassName); } } PUBLIC SCODE MCT BaseInheritClass ( ADDRESS * VTable, const _TCHAR * ClassName, REFIID Iid) { SCODE sc; ADDRESS *StoredV; UINT Size, i; /* Search for class */ sc = ClassNR->v->LookupRange(ClassNR, ClassName, Iid, (ADDRESS*) &StoredV, &Size); if (FAILED(sc)) return sc; sc = S_FALSE; /* no entries copied */ /* Inherit methods */ Size /= sizeof(ADDRESS); /* scale to number of slots */ for (i = 0; i < Size; i++) if (VTable[i] == 0) { VTable[i] = StoredV[i]; sc = S_OK; /* some entries copied */ } return sc; }