_Undocumented Corner_ by George Shepherd and Scot Wingo Listing One class ATL_NO_VTABLE CDefault : public CComObjectRootEx, public CComCoClass, public IDispatchImpl { public: CDefault() { } DECLARE_REGISTRY_RESOURCEID(IDR_DEFAULT) BEGIN_COM_MAP(CDefault) COM_INTERFACE_ENTRY(IDefault) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // IDefault public: }; Listing Two template class CComObjectRootEx : public CComObjectRootBase { public: typedef ThreadModel _ThreadModel; typedef _ThreadModel::AutoCriticalSection _CritSec; ULONG InternalAddRef() { return _ThreadModel::Increment(&m_dwRef); } ULONG InternalRelease() { return _ThreadModel::Decrement(&m_dwRef); } void Lock() {m_critsec.Lock();} void Unlock() {m_critsec.Unlock();} private: _CritSec m_critsec; }; Listing Three class CComMultiThreadModelNoCS { public: static ULONG WINAPI Increment(LPLONG p) {return InterlockedIncrement(p);} static ULONG WINAPI Decrement(LPLONG p) {return InterlockedDecrement(p);} typedef CComFakeCriticalSection AutoCriticalSection; typedef CComFakeCriticalSection CriticalSection; typedef CComMultiThreadModelNoCS ThreadModelNoCS; }; class CComMultiThreadModel { public: static ULONG WINAPI Increment(LPLONG p) {return InterlockedIncrement(p);} static ULONG WINAPI Decrement(LPLONG p) {return InterlockedDecrement(p);} typedef CComAutoCriticalSection AutoCriticalSection; typedef CComCriticalSection CriticalSection; typedef CComMultiThreadModelNoCS ThreadModelNoCS; }; class CComSingleThreadModel { public: static ULONG WINAPI Increment(LPLONG p) {return ++(*p);} static ULONG WINAPI Decrement(LPLONG p) {return --(*p);} typedef CComFakeCriticalSection AutoCriticalSection; typedef CComFakeCriticalSection CriticalSection; typedef CComSingleThreadModel ThreadModelNoCS; }; Listing Four Class CDefault : public IDispatch, IDefault { HRESULT QueryInterface(RIID riid, void** ppv) { if(riid == IID_IDispatch) *ppv = (IDispatch*) this; else if(riid == IID_IDefault) *ppv = (IDefault*) this; else { *ppv = 0; return E_NOINTERFACE; } ((IUnknown*)(*ppv))->AddRef(); return NOERROR; } // AddRef, Release, and other functions }; Listing Five #define BEGIN_COM_MAP(x) public: typedef x _ComMapClass; static HRESULT WINAPI _Cache(void* pv,REFIID iid,void** ppvObject,DWORD dw){ _ComMapClass* p = (_ComMapClass*)pv; p->Lock(); HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw); p->Unlock(); return hRes; } IUnknown* GetUnknown() { _ASSERTE(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((int)this+_GetEntries()->dw); } HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries() { static const _ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x) ... #define END_COM_MAP() {NULL, 0, 0}};\ return _entries;} Listing Six struct _ATL_INTMAP_ENTRY { const IID* piid; DWORD dw; _ATL_CREATORARGFUNC* pFunc; } Listing Seven #define offsetofclass(base,derived)((DWORD)(static_cast((derived*)8))-8) #define COM_INTERFACE_ENTRY(x)\ {&IID_##x, \ offsetofclass(x, _ComMapClass), \ _ATL_SIMPLEMAPENTRY}, Listing Eight const static _ATL_INTMAP_ENTRY* __stdcall _GetEntries() { static const _ATL_INTMAP_ENTRY _entries[] = { {&IID_IDefault, ((DWORD)(static_cast((_ComMapClass*)8))-8), ((_ATL_CREATORARGFUNC*)1)}, {&IID_IDispatch, ((DWORD)(static_cast((_ComMapClass*)8))-8), ((_ATL_CREATORARGFUNC*)1)}, {0, 0, 0} }; return _entries; }