560 lines
15 KiB
C++
560 lines
15 KiB
C++
|
/*======================================================================================//
|
||
|
| Process Control //
|
||
|
| //
|
||
|
|Copyright (c) 1998 Sequent Computer Systems, Incorporated. All rights reserved. //
|
||
|
| //
|
||
|
|File Name: DataObj.cpp //
|
||
|
| //
|
||
|
|Description: //
|
||
|
| //
|
||
|
|Created: //
|
||
|
| //
|
||
|
|Rev History: //
|
||
|
| //
|
||
|
|=======================================================================================*/
|
||
|
|
||
|
// from samples...
|
||
|
|
||
|
#include "StdAfx.h"
|
||
|
|
||
|
#include "DataObj.h"
|
||
|
#include "BaseNode.h"
|
||
|
#include "Resource.h"
|
||
|
|
||
|
//#define COUNT_DEBUG
|
||
|
|
||
|
// not required but needed formats
|
||
|
UINT CDataObject::s_cfNodeID = ::RegisterClipboardFormat(CCF_NODEID); // not used in MMC 1.2 if CCF_NODEID2 is supported
|
||
|
UINT CDataObject::s_cfNodeID2 = ::RegisterClipboardFormat(CCF_NODEID2);
|
||
|
UINT CDataObject::s_cfSnapinPreloads = ::RegisterClipboardFormat(CCF_SNAPIN_PRELOADS);
|
||
|
UINT CDataObject::s_cfWindowTitle = ::RegisterClipboardFormat(CCF_WINDOW_TITLE);
|
||
|
|
||
|
// required formats
|
||
|
UINT CDataObject::s_cfNodeType = ::RegisterClipboardFormat(CCF_NODETYPE);
|
||
|
UINT CDataObject::s_cfNodeTypeString = ::RegisterClipboardFormat(CCF_SZNODETYPE);
|
||
|
UINT CDataObject::s_cfDisplayName = ::RegisterClipboardFormat(CCF_DISPLAY_NAME);
|
||
|
UINT CDataObject::s_cfSnapinClsid = ::RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
|
||
|
|
||
|
// our additional formats...
|
||
|
UINT CDataObject::s_cfInternal = ::RegisterClipboardFormat(CCF_SNAPIN_INTERNAL);
|
||
|
UINT CDataObject::s_cfBaseInternal = ::RegisterClipboardFormat(CCF_SNAPIN_BASEINTERNAL);
|
||
|
|
||
|
LONG CDataObject::s_nCount = 0;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CDataObject - This class is used to pass data back and forth with MMC. It
|
||
|
// uses a standard interface, IDataObject to acomplish this.
|
||
|
// Refer to OLE documentation for a description of clipboard
|
||
|
// formats and the IdataObject interface.
|
||
|
CDataObject::CDataObject()
|
||
|
{
|
||
|
m_Cookie = SPECIAL_COOKIE_MIN;
|
||
|
m_Context = CCT_UNINITIALIZED;
|
||
|
m_pFolderObj = NULL;
|
||
|
m_bResultItem = FALSE;
|
||
|
|
||
|
InterlockedIncrement(&s_nCount);
|
||
|
#ifdef COUNT_DEBUG
|
||
|
ATLTRACE( _T("CDataObj::CDataObj() %ld\n"), s_nCount );
|
||
|
#endif
|
||
|
|
||
|
} // end Constructor()
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
CDataObject::~CDataObject()
|
||
|
{
|
||
|
InterlockedDecrement(&s_nCount);
|
||
|
#ifdef COUNT_DEBUG
|
||
|
ATLTRACE( _T("CDataObj::~CDataObj() %ld\n"), s_nCount );
|
||
|
#endif
|
||
|
} // end Destructor()
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// IDataObject implementation
|
||
|
//
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CDataObject::GetDataHere
|
||
|
(
|
||
|
FORMATETC *pFormatEtc, // [in] Pointer to the FORMATETC structure
|
||
|
STGMEDIUM *pStgMedium // [out] Pointer to the STGMEDIUM structure
|
||
|
)
|
||
|
{
|
||
|
ASSERT(pFormatEtc && pStgMedium );
|
||
|
if (!pFormatEtc || !pStgMedium)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
HRESULT hr = DV_E_FORMATETC; // Unknown format
|
||
|
const CLIPFORMAT cf = pFormatEtc->cfFormat;
|
||
|
IStream *pStream = NULL;
|
||
|
|
||
|
pStgMedium->pUnkForRelease = NULL; // by OLE spec
|
||
|
|
||
|
// Make sure FORMATETC is something we can handle...
|
||
|
if( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
|
||
|
return DV_E_FORMATETC;
|
||
|
|
||
|
SIZE_T Size = GlobalSize(pStgMedium->hGlobal);
|
||
|
//
|
||
|
// $$ potential problem...
|
||
|
// the stream just gets bigger as needed
|
||
|
// but GetDataHere is not suppose to do that...
|
||
|
// is this an issue?
|
||
|
//
|
||
|
hr = CreateStreamOnHGlobal( pStgMedium->hGlobal, FALSE, &pStream );
|
||
|
if( FAILED(hr) )
|
||
|
return hr;
|
||
|
|
||
|
if( cf == s_cfNodeType )
|
||
|
{
|
||
|
hr = WriteNodeTypeGUID( pStream );
|
||
|
}
|
||
|
else if( cf == s_cfNodeTypeString )
|
||
|
{
|
||
|
hr = WriteNodeTypeGUIDString( pStream );
|
||
|
}
|
||
|
else if( cf == s_cfDisplayName )
|
||
|
{
|
||
|
hr = WriteDisplayName( pStream );
|
||
|
}
|
||
|
else if( cf == s_cfSnapinClsid )
|
||
|
{
|
||
|
hr = WriteClsid( pStream );
|
||
|
}
|
||
|
else if( cf == s_cfInternal )
|
||
|
{
|
||
|
hr = WriteInternal( pStream );
|
||
|
}
|
||
|
else if( cf == s_cfBaseInternal )
|
||
|
{
|
||
|
hr = WriteBaseInternal( pStream );
|
||
|
}
|
||
|
else if (cf == s_cfSnapinPreloads )
|
||
|
{
|
||
|
hr = WriteSnapinPreloads( pStream );
|
||
|
}
|
||
|
/* // wait and verify first, I haven't seen this yet
|
||
|
// and don't want to discover that some time down the
|
||
|
// road microsoft starts calling this and I'm not handling this correctly...
|
||
|
// see QueryDataObject() special cookies too... and IS_SPECIAL_COOKIE in sdk help
|
||
|
else if (cf == s_cfWindowTitle )
|
||
|
{
|
||
|
hr = WriteWindowTitle( pStream );
|
||
|
}
|
||
|
*/
|
||
|
else
|
||
|
{
|
||
|
hr = DV_E_FORMATETC;
|
||
|
}
|
||
|
|
||
|
SIZE_T Size2 = GlobalSize(pStgMedium->hGlobal);
|
||
|
|
||
|
ASSERT(Size == Size2);
|
||
|
|
||
|
pStream->Release();
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
} // end GetDataHere()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
STDMETHODIMP CDataObject::GetData
|
||
|
(
|
||
|
LPFORMATETC pFormatEtc, // [in] Pointer to the FORMATETC structure
|
||
|
LPSTGMEDIUM pStgMedium // [out] Pointer to the STGMEDIUM structure
|
||
|
)
|
||
|
{
|
||
|
ASSERT(pFormatEtc && pStgMedium );
|
||
|
if (!pFormatEtc || !pStgMedium)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
HRESULT hr = DV_E_FORMATETC; // Unknown format
|
||
|
const CLIPFORMAT cf = pFormatEtc->cfFormat;
|
||
|
pStgMedium->pUnkForRelease = NULL;
|
||
|
|
||
|
_TCHAR szFormatName[246];
|
||
|
if (!GetClipboardFormatName(cf, szFormatName, ARRAY_SIZE(szFormatName)))
|
||
|
_tcscpy(szFormatName, _T("Unknown format") );
|
||
|
|
||
|
// Make sure FORMATETC is something we can handle...
|
||
|
if( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
|
||
|
{
|
||
|
ATLTRACE( _T("CDataObject::GetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if (cf == s_cfNodeID ||
|
||
|
cf == s_cfNodeID2 ||
|
||
|
cf == s_cfSnapinPreloads )
|
||
|
{
|
||
|
IStream *pStream = NULL;
|
||
|
|
||
|
pStgMedium->tymed = TYMED_HGLOBAL;
|
||
|
pStgMedium->hGlobal = NULL;
|
||
|
|
||
|
// the stream gets bigger as needed, not a problem
|
||
|
hr = CreateStreamOnHGlobal( NULL, FALSE, &pStream );
|
||
|
if( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = GetHGlobalFromStream(pStream, &(pStgMedium->hGlobal));
|
||
|
ASSERT( SUCCEEDED(hr) );
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
if (cf == s_cfNodeID)
|
||
|
hr = WriteNodeID( pStream, TRUE );
|
||
|
else if (cf == s_cfNodeID2)
|
||
|
hr = WriteNodeID( pStream );
|
||
|
else if (cf == s_cfSnapinPreloads)
|
||
|
hr = WriteSnapinPreloads(pStream);
|
||
|
else
|
||
|
{
|
||
|
// a more expensive path to say no!
|
||
|
ASSERT(FALSE); // we already checked for format ...function out of sync?
|
||
|
GlobalFree(pStgMedium->hGlobal);
|
||
|
pStgMedium->hGlobal = NULL;
|
||
|
pStgMedium->tymed = TYMED_NULL;
|
||
|
hr = DV_E_FORMATETC;
|
||
|
}
|
||
|
}
|
||
|
pStream->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//ATLTRACE( _T("CDataObject::GetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
} // end GetData()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// SetData can be implemented if a data consumer needs to change the
|
||
|
// properties of one of our nodes.
|
||
|
//
|
||
|
STDMETHODIMP CDataObject::SetData
|
||
|
(
|
||
|
LPFORMATETC pFormatEtc, //[in] FormatEtc to use
|
||
|
LPSTGMEDIUM pStgMedium, //[in] StgMedium to use
|
||
|
BOOL bRelease //[in] TRUE if we release the memory
|
||
|
)
|
||
|
{
|
||
|
ASSERT( pFormatEtc && pStgMedium );
|
||
|
if (!pFormatEtc || !pStgMedium)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
HRESULT hr = DV_E_FORMATETC;
|
||
|
|
||
|
// Make sure FORMATETC is something we can handle.
|
||
|
if( (DVASPECT_CONTENT & pFormatEtc->dwAspect) &&
|
||
|
(TYMED_HGLOBAL & pFormatEtc->tymed ) )
|
||
|
{
|
||
|
//
|
||
|
}
|
||
|
|
||
|
if( bRelease )
|
||
|
ReleaseStgMedium( pStgMedium );
|
||
|
|
||
|
ATLTRACE( _T("CDataObject::SetData() returned 0x%X \n"), hr );
|
||
|
return hr;
|
||
|
|
||
|
} // end SetData()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
STDMETHODIMP CDataObject::QueryGetData
|
||
|
(
|
||
|
LPFORMATETC pFormatEtc // [in] FormatEtc struct to test.
|
||
|
)
|
||
|
{
|
||
|
ASSERT(pFormatEtc);
|
||
|
if (!pFormatEtc)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
HRESULT hr = DV_E_FORMATETC;
|
||
|
const CLIPFORMAT cf = pFormatEtc->cfFormat;
|
||
|
|
||
|
// Make sure FORMATETC is something we can handle.
|
||
|
if ( (DVASPECT_CONTENT != pFormatEtc->dwAspect) || (TYMED_HGLOBAL != pFormatEtc->tymed) )
|
||
|
hr = DV_E_FORMATETC;
|
||
|
else if (cf == s_cfNodeID || cf == s_cfNodeID2 || cf == s_cfSnapinPreloads)
|
||
|
hr = S_OK;
|
||
|
else
|
||
|
hr = DV_E_FORMATETC;
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
_TCHAR szFormatName[246];
|
||
|
if (!GetClipboardFormatName(cf, szFormatName, ARRAY_SIZE(szFormatName)))
|
||
|
_tcscpy(szFormatName, _T("Unknown format") );
|
||
|
//ATLTRACE( _T("CDataObject::QueryGetData() called with ClipFormat 0x%X %s return 0x%X\n"), cf, szFormatName, hr );
|
||
|
#endif
|
||
|
return hr;
|
||
|
|
||
|
} // end QueryGetData()
|
||
|
|
||
|
|
||
|
STDMETHODIMP CDataObject::EnumFormatEtc
|
||
|
(
|
||
|
DWORD dwDirection, //[in] Only DATADIR_GET supported
|
||
|
LPENUMFORMATETC* ppEnumFormatEtc //[out] Points to our IEnumFormatEtc
|
||
|
)
|
||
|
{
|
||
|
ATLTRACE( _T("CDataObject::EnumFormatEtc\n"));
|
||
|
return E_NOTIMPL;
|
||
|
} // end EnumFormatEtc()
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Support methods
|
||
|
//
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Write the appropriate GUID to the stream
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteNodeTypeGUID
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
if (!m_pFolderObj)
|
||
|
{
|
||
|
ASSERT( FALSE );
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
const GUID *pGuid = m_pFolderObj->GetGUIDptr();
|
||
|
|
||
|
return pStream->Write( (PVOID)pGuid, sizeof(GUID), NULL );
|
||
|
|
||
|
} // end WriteNodeTypeGUID()
|
||
|
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CDataObject::WriteNodeTypeGUIDString
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
if (!m_pFolderObj)
|
||
|
{
|
||
|
ASSERT( FALSE );
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
const TCHAR *szGuid = m_pFolderObj->GetGUIDsz();
|
||
|
ULONG ulSizeofString = ( _tcslen(szGuid) + 1) * sizeof(TCHAR);
|
||
|
|
||
|
return pStream->Write( szGuid, ulSizeofString, NULL );
|
||
|
|
||
|
} // end WriteNodeTypeGUIDString()
|
||
|
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Writes the display name to the stream, the node name
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteDisplayName
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
ASSERT(m_pFolderObj);
|
||
|
|
||
|
if (!m_pFolderObj)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
ULONG ulSizeofName = _tcslen(m_pFolderObj->GetNodeName());
|
||
|
|
||
|
if (ulSizeofName) // Count null character if we have a string
|
||
|
ulSizeofName++;
|
||
|
|
||
|
ulSizeofName *= sizeof(TCHAR);
|
||
|
|
||
|
return pStream->Write(m_pFolderObj->GetNodeName(), ulSizeofName, NULL);
|
||
|
|
||
|
} // end WriteDisplayName()
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Writes the Class ID to the stream
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteClsid
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
return pStream->Write( &CLSID_ComponentData,
|
||
|
sizeof(CLSID_ComponentData),
|
||
|
NULL
|
||
|
);
|
||
|
} // end WriteClsid()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Writes a pointer to this data object to the stream
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteInternal
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
ASSERT(m_pFolderObj);
|
||
|
if (!m_pFolderObj)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
CDataObject *pThis = this;
|
||
|
return pStream->Write( &pThis, sizeof(CDataObject*), NULL );
|
||
|
|
||
|
} // end WriteInternal
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Writes a CBaseNode pointer to the stream
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteBaseInternal
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
ASSERT(m_pFolderObj);
|
||
|
|
||
|
if (!m_pFolderObj)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
return pStream->Write( &m_pFolderObj, sizeof(CBaseNode *), NULL );
|
||
|
|
||
|
} // end WriteInternal
|
||
|
|
||
|
HRESULT
|
||
|
CDataObject::WriteNodeID
|
||
|
(
|
||
|
IStream* pStream, // [in] Stream we are writing to
|
||
|
BOOL bCCF_NODEID /* = FALSE */ // [in] reply with older CCF_NODEID format rather than CCF_NODEID2
|
||
|
)
|
||
|
{
|
||
|
if (!m_pFolderObj)
|
||
|
{
|
||
|
ASSERT( FALSE );
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
HRESULT hr;
|
||
|
DWORD dwFlags = 0;
|
||
|
BOOL bPersisted = m_pFolderObj->IsPersisted();
|
||
|
const TCHAR *szGuid = m_pFolderObj->GetGUIDsz();
|
||
|
DWORD cBytes = (_tcslen(szGuid) + 1) * sizeof(TCHAR);
|
||
|
|
||
|
if (bCCF_NODEID) // CCF_NODEID (originial or older format)
|
||
|
{
|
||
|
// CCF_NODEID cBytes = 0 implies don't persist this node's selection
|
||
|
if (!bPersisted)
|
||
|
cBytes = 0;
|
||
|
hr = pStream->Write(&cBytes, sizeof(cBytes), NULL);
|
||
|
if (hr == S_OK) hr = pStream->Write(szGuid, cBytes, NULL);
|
||
|
}
|
||
|
else // CCF_NODEID2 (newer format)
|
||
|
{
|
||
|
// CCF_NODEID2 doesn't permit writing cBytes = 0, Node GUID string is always written
|
||
|
if (!bPersisted)
|
||
|
dwFlags |= MMC_NODEID_SLOW_RETRIEVAL;
|
||
|
hr = pStream->Write(&dwFlags, sizeof(dwFlags), NULL);
|
||
|
if (hr == S_OK) hr = pStream->Write(&cBytes, sizeof(cBytes), NULL);
|
||
|
if (hr == S_OK) hr = pStream->Write(szGuid, cBytes, NULL);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
} // WriteNodeID()
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CDataObject::WriteSnapinPreloads
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
if (!m_pFolderObj)
|
||
|
{
|
||
|
ASSERT( FALSE );
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
BOOL bPreload = m_pFolderObj->GetPreload();
|
||
|
|
||
|
return pStream->Write( &bPreload, sizeof(bPreload), NULL );
|
||
|
|
||
|
} // end WriteSnapinPreloads()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Writes the display name to the stream, the node name
|
||
|
//
|
||
|
HRESULT
|
||
|
CDataObject::WriteWindowTitle
|
||
|
(
|
||
|
IStream* pStream // [in] Stream we are writing to
|
||
|
)
|
||
|
{
|
||
|
ASSERT(m_pFolderObj);
|
||
|
if (!m_pFolderObj)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
ULONG ulSizeofName = _tcslen(m_pFolderObj->GetWindowTitle());
|
||
|
|
||
|
if (ulSizeofName) // Count null character if we have a string
|
||
|
ulSizeofName++;
|
||
|
|
||
|
ulSizeofName *= sizeof(TCHAR);
|
||
|
|
||
|
return pStream->Write(m_pFolderObj->GetWindowTitle(), ulSizeofName, NULL);
|
||
|
|
||
|
} // end WriteWindowTitle()
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
VOID
|
||
|
CDataObject::SetDataObject
|
||
|
(
|
||
|
DATA_OBJECT_TYPES Context, // [in] Context of the caller
|
||
|
CBaseNode *pFolder
|
||
|
)
|
||
|
{
|
||
|
m_Context = Context;
|
||
|
m_pFolderObj = pFolder;
|
||
|
} // end SetDataObject()
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
VOID
|
||
|
CDataObject::SetDataObject
|
||
|
(
|
||
|
DATA_OBJECT_TYPES Context, // [in] Context of the caller
|
||
|
CBaseNode *pFolder,
|
||
|
MMC_COOKIE Cookie // [in] Unique indentifier
|
||
|
)
|
||
|
{
|
||
|
m_Context = Context;
|
||
|
m_pFolderObj = pFolder;
|
||
|
m_Cookie = Cookie;
|
||
|
|
||
|
m_bResultItem = TRUE;
|
||
|
|
||
|
} // end SetDataObject()
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|