mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1279 lines
35 KiB
1279 lines
35 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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);
|
|
pmedium->hGlobal = ::GlobalAlloc(GPTR, size);
|
|
SMMCDataObjects* pData =
|
|
reinterpret_cast<SMMCDataObjects*>(pmedium->hGlobal);
|
|
if (pData == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
pData->count = m_count;
|
|
for (UINT i=0; i<m_count; ++i)
|
|
{
|
|
pData->lpDataObject[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<BYTE*>(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<CSnapInNode*>(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<CMultiSelectDataObject*>(
|
|
static_cast<IDataObject*>(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<CConsoleVerbImpl*>(
|
|
static_cast<IConsoleVerb*>(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<CConsoleVerbImpl*>(
|
|
static_cast<IConsoleVerb*>(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<BYTE*>(::GlobalLock(hGlobal));
|
|
DWORD count = *((DWORD*)pb);
|
|
pb += sizeof(DWORD);
|
|
GUID* pGuid = reinterpret_cast<GUID*>(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<CMultiSelectDataObject>* pMSDObject;
|
|
hr = CComObject<CMultiSelectDataObject>::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<GUID, GUID&>& 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<GUID, GUID&>& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList();
|
|
ASSERT(objTypeGuidsList.IsEmpty() == FALSE);
|
|
if (objTypeGuidsList.IsEmpty() == TRUE)
|
|
return E_FAIL;
|
|
|
|
// Get dynamic extensions requested by the snap-in
|
|
CArray<GUID, GUID&> 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<GUID&>(it.GetCLSID()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CArray<CLSID, CLSID&> rgClsid;
|
|
for (; it.IsEnd() == FALSE; it.Advance())
|
|
{
|
|
rgClsid.Add(const_cast<CLSID&>(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<GUID, GUID&>& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList();
|
|
|
|
// Get dynamic extensions requested by the snap-in
|
|
CArray<GUID, GUID&> 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<SMMCDynamicExtensions*>(::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;
|
|
}
|
|
|
|
|