// SnapinDataObject.cpp : implementation file // #include "stdafx.h" #include "ScopePaneItem.h" #include "ResultsPaneItem.h" #include "SnapinDataObject.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CSnapinDataObject UINT CSnapinDataObject::s_cfInternal = 0; UINT CSnapinDataObject::s_cfExtension = 0; // *CLEAN ME* LPCTSTR CF_SNAPIN_INTERNAL = _T("HealthMonitor"); LPCTSTR CF_SNAPIN_EXTENSION = _T("HealthMonitorExtension"); // *CLEAN ME* // {FBBB8DAE-AB34-11d2-BD62-0000F87A3912} static const GUID CLSID_SnapIn = { 0xfbbb8dae, 0xab34, 0x11d2, { 0xbd, 0x62, 0x0, 0x0, 0xf8, 0x7a, 0x39, 0x12 } }; //{ 0x69a539f8, 0x9520, 0x11d2, { 0xbd, 0x4a, 0x0, 0x0, 0xf8, 0x7a, 0x39, 0x12 } }; IMPLEMENT_DYNCREATE(CSnapinDataObject, CCmdTarget) CSnapinDataObject::CSnapinDataObject() { TRACEX(_T("CSnapinDataObject::CSnapinDataObject\n")); EnableAutomation(); // To keep the application running as long as an OLE automation // object is active, the constructor calls AfxOleLockApp. AfxOleLockApp(); if( ! RegisterClipboardFormats() ) { TRACE(_T("FAILED : RegisterClipboardFormats failed.\n")); ASSERT(FALSE); } m_ulCookie = 0; m_ItemType = CCT_UNINITIALIZED; } CSnapinDataObject::~CSnapinDataObject() { // To terminate the application when all objects created with // with OLE automation, the destructor calls AfxOleUnlockApp. AfxOleUnlockApp(); } ///////////////////////////////////////////////////////////////////////////// // Clipboard Members inline bool CSnapinDataObject::RegisterClipboardFormats() { if( ! s_cfInternal ) s_cfInternal = RegisterClipboardFormat(CF_SNAPIN_INTERNAL); if( ! s_cfExtension ) s_cfExtension = RegisterClipboardFormat(CF_SNAPIN_EXTENSION); m_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME); m_cfSPIGuid = RegisterClipboardFormat(CCF_NODETYPE); m_cfSnapinCLSID = RegisterClipboardFormat(CCF_SNAPIN_CLASSID); return s_cfInternal && s_cfExtension && m_cfDisplayName && m_cfSPIGuid && m_cfSnapinCLSID; } ///////////////////////////////////////////////////////////////////////////// // Item Members DATA_OBJECT_TYPES CSnapinDataObject::GetItemType() { TRACEX(_T("CSnapinDataObject::GetItemType\n")); TRACEARGn(m_ItemType); return m_ItemType; } ULONG CSnapinDataObject::GetCookie() { TRACEX(_T("CSnapinDataObject::GetCookie\n")); TRACEARGn(m_ulCookie); return m_ulCookie; } bool CSnapinDataObject::GetItem(CScopePaneItem*& pSPItem) { TRACEX(_T("CSnapinDataObject::GetItem(SPI)\n")); if( GetItemType() != CCT_SCOPE ) { TRACE(_T("WARNING : Item is not of type CCT_SCOPE.\n")); pSPItem = NULL; return false; } pSPItem = (CScopePaneItem*)GetCookie(); if( ! CHECKOBJPTR(pSPItem,RUNTIME_CLASS(CScopePaneItem),sizeof(CScopePaneItem)) ) { TRACE(_T("FAILED : The cookie is invalid or corrupt.\n")); pSPItem = NULL; return false; } return true; } bool CSnapinDataObject::GetItem(CResultsPaneItem*& pRPItem) { TRACEX(_T("CSnapinDataObject::GetItem(RPI)\n")); if( GetItemType() != CCT_RESULT ) { TRACE(_T("WARNING : Item is not of type CCT_RESULT.\n")); pRPItem = NULL; return false; } pRPItem = (CResultsPaneItem*)GetCookie(); if( ! CHECKOBJPTR(pRPItem,RUNTIME_CLASS(CResultsPaneItem),sizeof(CResultsPaneItem)) ) { TRACE(_T("FAILED : The cookie is invalid or corrupt.\n")); pRPItem = NULL; return false; } return true; } void CSnapinDataObject::SetItem(CScopePaneItem* pSPItem) { TRACEX(_T("CSnapinDataObject::SetItem(SPI)\n")); TRACEARGn(pSPItem); if( ! CHECKOBJPTR(pSPItem,RUNTIME_CLASS(CScopePaneItem),sizeof(CScopePaneItem)) ) { TRACE(_T("FAILED : pSPItem is an invalid CScopePaneItem pointer.\n")); m_ulCookie = NULL; m_ItemType = CCT_UNINITIALIZED; return; } #ifndef IA64 m_ulCookie = (ULONG)pSPItem; #endif // IA64 m_ItemType = CCT_SCOPE; } void CSnapinDataObject::SetItem(CResultsPaneItem* pRPItem) { TRACEX(_T("CSnapinDataObject::SetItem(RPI)\n")); TRACEARGn(pRPItem); if( ! CHECKOBJPTR(pRPItem,RUNTIME_CLASS(CResultsPaneItem),sizeof(CResultsPaneItem)) ) { TRACE(_T("FAILED : pRPItem is an invalid CResultsPaneItem pointer.\n")); m_ulCookie = NULL; m_ItemType = CCT_UNINITIALIZED; return; } #ifndef IA64 m_ulCookie = (ULONG)pRPItem; #endif // IA64 m_ItemType = CCT_RESULT; } ///////////////////////////////////////////////////////////////////////////// // DataObject Members CSnapinDataObject* CSnapinDataObject::GetSnapinDataObject(LPDATAOBJECT lpDataObject) { TRACEX(_T("CSnapinDataObject::GetSnapinDataObject\n")); TRACEARGn(lpDataObject); if( ! CHECKPTR(lpDataObject,sizeof(IDataObject)) ) { TRACE(_T("FAILED : lpDataObject pointer is invalid!\n")); return NULL; } HGLOBAL hGlobal = NULL; CSnapinDataObject* psdo = NULL; HRESULT hr = GetDataObject( lpDataObject, CSnapinDataObject::s_cfInternal, sizeof(CSnapinDataObject**), &hGlobal ); if( hr == DV_E_FORMATETC || ! CHECKHRESULT(hr) ) { return NULL; } psdo = *((CSnapinDataObject**)(hGlobal)); if( ! CHECKOBJPTR(psdo,RUNTIME_CLASS(CSnapinDataObject),sizeof(CSnapinDataObject)) ) { return NULL; } GlobalFree(hGlobal); return psdo; } HRESULT CSnapinDataObject::GetDataObject(LPDATAOBJECT lpDataObject, UINT cfClipFormat, ULONG nByteCount, HGLOBAL* phGlobal) { TRACEX(_T("CSnapinDataObject::GetDataObject\n")); TRACEARGn(lpDataObject); TRACEARGn(cfClipFormat); TRACEARGn(nByteCount); TRACEARGn(phGlobal); if( ! CHECKPTR(lpDataObject,sizeof(IDataObject)) ) { TRACE(_T("FAILED : lpDataObject is invalid.\n")); return E_FAIL; } HRESULT hr = S_OK; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { (unsigned short)cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; *phGlobal = NULL; // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc( GMEM_SHARE, nByteCount ); if( ! stgmedium.hGlobal ) { hr = E_OUTOFMEMORY; TRACE(_T("FAILED : Out of Memory.\n")); return hr; } // Attempt to get data from the object hr = lpDataObject->GetDataHere( &formatetc, &stgmedium ); if( hr == DV_E_FORMATETC || ! CHECKHRESULT(hr) ) { TRACE(_T("lpDataObject->GetDataFromHere failed.\n")); GlobalFree(stgmedium.hGlobal); stgmedium.hGlobal = NULL; return hr; } // stgmedium now has the data we need *phGlobal = stgmedium.hGlobal; stgmedium.hGlobal = NULL; return hr; } ///////////////////////////////////////////////////////////////////////////// // Write Members HRESULT CSnapinDataObject::WriteGuid(LPSTREAM pStream) { TRACEX(_T("CSnapinDataObject::WriteGuid\n")); TRACEARGn(pStream); if( ! CHECKPTR(pStream,sizeof(IStream)) ) { TRACE(_T("FAILED : Invalid IStream pointer passed.\n")); return E_FAIL; } LPGUID pGuid = NULL; if( GetItemType() == CCT_SCOPE ) { CScopePaneItem* pItem = NULL; if( ! GetItem(pItem) ) { return S_OK; } ASSERT(pItem); pGuid = pItem->GetItemType(); } else if( GetItemType() == CCT_RESULT ) { CResultsPaneItem* pItem = NULL; if( ! GetItem(pItem) ) { return S_OK; } ASSERT(pItem); pGuid = pItem->GetItemType(); if( ! pGuid ) { return S_OK; } } if( pGuid == NULL ) { TRACE(_T("FAILED : CScopePaneItem::GetItemType returns NULL.\n")); return E_FAIL; } return pStream->Write( (LPVOID)pGuid, sizeof(GUID), NULL ); } HRESULT CSnapinDataObject::WriteDisplayName(LPSTREAM pStream) { TRACEX(_T("CSnapinDataObject::WriteDisplayName\n")); TRACEARGn(pStream); if( ! CHECKPTR(pStream,sizeof(IStream)) ) { TRACE(_T("FAILED : Invalid IStream pointer passed.\n")); return E_FAIL; } CString sDisplayName; switch(GetItemType()) { case CCT_SCOPE: { CScopePaneItem* pItem = NULL; if( ! GetItem(pItem) ) { TRACE(_T("FAILED : GetItem failed.\n")); return E_FAIL; } ASSERT(pItem); sDisplayName = pItem->GetDisplayName(); } break; case CCT_RESULT: { CResultsPaneItem* pItem = NULL; if( ! GetItem(pItem) ) { TRACE(_T("FAILED : GetItem failed.\n")); return E_FAIL; } ASSERT(pItem); sDisplayName = pItem->GetDisplayName(); } break; } ULONG ulSizeofName = sDisplayName.GetLength() + 1; ulSizeofName *= sizeof(TCHAR); return pStream->Write(sDisplayName, ulSizeofName, NULL); } HRESULT CSnapinDataObject::WriteSnapinCLSID(LPSTREAM pStream) { TRACEX(_T("CSnapinDataObject::WriteSnapinCLSID\n")); TRACEARGn(pStream); if( ! CHECKPTR(pStream,sizeof(IStream)) ) { TRACE(_T("FAILED : Invalid IStream pointer passed.\n")); return E_FAIL; } return pStream->Write(&CLSID_SnapIn,sizeof(CLSID_SnapIn),NULL); } HRESULT CSnapinDataObject::WriteDataObject(LPSTREAM pStream) { TRACEX(_T("CSnapinDataObject::WriteDataObject\n")); TRACEARGn(pStream); if( ! CHECKPTR(pStream,sizeof(IStream)) ) { TRACE(_T("FAILED : Invalid IStream pointer passed.\n")); return E_FAIL; } CSnapinDataObject* pThis = this; return pStream->Write(&pThis,sizeof(CSnapinDataObject*),NULL); } HRESULT CSnapinDataObject::WriteExtensionData(LPSTREAM pStream) { TRACEX(_T("CSnapinDataObject::WriteExtensionData\n")); TRACEARGn(pStream); if( ! CHECKPTR(pStream,sizeof(IStream)) ) { TRACE(_T("FAILED : Invalid IStream pointer passed.\n")); return E_FAIL; } switch(GetItemType()) { case CCT_SCOPE: { CScopePaneItem* pItem = NULL; if( ! GetItem(pItem) ) { TRACE(_T("FAILED : GetItem failed.\n")); return E_FAIL; } ASSERT(pItem); return pItem->WriteExtensionData(pStream); } break; case CCT_RESULT: { CResultsPaneItem* pItem = NULL; if( ! GetItem(pItem) ) { TRACE(_T("FAILED : GetItem failed.\n")); return E_FAIL; } ASSERT(pItem); return pItem->WriteExtensionData(pStream); } break; } return E_FAIL; } ///////////////////////////////////////////////////////////////////////////// // MFC Implementation Members void CSnapinDataObject::OnFinalRelease() { // When the last reference for an automation object is released // OnFinalRelease is called. The base class will automatically // deletes the object. Add additional cleanup required for your // object before calling the base class. CCmdTarget::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CSnapinDataObject, CCmdTarget) //{{AFX_MSG_MAP(CSnapinDataObject) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CSnapinDataObject, CCmdTarget) //{{AFX_DISPATCH_MAP(CSnapinDataObject) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() // Note: we add support for IID_ISnapinDataObject to support typesafe binding // from VBA. This IID must match the GUID that is attached to the // dispinterface in the .ODL file. // {7D4A685E-9056-11D2-BD45-0000F87A3912} static const IID IID_ISnapinDataObject = { 0x7d4a685e, 0x9056, 0x11d2, { 0xbd, 0x45, 0x0, 0x0, 0xf8, 0x7a, 0x39, 0x12 } }; BEGIN_INTERFACE_MAP(CSnapinDataObject, CCmdTarget) INTERFACE_PART(CSnapinDataObject, IID_ISnapinDataObject, Dispatch) INTERFACE_PART(CSnapinDataObject, IID_IDataObject, DataObject) END_INTERFACE_MAP() // {01CB0090-AFCB-11d2-BD6B-0000F87A3912} IMPLEMENT_OLECREATE_EX(CSnapinDataObject, "SnapIn.SnapinDataObject", 0x1cb0090, 0xafcb, 0x11d2, 0xbd, 0x6b, 0x0, 0x0, 0xf8, 0x7a, 0x39, 0x12); BOOL CSnapinDataObject::CSnapinDataObjectFactory::UpdateRegistry(BOOL bRegister) { if (bRegister) return AfxOleRegisterServerClass(m_clsid, m_lpszProgID, m_lpszProgID, m_lpszProgID, OAT_DISPATCH_OBJECT); else return AfxOleUnregisterClass(m_clsid, m_lpszProgID); } ///////////////////////////////////////////////////////////////////////////// // IDataObject Interface Part ULONG FAR EXPORT CSnapinDataObject::XDataObject::AddRef() { METHOD_PROLOGUE(CSnapinDataObject, DataObject) return pThis->ExternalAddRef(); } ULONG FAR EXPORT CSnapinDataObject::XDataObject::Release() { METHOD_PROLOGUE(CSnapinDataObject, DataObject) return pThis->ExternalRelease(); } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppvObj) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj); } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::GetData( /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn, /* [out] */ STGMEDIUM __RPC_FAR *pmedium) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::GetData")); TRACEARGn(pformatetcIn); TRACEARGn(pmedium); HRESULT hr = S_OK; // Make sure FORMATETC is something we can handle. if( !(DVASPECT_CONTENT & pformatetcIn->dwAspect) || !(TYMED_HGLOBAL & pformatetcIn->tymed) ) { hr = DATA_E_FORMATETC; } if( S_OK == hr ) { if( s_cfExtension == pformatetcIn->cfFormat ) { IStream *pStream = NULL; // Allocate memory for the stream pmedium->hGlobal = GlobalAlloc( GMEM_SHARE, 1024 ); if( ! pmedium->hGlobal ) { hr = E_OUTOFMEMORY; TRACE(_T("FAILED : Out of Memory.\n")); return hr; } hr = CreateStreamOnHGlobal( pmedium->hGlobal, FALSE, &pStream ); hr = pThis->WriteExtensionData( pStream ); pStream->Release(); } else { hr = DATA_E_FORMATETC; } } return hr; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::GetDataHere( /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, /* [out][in] */ STGMEDIUM __RPC_FAR *pmedium) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::GetDataHere")); TRACEARGn(pformatetc); TRACEARGn(pmedium); HRESULT hr = DV_E_FORMATETC; // Unknown format const CLIPFORMAT cf = pformatetc->cfFormat; IStream *pStream = NULL; pmedium->pUnkForRelease = NULL; // by OLE spec // Write data to the stream based // on the clipformat hr = CreateStreamOnHGlobal( pmedium->hGlobal, FALSE, &pStream ); if( ! CHECKHRESULT(hr) ) { TRACE(_T("FAILED : Failed on call to CreateStreamOnHGlobal.\n")); return hr; // Minimal error checking } if( pThis->m_cfDisplayName == cf ) { hr = pThis->WriteDisplayName( pStream ); } else if( pThis->s_cfInternal == cf ) { hr = pThis->WriteDataObject( pStream ); } else if( pThis->s_cfExtension == cf ) { hr = pThis->WriteExtensionData( pStream ); } else if( pThis->m_cfSPIGuid == cf ) { hr = pThis->WriteGuid( pStream ); } else if( pThis->m_cfSnapinCLSID == cf ) { hr = pThis->WriteSnapinCLSID( pStream ); } pStream->Release(); return hr; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::QueryGetData( /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::QueryGetData")); TRACEARGn(pformatetc); HRESULT hr = S_OK; // For this sample, we just do a simple test. if( s_cfExtension == pformatetc->cfFormat ) hr = S_OK; else hr = S_FALSE; return hr; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::GetCanonicalFormatEtc( /* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn, /* [out] */ FORMATETC __RPC_FAR *pformatetcOut) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::GetCanonicalFormatEtc")); TRACEARGn(pformatectIn); TRACEARGn(pformatetcOut); return E_NOTIMPL; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::SetData( /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc, /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium, /* [in] */ BOOL fRelease) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::SetData")); TRACEARGn(pformatetc); TRACEARGn(pmedium); TRACEARGn(fRelease); return E_NOTIMPL; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::EnumFormatEtc( /* [in] */ DWORD dwDirection, /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::EnumFormatEtc")); TRACEARGn(dwDirection); TRACEARGn(ppenumFormatEtc); HRESULT hr = S_OK; static FORMATETC ForEtcArr[1]; // Use array so we can add more later ForEtcArr[0].cfFormat = (CLIPFORMAT)s_cfExtension; ForEtcArr[0].dwAspect = DVASPECT_CONTENT; ForEtcArr[0].ptd = NULL; ForEtcArr[0].tymed = TYMED_HGLOBAL; ForEtcArr[0].lindex = -1; switch( dwDirection ) { case DATADIR_GET: *ppenumFormatEtc = new CEnumFormatEtc(1, ForEtcArr); break; case DATADIR_SET: default: *ppenumFormatEtc = NULL; break; } if( NULL == *ppenumFormatEtc ) { hr = E_FAIL; } else { (*ppenumFormatEtc)->AddRef(); hr = S_OK; } return hr; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::DAdvise( /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ DWORD advf, /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink, /* [out] */ DWORD __RPC_FAR *pdwConnection) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::DAdvise")); TRACEARGn(pformatetc); TRACEARGn(advf); TRACEARGn(pAdvSink); TRACEARGn(pdwConnection); return E_NOTIMPL; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::DUnadvise( /* [in] */ DWORD dwConnection) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::DUnadvise")); TRACEARGn(dwConnection); return E_NOTIMPL; } HRESULT FAR EXPORT CSnapinDataObject::XDataObject::EnumDAdvise( /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise) { METHOD_PROLOGUE(CSnapinDataObject, DataObject) TRACEX(_T("CSnapinDataObject::XDataObject::EnumDAdvise")); TRACEARGn(ppenumAdvise); return E_NOTIMPL; } ///////////////////////////////////////////////////////////////////////////// // CSnapinDataObject message handlers ///////////////////////////////////////////////////////////////////////////// // CEnumFormatEtc Implementation /* * CEnumFormatEtc::CEnumFormatEtc * CEnumFormatEtc::~CEnumFormatEtc * * Parameters (Constructor): * cFE ULONG number of FORMATETCs in pFE * prgFE LPFORMATETC to the array to enumerate. */ CEnumFormatEtc::CEnumFormatEtc(ULONG cFE, LPFORMATETC prgFE) { UINT i; m_cRef=0; m_iCur=0; m_cfe=cFE; m_prgfe=new FORMATETC[(UINT)cFE]; if (NULL!=m_prgfe) { for (i=0; i < cFE; i++) m_prgfe[i]=prgFE[i]; } return; } CEnumFormatEtc::~CEnumFormatEtc(void) { if (NULL!=m_prgfe) delete [] m_prgfe; } /* * CEnumFormatEtc::QueryInterface * CEnumFormatEtc::AddRef * CEnumFormatEtc::Release * * Purpose: * IUnknown members for CEnumFormatEtc object. For QueryInterface * we only return out own interfaces and not those of the data * object. However, since enumerating formats only makes sense * when the data object is around, we insure that it stays as * long as we stay by calling an outer IUnknown for AddRef * and Release. But since we are not controlled by the lifetime * of the outer object, we still keep our own reference count in * order to free ourselves. */ STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID riid, VOID ** ppv) { *ppv=NULL; /* * Enumerators are separate objects, not the data object, so * we only need to support out IUnknown and IEnumFORMATETC * interfaces here with no concern for aggregation. */ if (IID_IUnknown==riid || IID_IEnumFORMATETC==riid) *ppv=this; //AddRef any interface we'll return. if (NULL!=*ppv) { ((LPUNKNOWN)*ppv)->AddRef(); return NOERROR; } return ResultFromScode(E_NOINTERFACE); } STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void) { ++m_cRef; return m_cRef; } STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void) { if (0!=--m_cRef) return m_cRef; delete this; return 0; } /* * CEnumFormatEtc::Next * * Purpose: * Returns the next element in the enumeration. * * Parameters: * cFE ULONG number of FORMATETCs to return. * pFE LPFORMATETC in which to store the returned * structures. * pulFE ULONG * in which to return how many we * enumerated. * * Return Value: * HRESULT NOERROR if successful, S_FALSE otherwise, */ STDMETHODIMP CEnumFormatEtc::Next(ULONG cFE, LPFORMATETC pFE, ULONG *pulFE) { ULONG cReturn=0L; if (NULL==m_prgfe) return ResultFromScode(S_FALSE); if (NULL==pulFE) { if (1L!=cFE) return ResultFromScode(E_POINTER); } else *pulFE=0L; if (NULL==pFE || m_iCur >= m_cfe) return ResultFromScode(S_FALSE); while (m_iCur < m_cfe && cFE > 0) { *pFE++=m_prgfe[m_iCur++]; cReturn++; cFE--; } if (NULL!=pulFE) *pulFE=cReturn; return NOERROR; } /* * CEnumFormatEtc::Skip * * Purpose: * Skips the next n elements in the enumeration. * * Parameters: * cSkip ULONG number of elements to skip. * * Return Value: * HRESULT NOERROR if successful, S_FALSE if we could not * skip the requested number. */ STDMETHODIMP CEnumFormatEtc::Skip(ULONG cSkip) { if (((m_iCur+cSkip) >= m_cfe) || NULL==m_prgfe) return ResultFromScode(S_FALSE); m_iCur+=cSkip; return NOERROR; } /* * CEnumFormatEtc::Reset * * Purpose: * Resets the current element index in the enumeration to zero. * * Parameters: * None * * Return Value: * HRESULT NOERROR */ STDMETHODIMP CEnumFormatEtc::Reset(void) { m_iCur=0; return NOERROR; } /* * CEnumFormatEtc::Clone * * Purpose: * Returns another IEnumFORMATETC with the same state as ourselves. * * Parameters: * ppEnum LPENUMFORMATETC * in which to return the * new object. * * Return Value: * HRESULT NOERROR or a general error value. */ STDMETHODIMP CEnumFormatEtc::Clone(LPENUMFORMATETC *ppEnum) { PCEnumFormatEtc pNew; *ppEnum=NULL; //Create the clone pNew=new CEnumFormatEtc(m_cfe, m_prgfe); if (NULL==pNew) return ResultFromScode(E_OUTOFMEMORY); pNew->AddRef(); pNew->m_iCur=m_iCur; *ppEnum=pNew; return NOERROR; }