//============================================================================ // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: std.h // // History: // // 03/15/97 Kenn Takara Created. // // Declarations for some common code/macros. //============================================================================ #ifndef _STD_H_ #define _STD_H_ #if _MSC_VER >= 1000 // VC 5.0 or later #pragma once #endif #ifndef _DBGUTIL_H #include "dbgutil.h" #endif #include "malloc.h" #ifndef TFSCORE_API #define TFSCORE_API(type) __declspec( dllexport ) type FAR PASCAL #define TFSCORE_APIV(type) __declspec( dllexport ) type FAR CDECL #endif #define hrOK HRESULT(0) #define hrTrue HRESULT(0) #define hrFalse ResultFromScode(S_FALSE) #define hrFail ResultFromScode(E_FAIL) #define hrNotImpl ResultFromScode(E_NOTIMPL) #define hrNoInterface ResultFromScode(E_NOINTERFACE) #define hrNoMem ResultFromScode(E_OUTOFMEMORY) #define OffsetOf(s,m) (size_t)( (char *)&(((s *)0)->m) - (char *)0 ) #define EmbeddorOf(C,m,p) ((C *)(((char *)p) - OffsetOf(C,m))) #define DimensionOf(rgx) (sizeof((rgx)) / sizeof(*(rgx))) /*!-------------------------------------------------------------------------- DeclareSP, DeclareSPBasic DeclareSRG, DeclareSRGBasic DeclareSPT, DeclareSPTBasic DeclareSPM, DeclareSPMBasic These macros declare 'smart' pointers. Smart pointers behave like normal pointers with the exception that a smart pointer destructor frees the thing it is pointing at and assignment to a non-null smart pointer is not allowed. The DeclareSxx macros differ by how the generated smart pointer frees the memory: Macro Free Smart Pointer Type ====================== ============ ================== DeclareSP(TAG, Type) delete p; SPTAG DeclareSRG(TAG, Type) delete [] p; SRGTAG DeclareSPT(TAG, Type) TMemFree(p); SPTTAG DeclareSPM(TAG, Type) MMemFree(p); SPMTAG NOTE: use the 'Basic' variants (DeclareSPBasic, etc) for pointer to non-struct types (e.g. char, int, etc). Smart pointers have two methods: void SPTAG::Free() Free and then null the internally maintained pointer. Type *SPTAG::Transfer() Transfers pointer ownership to caller. The internally maintained pointer is cleared on exit. Author: GaryBu ---------------------------------------------------------------------------*/ #define DeclareSP(TAG,Type) DeclareSmartPointer(SP##TAG,Type,delete m_p) #define DeclareSRG(TAG,Type) DeclareSmartPointer(SRG##TAG,Type,delete [] m_p) #define DeclareSPT(TAG,Type) DeclareSmartPointer(SPT##TAG,Type,TMemFree(m_p)) #define DeclareSPM(TAG,Type) DeclareSmartPointer(SPM##TAG,Type,MMemFree(m_p)) #define DeclareSPBasic(TAG,Type)\ DeclareSPPrivateBasic(SP##TAG,Type, delete m_p) #define DeclareSRGBasic(TAG,Type)\ DeclareSPPrivateBasic(SRG##TAG,Type, delete [] m_p) #define DeclareSPTBasic(TAG,Type)\ DeclareSPPrivateBasic(SPT##TAG,Type,TMemFree(m_p)) #define DeclareSPMBasic(TAG,Type)\ DeclareSPPrivateBasic(SPM##TAG,Type,MMemFree(m_p)) #define DeclareSPPrivateCore(klass, Type, free)\ class klass \ {\ public:\ klass() { m_p = 0; }\ klass(Type *p) { m_p = p; }\ ~klass() { free; }\ operator Type*() const { return m_p; }\ Type &operator*() const { return *m_p; }\ Type &operator[](int i) const { return m_p[i]; }\ Type &nth(int i) const { return m_p[i]; }\ Type **operator &() { Assert(!m_p); return &m_p; }\ Type *operator=(Type *p){ Assert(!m_p); return m_p = p; }\ Type *Transfer() { Type *p = m_p; m_p = 0; return p; }\ void Free() { free; m_p = 0; }\ private:\ void *operator=(const klass &);\ klass(const klass &);\ Type *m_p; #define DeclareSPPrivateBasic(klass, Type, free)\ DeclareSPPrivateCore(klass, Type, free)\ }; /*!-------------------------------------------------------------------------- DeclareSPBasicEx Variant of smart pointers that allows an extra member variable. The klassFree parameter lets you supply an alias for Free(). An example is IPropertyAccess and StdRowEditingTable: DeclareSPPrivateBasicEx(SPIPropertyAccess,IPropertyAccess, m_pex->ReleaseContext(m_p), StdRowEditingTable, ReleaseContext) SPIPropertyAccess sppac(pstdtable); sppac = pstdtable->GetContext(0); ...use spfc... sppac.ReleaseContext(); Author: KennT ---------------------------------------------------------------------------*/ #define DeclareSPBasicEx(klass, Type, free, klassEx, klassFree)\ DeclareSPPrivateCore(klass, Type, free)\ public:\ klass(klassEx *pex) \ {\ m_p = 0; m_pex=pex; } \ void klassFree() \ { Free(); } \ private:\ klassEx *m_pex; \ }; #define DeclareSmartPointer(klass, Type, free)\ DeclareSPPrivateCore(klass, Type, free)\ public:\ Type * operator->() const { return m_p; }\ }; TFSCORE_API(HRESULT) HrQueryInterface(IUnknown *punk, REFIID iid, LPVOID *ppv); template class ComSmartPointer { public: typedef T _PtrClass; ComSmartPointer() {p=NULL;} ~ComSmartPointer() { Release(); } // set p to NULL before releasing, this fixes a subtle bug // A has a ptr to B, B has a ptr to A // A gets told to release B // A calls spB.Release(); // in spB.Release(), B gets destructed and calls spA.Release() // in spA.Release(), A gets destructed and calls spB.Release() // since the ptr in spB has not been set to NULL (which is bad // since B has already gone away). void Release() {T* pTemp = p; if (p) { p=NULL; pTemp->Release(); }} operator T*() {return (T*)p;} T& operator*() {Assert(p!=NULL); return *p; } T** operator&() { Assert(p==NULL); return &p; } T* operator->() { Assert(p!=NULL); return p; } T* operator=(T* lp){ Release(); p = lp; return p;} T* operator=(const ComSmartPointer& lp) { if (p) p->Release(); p = lp.p; return p; } void Set(T* lp) { Release(); p = lp; if (p) p->AddRef(); } T * Transfer() { T* pTemp=p; p=NULL; return pTemp; } BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} void Query(IUnknown *punk) { HrQuery(punk); } HRESULT HrQuery(IUnknown *punk) { return ::HrQueryInterface(punk, *piid, (LPVOID *) &p); } T* p; private: // These methods should NEVER get called. ComSmartPointer(T* lp); ComSmartPointer(const ComSmartPointer& lp); }; // Interface utilities TFSCORE_API(void) SetI(IUnknown * volatile *punkL, IUnknown *punkR); TFSCORE_API(void) ReleaseI(IUnknown *punk); // Utilities for dealing with embedded classes #define DeclareEmbeddedInterface(interface, base) \ class E##interface : public interface \ { \ public: \ Declare##base##Members(IMPL) \ Declare##interface##Members(IMPL) \ } m_##interface; \ friend class E##interface; #define ImplementEmbeddedUnknown(embeddor, interface) \ STDMETHODIMP embeddor::E##interface::QueryInterface(REFIID iid,void **ppv)\ { \ return EmbeddorOf(embeddor,m_##interface,this)->QueryInterface(iid,ppv);\ } \ STDMETHODIMP_(ULONG) embeddor::E##interface::AddRef() \ { \ return EmbeddorOf(embeddor, m_##interface, this)->AddRef(); \ } \ STDMETHODIMP_(ULONG) embeddor::E##interface::Release() \ { \ return EmbeddorOf(embeddor, m_##interface, this)->Release(); \ } #define ImplementEmbeddedUnknownNoRefCount(embeddor, interface) \ STDMETHODIMP embeddor::E##interface::QueryInterface(REFIID iid,void **ppv)\ { \ return EmbeddorOf(embeddor,m_##interface,this)->QueryInterface(iid,ppv);\ } #define EMPrologIsolated(embeddor, interface, method) \ embeddor *pThis = EmbeddorOf(embeddor, m_##interface, this); #define ImplementIsolatedUnknown(embeddor, interface) \ STDMETHODIMP embeddor::E##interface::QueryInterface(REFIID iid,void **ppv)\ { \ EMPrologIsolated(embeddor, interface, QueryInterface); \ Assert(!FHrSucceeded(pThis->QueryInterface(IID_##interface, ppv))); \ *ppv = 0; \ if (iid == IID_IUnknown) *ppv = (IUnknown *) this; \ else if (iid == IID_##interface) *ppv = (interface *) this; \ else return ResultFromScode(E_NOINTERFACE); \ ((IUnknown *) *ppv)->AddRef(); \ return HRESULT_OK; \ } \ STDMETHODIMP_(ULONG) embeddor::E##interface::AddRef() \ { \ EMPrologIsolated(embeddor, interface, AddRef) \ return 1; \ } \ STDMETHODIMP_(ULONG) embeddor::E##interface::Release() \ { \ EMPrologIsolated(embeddor, interface, Release) \ return 1; \ } #define InitPThis(embeddor, object)\ embeddor *pThis = EmbeddorOf(embeddor, m_##object, this);\ /*--------------------------------------------------------------------------- Implements the controlling IUnknown interface for the inner object of an aggregation. ---------------------------------------------------------------------------*/ #define IMPLEMENT_AGGREGATION_IUNKNOWN(klass) \ STDMETHODIMP_(ULONG) klass::AddRef() \ { \ Assert(m_pUnknownOuter); \ return m_pUnknownOuter->AddRef(); \ } \ STDMETHODIMP_(ULONG) klass::Release() \ { \ Assert(m_pUnknownOuter); \ return m_pUnknownOuter->Release(); \ } \ STDMETHODIMP klass::QueryInterface(REFIID riid, LPVOID *ppv) \ { \ Assert(m_pUnknownOuter); \ return m_pUnknownOuter->QueryInterface(riid, ppv); \ } \ /*--------------------------------------------------------------------------- Declares the non-delegating IUnknown implementation in a class. ---------------------------------------------------------------------------*/ #define DECLARE_AGGREGATION_NONDELEGATING_IUNKNOWN(klass) \ class ENonDelegatingIUnknown : public IUnknown \ { \ public: \ DeclareIUnknownMembers(IMPL) \ } m_ENonDelegatingIUnknown; \ friend class ENonDelegatingIUnknown; \ IUnknown *m_pUnknownOuter; \ /*--------------------------------------------------------------------------- Implements the non-delegating IUnknown for a class. ---------------------------------------------------------------------------*/ #define IMPLEMENT_AGGREGATION_NONDELEGATING_ADDREFRELEASE(klass,interface) \ STDMETHODIMP_(ULONG) klass::ENonDelegatingIUnknown::AddRef() \ { \ InitPThis(klass, ENonDelegatingIUnknown); \ return InterlockedIncrement(&(pThis->m_cRef)); \ } \ STDMETHODIMP_(ULONG) klass::ENonDelegatingIUnknown::Release() \ { \ InitPThis(klass, ENonDelegatingIUnknown); \ if (0 == InterlockedDecrement(&(pThis->m_cRef))) \ { \ delete pThis; \ return 0; \ } \ return pThis->m_cRef; \ } \ #define IMPLEMENT_AGGREGATION_NONDELEGATING_IUNKNOWN(klass,interface) \ IMPLEMENT_AGGREGATION_NONDELEGATING_ADDREFRELEASE(klass,interface) \ STDMETHODIMP klass::ENonDelegatingIUnknown::QueryInterface(REFIID riid, LPVOID *ppv) \ { \ InitPThis(klass, ENonDelegatingIUnknown); \ if (ppv == NULL) \ return E_INVALIDARG; \ *ppv = NULL; \ if (riid == IID_IUnknown) \ *ppv = (IUnknown *) this; \ else if (riid == IID_##interface) \ *ppv = (interface *) pThis; \ else \ return E_NOINTERFACE; \ ((IUnknown *)*ppv)->AddRef(); \ return hrOK; \ } \ /*--------------------------------------------------------------------------- Standard TRY/CATCH wrappers for the COM interfaces ---------------------------------------------------------------------------*/ #define COM_PROTECT_TRY \ try #define COM_PROTECT_ERROR_LABEL Error: ;\ #ifdef DEBUG #define COM_PROTECT_CATCH \ catch(CException *pe) \ { \ hr = COleException::Process(pe); \ } \ catch(...) \ { \ hr = E_FAIL; \ } #else #define COM_PROTECT_CATCH \ catch(CException *pe) \ { \ hr = COleException::Process(pe); \ } \ catch(...) \ { \ hr = E_FAIL; \ } #endif /*--------------------------------------------------------------------------- Some useful smart pointers ---------------------------------------------------------------------------*/ DeclareSPPrivateBasic(SPSZ, TCHAR, delete[] m_p); DeclareSPPrivateBasic(SPWSZ, WCHAR, delete[] m_p); DeclareSPPrivateBasic(SPASZ, char, delete[] m_p); DeclareSPPrivateBasic(SPBYTE, BYTE, delete m_p); typedef ComSmartPointer SPIUnknown; typedef ComSmartPointer SPIStream; typedef ComSmartPointer SPIPersistStreamInit; #endif // _STD_H_