Source code of Windows XP (NT5)
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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: multisel.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "objfmts.h"
  12. #include "multisel.h"
  13. #include "nmutil.h"
  14. #include "regutil.h"
  15. #include "copypast.h"
  16. #include "dbg.h"
  17. #include "rsltitem.h"
  18. DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinSelData);
  19. DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinSelDataList);
  20. UINT GetRelation(CMTNode* pMTNodeSrc, CMTNode* pMTNodeDest);
  21. CLIPFORMAT GetMultiSelectSnapinsCF()
  22. {
  23. static CLIPFORMAT s_cf = 0;
  24. if (s_cf == 0)
  25. {
  26. USES_CONVERSION;
  27. s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MULTI_SELECT_SNAPINS));
  28. }
  29. return s_cf;
  30. }
  31. CLIPFORMAT GetMultiSelectStaticDataCF()
  32. {
  33. static CLIPFORMAT s_cf = 0;
  34. if (s_cf == 0)
  35. {
  36. USES_CONVERSION;
  37. s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MULTI_SELECT_STATIC_DATA));
  38. }
  39. return s_cf;
  40. }
  41. CLIPFORMAT GetMultiSelObjectTypesCF()
  42. {
  43. static CLIPFORMAT s_cf = 0;
  44. if (s_cf == 0)
  45. {
  46. USES_CONVERSION;
  47. s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_OBJECT_TYPES_IN_MULTI_SELECT));
  48. }
  49. return s_cf;
  50. }
  51. CLIPFORMAT GetMMCMultiSelDataObjectCF()
  52. {
  53. static CLIPFORMAT s_cf = 0;
  54. if (s_cf == 0)
  55. {
  56. USES_CONVERSION;
  57. s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT));
  58. }
  59. return s_cf;
  60. }
  61. CLIPFORMAT GetMMCDynExtensionsCF()
  62. {
  63. static CLIPFORMAT s_cf = 0;
  64. if (s_cf == 0)
  65. {
  66. USES_CONVERSION;
  67. s_cf = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_DYNAMIC_EXTENSIONS));
  68. }
  69. return s_cf;
  70. }
  71. HRESULT
  72. DataObject_GetHGLOBALData(
  73. IDataObject* piDataObject,
  74. CLIPFORMAT cfClipFormat,
  75. HGLOBAL* phGlobal)
  76. {
  77. ASSERT(piDataObject != NULL);
  78. ASSERT(phGlobal != NULL);
  79. if (piDataObject == NULL || phGlobal == NULL)
  80. return E_INVALIDARG;
  81. FORMATETC fmt = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  82. STGMEDIUM stgm = {TYMED_HGLOBAL, NULL, NULL};
  83. HRESULT hr = piDataObject->GetData(&fmt, &stgm);
  84. if (SUCCEEDED(hr) && (stgm.tymed == TYMED_HGLOBAL) && (stgm.hGlobal != NULL))
  85. {
  86. *phGlobal = stgm.hGlobal;
  87. }
  88. else
  89. {
  90. ReleaseStgMedium(&stgm);
  91. if (SUCCEEDED(hr))
  92. hr = (stgm.tymed != TYMED_HGLOBAL) ? DV_E_TYMED : E_UNEXPECTED;
  93. }
  94. return hr;
  95. }
  96. DEBUG_DECLARE_INSTANCE_COUNTER(CMultiSelectDataObject);
  97. CMultiSelectDataObject::~CMultiSelectDataObject()
  98. {
  99. if (m_pMS)
  100. m_pMS->Release();
  101. if (m_ppDataObjects != NULL)
  102. {
  103. delete [] m_ppDataObjects;
  104. }
  105. DEBUG_DECREMENT_INSTANCE_COUNTER(CMultiSelectDataObject);
  106. }
  107. STDMETHODIMP
  108. CMultiSelectDataObject::GetData(
  109. FORMATETC* pfmt,
  110. STGMEDIUM* pmedium)
  111. {
  112. if (m_ppDataObjects == NULL && m_ppMTNodes == NULL)
  113. return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
  114. pmedium->hGlobal = NULL; // init
  115. if (pfmt->tymed & TYMED_HGLOBAL)
  116. {
  117. if (pfmt->cfFormat == GetMultiSelectSnapinsCF())
  118. {
  119. UINT size = sizeof(DWORD) + m_count * sizeof(LPDATAOBJECT);
  120. pmedium->hGlobal = ::GlobalAlloc(GPTR, size);
  121. SMMCDataObjects* pData =
  122. reinterpret_cast<SMMCDataObjects*>(pmedium->hGlobal);
  123. if (pData == NULL)
  124. return E_OUTOFMEMORY;
  125. pData->count = m_count;
  126. for (UINT i=0; i<m_count; ++i)
  127. {
  128. pData->lpDataObject[i] = m_ppDataObjects[i];
  129. }
  130. }
  131. else if (pfmt->cfFormat == GetMultiSelectStaticDataCF())
  132. {
  133. ASSERT(m_nSize >= 0);
  134. typedef CMTNode* _PMTNODE;
  135. // m_ppDataObjects m_count
  136. UINT cb = sizeof(DWORD) + sizeof(_PMTNODE) * m_nSize;
  137. pmedium->hGlobal = ::GlobalAlloc(GPTR, cb);
  138. BYTE* pb = reinterpret_cast<BYTE*>(pmedium->hGlobal);
  139. if (pb == NULL)
  140. return E_OUTOFMEMORY;
  141. *((DWORD*)pb) = m_nSize;
  142. if (m_nSize > 0)
  143. {
  144. pb += sizeof(DWORD);
  145. _PMTNODE* ppMTNodes = (_PMTNODE*)pb;
  146. CopyMemory(ppMTNodes, m_ppMTNodes, m_nSize * sizeof(_PMTNODE));
  147. }
  148. }
  149. else if (pfmt->cfFormat == GetMMCMultiSelDataObjectCF())
  150. {
  151. pmedium->hGlobal = ::GlobalAlloc(GPTR, sizeof(DWORD));
  152. if (pmedium->hGlobal == NULL)
  153. return E_OUTOFMEMORY;
  154. *((DWORD*)pmedium->hGlobal) = 1;
  155. }
  156. else
  157. {
  158. pmedium->tymed = TYMED_NULL;
  159. pmedium->hGlobal = NULL;
  160. pmedium->pUnkForRelease = NULL;
  161. return DATA_E_FORMATETC;
  162. }
  163. if (pmedium->hGlobal != NULL)
  164. {
  165. pmedium->tymed = TYMED_HGLOBAL;
  166. pmedium->pUnkForRelease = NULL;
  167. return S_OK;
  168. }
  169. else
  170. {
  171. return E_OUTOFMEMORY;
  172. }
  173. }
  174. return DV_E_TYMED;
  175. }
  176. STDMETHODIMP
  177. CMultiSelectDataObject::GetDataHere(
  178. FORMATETC* pfmt,
  179. STGMEDIUM* pmedium)
  180. {
  181. return E_NOTIMPL;
  182. }
  183. STDMETHODIMP
  184. CMultiSelectDataObject::EnumFormatEtc(
  185. DWORD dwDirection,
  186. IEnumFORMATETC **ppenumFormatEtc)
  187. {
  188. if (m_ppDataObjects == NULL && m_ppMTNodes == NULL)
  189. return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
  190. if (dwDirection == DATADIR_SET)
  191. return E_FAIL;
  192. FORMATETC fmte[] = {
  193. {GetMultiSelectSnapinsCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
  194. {GetMMCMultiSelDataObjectCF(), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
  195. };
  196. HRESULT hr = ::GetObjFormats(countof(fmte), fmte, (void**)ppenumFormatEtc);
  197. return hr;
  198. }
  199. STDMETHODIMP CMultiSelectDataObject::QueryGetData(LPFORMATETC pfmt)
  200. {
  201. if (m_ppDataObjects == NULL && m_ppMTNodes == NULL)
  202. return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
  203. //
  204. // Check the aspects we support.
  205. //
  206. if (!(DVASPECT_CONTENT & pfmt->dwAspect))
  207. return DATA_E_FORMATETC;
  208. ASSERT(GetMultiSelectSnapinsCF() != 0);
  209. if (pfmt->cfFormat == GetMMCMultiSelDataObjectCF() ||
  210. pfmt->cfFormat == GetMultiSelectSnapinsCF())
  211. return S_OK;
  212. return S_FALSE;
  213. }
  214. ///////////////////////////////////////////////////////////////////////////////
  215. ///////////////////////////////////////////////////////////////////////////////
  216. ///////////////////////////////////////////////////////////////////////////////
  217. ///////////////////////////////////////////////////////////////////////////////
  218. ///////////////////////////////////////////////////////////////////////////////
  219. ///////////////////////////////////////////////////////////////////////////////
  220. ///////////////////////////////////////////////////////////////////////////////
  221. void CSnapinSelDataList::Add(CSnapinSelData& snapinSelData, BOOL bStaticNode)
  222. {
  223. BOOL bCreateNew = TRUE;
  224. if (bStaticNode == FALSE &&
  225. snapinSelData.GetID() != TVOWNED_MAGICWORD)
  226. {
  227. POSITION pos = GetHeadPosition();
  228. while (pos)
  229. {
  230. CSnapinSelData* pSnapinSelData = GetNext(pos);
  231. if (pSnapinSelData->GetID() == snapinSelData.GetID())
  232. {
  233. pSnapinSelData->IncrementNumOfItems();
  234. pSnapinSelData->AddScopeNodes( snapinSelData.GetScopeNodes() );
  235. bCreateNew = FALSE;
  236. break;
  237. }
  238. }
  239. }
  240. if (bCreateNew == TRUE)
  241. {
  242. CSnapinSelData* pSnapinSelData = new CSnapinSelData;
  243. pSnapinSelData->SetNumOfItems(snapinSelData.GetNumOfItems());
  244. pSnapinSelData->AddScopeNodes(snapinSelData.GetScopeNodes());
  245. pSnapinSelData->SetIsScopeItem(snapinSelData.IsScopeItem());
  246. pSnapinSelData->SetCookie(snapinSelData.GetCookie());
  247. pSnapinSelData->SetID(snapinSelData.GetID());
  248. pSnapinSelData->SetSnapIn(snapinSelData.GetSnapIn());
  249. AddHead(pSnapinSelData);
  250. }
  251. }
  252. DEBUG_DECLARE_INSTANCE_COUNTER(CMultiSelection);
  253. CMultiSelection::CMultiSelection(CNode* pNode)
  254. : m_pNode(pNode), m_pMTSINode(NULL), m_bHasNodes(FALSE),
  255. m_pSINode(dynamic_cast<CSnapInNode*>(pNode)),
  256. m_bInUse(FALSE), m_cRef(1)
  257. {
  258. ASSERT(pNode != NULL);
  259. #ifdef DBG
  260. m_bInit = FALSE;
  261. #endif
  262. DEBUG_INCREMENT_INSTANCE_COUNTER(CMultiSelection);
  263. }
  264. CMultiSelection::~CMultiSelection()
  265. {
  266. ASSERT(m_bInUse == FALSE);
  267. if (m_spDataObjectMultiSel != NULL)
  268. {
  269. CMultiSelectDataObject* pObj =
  270. dynamic_cast<CMultiSelectDataObject*>(
  271. static_cast<IDataObject*>(m_spDataObjectMultiSel));
  272. ASSERT(pObj != NULL);
  273. if (pObj)
  274. pObj->SetDataObjects(NULL, 0);
  275. }
  276. DEBUG_DECREMENT_INSTANCE_COUNTER(CMultiSelection);
  277. }
  278. HRESULT CMultiSelection::Init()
  279. {
  280. #ifdef DBG
  281. m_bInit = TRUE;
  282. #endif
  283. // compute m_pSINode, m_pMTSINode, m_pszExtensionTypeKey
  284. if (m_pNode != NULL)
  285. {
  286. if (m_pSINode == NULL)
  287. m_pSINode = m_pNode->GetStaticParent();
  288. ASSERT(m_pMTSINode == NULL);
  289. ASSERT(m_pNode->GetMTNode() != NULL);
  290. if (m_pNode->GetMTNode() == NULL)
  291. return E_UNEXPECTED;
  292. m_pMTSINode = m_pNode->GetMTNode()->GetStaticParent();
  293. ASSERT(m_pMTSINode != NULL);
  294. if (m_pMTSINode == NULL)
  295. return E_UNEXPECTED;
  296. }
  297. return S_OK;
  298. }
  299. bool CMultiSelection::RemoveStaticNode(CMTNode* pMTNode)
  300. {
  301. int iMax = m_rgStaticNodes.size()-1;
  302. if (iMax < 0)
  303. return false;
  304. if (::GetRelation(pMTNode, m_rgStaticNodes[0]) == 2)
  305. {
  306. m_rgStaticNodes.clear();
  307. return m_snapinSelDataList.IsEmpty();
  308. }
  309. for (int i=iMax; i >= 0; --i)
  310. {
  311. if (m_rgStaticNodes[i] == pMTNode)
  312. {
  313. CMTNodePtrArray::iterator iter = m_rgStaticNodes.begin();
  314. std::advance(iter, iMax);
  315. m_rgStaticNodes[i] = m_rgStaticNodes[iMax];
  316. m_rgStaticNodes.erase(iter);
  317. break;
  318. }
  319. }
  320. return m_rgStaticNodes.size();
  321. }
  322. CComponent* CMultiSelection::_GetComponent(CSnapinSelData* pSnapinSelData)
  323. {
  324. CComponent* pCC = NULL;
  325. if ((pSnapinSelData->GetNumOfItems() > 1) ||
  326. (pSnapinSelData->GetID() > 0) ||
  327. (pSnapinSelData->IsScopeItem() == FALSE))
  328. {
  329. CSnapInNode* pSINode = _GetStaticNode();
  330. if (pSINode == NULL)
  331. return NULL;
  332. pCC = pSINode->GetComponent(pSnapinSelData->GetID());
  333. ASSERT(pCC != NULL);
  334. }
  335. else
  336. {
  337. ASSERT(pSnapinSelData->IsScopeItem() == TRUE);
  338. CNode* pNode = CNode::FromHandle ((HNODE) pSnapinSelData->GetCookie());
  339. ASSERT(pNode != NULL);
  340. if (pNode != NULL)
  341. pCC = pNode->GetPrimaryComponent();
  342. }
  343. return pCC;
  344. }
  345. HRESULT CMultiSelection::_ComputeSelectionDataList()
  346. {
  347. #ifdef DBG
  348. ASSERT(m_bInit == TRUE);
  349. #endif
  350. ASSERT(m_pNode != NULL);
  351. ASSERT(m_pNode->GetViewData() != NULL);
  352. HWND hwnd = m_pNode->GetViewData() ?
  353. m_pNode->GetViewData()->GetListCtrl() : NULL;
  354. ASSERT(hwnd != NULL);
  355. if (hwnd == NULL)
  356. return E_UNEXPECTED;
  357. ASSERT(::IsWindow(hwnd));
  358. if (!(::IsWindow(hwnd)))
  359. return E_UNEXPECTED;
  360. if (m_pNode->GetViewData()->IsVirtualList() == TRUE)
  361. {
  362. CSnapinSelData snapinSelData;
  363. snapinSelData.SetID(m_pNode->GetPrimaryComponent()->GetComponentID());
  364. snapinSelData.SetNumOfItems(ListView_GetSelectedCount(hwnd));
  365. if (snapinSelData.GetNumOfItems() == 1)
  366. snapinSelData.SetCookie(ListView_GetNextItem(hwnd, -1, LVIS_SELECTED));
  367. m_snapinSelDataList.Add(snapinSelData, FALSE);
  368. }
  369. else
  370. {
  371. int iSel = ListView_GetNextItem(hwnd, -1, LVIS_SELECTED);
  372. if (iSel < 0)
  373. return S_FALSE;
  374. for (; iSel >= 0; iSel = ListView_GetNextItem(hwnd, iSel, LVIS_SELECTED))
  375. {
  376. LPARAM lParam = ListView_GetItemData(hwnd, iSel);
  377. CResultItem* pri = CResultItem::FromHandle(lParam);
  378. ASSERT(pri != NULL);
  379. if (pri == NULL)
  380. return E_FAIL;
  381. CSnapinSelData snapinSelData;
  382. snapinSelData.SetID(pri->GetOwnerID());
  383. snapinSelData.IncrementNumOfItems();
  384. snapinSelData.SetCookie(pri->GetSnapinData());
  385. BOOL bStaticNode = FALSE;
  386. if (pri->IsScopeItem())
  387. {
  388. CNode* pNodeContext = CNode::FromResultItem (pri);
  389. ASSERT(pNodeContext != NULL);
  390. if (pNodeContext->IsInitialized() == FALSE)
  391. {
  392. HRESULT hr = pNodeContext->InitComponents();
  393. ASSERT(SUCCEEDED(hr));
  394. if (FAILED(hr))
  395. {
  396. m_rgStaticNodes.clear();
  397. m_snapinSelDataList.RemoveAll();
  398. return hr;
  399. }
  400. }
  401. // its a scope node - store to scope node array for this data object
  402. snapinSelData.AddScopeNodes(CSnapinSelData::CNodePtrArray(1, pNodeContext));
  403. m_bHasNodes = TRUE;
  404. snapinSelData.SetID(::GetComponentID(NULL, pri));
  405. snapinSelData.SetIsScopeItem(TRUE);
  406. if (snapinSelData.GetID() == TVOWNED_MAGICWORD)
  407. {
  408. ASSERT(pNodeContext->GetMTNode() != NULL);
  409. m_rgStaticNodes.push_back(pNodeContext->GetMTNode());
  410. continue;
  411. }
  412. if (snapinSelData.GetID() == 0)
  413. {
  414. ASSERT(pri->IsScopeItem());
  415. bStaticNode = pNodeContext->IsStaticNode();
  416. if (bStaticNode)
  417. {
  418. ASSERT(pNodeContext->GetMTNode() != NULL);
  419. m_rgStaticNodes.push_back(pNodeContext->GetMTNode());
  420. }
  421. }
  422. }
  423. // Add to the list
  424. m_snapinSelDataList.Add(snapinSelData, bStaticNode);
  425. }
  426. }
  427. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  428. HRESULT hr = S_OK;
  429. while (pos)
  430. {
  431. CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(pos);
  432. if (pSnapinSelData->GetNumOfItems() == 1)
  433. {
  434. // Get object type for single snapin item sel
  435. hr = _GetObjectTypeForSingleSel(pSnapinSelData);
  436. if (FAILED(hr))
  437. return hr;
  438. }
  439. else if (pSnapinSelData->GetNumOfItems() > 1)
  440. {
  441. // Get object type(s) for multiple snapin items sel
  442. hr = _GetObjectTypesForMultipleSel(pSnapinSelData);
  443. if (FAILED(hr))
  444. return hr;
  445. }
  446. }
  447. return hr;
  448. }
  449. HRESULT
  450. CMultiSelection::_GetObjectTypeForSingleSel(
  451. CSnapinSelData* pSnapinSelData)
  452. {
  453. ASSERT(pSnapinSelData->GetNumOfItems() == 1);
  454. if (m_pNode->GetViewData()->IsVirtualList() == FALSE)
  455. {
  456. ASSERT(pSnapinSelData->GetCookie() != 0);
  457. if (pSnapinSelData->GetNumOfItems() != 1 ||
  458. pSnapinSelData->GetCookie() == 0)
  459. return E_INVALIDARG;
  460. }
  461. HRESULT hr = S_OK;
  462. IDataObjectPtr spDO;
  463. CComponent* pCC = _GetComponent(pSnapinSelData);
  464. if (pCC == NULL)
  465. return E_UNEXPECTED;
  466. if (pSnapinSelData->GetID() == TVOWNED_MAGICWORD)
  467. {
  468. ASSERT(pSnapinSelData->IsScopeItem() == TRUE);
  469. }
  470. else if (pSnapinSelData->IsScopeItem() == TRUE)
  471. {
  472. CNode* pNode = CNode::FromHandle ((HNODE) pSnapinSelData->GetCookie());
  473. ASSERT(pNode != NULL);
  474. if (pNode == NULL)
  475. return E_FAIL;
  476. CComponentData* pCCD = NULL;
  477. if (pNode->IsStaticNode())
  478. {
  479. CMTNode* pMTNode = pNode->GetMTNode();
  480. ASSERT(pMTNode != NULL);
  481. if (pMTNode == NULL)
  482. return E_FAIL;
  483. pCCD = pMTNode->GetPrimaryComponentData();
  484. }
  485. else
  486. {
  487. CMTSnapInNode* pMTSINode = _GetStaticMasterNode();
  488. ASSERT(pMTSINode != NULL);
  489. if (pMTSINode == NULL)
  490. return E_UNEXPECTED;
  491. pCCD = pMTSINode->GetComponentData(pSnapinSelData->GetID());
  492. }
  493. ASSERT(pCCD != NULL);
  494. if (pCCD == NULL)
  495. return E_UNEXPECTED;
  496. hr = pCCD->QueryDataObject(pNode->GetUserParam(), CCT_SCOPE, &spDO);
  497. ASSERT(SUCCEEDED(hr));
  498. if (FAILED(hr))
  499. return hr;
  500. pSnapinSelData->SetSnapIn(pCCD->GetSnapIn());
  501. }
  502. else
  503. {
  504. hr = pCC->QueryDataObject(pSnapinSelData->GetCookie(), CCT_RESULT, &spDO);
  505. ASSERT(SUCCEEDED(hr));
  506. if (FAILED(hr))
  507. return hr;
  508. pSnapinSelData->SetSnapIn(pCC->GetSnapIn());
  509. }
  510. do // not a loop
  511. {
  512. if (pCC == NULL)
  513. break;
  514. pSnapinSelData->SetComponent(pCC);
  515. IFramePrivate* pIFP = pCC->GetIFramePrivate();
  516. ASSERT(pIFP != NULL);
  517. if (pIFP == NULL)
  518. break;
  519. IConsoleVerbPtr spConsoleVerb;
  520. hr = pIFP->QueryConsoleVerb(&spConsoleVerb);
  521. if (SUCCEEDED(hr))
  522. {
  523. ASSERT(spConsoleVerb != NULL);
  524. pSnapinSelData->SetConsoleVerb(spConsoleVerb);
  525. CConsoleVerbImpl* pCVI = dynamic_cast<CConsoleVerbImpl*>(
  526. static_cast<IConsoleVerb*>(spConsoleVerb));
  527. ASSERT(pCVI != NULL);
  528. if (pCVI)
  529. pCVI->SetDisabledAll();
  530. }
  531. Dbg(DEB_USER1, _T("MMCN_SELECT> MS-1 \n"));
  532. pCC->Notify(spDO, MMCN_SELECT, MAKELONG((WORD)FALSE, (WORD)TRUE), 0);
  533. } while (0);
  534. GUID guid;
  535. hr = ExtractObjectTypeGUID(spDO, &guid);
  536. ASSERT(SUCCEEDED(hr));
  537. if (SUCCEEDED(hr))
  538. {
  539. pSnapinSelData->SetDataObject(spDO);
  540. pSnapinSelData->AddObjectType(guid);
  541. }
  542. return hr;
  543. }
  544. HRESULT
  545. CMultiSelection::_GetObjectTypesForMultipleSel(
  546. CSnapinSelData* pSnapinSelData)
  547. {
  548. ASSERT(m_pSINode != NULL);
  549. ASSERT(m_pMTSINode != NULL);
  550. ASSERT(pSnapinSelData != NULL);
  551. if (pSnapinSelData == NULL)
  552. return E_POINTER;
  553. CComponent* pCC = _GetComponent(pSnapinSelData);
  554. if (pCC == NULL)
  555. return E_UNEXPECTED;
  556. pSnapinSelData->SetSnapIn(pCC->GetSnapIn());
  557. IDataObjectPtr spDO;
  558. HRESULT hr = pCC->QueryDataObject(MMC_MULTI_SELECT_COOKIE,
  559. CCT_UNINITIALIZED, &spDO);
  560. ASSERT(SUCCEEDED(hr));
  561. if (FAILED(hr))
  562. return hr;
  563. do // not a loop
  564. {
  565. if (pCC == NULL)
  566. break;
  567. pSnapinSelData->SetComponent(pCC);
  568. IFramePrivate* pIFP = pCC->GetIFramePrivate();
  569. ASSERT(pIFP != NULL);
  570. if (pIFP == NULL)
  571. break;
  572. IConsoleVerbPtr spConsoleVerb;
  573. hr = pIFP->QueryConsoleVerb(&spConsoleVerb);
  574. if (SUCCEEDED(hr))
  575. {
  576. ASSERT(spConsoleVerb != NULL);
  577. pSnapinSelData->SetConsoleVerb(spConsoleVerb);
  578. CConsoleVerbImpl* pCVI = dynamic_cast<CConsoleVerbImpl*>(
  579. static_cast<IConsoleVerb*>(spConsoleVerb));
  580. ASSERT(pCVI != NULL);
  581. if (pCVI)
  582. pCVI->SetDisabledAll();
  583. }
  584. Dbg(DEB_USER1, _T("MMCN_SELECT> MS-2 \n"));
  585. pCC->Notify(spDO, MMCN_SELECT, MAKELONG((WORD)FALSE, (WORD)TRUE), 0);
  586. } while (0);
  587. if (spDO == NULL)
  588. return E_UNEXPECTED;
  589. // Get the data
  590. HGLOBAL hGlobal = NULL;
  591. hr = DataObject_GetHGLOBALData(spDO, GetMultiSelObjectTypesCF(),
  592. &hGlobal);
  593. if (FAILED(hr))
  594. return hr;
  595. BYTE* pb = reinterpret_cast<BYTE*>(::GlobalLock(hGlobal));
  596. DWORD count = *((DWORD*)pb);
  597. pb += sizeof(DWORD);
  598. GUID* pGuid = reinterpret_cast<GUID*>(pb);
  599. for (DWORD index=0; index < count; ++index)
  600. {
  601. pSnapinSelData->AddObjectType(pGuid[index]);
  602. }
  603. ::GlobalUnlock(hGlobal);
  604. ::GlobalFree(hGlobal);
  605. pSnapinSelData->SetDataObject(spDO);
  606. return S_OK;
  607. }
  608. HRESULT
  609. CMultiSelection::GetMultiSelDataObject(
  610. IDataObject** ppDataObject)
  611. {
  612. if (m_spDataObjectMultiSel == NULL)
  613. {
  614. HRESULT hr = S_OK;
  615. if (HasData() == FALSE)
  616. {
  617. hr = _ComputeSelectionDataList();
  618. if (FAILED(hr))
  619. return hr;
  620. ASSERT(HasData() == TRUE);
  621. if (HasData() == FALSE)
  622. return E_FAIL;
  623. }
  624. // CreateDataObjectForMultiSelection
  625. CComObject<CMultiSelectDataObject>* pMSDObject;
  626. hr = CComObject<CMultiSelectDataObject>::CreateInstance(&pMSDObject);
  627. ASSERT(SUCCEEDED(hr));
  628. if (FAILED(hr))
  629. return hr;
  630. ASSERT(pMSDObject != NULL);
  631. if (pMSDObject == NULL)
  632. return E_FAIL;
  633. pMSDObject->SetMultiSelection(this);
  634. UINT count = m_snapinSelDataList.GetCount();
  635. if (count > 0)
  636. {
  637. LPDATAOBJECT* ppDOs = new LPDATAOBJECT[count];
  638. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  639. for (int i=0; pos; ++i)
  640. {
  641. CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(pos);
  642. ASSERT(pSnapinSelData != NULL);
  643. ASSERT(i < count);
  644. ppDOs[i] = pSnapinSelData->GetDataObject();
  645. ASSERT(ppDOs[i] != NULL);
  646. }
  647. pMSDObject->SetDataObjects(ppDOs, count);
  648. }
  649. int nSize = m_rgStaticNodes.size();
  650. if (nSize > 0)
  651. {
  652. pMSDObject->SetStaticNodes(m_rgStaticNodes, nSize);
  653. }
  654. m_spDataObjectMultiSel = pMSDObject;
  655. }
  656. *ppDataObject = m_spDataObjectMultiSel;
  657. m_spDataObjectMultiSel.AddRef();
  658. return S_OK;
  659. }
  660. HRESULT
  661. CMultiSelection::GetExtensionSnapins(
  662. LPCTSTR pszExtensionTypeKey,
  663. CList<GUID, GUID&>& extnClsidList)
  664. {
  665. DECLARE_SC(sc, TEXT("CMultiSelection::GetExtensionSnapins"));
  666. ASSERT(&extnClsidList != NULL);
  667. extnClsidList.RemoveAll(); //init
  668. HRESULT hr = S_OK;
  669. if (HasData() == FALSE)
  670. {
  671. hr = _ComputeSelectionDataList();
  672. if (FAILED(hr))
  673. return hr;
  674. if (hr == S_FALSE)
  675. return hr;
  676. ASSERT(HasData() == TRUE);
  677. if (HasData() == FALSE)
  678. return E_FAIL;
  679. }
  680. if (HasSnapinData() == FALSE)
  681. return S_FALSE;
  682. //
  683. // Add the extension snapin clsids for the first object type
  684. // to extnClsidList.
  685. //
  686. {
  687. CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetHead();
  688. CList<GUID, GUID&>& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList();
  689. ASSERT(objTypeGuidsList.IsEmpty() == FALSE);
  690. if (objTypeGuidsList.IsEmpty() == TRUE)
  691. return E_FAIL;
  692. // Get dynamic extensions requested by the snap-in
  693. CArray<GUID, GUID&> DynExtens;
  694. ExtractDynExtensions(pSnapinSelData->GetDataObject(), DynExtens);
  695. POSITION pos = objTypeGuidsList.GetHeadPosition();
  696. BOOL bFirstTime = TRUE;
  697. while (pos)
  698. {
  699. GUID& objectTypeGuid = objTypeGuidsList.GetNext(pos);
  700. CExtensionsIterator it;
  701. sc = it.ScInitialize(pSnapinSelData->GetSnapIn(), objectTypeGuid, pszExtensionTypeKey, DynExtens.GetData(), DynExtens.GetSize());
  702. if (sc)
  703. return hr;
  704. if (bFirstTime == TRUE)
  705. {
  706. bFirstTime = FALSE;
  707. for (; it.IsEnd() == FALSE; it.Advance())
  708. {
  709. extnClsidList.AddHead(const_cast<GUID&>(it.GetCLSID()));
  710. }
  711. }
  712. else
  713. {
  714. CArray<CLSID, CLSID&> rgClsid;
  715. for (; it.IsEnd() == FALSE; it.Advance())
  716. {
  717. rgClsid.Add(const_cast<CLSID&>(it.GetCLSID()));
  718. }
  719. POSITION pos = extnClsidList.GetHeadPosition();
  720. POSITION posCurr = 0;
  721. while (pos)
  722. {
  723. posCurr = pos;
  724. CLSID& clsid = extnClsidList.GetNext(pos);
  725. BOOL bPresent = FALSE;
  726. for (int k=0; k <= rgClsid.GetUpperBound(); ++k)
  727. {
  728. if (::IsEqualCLSID(rgClsid[k], clsid) == TRUE)
  729. {
  730. bPresent = TRUE;
  731. break;
  732. }
  733. }
  734. if (bPresent == FALSE)
  735. {
  736. // Remove from list
  737. ASSERT(posCurr != 0);
  738. extnClsidList.RemoveAt(posCurr);
  739. }
  740. } // end while
  741. } // end else
  742. // No point continuing if the extension clsid list is empty.
  743. if (extnClsidList.IsEmpty() == TRUE)
  744. break;
  745. }
  746. }
  747. if (extnClsidList.IsEmpty() == TRUE)
  748. return S_FALSE;
  749. // If only items from one snapin were selected return.
  750. if (m_snapinSelDataList.GetCount() == 1)
  751. return S_OK;
  752. // loop through the extension clsids
  753. POSITION pos = extnClsidList.GetHeadPosition();
  754. while (pos)
  755. {
  756. // Get the first extension clsid
  757. POSITION posCurr = pos;
  758. CLSID& clsidSnapin = extnClsidList.GetNext(pos);
  759. // See if this clsid extends selected items put up by other snapins.
  760. BOOL bExtends = FALSE;
  761. POSITION posSDL = m_snapinSelDataList.GetHeadPosition();
  762. m_snapinSelDataList.GetNext(posSDL); // skip the first one.
  763. while (posSDL)
  764. {
  765. CSnapinSelData* pSnapinSelData = m_snapinSelDataList.GetNext(posSDL);
  766. CList<GUID, GUID&>& objTypeGuidsList = pSnapinSelData->GetObjectTypeGuidList();
  767. // Get dynamic extensions requested by the snap-in
  768. CArray<GUID, GUID&> DynExtens;
  769. ExtractDynExtensions(pSnapinSelData->GetDataObject(), DynExtens);
  770. POSITION pos2 = objTypeGuidsList.GetHeadPosition();
  771. while (pos2)
  772. {
  773. bExtends = FALSE; // re-init
  774. GUID& guidObjectType = objTypeGuidsList.GetNext(pos2);
  775. CExtensionsIterator it;
  776. sc = it.ScInitialize(pSnapinSelData->GetSnapIn(), guidObjectType, pszExtensionTypeKey, DynExtens.GetData(), DynExtens.GetSize());
  777. if (sc)
  778. break;
  779. for (; it.IsEnd() == FALSE; it.Advance())
  780. {
  781. if (::IsEqualCLSID(clsidSnapin, it.GetCLSID()) == TRUE)
  782. {
  783. bExtends = TRUE;
  784. break;
  785. }
  786. }
  787. if (bExtends == FALSE)
  788. break;
  789. }
  790. if (bExtends == FALSE)
  791. break;
  792. }
  793. ASSERT(posCurr != 0);
  794. if (bExtends == FALSE)
  795. extnClsidList.RemoveAt(posCurr);
  796. }
  797. return S_OK;
  798. }
  799. BOOL CMultiSelection::IsAnExtensionSnapIn(const CLSID& rclsid)
  800. {
  801. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  802. while (pos)
  803. {
  804. CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos);
  805. ASSERT(pSSD != NULL);
  806. if (pSSD->GetSnapIn() != NULL &&
  807. ::IsEqualCLSID(rclsid, pSSD->GetSnapIn()->GetSnapInCLSID()))
  808. {
  809. return TRUE;
  810. }
  811. }
  812. return FALSE;
  813. }
  814. //+-------------------------------------------------------------------
  815. //
  816. // Member: CMultiSelection::ScVerbInvoked
  817. //
  818. // Synopsis: A verb was invoked, inform the snapin about invocation.
  819. //
  820. // Arguments: [verb] - that is invoked.
  821. //
  822. // Returns: SC
  823. //
  824. //--------------------------------------------------------------------
  825. SC CMultiSelection::ScVerbInvoked (MMC_CONSOLE_VERB verb)
  826. {
  827. DECLARE_SC(sc, _T("CMultiSelection::ScVerbInvoked"));
  828. /*
  829. * If you make any modifications do not forget to Release
  830. * the ref as shown below.
  831. */
  832. AddRef();
  833. sc = _ScVerbInvoked(verb);
  834. Release();
  835. if (sc)
  836. return sc;
  837. return (sc);
  838. }
  839. //+-------------------------------------------------------------------
  840. //
  841. // Member: CMultiSelection::_ScVerbInvoked
  842. //
  843. // Synopsis: A verb was invoked, inform the snapin about invocation.
  844. //
  845. // Arguments: [verb] - that is invoked.
  846. //
  847. // Returns: SC
  848. //
  849. // Note: We handle only Delete & Print. If you want to handle
  850. // any other notifications, make sure the IComponent::Notify
  851. // gets right arg & param values (they are unused for Delete & Print).
  852. //
  853. //--------------------------------------------------------------------
  854. SC CMultiSelection::_ScVerbInvoked (MMC_CONSOLE_VERB verb)
  855. {
  856. DECLARE_SC(sc, _T("CMultiSelection::_ScVerbInvoked"));
  857. if (! HasSnapinData())
  858. return (sc = E_UNEXPECTED);
  859. MMC_NOTIFY_TYPE eNotifyCode;
  860. switch(verb)
  861. {
  862. case MMC_VERB_DELETE:
  863. eNotifyCode = MMCN_DELETE;
  864. break;
  865. case MMC_VERB_PRINT:
  866. eNotifyCode = MMCN_PRINT;
  867. break;
  868. default:
  869. /*
  870. * We handle only Delete & Print. If you want to handle
  871. * any other notifications, make sure the IComponent::Notify
  872. * gets right arg & param values (they are unused for Delete & Print).
  873. */
  874. sc = E_INVALIDARG;
  875. return sc;
  876. }
  877. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  878. while (pos)
  879. {
  880. BOOL bFlag = FALSE;
  881. CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos);
  882. sc = ScCheckPointers(pSSD, E_UNEXPECTED);
  883. if (sc)
  884. return sc;
  885. IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb();
  886. sc = ScCheckPointers(pConsoleVerb, E_UNEXPECTED);
  887. if (sc)
  888. return sc;
  889. pConsoleVerb->GetVerbState(verb, ENABLED, &bFlag);
  890. // If snapin did not enable verb for this item then skip it.
  891. if (!bFlag)
  892. continue;
  893. CComponent *pComponent = pSSD->GetComponent();
  894. sc = ScCheckPointers(pComponent, E_UNEXPECTED);
  895. if (sc)
  896. return sc;
  897. sc = pComponent->Notify( pSSD->GetDataObject(),
  898. eNotifyCode, 0, 0);
  899. // Trace & Ignore snapin returned errors.
  900. if (sc)
  901. sc.TraceAndClear();
  902. }
  903. return (sc);
  904. }
  905. bool IsMultiSelectDataObject(IDataObject* pdtobjCBSelData)
  906. {
  907. if (!pdtobjCBSelData)
  908. return FALSE;
  909. FORMATETC fmt;
  910. ZeroMemory(&fmt, sizeof(fmt));
  911. fmt.dwAspect = DVASPECT_CONTENT;
  912. fmt.cfFormat = GetMMCMultiSelDataObjectCF();
  913. return (pdtobjCBSelData->QueryGetData(&fmt) == S_OK);
  914. }
  915. HRESULT ExtractDynExtensions(IDataObject* pdataObj, CGuidArray& arGuid)
  916. {
  917. ASSERT(pdataObj != NULL);
  918. static CLIPFORMAT cfDynExtensions = 0;
  919. if (cfDynExtensions == 0)
  920. {
  921. USES_CONVERSION;
  922. cfDynExtensions = (CLIPFORMAT) RegisterClipboardFormat(W2T(CCF_MMC_DYNAMIC_EXTENSIONS));
  923. ASSERT(cfDynExtensions != 0);
  924. }
  925. // Get the data
  926. HGLOBAL hGlobal = NULL;
  927. HRESULT hr = DataObject_GetHGLOBALData(pdataObj, cfDynExtensions, &hGlobal);
  928. if (FAILED(hr))
  929. return hr;
  930. SMMCDynamicExtensions* pExtenData = reinterpret_cast<SMMCDynamicExtensions*>(::GlobalLock(hGlobal));
  931. ASSERT(pExtenData != NULL);
  932. for (DWORD index=0; index < pExtenData->count; ++index)
  933. {
  934. arGuid.Add(pExtenData->guid[index]);
  935. }
  936. ::GlobalUnlock(hGlobal);
  937. ::GlobalFree(hGlobal);
  938. return S_OK;
  939. }
  940. //+-------------------------------------------------------------------
  941. //
  942. // Member: CMultiSelection::ScIsVerbEnabledInclusively
  943. //
  944. // Synopsis: Is the given verb enabled under current multi-selection.
  945. // Should be used only if items from more than one snapin
  946. // is selected.
  947. // Inclusive means, bEnable will be true if any one snapin
  948. // enables given verb.
  949. //
  950. //
  951. // Arguments: [mmcVerb] - The verb to check.
  952. // [bEnable] - Enabled or not, Return value.
  953. //
  954. // Returns: SC
  955. //
  956. //--------------------------------------------------------------------
  957. SC CMultiSelection::ScIsVerbEnabledInclusively(MMC_CONSOLE_VERB mmcVerb, BOOL& bEnable)
  958. {
  959. DECLARE_SC(sc, _T("CMultiSelection::ScIsVerbEnabledInclusively"));
  960. bEnable = false;
  961. if (IsSingleSnapinSelection())
  962. return (sc = E_UNEXPECTED);
  963. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  964. while (pos)
  965. {
  966. CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos);
  967. sc = ScCheckPointers(pSSD, E_UNEXPECTED);
  968. if (sc)
  969. return sc;
  970. IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb();
  971. sc = ScCheckPointers(pConsoleVerb, E_UNEXPECTED);
  972. if (sc)
  973. return sc;
  974. sc = pConsoleVerb->GetVerbState(mmcVerb, ENABLED, &bEnable);
  975. if (sc)
  976. return sc;
  977. if (bEnable)
  978. return sc;
  979. }
  980. return (sc);
  981. }
  982. /***************************************************************************\
  983. *
  984. * METHOD: CMultiSelection::ScGetSnapinDataObjects
  985. *
  986. * PURPOSE: Adds all contained data objects to CMMCClipBoardDataObject
  987. *
  988. * PARAMETERS:
  989. * CMMCClipBoardDataObject *pResultObject [in] - container to add data objects
  990. *
  991. * RETURNS:
  992. * SC - result code
  993. *
  994. \***************************************************************************/
  995. SC CMultiSelection::ScGetSnapinDataObjects(CMMCClipBoardDataObject *pResultObject)
  996. {
  997. DECLARE_SC(sc, TEXT("CMultiSelection::ScGetSnapinDataObjects"));
  998. // for each snapin...
  999. POSITION pos = m_snapinSelDataList.GetHeadPosition();
  1000. while (pos)
  1001. {
  1002. CSnapinSelData* pSSD = m_snapinSelDataList.GetNext(pos);
  1003. sc = ScCheckPointers(pSSD, E_UNEXPECTED);
  1004. if (sc)
  1005. return sc;
  1006. // get snapin data
  1007. CComponent *pComponent = pSSD->GetComponent();
  1008. IConsoleVerb *pConsoleVerb = pSSD->GetConsoleVerb();
  1009. sc = ScCheckPointers(pComponent, pConsoleVerb, E_UNEXPECTED);
  1010. if (sc)
  1011. return sc;
  1012. // get verbs
  1013. bool bCopyEnabled = false;
  1014. bool bCutEnabled = false;
  1015. BOOL bEnable = FALSE;
  1016. sc = pConsoleVerb->GetVerbState(MMC_VERB_COPY, ENABLED, &bEnable);
  1017. bCopyEnabled = bEnable;
  1018. if (sc)
  1019. return sc;
  1020. sc = pConsoleVerb->GetVerbState(MMC_VERB_CUT, ENABLED, &bEnable);
  1021. bCutEnabled = bEnable;
  1022. if (sc)
  1023. return sc;
  1024. // construct the array of scope nodes in this data object
  1025. CSnapinSelData::CNodePtrArray nodes;
  1026. // if regular result items exist - add active scope node
  1027. if ( pSSD->GetNumOfItems() != pSSD->GetScopeNodes().size() )
  1028. nodes.push_back(m_pNode);
  1029. // add scope items from result pane
  1030. nodes.insert( nodes.end(), pSSD->GetScopeNodes().begin(), pSSD->GetScopeNodes().end() );
  1031. // add to the MMC DO
  1032. sc = pResultObject->ScAddSnapinDataObject( nodes,
  1033. pComponent->GetIComponent(),
  1034. pSSD->GetDataObject(),
  1035. bCopyEnabled, bCutEnabled );
  1036. if (sc)
  1037. return sc;
  1038. }
  1039. return sc;
  1040. }