Leaked source code of windows server 2003
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.

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