/*++ Copyright (c) 2001 Microsoft Corporation Module Name : txnsup.h Abstract: Defines class for implementation of transaction routines SetAbort and SetComplete. Author: Andy Morrison ( andymorr ) April-2001 Revision History: --*/ #ifndef _TXNSUP_H #define _TXNSUP_H #include "asptxn.h" class CASPObjectContext : public IASPObjectContextImpl, public ITransactionStatus { private: LONG m_cRefs; BOOL m_fAborted; // FTM Support IUnknown *m_pUnkFTM; public: CASPObjectContext() { m_cRefs = 1; m_fAborted = FALSE; CDispatch::Init(IID_IASPObjectContext, Glob(pITypeLibTxn)); // Create the FTM CoCreateFreeThreadedMarshaler( (IUnknown*)((IASPObjectContextImpl *)this), &m_pUnkFTM ); }; ~CASPObjectContext() { if ( m_pUnkFTM != NULL ) { m_pUnkFTM->Release(); m_pUnkFTM = NULL; } }; //Non-delegating object IUnknown STDMETHODIMP QueryInterface(REFIID, PPVOID); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IASPObjectContext STDMETHOD(SetAbort)(); STDMETHOD(SetComplete)(); // ITransactionStatus STDMETHODIMP SetTransactionStatus(HRESULT hr); STDMETHODIMP GetTransactionStatus(HRESULT *pHrStatus); BOOL FAborted() { return m_fAborted; }; }; inline HRESULT CASPObjectContext::SetAbort() { HRESULT hr = E_NOTIMPL; IObjectContext * pContext = NULL; hr = GetObjectContext(&pContext); if( SUCCEEDED(hr) ) { hr = pContext->SetAbort(); pContext->Release(); m_fAborted = TRUE; } return hr; } inline HRESULT CASPObjectContext::SetComplete() { HRESULT hr = E_NOTIMPL; IObjectContext * pContext = NULL; hr = GetObjectContext(&pContext); if( SUCCEEDED(hr) ) { hr = pContext->SetComplete(); pContext->Release(); m_fAborted = FALSE; } return hr; } inline HRESULT CASPObjectContext::SetTransactionStatus(HRESULT hr) { // if m_fAborted is already set, this indicates that the // script set it and we should not reset it. if (m_fAborted == TRUE); else if (hr == XACT_E_ABORTED) { m_fAborted = TRUE; } else if (hr == S_OK) { m_fAborted = FALSE; } return S_OK; } inline HRESULT CASPObjectContext::GetTransactionStatus(HRESULT *pHrResult) { if (m_fAborted == TRUE) { *pHrResult = XACT_E_ABORTED; } else { *pHrResult = S_OK; } return S_OK; } /*=================================================================== CASPObjectContext::QueryInterface CASPObjectContext::AddRef CASPObjectContext::Release IUnknown members for CASPObjectContext object. ===================================================================*/ inline HRESULT CASPObjectContext::QueryInterface ( REFIID riid, PPVOID ppv ) { *ppv = NULL; /* * The only calls for IUnknown are either in a nonaggregated * case or when created in an aggregation, so in either case * always return our IUnknown for IID_IUnknown. */ if (IID_IUnknown == riid || IID_IDispatch == riid || IID_IASPObjectContext == riid) *ppv = static_cast(this); else if (IID_ITransactionStatus == riid) *ppv = static_cast(this); else if (IID_IMarshal == riid) { Assert( m_pUnkFTM != NULL ); if ( m_pUnkFTM == NULL ) { return E_UNEXPECTED; } return m_pUnkFTM->QueryInterface( riid, ppv ); } //AddRef any interface we'll return. if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; } return ResultFromScode(E_NOINTERFACE); } inline STDMETHODIMP_(ULONG) CASPObjectContext::AddRef(void) { return InterlockedIncrement(&m_cRefs); } inline STDMETHODIMP_(ULONG) CASPObjectContext::Release(void) { LONG cRefs = InterlockedDecrement(&m_cRefs); if (cRefs) return cRefs; delete this; return 0; } class CASPDummyObjectContext : public IASPObjectContextImpl { private: LONG m_cRefs; IUnknown *m_pUnkFTM; public: CASPDummyObjectContext::CASPDummyObjectContext() { m_cRefs = 1; CoCreateFreeThreadedMarshaler( (IUnknown*)((IASPObjectContextImpl*)this), &m_pUnkFTM ); }; CASPDummyObjectContext::~CASPDummyObjectContext() { if ( m_pUnkFTM != NULL ) { m_pUnkFTM->Release(); m_pUnkFTM = NULL; } }; //Non-delegating object IUnknown STDMETHODIMP QueryInterface(REFIID, PPVOID); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IASPObjectContext STDMETHOD(SetAbort)(); STDMETHOD(SetComplete)(); }; /*=================================================================== CASPDummyObjectContext::QueryInterface CASPDummyObjectContext::AddRef CASPDummyObjectContext::Release IUnknown members for CASPDummyObjectContext object. ===================================================================*/ inline HRESULT CASPDummyObjectContext::QueryInterface ( REFIID riid, PPVOID ppv ) { *ppv = NULL; /* * The only calls for IUnknown are either in a nonaggregated * case or when created in an aggregation, so in either case * always return our IUnknown for IID_IUnknown. */ if (IID_IUnknown == riid || IID_IDispatch == riid || IID_IASPObjectContext == riid) *ppv = static_cast(this); else if (IID_IMarshal == riid) { Assert( m_pUnkFTM != NULL ); if ( m_pUnkFTM == NULL ) { return E_UNEXPECTED; } return m_pUnkFTM->QueryInterface( riid, ppv ); } //AddRef any interface we'll return. if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); return S_OK; } return ResultFromScode(E_NOINTERFACE); } inline STDMETHODIMP_(ULONG) CASPDummyObjectContext::AddRef(void) { return InterlockedIncrement(&m_cRefs); } inline STDMETHODIMP_(ULONG) CASPDummyObjectContext::Release(void) { LONG cRefs = InterlockedDecrement(&m_cRefs); if (cRefs) return cRefs; delete this; return 0; } inline HRESULT CASPDummyObjectContext::SetAbort() { ExceptionId(IID_IASPObjectContext, IDE_OBJECTCONTEXT, IDE_OBJECTCONTEXT_NOT_TRANSACTED); return E_FAIL; } inline HRESULT CASPDummyObjectContext::SetComplete() { ExceptionId(IID_IASPObjectContext, IDE_OBJECTCONTEXT, IDE_OBJECTCONTEXT_NOT_TRANSACTED); return E_FAIL; } #endif