/*======================================================================================// | 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()