//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: multisel.cpp // //-------------------------------------------------------------------------- #include "stdafx.h" #include "objfmts.h" #include "multisel.h" #include "nmutil.h" #include "regutil.h" #include "copypast.h" #include "dbg.h" #include "rsltitem.h" DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinSelData); DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinSelDataList); UINT GetRelation(CMTNode* pMTNodeSrc, CMTNode* pMTNodeDest); CLIPFORMAT GetMultiSelectSnapinsCF() { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MULTI_SELECT_SNAPINS)); } return s_cf; } CLIPFORMAT GetMultiSelectStaticDataCF() { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MULTI_SELECT_STATIC_DATA)); } return s_cf; } CLIPFORMAT GetMultiSelObjectTypesCF() { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_OBJECT_TYPES_IN_MULTI_SELECT)); } return s_cf; } CLIPFORMAT GetMMCMultiSelDataObjectCF() { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT)); } return s_cf; } CLIPFORMAT GetMMCDynExtensionsCF() { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_DYNAMIC_EXTENSIONS)); } return s_cf; } HRESULT DataObject_GetHGLOBALData( IDataObject* piDataObject, CLIPFORMAT cfClipFormat, HGLOBAL* phGlobal) { ASSERT(piDataObject != NULL); ASSERT(phGlobal != NULL); if (piDataObject == NULL || phGlobal == NULL) return E_INVALIDARG; FORMATETC fmt = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM stgm = {TYMED_HGLOBAL, NULL, NULL}; HRESULT hr = piDataObject->GetData(&fmt, &stgm); if (SUCCEEDED(hr) && (stgm.tymed == TYMED_HGLOBAL) && (stgm.hGlobal != NULL)) { *phGlobal = stgm.hGlobal; } else { ReleaseStgMedium(&stgm); if (SUCCEEDED(hr)) hr = (stgm.tymed != TYMED_HGLOBAL) ? DV_E_TYMED : E_UNEXPECTED; } return hr; } DEBUG_DECLARE_INSTANCE_COUNTER(CMultiSelectDataObject); CMultiSelectDataObject::~CMultiSelectDataObject() { if (m_pMS) m_pMS->Release(); if (m_ppDataObjects != NULL) { delete [] m_ppDataObjects; } DEBUG_DECREMENT_INSTANCE_COUNTER(CMultiSelectDataObject); } STDMETHODIMP CMultiSelectDataObject::GetData( FORMATETC* pfmt, STGMEDIUM* pmedium) { if (m_ppDataObjects == NULL && m_ppMTNodes == NULL) return HRESULT_FROM_WIN32(ERROR_TIMEOUT); pmedium->hGlobal = NULL; // init if (pfmt->tymed & TYMED_HGLOBAL) { if (pfmt->cfFormat == GetMultiSelectSnapinsCF()) { // UINT size = sizeof(DWORD) + m_count * sizeof(LPDATAOBJECT); // Windows bug 662181: On IA64 there are 4 bytes of padding after the DWORD. // Changed to the platform-independent expression below. UINT size = sizeof(SMMCDataObjects) + m_count * sizeof(LPDATAOBJECT) - sizeof(LPDATAOBJECT); pmedium->hGlobal = ::GlobalAlloc(GPTR, size); SMMCDataObjects* pData = reinterpret_cast(pmedium->hGlobal); if (pData == NULL) return E_OUTOFMEMORY; pData->count = m_count; for (UINT i=0; ilpDataObject[i] = m_ppDataObjects[i]; } } else if (pfmt->cfFormat == GetMultiSelectStaticDataCF()) { ASSERT(m_nSize >= 0); typedef CMTNode* _PMTNODE; // m_ppDataObjects m_count UINT cb = sizeof(DWORD) + sizeof(_PMTNODE) * m_nSize; pmedium->hGlobal = ::GlobalAlloc(GPTR, cb); BYTE* pb = reinterpret_cast(pmedium->hGlobal); if (pb == NULL) return E_OUTOFMEMORY; *((DWORD*)pb) = m_nSize; if (m_nSize > 0) { pb += sizeof(DWORD); _PMTNODE* ppMTNodes = (_PMTNODE*)pb; CopyMemory(ppMTNodes, m_ppMTNodes, m_nSize * sizeof(_PMTNODE)); } } else if (pfmt->cfFormat == GetMMCMultiSelDataObjectCF()) { pmedium->hGlobal = ::GlobalAlloc(GPTR, sizeof(DWORD)); if (pmedium->hGlobal == NULL) return E_OUTOFMEMORY; *((DWORD*)pmedium->hGlobal) = 1; } else { pmedium->tymed = TYMED_NULL; pmedium->hGlobal = NULL; pmedium->pUnkForRelease = NULL; return DATA_E_FORMATETC; } if (pmedium->hGlobal != NULL) { pmedium->tymed = TYMED_HGLOBAL; pmedium->pUnkForRelease = NULL; return S_OK; } else { return E_OUTOFMEMORY; } } return DV_E_TYMED; } STDMETHODIMP CMultiSelectDataObject::GetDataHere( FORMATETC* pfmt, STGMEDIUM* pmedium) { return E_NOTIMPL; } STDMETHODIMP CMultiSelectDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) { if (m_ppDataObjects == NULL && m_ppMTNodes == NULL) return HRESULT_FROM_WIN32(ERROR_TIMEOUT); if (dwDirection == DATADIR_SET) return E_FAIL; FORMATETC fmte[] = { {GetMultiSelectSnapinsCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, {GetMMCMultiSelDataObjectCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, }; HRESULT hr = ::GetObjFormats(countof(fmte), fmte, (void**)ppenumFormatEtc); return hr; } STDMETHODIMP CMultiSelectDataObject::QueryGetData(LPFORMATETC pfmt) { if (m_ppDataObjects == NULL && m_ppMTNodes == NULL) return HRESULT_FROM_WIN32(ERROR_TIMEOUT); // // Check the aspects we support. // if (!(DVASPECT_CONTENT & pfmt->dwAspect)) return DATA_E_FORMATETC; ASSERT(GetMultiSelectSnapinsCF() != 0); if (pfmt->cfFormat == GetMMCMultiSelDataObjectCF() || pfmt->cfFormat == GetMultiSelectSnapinsCF()) return S_OK; return S_FALSE; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void CSnapinSelDataList::Add(CSnapinSelData& snapinSelData, BOOL bStaticNode) { BOOL bCreateNew = TRUE; if (bStaticNode == FALSE && snapinSelData.GetID() != TVOWNED_MAGICWORD) { POSITION pos = GetHeadPosition(); while (pos) { CSnapinSelData* pSnapinSelData = GetNext(pos); if (pSnapinSelData->GetID() == snapinSelData.GetID()) { pSnapinSelData->IncrementNumOfItems(); pSnapinSelData->AddScopeNodes( snapinSelData.GetScopeNodes() ); bCreateNew = FALSE; break; } } } if (bCreateNew == TRUE) { CSnapinSelData* pSnapinSelData = new CSnapinSelData; pSnapinSelData->SetNumOfItems(snapinSelData.GetNumOfItems()); pSnapinSelData->AddScopeNodes(snapinSelData.GetScopeNodes()); pSnapinSelData->SetIsScopeItem(snapinSelData.IsScopeItem()); pSnapinSelData->SetCookie(snapinSelData.GetCookie()); pSnapinSelData->SetID(snapinSelData.GetID()); pSnapinSelData->SetSnapIn(snapinSelData.GetSnapIn()); AddHead(pSnapinSelData); } } DEBUG_DECLARE_INSTANCE_COUNTER(CMultiSelection); CMultiSelection::CMultiSelection(CNode* pNode) : m_pNode(pNode), m_pMTSINode(NULL), m_bHasNodes(FALSE), m_pSINode(dynamic_cast(pNode)), m_bInUse(FALSE), m_cRef(1) { ASSERT(pNode != NULL); #ifdef DBG m_bInit = FALSE; #endif DEBUG_INCREMENT_INSTANCE_COUNTER(CMultiSelection); } CMultiSelection::~CMultiSelection() { ASSERT(m_bInUse == FALSE); if (m_spDataObjectMultiSel != NULL) { CMultiSelectDataObject* pObj = dynamic_cast( static_cast(m_spDataObjectMultiSel)); ASSERT(pObj != NULL); if (pObj) pObj->SetDataObjects(NULL, 0); } DEBUG_DECREMENT_INSTANCE_COUNTER(CMultiSelection); } HRESULT CMultiSelection::Init() { #ifdef DBG m_bInit = TRUE; #endif // compute m_pSINode, m_pMTSINode, m_pszExtensionTypeKey if (m_pNode != NULL) { if (m_pSINode == NULL) m_pSINode = m_pNode->GetStaticParent(); ASSERT(m_pMTSINode == NULL); ASSERT(m_pNode->GetMTNode() != NULL); if (m_pNode->GetMTNode() == NULL) return E_UNEXPECTED; m_pMTSINode = m_pNode->GetMTNode()->GetStaticParent(); ASSERT(m_pMTSINode != NULL); if (m_pMTSINode == NULL) return E_UNEXPECTED; } return S_OK; } bool CMultiSelection::RemoveStaticNode(CMTNode* pMTNode) { int iMax = m_rgStaticNodes.size()-1; if (iMax < 0) return false; if (::GetRelation(pMTNode, m_rgStaticNodes[0]) == 2) { m_rgStaticNodes.clear(); return m_snapinSelDataList.IsEmpty(); } for (int i=iMax; i >= 0; --i) { if (m_rgStaticNodes[i] == pMTNode) { CMTNodePtrArray::iterator iter = m_rgStaticNodes.begin(); std::advance(iter, iMax); m_rgStaticNodes[i] = m_rgStaticNodes[iMax]; m_rgStaticNodes.erase(iter); break; } } return m_rgStaticNodes.size(); } CComponent* CMultiSelection::_GetComponent(CSnapinSelData* pSnapinSelData) { CComponent* pCC = NULL; if ((pSnapinSelData->GetNumOfItems() > 1) || (pSnapinSelData->GetID() > 0) || (pSnapinSelData->IsScopeItem() == FALSE)) { CSnapInNode* pSINode = _GetStaticNode(); if (pSINode == NULL) return NULL; pCC = pSINode->GetComponent(pSnapinSelData->GetID()); ASSERT(pCC != NULL); } else { ASSERT(pSnapinSelData->IsScopeItem() == TRUE); CNode* pNode = CNode::FromHandle ((HNODE) pSnapinSelData->GetCookie()); ASSERT(pNode != NULL); if (pNode != NULL) pCC = pNode->GetPrimaryComponent(); } return pCC; } HRESULT CMultiSelection::_ComputeSelectionDataList() { #ifdef DBG ASSERT(m_bInit == TRUE); #endif ASSERT(m_pNode != NULL); ASSERT(m_pNode->GetViewData() != NULL); HWND hwnd = m_pNode->GetViewData() ? m_pNode->GetViewData()->GetListCtrl() : NULL; ASSERT(hwnd != NULL); if (hwnd == NULL) return E_UNEXPECTED; ASSERT(::IsWindow(hwnd)); if (!(::IsWindow(hwnd))) return E_UNEXPECTED; if (m_pNode->GetViewData()->IsVirtualList() == TRUE) { CSnapinSelData snapinSelData; snapinSelData.SetID(m_pNode->GetPrimaryComponent()->GetComponentID()); snapinSelData.SetNumOfItems(ListView_GetSelectedCount(hwnd)); if (snapinSelData.GetNumOfItems() == 1) snapinSelData.SetCookie(ListView_GetNextItem(hwnd, -1, LVIS_SELECTED)); m_snapinSelDataList.Add(snapinSelData, FALSE); } else { int iSel = ListView_GetNextItem(hwnd, -1, LVIS_SELECTED); if (iSel < 0) return S_FALSE; for (; iSel >= 0; iSel = ListView_GetNextItem(hwnd, iSel, LVIS_SELECTED)) { LPARAM lParam = ListView_GetItemData(hwnd, iSel); CResultItem* pri = CResultItem::FromHandle(lParam); ASSERT(pri != NULL); if (pri == NULL) return E_FAIL; CSnapinSelData snapinSelData; snapinSelData.SetID(pri->GetOwnerID()); snapinSelData.IncrementNumOfItems(); snapinSelData.SetCookie(pri->GetSnapinData()); BOOL bStaticNode = FALSE; if (pri->IsScopeItem()) { CNode* pNodeContext = CNode::FromResultItem (pri); ASSERT(pNodeContext != NULL); if (pNodeContext->IsInitialized() == FALSE) { HRESULT hr = pNodeContext->InitComponents(); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { m_rgStaticNodes.clear(); m_snapinSelDataList.RemoveAll(); return hr; } } // its a scope node - store to scope node array for this data object snapinSelData.AddScopeNodes(CSnapinSelData::CNodePtrArray(1, pNodeContext)); m_bHasNodes = TRUE; snapinSelData.SetID(::GetComponentID(NULL, pri)); snapinSelData.SetIsScopeItem(TRUE); if (snapinSelData.GetID() == TVOWNED_MAGICWORD) { ASSERT(pNodeContext->GetMTNode() != NULL); m_rgStaticNodes.push_back(pNodeContext->GetMTNode()); continue; } if (snapinSelData.GetID() == 0) { ASSERT(pri->IsScopeItem()); bStaticNode = pNodeContext->IsStaticNode(); if (bStaticNode) { ASSERT(pNodeContext->GetMTNode() != NULL); m_rgStaticNodes.push_back(pNodeContext->GetMTNode()); } } } // Add to the list m_snapinSelDataList.Add(snapinSelData, bStaticNode); } } POSITION pos = m_snapinSelDataList.GetHeadPosition(); HRESULT hr = S_OK; while (pos) { CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(pos); if (pSnapinSelData->GetNumOfItems() == 1) { // Get object type for single snapin item sel hr = _GetObjectTypeForSingleSel(pSnapinSelData); if (FAILED(hr)) return hr; } else if (pSnapinSelData->GetNumOfItems() > 1) { // Get object type(s) for multiple snapin items sel hr = _GetObjectTypesForMultipleSel(pSnapinSelData); if (FAILED(hr)) return hr; } } return hr; } HRESULT CMultiSelection::_GetObjectTypeForSingleSel( CSnapinSelData* pSnapinSelData) { ASSERT(pSnapinSelData->GetNumOfItems() == 1); if (m_pNode->GetViewData()->IsVirtualList() == FALSE) { ASSERT(pSnapinSelData->GetCookie() != 0); if (pSnapinSelData->GetNumOfItems() != 1 || pSnapinSelData->GetCookie() == 0) return E_INVALIDARG; } HRESULT hr = S_OK; IDataObjectPtr spDO; CComponent* pCC = _GetComponent(pSnapinSelData); if (pCC == NULL) return E_UNEXPECTED; if (pSnapinSelData->GetID() == TVOWNED_MAGICWORD) { ASSERT(pSnapinSelData->IsScopeItem() == TRUE); } else if (pSnapinSelData->IsScopeItem() == TRUE) { CNode* pNode = CNode::FromHandle ((HNODE) pSnapinSelData->GetCookie()); ASSERT(pNode != NULL); if (pNode == NULL) return E_FAIL; CComponentData* pCCD = NULL; if (pNode->IsStaticNode()) { CMTNode* pMTNode = pNode->GetMTNode(); ASSERT(pMTNode != NULL); if (pMTNode == NULL) return E_FAIL; pCCD = pMTNode->GetPrimaryComponentData(); } else { CMTSnapInNode* pMTSINode = _GetStaticMasterNode(); ASSERT(pMTSINode != NULL); if (pMTSINode == NULL) return E_UNEXPECTED; pCCD = pMTSINode->GetComponentData(pSnapinSelData->GetID()); } ASSERT(pCCD != NULL); if (pCCD == NULL) return E_UNEXPECTED; hr = pCCD->QueryDataObject(pNode->GetUserParam(), CCT_SCOPE, &spDO); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; pSnapinSelData->SetSnapIn(pCCD->GetSnapIn()); } else { hr = pCC->QueryDataObject(pSnapinSelData->GetCookie(), CCT_RESULT, &spDO); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; pSnapinSelData->SetSnapIn(pCC->GetSnapIn()); } do // not a loop { if (pCC == NULL) break; pSnapinSelData->SetComponent(pCC); IFramePrivate* pIFP = pCC->GetIFramePrivate(); ASSERT(pIFP != NULL); if (pIFP == NULL) break; IConsoleVerbPtr spConsoleVerb; hr = pIFP->QueryConsoleVerb(&spConsoleVerb); if (SUCCEEDED(hr)) { ASSERT(spConsoleVerb != NULL); pSnapinSelData->SetConsoleVerb(spConsoleVerb); CConsoleVerbImpl* pCVI = dynamic_cast( static_cast(spConsoleVerb)); ASSERT(pCVI != NULL); if (pCVI) pCVI->SetDisabledAll(); } Dbg(DEB_USER1, _T("MMCN_SELECT> MS-1 \n")); pCC->Notify(spDO, MMCN_SELECT, MAKELONG((WORD)FALSE, (WORD)TRUE), 0); } while (0); GUID guid; hr = ExtractObjectTypeGUID(spDO, &guid); ASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { pSnapinSelData->SetDataObject(spDO); pSnapinSelData->AddObjectType(guid); } return hr; } HRESULT CMultiSelection::_GetObjectTypesForMultipleSel( CSnapinSelData* pSnapinSelData) { ASSERT(m_pSINode != NULL); ASSERT(m_pMTSINode != NULL); ASSERT(pSnapinSelData != NULL); if (pSnapinSelData == NULL) return E_POINTER; CComponent* pCC = _GetComponent(pSnapinSelData); if (pCC == NULL) return E_UNEXPECTED; pSnapinSelData->SetSnapIn(pCC->GetSnapIn()); IDataObjectPtr spDO; HRESULT hr = pCC->QueryDataObject(MMC_MULTI_SELECT_COOKIE, CCT_UNINITIALIZED, &spDO); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; do // not a loop { if (pCC == NULL) break; pSnapinSelData->SetComponent(pCC); IFramePrivate* pIFP = pCC->GetIFramePrivate(); ASSERT(pIFP != NULL); if (pIFP == NULL) break; IConsoleVerbPtr spConsoleVerb; hr = pIFP->QueryConsoleVerb(&spConsoleVerb); if (SUCCEEDED(hr)) { ASSERT(spConsoleVerb != NULL); pSnapinSelData->SetConsoleVerb(spConsoleVerb); CConsoleVerbImpl* pCVI = dynamic_cast( static_cast(spConsoleVerb)); ASSERT(pCVI != NULL); if (pCVI) pCVI->SetDisabledAll(); } Dbg(DEB_USER1, _T("MMCN_SELECT> MS-2 \n")); pCC->Notify(spDO, MMCN_SELECT, MAKELONG((WORD)FALSE, (WORD)TRUE), 0); } while (0); if (spDO == NULL) return E_UNEXPECTED; // Get the data HGLOBAL hGlobal = NULL; hr = DataObject_GetHGLOBALData(spDO, GetMultiSelObjectTypesCF(), &hGlobal); if (FAILED(hr)) return hr; BYTE* pb = reinterpret_cast(::GlobalLock(hGlobal)); DWORD count = *((DWORD*)pb); pb += sizeof(DWORD); GUID* pGuid = reinterpret_cast(pb); for (DWORD index=0; index < count; ++index) { pSnapinSelData->AddObjectType(pGuid[index]); } ::GlobalUnlock(hGlobal); ::GlobalFree(hGlobal); pSnapinSelData->SetDataObject(spDO); return S_OK; } HRESULT CMultiSelection::GetMultiSelDataObject( IDataObject** ppDataObject) { if (m_spDataObjectMultiSel == NULL) { HRESULT hr = S_OK; if (HasData() == FALSE) { hr = _ComputeSelectionDataList(); if (FAILED(hr)) return hr; ASSERT(HasData() == TRUE); if (HasData() == FALSE) return E_FAIL; } // CreateDataObjectForMultiSelection CComObject* pMSDObject; hr = CComObject::CreateInstance(&pMSDObject); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; ASSERT(pMSDObject != NULL); if (pMSDObject == NULL) return E_FAIL; pMSDObject->SetMultiSelection(this); UINT count = m_snapinSelDataList.GetCount(); if (count > 0) { LPDATAOBJECT* ppDOs = new LPDATAOBJECT[count]; POSITION pos = m_snapinSelDataList.GetHeadPosition(); for (int i=0; pos; ++i) { CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(pos); ASSERT(pSnapinSelData != NULL); ASSERT(i < count); ppDOs[i] = pSnapinSelData->GetDataObject(); ASSERT(ppDOs[i] != NULL); } pMSDObject->SetDataObjects(ppDOs, count); } int nSize = m_rgStaticNodes.size(); if (nSize > 0) { pMSDObject->SetStaticNodes(m_rgStaticNodes, nSize); } m_spDataObjectMultiSel = pMSDObject; } *ppDataObject = m_spDataObjectMultiSel; m_spDataObjectMultiSel.AddRef(); return S_OK; } HRESULT CMultiSelection::GetExtensionSnapins( LPCTSTR pszExtensionTypeKey, CList& extnClsidList) { DECLARE_SC(sc, TEXT("CMultiSelection::GetExtensionSnapins")); ASSERT(&extnClsidList != NULL); extnClsidList.RemoveAll(); //init HRESULT hr = S_OK; if (HasData() == FALSE) { hr = _ComputeSelectionDataList(); if (FAILED(hr)) return hr; if (hr == S_FALSE) return hr; ASSERT(HasData() == TRUE); if (HasData() == FALSE) return E_FAIL; } if (HasSnapinData() == FALSE) return S_FALSE; // // Add the extension snapin clsids for the first object type // to extnClsidList. // { CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetHead(); CList& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList(); ASSERT(objTypeGuidsList.IsEmpty() == FALSE); if (objTypeGuidsList.IsEmpty() == TRUE) return E_FAIL; // Get dynamic extensions requested by the snap-in CArray DynExtens; ExtractDynExtensions(pSnapinSelData->GetDataObject(), DynExtens); POSITION pos = objTypeGuidsList.GetHeadPosition(); BOOL bFirstTime = TRUE; while (pos) { GUID& objectTypeGuid = objTypeGuidsList.GetNext(pos); CExtensionsIterator it; sc = it.ScInitialize(pSnapinSelData->GetSnapIn(), objectTypeGuid, pszExtensionTypeKey, DynExtens.GetData(), DynExtens.GetSize()); if (sc) return hr; if (bFirstTime == TRUE) { bFirstTime = FALSE; for (; it.IsEnd() == FALSE; it.Advance()) { extnClsidList.AddHead(const_cast(it.GetCLSID())); } } else { CArray rgClsid; for (; it.IsEnd() == FALSE; it.Advance()) { rgClsid.Add(const_cast(it.GetCLSID())); } POSITION pos = extnClsidList.GetHeadPosition(); POSITION posCurr = 0; while (pos) { posCurr = pos; CLSID& clsid = extnClsidList.GetNext(pos); BOOL bPresent = FALSE; for (int k=0; k <= rgClsid.GetUpperBound(); ++k) { if (::IsEqualCLSID(rgClsid[k], clsid) == TRUE) { bPresent = TRUE; break; } } if (bPresent == FALSE) { // Remove from list ASSERT(posCurr != 0); extnClsidList.RemoveAt(posCurr); } } // end while } // end else // No point continuing if the extension clsid list is empty. if (extnClsidList.IsEmpty() == TRUE) break; } } if (extnClsidList.IsEmpty() == TRUE) return S_FALSE; // If only items from one snapin were selected return. if (m_snapinSelDataList.GetCount() == 1) return S_OK; // loop through the extension clsids POSITION pos = extnClsidList.GetHeadPosition(); while (pos) { // Get the first extension clsid POSITION posCurr = pos; CLSID& clsidSnapin = extnClsidList.GetNext(pos); // See if this clsid extends selected items put up by other snapins. BOOL bExtends = FALSE; POSITION posSDL = m_snapinSelDataList.GetHeadPosition(); m_snapinSelDataList.GetNext(posSDL); // skip the first one. while (posSDL) { CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(posSDL); CList& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList(); // Get dynamic extensions requested by the snap-in CArray DynExtens; ExtractDynExtensions(pSnapinSelData->GetDataObject(), DynExtens); POSITION pos2 = objTypeGuidsList.GetHeadPosition(); while (pos2) { bExtends = FALSE; // re-init GUID& guidObjectType = objTypeGuidsList.GetNext(pos2); CExtensionsIterator it; sc = it.ScInitialize(pSnapinSelData->GetSnapIn(), guidObjectType, pszExtensionTypeKey, DynExtens.GetData(), DynExtens.GetSize()); if (sc) break; for (; it.IsEnd() == FALSE; it.Advance()) { if (::IsEqualCLSID(clsidSnapin, it.GetCLSID()) == TRUE) { bExtends = TRUE; break; } } if (bExtends == FALSE) break; } if (bExtends == FALSE) break; } ASSERT(posCurr != 0); if (bExtends == FALSE) extnClsidList.RemoveAt(posCurr); } return S_OK; } BOOL CMultiSelection::IsAnExtensionSnapIn(const CLSID& rclsid) { POSITION pos = m_snapinSelDataList.GetHeadPosition(); while (pos) { CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos); ASSERT(pSSD != NULL); if (pSSD->GetSnapIn() != NULL && ::IsEqualCLSID(rclsid, pSSD->GetSnapIn()->GetSnapInCLSID())) { return TRUE; } } return FALSE; } //+------------------------------------------------------------------- // // Member: CMultiSelection::ScVerbInvoked // // Synopsis: A verb was invoked, inform the snapin about invocation. // // Arguments: [verb] - that is invoked. // // Returns: SC // //-------------------------------------------------------------------- SC CMultiSelection::ScVerbInvoked (MMC_CONSOLE_VERB verb) { DECLARE_SC(sc, _T("CMultiSelection::ScVerbInvoked")); /* * If you make any modifications do not forget to Release * the ref as shown below. */ AddRef(); sc = _ScVerbInvoked(verb); Release(); if (sc) return sc; return (sc); } //+------------------------------------------------------------------- // // Member: CMultiSelection::_ScVerbInvoked // // Synopsis: A verb was invoked, inform the snapin about invocation. // // Arguments: [verb] - that is invoked. // // Returns: SC // // Note: We handle only Delete & Print. If you want to handle // any other notifications, make sure the IComponent::Notify // gets right arg & param values (they are unused for Delete & Print). // //-------------------------------------------------------------------- SC CMultiSelection::_ScVerbInvoked (MMC_CONSOLE_VERB verb) { DECLARE_SC(sc, _T("CMultiSelection::_ScVerbInvoked")); if (! HasSnapinData()) return (sc = E_UNEXPECTED); MMC_NOTIFY_TYPE eNotifyCode; switch(verb) { case MMC_VERB_DELETE: eNotifyCode = MMCN_DELETE; break; case MMC_VERB_PRINT: eNotifyCode = MMCN_PRINT; break; default: /* * We handle only Delete & Print. If you want to handle * any other notifications, make sure the IComponent::Notify * gets right arg & param values (they are unused for Delete & Print). */ sc = E_INVALIDARG; return sc; } POSITION pos = m_snapinSelDataList.GetHeadPosition(); while (pos) { BOOL bFlag = FALSE; CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos); sc = ScCheckPointers(pSSD, E_UNEXPECTED); if (sc) return sc; IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb(); sc = ScCheckPointers(pConsoleVerb, E_UNEXPECTED); if (sc) return sc; pConsoleVerb->GetVerbState(verb, ENABLED, &bFlag); // If snapin did not enable verb for this item then skip it. if (!bFlag) continue; CComponent *pComponent = pSSD->GetComponent(); sc = ScCheckPointers(pComponent, E_UNEXPECTED); if (sc) return sc; sc = pComponent->Notify( pSSD->GetDataObject(), eNotifyCode, 0, 0); // Trace & Ignore snapin returned errors. if (sc) sc.TraceAndClear(); } return (sc); } bool IsMultiSelectDataObject(IDataObject* pdtobjCBSelData) { if (!pdtobjCBSelData) return FALSE; FORMATETC fmt; ZeroMemory(&fmt, sizeof(fmt)); fmt.dwAspect = DVASPECT_CONTENT; fmt.cfFormat = GetMMCMultiSelDataObjectCF(); return (pdtobjCBSelData->QueryGetData(&fmt) == S_OK); } HRESULT ExtractDynExtensions(IDataObject* pdataObj, CGuidArray& arGuid) { ASSERT(pdataObj != NULL); static CLIPFORMAT cfDynExtensions = 0; if (cfDynExtensions == 0) { USES_CONVERSION; cfDynExtensions = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_DYNAMIC_EXTENSIONS)); ASSERT(cfDynExtensions != 0); } // Get the data HGLOBAL hGlobal = NULL; HRESULT hr = DataObject_GetHGLOBALData(pdataObj, cfDynExtensions, &hGlobal); if (FAILED(hr)) return hr; SMMCDynamicExtensions* pExtenData = reinterpret_cast(::GlobalLock(hGlobal)); ASSERT(pExtenData != NULL); for (DWORD index=0; index < pExtenData->count; ++index) { arGuid.Add(pExtenData->guid[index]); } ::GlobalUnlock(hGlobal); ::GlobalFree(hGlobal); return S_OK; } //+------------------------------------------------------------------- // // Member: CMultiSelection::ScIsVerbEnabledInclusively // // Synopsis: Is the given verb enabled under current multi-selection. // Should be used only if items from more than one snapin // is selected. // Inclusive means, bEnable will be true if any one snapin // enables given verb. // // // Arguments: [mmcVerb] - The verb to check. // [bEnable] - Enabled or not, Return value. // // Returns: SC // //-------------------------------------------------------------------- SC CMultiSelection::ScIsVerbEnabledInclusively(MMC_CONSOLE_VERB mmcVerb, BOOL& bEnable) { DECLARE_SC(sc, _T("CMultiSelection::ScIsVerbEnabledInclusively")); bEnable = false; if (IsSingleSnapinSelection()) return (sc = E_UNEXPECTED); POSITION pos = m_snapinSelDataList.GetHeadPosition(); while (pos) { CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos); sc = ScCheckPointers(pSSD, E_UNEXPECTED); if (sc) return sc; IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb(); sc = ScCheckPointers(pConsoleVerb, E_UNEXPECTED); if (sc) return sc; sc = pConsoleVerb->GetVerbState(mmcVerb, ENABLED, &bEnable); if (sc) return sc; if (bEnable) return sc; } return (sc); } /***************************************************************************\ * * METHOD: CMultiSelection::ScGetSnapinDataObjects * * PURPOSE: Adds all contained data objects to CMMCClipBoardDataObject * * PARAMETERS: * CMMCClipBoardDataObject *pResultObject [in] - container to add data objects * * RETURNS: * SC - result code * \***************************************************************************/ SC CMultiSelection::ScGetSnapinDataObjects(CMMCClipBoardDataObject *pResultObject) { DECLARE_SC(sc, TEXT("CMultiSelection::ScGetSnapinDataObjects")); // for each snapin... POSITION pos = m_snapinSelDataList.GetHeadPosition(); while (pos) { CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos); sc = ScCheckPointers(pSSD, E_UNEXPECTED); if (sc) return sc; // get snapin data CComponent *pComponent = pSSD->GetComponent(); IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb(); sc = ScCheckPointers(pComponent, pConsoleVerb, E_UNEXPECTED); if (sc) return sc; // get verbs bool bCopyEnabled = false; bool bCutEnabled = false; BOOL bEnable = FALSE; sc = pConsoleVerb->GetVerbState(MMC_VERB_COPY, ENABLED, &bEnable); bCopyEnabled = bEnable; if (sc) return sc; sc = pConsoleVerb->GetVerbState(MMC_VERB_CUT, ENABLED, &bEnable); bCutEnabled = bEnable; if (sc) return sc; // construct the array of scope nodes in this data object CSnapinSelData::CNodePtrArray nodes; // if regular result items exist - add active scope node if ( pSSD->GetNumOfItems() != pSSD->GetScopeNodes().size() ) nodes.push_back(m_pNode); // add scope items from result pane nodes.insert( nodes.end(), pSSD->GetScopeNodes().begin(), pSSD->GetScopeNodes().end() ); // add to the MMC DO sc = pResultObject->ScAddSnapinDataObject( nodes, pComponent->GetIComponent(), pSSD->GetDataObject(), bCopyEnabled, bCutEnabled ); if (sc) return sc; } return sc; }