/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1998 **/ /**********************************************************************/ /* dataobj.cpp Implementation for data objects in the MMC FILE HISTORY: */ #include "stdafx.h" #include "dataobj.h" #include "extract.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /////////////////////////////////////////////////////////////////////////////// // Sample code to show how to Create DataObjects // Minimal error checking for clarity // Internal private format const wchar_t* SNAPIN_INTERNAL = L"SNAPIN_INTERNAL"; /////////////////////////////////////////////////////////////////////////////// // Snap-in NodeType in both GUID format and string format // Note - Typically there is a node type for each different object, sample // only uses one node type. // MMC required clipboard formats unsigned int CDataObject::m_cfNodeType = RegisterClipboardFormat(CCF_NODETYPE); unsigned int CDataObject::m_cfNodeTypeString = RegisterClipboardFormat(CCF_SZNODETYPE); unsigned int CDataObject::m_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME); unsigned int CDataObject::m_cfCoClass = RegisterClipboardFormat(CCF_SNAPIN_CLASSID); unsigned int CDataObject::m_cfMultiSel = RegisterClipboardFormat(CCF_OBJECT_TYPES_IN_MULTI_SELECT); unsigned int CDataObject::m_cfMultiSelDobj = RegisterClipboardFormat(CCF_MMC_MULTISELECT_DATAOBJECT); unsigned int CDataObject::m_cfDynamicExtension = RegisterClipboardFormat(CCF_MMC_DYNAMIC_EXTENSIONS); unsigned int CDataObject::m_cfNodeId2 = RegisterClipboardFormat(CCF_NODEID2); // snpain specific clipboard formats unsigned int CDataObject::m_cfInternal = RegisterClipboardFormat(SNAPIN_INTERNAL); ///////////////////////////////////////////////////////////////////////////// // CDataObject implementations DEBUG_DECLARE_INSTANCE_COUNTER(CDataObject); IMPLEMENT_ADDREF_RELEASE(CDataObject) STDMETHODIMP CDataObject::QueryInterface(REFIID riid, LPVOID *ppv) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Is the pointer bad? if (ppv == NULL) return E_INVALIDARG; // Place NULL in *ppv in case of failure *ppv = NULL; // This is the non-delegating IUnknown implementation if (riid == IID_IUnknown) *ppv = (LPVOID) this; else if (riid == IID_IDataObject) *ppv = (IDataObject *) this; else if (m_spUnknownInner) { // blind aggregation, we don't know what we're aggregating // with, so just pass it down. return m_spUnknownInner->QueryInterface(riid, ppv); } // If we're going to return an interface, AddRef it first if (*ppv) { ((LPUNKNOWN) *ppv)->AddRef(); return hrOK; } else return E_NOINTERFACE; } STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium) { HRESULT hr = DV_E_CLIPFORMAT; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Based on the CLIPFORMAT write data to the stream const CLIPFORMAT cf = lpFormatetc->cfFormat; if(cf == m_cfNodeType) { hr = CreateNodeTypeData(lpMedium); } else if (cf == m_cfCoClass) { hr = CreateCoClassID(lpMedium); } else if(cf == m_cfNodeTypeString) { hr = CreateNodeTypeStringData(lpMedium); } else if (cf == m_cfDisplayName) { hr = CreateDisplayName(lpMedium); } else if (cf == m_cfInternal) { hr = CreateInternal(lpMedium); } else { // // Call the derived class and see if it can handle // this clipboard format // hr = GetMoreDataHere(lpFormatetc, lpMedium); } return hr; } STDMETHODIMP CDataObject::GetData(LPFORMATETC lpFormatetcIn, LPSTGMEDIUM lpMedium) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = DV_E_CLIPFORMAT; if (lpFormatetcIn->cfFormat == m_cfMultiSel) { ASSERT(m_internal.m_cookie == MMC_MULTI_SELECT_COOKIE); if (m_internal.m_cookie != MMC_MULTI_SELECT_COOKIE) return E_FAIL; //return CreateMultiSelData(lpMedium); ASSERT(m_pbMultiSelData != 0); ASSERT(m_cbMultiSelData != 0); lpMedium->tymed = TYMED_HGLOBAL; lpMedium->hGlobal = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, (m_cbMultiSelData + sizeof(DWORD))); if (lpMedium->hGlobal == NULL) return STG_E_MEDIUMFULL; BYTE* pb = reinterpret_cast(::GlobalLock(lpMedium->hGlobal)); *((DWORD*)pb) = m_cbMultiSelData / sizeof(GUID); pb += sizeof(DWORD); CopyMemory(pb, m_pbMultiSelData, m_cbMultiSelData); ::GlobalUnlock(lpMedium->hGlobal); hr = S_OK; } else if (lpFormatetcIn->cfFormat == m_cfDynamicExtension) { if (m_pDynExt) { // get the data... m_pDynExt->BuildMMCObjectTypes(&lpMedium->hGlobal); if (lpMedium->hGlobal == NULL) return STG_E_MEDIUMFULL; hr = S_OK; } } else if (lpFormatetcIn->cfFormat == m_cfNodeId2) { hr = CreateNodeId2(lpMedium); } return hr; } STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC lpFormatEtc) { HRESULT hr = E_INVALIDARG; if (lpFormatEtc == NULL) return DV_E_FORMATETC; if (lpFormatEtc->lindex != -1) return DV_E_LINDEX; if (lpFormatEtc->tymed != TYMED_HGLOBAL) return DV_E_TYMED; if (!(lpFormatEtc->dwAspect & DVASPECT_CONTENT)) return DV_E_DVASPECT; // these are our supported clipboard formats. If it isn't one // of these then return invalid. if ( (lpFormatEtc->cfFormat == m_cfNodeType) || (lpFormatEtc->cfFormat == m_cfNodeTypeString) || (lpFormatEtc->cfFormat == m_cfDisplayName) || (lpFormatEtc->cfFormat == m_cfCoClass) || (lpFormatEtc->cfFormat == m_cfInternal) || (lpFormatEtc->cfFormat == m_cfNodeId2) || (lpFormatEtc->cfFormat == m_cfDynamicExtension) ) { hr = S_OK; } else if ((lpFormatEtc->cfFormat == m_cfMultiSel) || (lpFormatEtc->cfFormat == m_cfMultiSelDobj)) { // Support multi-selection format only if this // is a multi-select data object if (m_bMultiSelDobj) hr = S_OK; } else hr = QueryGetMoreData(lpFormatEtc); #ifdef DEBUG TCHAR buf[2000]; ::GetClipboardFormatName(lpFormatEtc->cfFormat, buf, sizeof(buf)); Trace2("CDataObject::QueryGetData - query format %s returning %lx\n", buf, hr); #endif return hr; } // Note - Sample does not implement these STDMETHODIMP CDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC* ppEnumFormatEtc) { return E_NOTIMPL; } STDMETHODIMP CDataObject::GetCanonicalFormatEtc(LPFORMATETC lpFormatEtcIn, LPFORMATETC lpFormatEtcOut) { return E_NOTIMPL; } STDMETHODIMP CDataObject::SetData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpMedium, BOOL bRelease) { return E_NOTIMPL; } STDMETHODIMP CDataObject::DAdvise(LPFORMATETC lpFormatEc, DWORD advf, LPADVISESINK pAdvSink, LPDWORD pdwConn) { return E_NOTIMPL; } STDMETHODIMP CDataObject::DUnadvise(DWORD dwConnection) { return E_NOTIMPL; } STDMETHODIMP CDataObject::EnumDAdvise(LPENUMSTATDATA *ppEnumAdvise) { return E_NOTIMPL; } ///////////////////////////////////////////////////////////////////////////// // CDataObject creation members HRESULT CDataObject::Create(const void* pBuffer, int len, LPSTGMEDIUM lpMedium) { HRESULT hr = DV_E_TYMED; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Do some simple validation if (pBuffer == NULL || lpMedium == NULL) return E_POINTER; // Make sure the type medium is HGLOBAL if (lpMedium->tymed == TYMED_HGLOBAL) { // Create the stream on the hGlobal passed in LPSTREAM lpStream; hr = CreateStreamOnHGlobal(lpMedium->hGlobal, FALSE, &lpStream); if (SUCCEEDED(hr)) { // Write to the stream the number of bytes unsigned long written; hr = lpStream->Write(pBuffer, len, &written); // Because we told CreateStreamOnHGlobal with 'FALSE', // only the stream is released here. // Note - the caller (i.e. snap-in, object) will free the HGLOBAL // at the correct time. This is according to the IDataObject specification. lpStream->Release(); } } return hr; } HRESULT CDataObject::CreateNodeTypeData(LPSTGMEDIUM lpMedium) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Create the node type object in GUID format SPITFSNode spNode; spNode = GetDataFromComponentData(); const GUID* pNodeType = spNode->GetNodeType(); return Create(reinterpret_cast(pNodeType), sizeof(GUID), lpMedium); } HRESULT CDataObject::CreateNodeTypeStringData(LPSTGMEDIUM lpMedium) { // Create the node type object in GUID string format OLECHAR szNodeType[128]; SPITFSNode spNode; spNode = GetDataFromComponentData(); const GUID* pNodeType = spNode->GetNodeType(); ::StringFromGUID2(*pNodeType,szNodeType,128); return Create(szNodeType, ((wcslen(szNodeType)+1) * sizeof(wchar_t)), lpMedium); } HRESULT CDataObject::CreateDisplayName(LPSTGMEDIUM lpMedium) { // This is the display named used in the scope pane and snap-in manager CString szDispName; SPITFSNode spNode; spNode = GetDataFromComponentData(); szDispName = spNode->GetString(-1); return Create(szDispName, ((szDispName.GetLength()+1) * sizeof(wchar_t)), lpMedium); } HRESULT CDataObject::CreateInternal(LPSTGMEDIUM lpMedium) { return Create(&m_internal, sizeof(INTERNAL), lpMedium); } HRESULT CDataObject::CreateCoClassID(LPSTGMEDIUM lpMedium) { // Create the CoClass information return Create(reinterpret_cast(&m_internal.m_clsid), sizeof(CLSID), lpMedium); } HRESULT CDataObject::CreateMultiSelData(LPSTGMEDIUM lpMedium) { Assert(m_internal.m_cookie == MMC_MULTI_SELECT_COOKIE); Assert(m_pbMultiSelData != 0); Assert(m_cbMultiSelData != 0); return Create(reinterpret_cast(m_pbMultiSelData), m_cbMultiSelData, lpMedium); } HRESULT CDataObject::CreateNodeId2(LPSTGMEDIUM lpMedium) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = hrOK; // Create the node type object in GUID format SPITFSNode spNode; spNode = GetDataFromComponentData(); SPITFSNodeHandler spHandler; spNode->GetHandler(&spHandler); if (spHandler) { CComBSTR bstrId; DWORD dwFlags = 0; hr = spHandler->CreateNodeId2(spNode, &bstrId, &dwFlags); if (SUCCEEDED(hr) && hr != S_FALSE && bstrId.Length() > 0) { int nSize = sizeof(SNodeID2) + (bstrId.Length() * sizeof(TCHAR)); lpMedium->tymed = TYMED_HGLOBAL; lpMedium->hGlobal = ::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, nSize); if (lpMedium->hGlobal == NULL) { hr = STG_E_MEDIUMFULL; } else { SNodeID2 * pNodeId = reinterpret_cast(::GlobalLock(lpMedium->hGlobal)); ::ZeroMemory(pNodeId, nSize); pNodeId->cBytes = bstrId.Length() * sizeof(TCHAR); pNodeId->dwFlags = dwFlags; _tcscpy((LPTSTR) pNodeId->id, bstrId); ::GlobalUnlock(lpMedium->hGlobal); } } } else { hr = E_UNEXPECTED; } return hr; } ITFSNode* CDataObject::GetDataFromComponentData() { SPITFSNodeMgr spNodeMgr; SPITFSNode spNode; Assert(m_spTFSComponentData); m_spTFSComponentData->GetNodeMgr(&spNodeMgr); spNodeMgr->FindNode(m_internal.m_cookie, &spNode); return spNode.Transfer(); }