/* * dataobject.cxx * * * Copyright (c) 1998-1999 Microsoft Corporation * * PURPOSE: Implements the CDataObject class * * * OWNER: ptousig */ #include // ----------------------------------------------------------------------------- // static variables UINT CBaseDataObject::s_cfAdminHscopeitem = RegisterClipboardFormat(CF_EXCHANGE_ADMIN_HSCOPEITEM); // The HSCOPEITEM of this node UINT CBaseDataObject::s_cfMMCSnapinMachineName = RegisterClipboardFormat(CF_MMC_SNAPIN_MACHINE_NAME); // Format supplied by the Computer manager snapin. Passes in the name of the server. UINT CBaseDataObject::s_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME); UINT CBaseDataObject::s_cfNodeType = RegisterClipboardFormat(CCF_NODETYPE); UINT CBaseDataObject::s_cfSzNodeType = RegisterClipboardFormat(CCF_SZNODETYPE); UINT CBaseDataObject::s_cfSnapinClsid = RegisterClipboardFormat(CCF_SNAPIN_CLASSID); UINT CBaseDataObject::s_cfNodeID = RegisterClipboardFormat(CCF_NODEID); UINT CBaseDataObject::s_cfColumnSetId = RegisterClipboardFormat(CCF_COLUMN_SET_ID); UINT CBaseDataObject::s_cfMultiSelectionItemTypes = RegisterClipboardFormat(CCF_OBJECT_TYPES_IN_MULTI_SELECT); // Multiselect - list of types for the selected nodes // ----------------------------------------------------------------------------- HRESULT CBaseDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) { DECLARE_SC(sc,_T("")); Trace(tagBaseSnapinIDataObject, _T("--> %S::IDataObject::GetDataHere(pformatetc->cfFormat=%s)"), SzGetSnapinItemClassName(), SzDebugNameFromFormatEtc(pformatetc->cfFormat)); ADMIN_TRY; sc=ScGetDataHere(pformatetc, pmedium); ADMIN_CATCH_HR Trace(tagBaseSnapinIDataObject, _T("<-- %S::IDataObject::GetDataHere is returning hr=%s"), SzGetSnapinItemClassName(), SzGetDebugNameOfHr(sc.ToHr())); if (sc == SC(DV_E_FORMATETC) ) { sc.Clear(); return DV_E_FORMATETC; } return(sc.ToHr()); } // ----------------------------------------------------------------------------- HRESULT CBaseDataObject::GetData(FORMATETC *pformatetc, STGMEDIUM *pmedium) { DECLARE_SC(sc,_T("")); Trace(tagBaseSnapinIDataObject, _T("--> %S::IDataObject::GetData(pformatetc->cfFormat=%s)"), SzGetSnapinItemClassName(), SzDebugNameFromFormatEtc(pformatetc->cfFormat)); ADMIN_TRY; sc=ScGetData(pformatetc, pmedium); ADMIN_CATCH_HR Trace(tagBaseSnapinIDataObject, _T("<-- %S::IDataObject::GetData is returning hr=%s"), SzGetSnapinItemClassName(), SzGetDebugNameOfHr(sc.ToHr())); if (sc == SC(DV_E_FORMATETC) ) { sc.Clear(); return DV_E_FORMATETC; } return(sc.ToHr()); } // ----------------------------------------------------------------------------- HRESULT CBaseDataObject::QueryGetData(FORMATETC *pformatetc) { DECLARE_SC(sc,_T("")); Trace(tagBaseSnapinIDataObject, _T("--> %S::IDataObject::QueryGetData(pformatetc->cfFormat=%s)"), SzGetSnapinItemClassName(), SzDebugNameFromFormatEtc(pformatetc->cfFormat)); ADMIN_TRY; sc=ScQueryGetData(pformatetc); ADMIN_CATCH_HR Trace(tagBaseSnapinIDataObject, _T("<-- %S::IDataObject::QueryGetData is returning hr=%s"), SzGetSnapinItemClassName(), SzGetDebugNameOfHr(sc.ToHr())); return(sc.ToHr()); } // ----------------------------------------------------------------------------- HRESULT CBaseDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC* ppEnumFormatEtc) { DECLARE_SC(sc,_T("")); Trace(tagBaseSnapinIDataObject, _T("--> %S::IDataObject::EnumFormatEtc(dwDirection=%d)"), SzGetSnapinItemClassName(), dwDirection); ADMIN_TRY; sc=ScEnumFormatEtc(dwDirection, ppEnumFormatEtc); ADMIN_CATCH_HR Trace(tagBaseSnapinIDataObject, _T("<-- %S::IDataObject::EnumFormatEtc is returning hr=%s"), SzGetSnapinItemClassName(), SzGetDebugNameOfHr(sc.ToHr())); return(sc.ToHr()); } // ----------------------------------------------------------------------------- // Renders the data in a preallocated medium. // SC CBaseDataObject::ScGetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pMedium) { SC sc = S_OK; // check parameters if (pFormatEtc == NULL || pMedium == NULL) return sc = E_INVALIDARG; const CLIPFORMAT cf = pFormatEtc->cfFormat; CComPtr spStream; HGLOBAL hGlobal = NULL; // see what kind of medium we have if (pFormatEtc->tymed == TYMED_ISTREAM) { // it's a stream spStream = pMedium->pstm; if (spStream == NULL) { sc = E_UNEXPECTED; goto Error; } } else if (pFormatEtc->tymed == TYMED_HGLOBAL) { // it's hGlobal hGlobal = pMedium->hGlobal; sc = CreateStreamOnHGlobal( hGlobal, FALSE, &spStream ); if ( sc ) goto Error; // Minimal error checking } else // got the media we do not support { sc = DV_E_TYMED; goto Error; } pMedium->tymed = pFormatEtc->tymed; pMedium->pUnkForRelease = NULL; // by OLE spec if (cf == s_cfDisplayName ) sc = ScWriteDisplayName( spStream ); else if ( cf == s_cfAdminHscopeitem ) sc = ScWriteAdminHscopeitem( spStream ); else if ( cf == s_cfNodeType ) sc = ScWriteNodeType( spStream ); else if ( cf == s_cfSzNodeType ) sc = ScWriteSzNodeType( spStream ); else if ( cf == s_cfSnapinClsid ) sc = ScWriteClsid( spStream ); else if ( cf == s_cfNodeID ) sc = ScWriteNodeID( spStream ); else if (cf == s_cfColumnSetId ) sc = ScWriteColumnSetId( spStream ); else if ( (cf == s_cfMultiSelectionItemTypes) && FIsMultiSelectDataObject()) // the clipboard format is enabled only for multiselect data objects sc = ScWriteMultiSelectionItemTypes( spStream ); else if ( cf == CF_TEXT) sc = ScWriteAnsiName( spStream ); else // Unknown format { // we will pretend to suport it for IStream based media (it probably comes from object model) if (pFormatEtc->tymed == TYMED_ISTREAM) { WCHAR szDescription[] = L"Sample Value For Requested Format Of: "; spStream->Write(szDescription, wcslen(szDescription) * sizeof(WCHAR), NULL); TCHAR szFormatName[512]; int nChars = GetClipboardFormatName(cf, szFormatName, sizeof(szFormatName) / sizeof(szFormatName[0])); USES_CONVERSION; spStream->Write(T2W(szFormatName), nChars * sizeof(WCHAR), NULL); } else { sc = DV_E_FORMATETC; goto Cleanup; } } if (sc) goto Error; if (pFormatEtc->tymed == TYMED_HGLOBAL) { sc = GetHGlobalFromStream(spStream, &hGlobal); if (sc) goto Error; ASSERT(pMedium->hGlobal == NULL || pMedium->hGlobal == hGlobal); pMedium->hGlobal = hGlobal; } Cleanup: return sc; Error: if (sc == E_NOTIMPL) { sc = DV_E_FORMATETC; // Format not supported by this node goto Cleanup; } TraceError(_T("CBaseDataObject::GetDataHere"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // Renders the data in a newly allocated medium. // SC CBaseDataObject::ScGetData(FORMATETC *pFormatEtc, STGMEDIUM *pmedium) { SC sc = S_OK; pmedium->tymed = TYMED_HGLOBAL; pmedium->pUnkForRelease = NULL; pmedium->hGlobal = NULL; sc = ScGetDataHere(pFormatEtc, pmedium); if (sc == SC(DV_E_FORMATETC) ) { sc.Clear(); return DV_E_FORMATETC; } if (sc) goto Error; Cleanup: return sc; Error: TraceError(_T("CBaseDataObject::ScGetData"), sc); if (pmedium->hGlobal) GlobalFree(pmedium->hGlobal); pmedium->hGlobal = NULL; goto Cleanup; } // ----------------------------------------------------------------------------- // Asks whether a given format is supported by this data object. // SC CBaseDataObject::ScQueryGetData(FORMATETC *pFormatEtc) { SC sc = S_OK; const CLIPFORMAT cf = pFormatEtc->cfFormat; if ( ( cf == s_cfDisplayName ) || ( cf == s_cfNodeType ) || ( cf == s_cfSzNodeType ) || ( cf == s_cfSnapinClsid ) || ( cf == s_cfNodeID ) || ( cf == CF_TEXT) || ( (cf == s_cfMultiSelectionItemTypes) && FIsMultiSelectDataObject() ) // the clipboard format is enabled only for multiselect data objects ) { sc = S_OK; // known and acceptable format } else { sc = S_FALSE; // unknown or unacceptable format } return sc; } // ----------------------------------------------------------------------------- // Enumerates available clipboard format supported by this data object. // Only implemented in DEBUG. // SC CBaseDataObject::ScEnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC* ppEnumFormatEtc) #ifdef DBG { SC sc = S_OK; CComObject *pEnum = NULL; ASSERT(ppEnumFormatEtc); sc = CComObject::CreateInstance(&pEnum); if (!pEnum) goto MemoryError; sc = pEnum->QueryInterface(__uuidof(IEnumFORMATETC),(void **) ppEnumFormatEtc ); pEnum = NULL; if (sc) goto Error; Cleanup: return sc; MemoryError: if (pEnum) delete pEnum; pEnum = NULL; Error: TraceError(_T("CBaseDataObject::ScEnumFormatEtc"), sc); goto Cleanup; } #else { return E_NOTIMPL; } #endif // ----------------------------------------------------------------------------- // A convenience function to extract a GUID of the specified clipboard format // from a dataobject. // SC CBaseDataObject::ScGetGUID(UINT cf, LPDATAOBJECT lpDataObject, GUID *pguid) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; // validate parameters ASSERT(lpDataObject); ASSERT(pguid); // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(GUID)); if (!stgmedium.hGlobal) goto MemoryError; // Attempt to get data from the object sc = lpDataObject->GetDataHere(&formatetc, &stgmedium); if (sc == SC(DV_E_FORMATETC) ) { SC scNoTrace = sc; sc.Clear(); return scNoTrace; } if (sc) goto Error; // Copy the GUID into the return buffer pb = (BYTE*) GlobalLock(stgmedium.hGlobal); CopyMemory(pguid, pb, sizeof(GUID)); Cleanup: if (pb) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) { ASSERT(GlobalFree(stgmedium.hGlobal) == NULL); } stgmedium.hGlobal = NULL; return sc; MemoryError: sc = E_OUTOFMEMORY; Error: TraceError(_T("CBaseDataObject::ScGetGUID"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // A convenience function to extract a string of the specified clipboard format // from a dataobject. // SC CBaseDataObject::ScGetString(UINT cf, LPDATAOBJECT lpDataObject, tstring& str) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; // validate parameters ASSERT(lpDataObject); // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, str.length()); if (!stgmedium.hGlobal) goto MemoryError; // Attempt to get data from the object sc = lpDataObject->GetData(&formatetc, &stgmedium); if (sc) goto Error; // copy the string into the return buffer pb = (BYTE*) GlobalLock(stgmedium.hGlobal); str = (LPTSTR)pb; Cleanup: if (pb) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) { ASSERT(GlobalFree(stgmedium.hGlobal) == NULL); } stgmedium.hGlobal = NULL; return sc; MemoryError: sc = E_OUTOFMEMORY; Error: TraceError(_T("CBaseDataObject::ScGetString"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // A convenience function to extract a bool of the specified clipboard format // from a dataobject. // SC CBaseDataObject::ScGetBool(UINT cf, LPDATAOBJECT lpDataObject, BOOL *pf) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; // validate parameters ASSERT(lpDataObject); ASSERT(pf); // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(BOOL)); if (!stgmedium.hGlobal) goto MemoryError; // Attempt to get data from the object sc = lpDataObject->GetDataHere(&formatetc, &stgmedium); if (sc) goto Error; // copy the BOOL into the return buffer pb = (BYTE*) GlobalLock(stgmedium.hGlobal); CopyMemory(pf, pb, sizeof(BOOL)); Cleanup: if (pb) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) { ASSERT(GlobalFree(stgmedium.hGlobal) == NULL); } stgmedium.hGlobal = NULL; return sc; MemoryError: sc = E_OUTOFMEMORY; Error: TraceError(_T("CBaseDataObject::ScGetBool"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // A convenience function to extract a dword of the specified clipboard format // from a dataobject. // SC CBaseDataObject::ScGetDword(UINT cf, LPDATAOBJECT lpDataObject, DWORD *pdw) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; // validate parameters ASSERT(lpDataObject); ASSERT(pdw); // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(DWORD)); if (!stgmedium.hGlobal) goto MemoryError; // Attempt to get data from the object sc = lpDataObject->GetDataHere(&formatetc, &stgmedium); if (sc) goto Error; // copy the DWORD into the return buffer pb = (BYTE*) GlobalLock(stgmedium.hGlobal); CopyMemory(pdw, pb, sizeof(DWORD)); Cleanup: if (pb) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) { ASSERT(GlobalFree(stgmedium.hGlobal) == NULL); } stgmedium.hGlobal = NULL; return sc; MemoryError: sc = E_OUTOFMEMORY; Error: TraceError(_T("CBaseDataObject::ScGetDword"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // A convenience function to extract the SNodeID from a dataobject. // The SNodeID will be allocated with PvAlloc() and needs to be freed by // the caller. // SC CBaseDataObject::ScGetNodeID(LPDATAOBJECT lpDataObject, SNodeID **ppsnodeid) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)s_cfNodeID, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; int cb = 0; SNodeID * psnodeid = NULL; // validate parameters ASSERT(lpDataObject); ASSERT(ppsnodeid); ASSERT(*ppsnodeid == NULL); // Attempt to get data from the object sc = lpDataObject->GetData(&formatetc, &stgmedium); if (sc) goto Error; // Get a pointer to the blob pb = (BYTE*) GlobalLock(stgmedium.hGlobal); psnodeid = (SNodeID *) pb; cb = sizeof(DWORD) + psnodeid->cBytes; // Allocate a new buffer with PvAlloc psnodeid = (SNodeID *) GlobalAlloc(GMEM_FIXED, cb); if (psnodeid == NULL) goto MemoryError; CopyMemory(psnodeid, pb, cb); // Transfer ownership to our caller *ppsnodeid = psnodeid; psnodeid = NULL; Cleanup: if (pb) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) GlobalFree(stgmedium.hGlobal); if (psnodeid) GlobalFree(psnodeid); return sc; MemoryError: sc = E_OUTOFMEMORY; Error: TraceError(_T("CBaseDataObject::ScGetNodeID"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // A convenience function to extract an MMC Column Set ID from a dataobject. // SC CBaseDataObject::ScGetColumnSetID(LPDATAOBJECT lpDataObject, SColumnSetID ** ppColumnSetID) { SC sc = S_OK; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; FORMATETC formatetc = {(CLIPFORMAT)s_cfColumnSetId, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; BYTE* pb = NULL; SColumnSetID * pColumnSetID = NULL; int cb = 0; // validate parameters ASSERT(lpDataObject); ASSERT(ppColumnSetID); ASSERT(!*ppColumnSetID); // Attempt to get data from the object sc = lpDataObject->GetData(&formatetc, &stgmedium); if (sc) goto Error; pb = (BYTE*)GlobalLock(stgmedium.hGlobal); pColumnSetID = (SColumnSetID *) pb; cb = sizeof(SColumnSetID) + pColumnSetID->cBytes; // Allocate a new buffer with PvAlloc *ppColumnSetID = (SColumnSetID *)GlobalAlloc(GMEM_FIXED, cb); if (*ppColumnSetID == NULL) goto MemoryError; CopyMemory(*ppColumnSetID, pColumnSetID, cb); Cleanup: if (pColumnSetID) GlobalUnlock(stgmedium.hGlobal); if (stgmedium.hGlobal) { ASSERT(GlobalFree(stgmedium.hGlobal) == NULL); } stgmedium.hGlobal = NULL; return sc; MemoryError: sc = E_OUTOFMEMORY; Error: if(*ppColumnSetID) delete (*ppColumnSetID); (*ppColumnSetID) = NULL; TraceError(_T("CBaseDataObject::ScGetColumnSetID"), sc); goto Cleanup; } // ----------------------------------------------------------------------------- // Returns the name of the clipboard format (debug only) // #ifdef DBG LPTSTR CBaseDataObject::SzDebugNameFromFormatEtc(UINT format) { const int cchMaxLine = 256; static TCHAR s_szName[cchMaxLine]; int ret = 0; ret = GetClipboardFormatName(format, s_szName, cchMaxLine); if (ret == 0) _tcscpy(s_szName, _T("Unknown Clipboard Format")); return s_szName; } #endif // ----------------------------------------------------------------------------- // Moves to the next available clipboard format (debug only) // #ifdef DBG STDMETHODIMP CEnumFormatEtc::Next( /* [in] */ ULONG celt, /* [length_is][size_is][out] */ FORMATETC *rgelt, /* [out] */ ULONG *pceltFetched) { ASSERT(rgelt); if (celt != 1) return E_FAIL; if (m_dwIndex > 0) return S_FALSE; if (pceltFetched) *pceltFetched = 1; if (rgelt) { rgelt->cfFormat = CF_UNICODETEXT; rgelt->dwAspect = DVASPECT_CONTENT; rgelt->tymed = TYMED_HGLOBAL; } else return E_INVALIDARG; m_dwIndex++; return S_OK; } #endif