windows-nt/Source/XPSP1/NT/admin/hmonitor/snapin/snapindataobject.cpp
2020-09-26 16:20:57 +08:00

971 lines
22 KiB
C++

// 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;
}