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.

3108 lines
85 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Administration SnapIn
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: DSEvent.cpp
  9. //
  10. // Contents: Main DS Snapin file
  11. // This file contains all the interfaces between the snapin and
  12. // the slate console. IComponent, IDataObject...etc
  13. //
  14. // History: 02-Oct-96 WayneSc Created
  15. // 06-Mar-97 EricB - added Property Page Extension support
  16. //
  17. //-----------------------------------------------------------------------------
  18. #include "stdafx.h"
  19. #include "uiutil.h"
  20. #include "dsutil.h"
  21. #include "dssnap.h" // Note: this has to be before dsevent.h
  22. #include "DSEvent.h"
  23. #include "ContextMenu.h"
  24. #include "DataObj.h"
  25. #include "dsctx.h"
  26. #include "dsdirect.h"
  27. #include "dsfilter.h"
  28. #include "helpids.h"
  29. #include "query.h"
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. // DS Snapin CLSID - {E355E538-1C2E-11d0-8C37-00C04FD8FE93}
  36. const CLSID CLSID_DSSnapin =
  37. {0xe355e538, 0x1c2e, 0x11d0, {0x8c, 0x37, 0x0, 0xc0, 0x4f, 0xd8, 0xfe, 0x93}};
  38. // DS Snapin Extension CLSID - {006A2A75-547F-11d1-B930-00A0C9A06D2D}
  39. const CLSID CLSID_DSSnapinEx =
  40. { 0x6a2a75, 0x547f, 0x11d1, { 0xb9, 0x30, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  41. // DS Site CLSID - {d967f824-9968-11d0-b936-00c04fd8d5b0}
  42. const CLSID CLSID_SiteSnapin = { 0xd967f824, 0x9968, 0x11d0, { 0xb9, 0x36, 0x0, 0xc0, 0x4f, 0xd8, 0xd5, 0xb0 } };
  43. // Default Nodetype GUID - {FC04A81C-1DFA-11D0-8C3b-00C04FD8FE93}
  44. const GUID cDefaultNodeType =
  45. {0xFC04A81C, 0x1dfa, 0x11d0, {0x8C, 0x3B, 0x00, 0xC0, 0x4F, 0xD8, 0xFE, 0x93}};
  46. // DS About Snapin CLSID - {c3a904fe-c4f2-11d1-b10b-00104b243180}
  47. const CLSID CLSID_DSAboutSnapin =
  48. {0xc3a904fe, 0xc4f2, 0x11d1, {0xb1, 0x0b, 0x00, 0x10, 0x4b, 0x24, 0x31, 0x80}};
  49. // DS About Snapin CLSID - {765901ea-c5a1-11d1-b10c-00104b243180}
  50. const CLSID CLSID_SitesAboutSnapin =
  51. {0x765901ea, 0xc5a1, 0x11d1, {0xb1, 0x0c, 0x00, 0x10, 0x4b, 0x24, 0x31, 0x80}};
  52. // DS Query UI Form extension for saved queries {8C16E7CB-17C2-4729-A669-8474D6712B81}
  53. const CLSID CLSID_DSAdminQueryUIForm =
  54. { 0x8c16e7cb, 0x17c2, 0x4729, { 0xa6, 0x69, 0x84, 0x74, 0xd6, 0x71, 0x2b, 0x81 } };
  55. const wchar_t* cszDefaultNodeType = _T("{FC04A81C-1DFA-11d0-8C3B-00C04FD8FE93}");
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CDSEvent
  58. //+-------------------------------------------------------------------------
  59. //
  60. // Function: Constructor / Destructor
  61. //
  62. // Synopsis:
  63. //
  64. //--------------------------------------------------------------------------
  65. CDSEvent::CDSEvent() :
  66. m_pFrame(NULL),
  67. m_pHeader(NULL),
  68. m_pResultData(NULL),
  69. m_pScopeData(NULL),
  70. m_pConsoleVerb(NULL),
  71. m_pRsltImageList(NULL),
  72. m_pSelectedFolderNode(NULL),
  73. m_pComponentData( NULL ),
  74. m_pToolbar(NULL),
  75. m_pControlbar(NULL),
  76. m_bUpdateAllViewsOrigin(FALSE)
  77. {
  78. TRACE(_T("CDSEvent::CDSEvent() - Constructor\n"));
  79. }
  80. CDSEvent::~CDSEvent()
  81. {
  82. TRACE(_T("CDSEvent::~CDSEvent() - Destructor\n"));
  83. SetIComponentData( NULL );
  84. }
  85. /////////////////////////////////////////////////////////////////////////////
  86. // IComponent Interfaces
  87. //+-------------------------------------------------------------------------
  88. //
  89. // Function: Destroy
  90. //
  91. // Synopsis: Used for clean up
  92. //
  93. //--------------------------------------------------------------------------
  94. STDMETHODIMP CDSEvent::Destroy(MMC_COOKIE)
  95. {
  96. TRACE(_T("CDSEvent::Destroy()\n"));
  97. if (NULL != m_pHeader)
  98. m_pFrame->SetHeader(NULL);
  99. if (NULL != m_pToolbar)
  100. {
  101. m_pToolbar->Release();
  102. }
  103. m_pHeader->Release();
  104. m_pResultData->Release();
  105. m_pScopeData->Release();
  106. m_pRsltImageList->Release();
  107. m_pFrame->Release();
  108. m_pConsoleVerb->Release();
  109. return S_OK;
  110. }
  111. //+-------------------------------------------------------------------------
  112. //
  113. // Function: Initialize
  114. //
  115. // Synopsis: Called everytime the snapin get created.
  116. //
  117. // Arguments: IConsole - Pointer to calling object
  118. //
  119. //--------------------------------------------------------------------------
  120. STDMETHODIMP CDSEvent::Initialize(IConsole* pConsole)
  121. {
  122. TRACE(_T("CDSEvent::Initialize()\n"));
  123. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  124. CWaitCursor wait;
  125. if (pConsole == NULL)
  126. {
  127. // Invalid argument
  128. return E_POINTER;
  129. }
  130. // hold on to the frame
  131. HRESULT hr = pConsole->QueryInterface(IID_IConsole3, (void**)&m_pFrame);
  132. if (FAILED(hr))
  133. return hr;
  134. // cache interface pointers we use
  135. hr = m_pFrame->QueryInterface(IID_IHeaderCtrl, (void**)&m_pHeader);
  136. if (FAILED(hr))
  137. return hr;
  138. ASSERT(m_pHeader != NULL);
  139. hr = m_pFrame->SetHeader(m_pHeader);
  140. if (FAILED(hr))
  141. return hr;
  142. hr = m_pFrame->QueryInterface(IID_IResultData2, (void**)&m_pResultData);
  143. if (FAILED(hr))
  144. return hr;
  145. ASSERT(m_pResultData != NULL);
  146. hr = m_pFrame->QueryInterface(IID_IConsoleNameSpace, (void**)&m_pScopeData);
  147. if (FAILED(hr))
  148. return hr;
  149. ASSERT(m_pScopeData != NULL);
  150. hr = m_pFrame->QueryResultImageList(&m_pRsltImageList);
  151. if (FAILED(hr))
  152. return hr;
  153. ASSERT(m_pRsltImageList != NULL);
  154. hr = m_pFrame->QueryConsoleVerb (&m_pConsoleVerb);
  155. if (FAILED(hr))
  156. return hr;
  157. m_hwnd = m_pComponentData->GetHWnd();
  158. return S_OK;
  159. }
  160. STDMETHODIMP CDSEvent::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
  161. {
  162. TRACE(_T("CDSEvent::GetDataObject()\n"));
  163. HRESULT hr=S_OK;
  164. CUINode* pUINode;
  165. CDSDataObject* const pDataObject = new CComObject<CDSDataObject>;
  166. ASSERT(pDataObject != 0);
  167. pDataObject->SetType(type, m_pComponentData->QuerySnapinType());
  168. pDataObject->SetComponentData(m_pComponentData);
  169. if (cookie != MMC_MULTI_SELECT_COOKIE)
  170. {
  171. pUINode = reinterpret_cast<CUINode*>(cookie);
  172. pDataObject->SetCookie(pUINode);
  173. }
  174. else
  175. {
  176. TRACE(_T("CDSEvent::GetDataObject() - multi-select.\n"));
  177. RESULTDATAITEM rdi;
  178. ZeroMemory(&rdi, sizeof(rdi));
  179. rdi.mask = RDI_STATE;
  180. rdi.nIndex = -1;
  181. rdi.nState = LVIS_SELECTED;
  182. do
  183. {
  184. rdi.lParam = 0;
  185. ASSERT(rdi.mask == RDI_STATE);
  186. ASSERT(rdi.nState == LVIS_SELECTED);
  187. hr = m_pResultData->GetNextItem(&rdi);
  188. if (hr != S_OK)
  189. break;
  190. pUINode = reinterpret_cast<CUINode*>(rdi.lParam);
  191. pDataObject->AddCookie(pUINode);
  192. } while (1);
  193. }
  194. // addref() the new pointer and return it.
  195. pDataObject->AddRef();
  196. *ppDataObject = pDataObject;
  197. TRACE(_T("new data object is at %lx(%lx).\n"),
  198. pDataObject, *pDataObject);
  199. return hr;
  200. }
  201. STDMETHODIMP CDSEvent::GetDisplayInfo(LPRESULTDATAITEM pResult)
  202. {
  203. ASSERT(pResult != NULL);
  204. HRESULT hr = S_OK;
  205. // get the node we are interested in
  206. CUINode* pUINode = reinterpret_cast<CUINode*>(pResult->lParam);
  207. ASSERT( NULL != pUINode );
  208. if (pResult->mask & RDI_STR)
  209. {
  210. // need string value
  211. // get the parent to retrieve the column set
  212. CUINode* pUIParentNode = pUINode->GetParent();
  213. ASSERT(pUIParentNode != NULL);
  214. ASSERT(pUIParentNode->IsContainer());
  215. // retrieve the column set
  216. CDSColumnSet* pColumnSet = pUIParentNode->GetColumnSet(m_pComponentData);
  217. ASSERT(pColumnSet != NULL);
  218. // ask the node to provide the string for the
  219. // given column in the column set
  220. pResult->str = const_cast<LPWSTR>(pUINode->GetDisplayString(pResult->nCol, pColumnSet));
  221. }
  222. if (pResult->mask & RDI_IMAGE)
  223. {
  224. // need an icon for result pane
  225. pResult->nImage = m_pComponentData->GetImage(pUINode, FALSE);
  226. }
  227. return hr;
  228. }
  229. /////////////////////////////////////////////////////////////////////////////
  230. //IResultCallback
  231. STDMETHODIMP CDSEvent::GetResultViewType(MMC_COOKIE, LPWSTR* ppViewType,
  232. long *pViewOptions)
  233. {
  234. *ppViewType = NULL;
  235. *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT;
  236. return S_FALSE;
  237. }
  238. //+----------------------------------------------------------------------------
  239. //
  240. // Member: CDSEvent::IExtendPropertySheet::CreatePropertyPages
  241. //
  242. // Synopsis: Called in response to a user click on the Properties context
  243. // menu item.
  244. //
  245. //-----------------------------------------------------------------------------
  246. STDMETHODIMP
  247. CDSEvent::CreatePropertyPages(LPPROPERTYSHEETCALLBACK pCall,
  248. LONG_PTR lNotifyHandle,
  249. LPDATAOBJECT pDataObject)
  250. {
  251. IExtendPropertySheet * pEPS = (IExtendPropertySheet *)m_pComponentData;
  252. return pEPS->CreatePropertyPages(pCall, lNotifyHandle, pDataObject);
  253. }
  254. //+----------------------------------------------------------------------------
  255. //
  256. // Member: CDSEvent::IExtendPropertySheet::QueryPagesFor
  257. //
  258. // Synopsis: Called before a context menu is posted. If we support a
  259. // property sheet for this object, then return S_OK.
  260. //
  261. //-----------------------------------------------------------------------------
  262. STDMETHODIMP
  263. CDSEvent::QueryPagesFor(LPDATAOBJECT pDataObject)
  264. {
  265. TRACE(TEXT("CDSEvent::QueryPagesFor().\n"));
  266. return m_pComponentData->QueryPagesFor( pDataObject);
  267. }
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Function: LocaleStrCmp
  271. //
  272. // Synopsis: Do a case insensitive string compare that is safe for any
  273. // locale.
  274. //
  275. // Arguments: [ptsz1] - strings to compare
  276. // [ptsz2]
  277. //
  278. // Returns: -1, 0, or 1 just like lstrcmpi
  279. //
  280. // History: 10-28-96 DavidMun Created
  281. //
  282. // Notes: This is slower than lstrcmpi, but will work when sorting
  283. // strings even in Japanese.
  284. //
  285. //----------------------------------------------------------------------------
  286. int LocaleStrCmp(LPCTSTR ptsz1, LPCTSTR ptsz2)
  287. {
  288. int iRet = 0;
  289. iRet = CompareString(LOCALE_USER_DEFAULT,
  290. NORM_IGNORECASE |
  291. NORM_IGNOREKANATYPE |
  292. NORM_IGNOREWIDTH,
  293. ptsz1,
  294. -1,
  295. ptsz2,
  296. -1);
  297. if (iRet)
  298. {
  299. iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1
  300. if ( 0 == iRet )
  301. {
  302. UNICODE_STRING unistr1;
  303. unistr1.Length = (USHORT)(::lstrlen(ptsz1)*sizeof(WCHAR));
  304. unistr1.MaximumLength = unistr1.Length;
  305. unistr1.Buffer = (LPWSTR)ptsz1;
  306. UNICODE_STRING unistr2;
  307. unistr2.Length = (USHORT)(::lstrlen(ptsz2)*sizeof(WCHAR));
  308. unistr2.MaximumLength = unistr2.Length;
  309. unistr2.Buffer = (LPWSTR)ptsz2;
  310. iRet = ::RtlCompareUnicodeString(
  311. &unistr1,
  312. &unistr2,
  313. FALSE );
  314. }
  315. }
  316. else
  317. {
  318. DWORD dwErr = GetLastError ();
  319. if (dwErr != 0)
  320. {
  321. TRACE3 ("CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr);
  322. }
  323. }
  324. return iRet;
  325. }
  326. //+----------------------------------------------------------------------------
  327. //
  328. // Member: CDSEvent::IResultDataCompareEx::Compare
  329. //
  330. // Synopsis: called to do the comparison for sorting in the result
  331. // pane
  332. //
  333. //-----------------------------------------------------------------------------
  334. STDMETHODIMP CDSEvent::Compare(RDCOMPARE* prdc, int* pnResult)
  335. {
  336. HRESULT hr = S_OK;
  337. if (pnResult == NULL)
  338. {
  339. ASSERT(FALSE);
  340. return E_POINTER;
  341. }
  342. *pnResult = 0;
  343. if (prdc == NULL)
  344. {
  345. ASSERT(FALSE);
  346. return E_POINTER;
  347. }
  348. CUINode* pUINodeA = reinterpret_cast<CUINode*>(prdc->prdch1->cookie);
  349. CUINode* pUINodeB = reinterpret_cast<CUINode*>(prdc->prdch2->cookie);
  350. ASSERT(pUINodeA != NULL);
  351. ASSERT(pUINodeB != NULL);
  352. if ( (pUINodeA == NULL) || (pUINodeB == NULL) )
  353. {
  354. return E_INVALIDARG;
  355. }
  356. CString strA, strB;
  357. CDSColumnSet* pColSetA = pUINodeA->GetParent()->GetColumnSet(m_pComponentData);
  358. CDSColumnSet* pColSetB = pUINodeB->GetParent()->GetColumnSet(m_pComponentData);
  359. if ((pColSetA == NULL) || (pColSetB == NULL))
  360. {
  361. return E_INVALIDARG;
  362. }
  363. CDSColumn* pColA = (CDSColumn*)pColSetA->GetColumnAt(prdc->nColumn);
  364. if (IS_CLASS(CDSUINode, *pUINodeA) && IS_CLASS(CDSUINode, *pUINodeB))
  365. {
  366. //
  367. // extract cookie info (DS objects)
  368. //
  369. CDSCookie* pCookieA = GetDSCookieFromUINode(pUINodeA);
  370. CDSCookie* pCookieB = GetDSCookieFromUINode(pUINodeB);
  371. if ( (pCookieB == NULL) || (pCookieA == NULL))
  372. {
  373. return E_INVALIDARG;
  374. }
  375. switch (pColA->GetColumnType())
  376. {
  377. case ATTR_COLTYPE_NAME: //name
  378. strA = pCookieA->GetName();
  379. strB = pCookieB->GetName();
  380. *pnResult = LocaleStrCmp(strA, strB);
  381. break;
  382. case ATTR_COLTYPE_CLASS: //class
  383. strA = pCookieA->GetLocalizedClassName();
  384. strB = pCookieB->GetLocalizedClassName();
  385. *pnResult = LocaleStrCmp(strA, strB);
  386. break;
  387. case ATTR_COLTYPE_DESC: //description
  388. strA = pCookieA->GetDesc();
  389. strB = pCookieB->GetDesc();
  390. *pnResult = LocaleStrCmp(strA, strB);
  391. break;
  392. case ATTR_COLTYPE_SPECIAL: //special columns
  393. {
  394. int nSpecialCol = 0;
  395. int idx = 0;
  396. POSITION pos = pColSetA->GetHeadPosition();
  397. while (idx < prdc->nColumn && pos != NULL) // JonN 4/3/01 313564
  398. {
  399. CDSColumn* pColumn = (CDSColumn*)pColSetA->GetNext(pos);
  400. ASSERT(pColumn != NULL);
  401. if ((pColumn->GetColumnType() == ATTR_COLTYPE_SPECIAL || pColumn->GetColumnType() == ATTR_COLTYPE_MODIFIED_TIME) &&
  402. pColumn->IsVisible())
  403. {
  404. nSpecialCol++;
  405. }
  406. idx++;
  407. }
  408. CStringList& strlistA = pCookieA->GetParentClassSpecificStrings();
  409. POSITION posA = strlistA.FindIndex( nSpecialCol );
  410. CStringList& strlistB = pCookieB->GetParentClassSpecificStrings();
  411. POSITION posB = strlistB.FindIndex( nSpecialCol );
  412. if ( NULL != posA && NULL != posB)
  413. {
  414. strA = strlistA.GetAt( posA );
  415. strB = strlistB.GetAt( posB );
  416. }
  417. *pnResult = LocaleStrCmp(strA, strB);
  418. break;
  419. }
  420. case ATTR_COLTYPE_MODIFIED_TIME:
  421. {
  422. SYSTEMTIME* pTimeA = pCookieA->GetModifiedTime();
  423. SYSTEMTIME* pTimeB = pCookieB->GetModifiedTime();
  424. if (pTimeA == NULL)
  425. {
  426. *pnResult = -1;
  427. break;
  428. }
  429. else if (pTimeB == NULL)
  430. {
  431. *pnResult = 1;
  432. break;
  433. }
  434. FILETIME fileTimeA, fileTimeB;
  435. if (!SystemTimeToFileTime(pTimeA, &fileTimeA))
  436. return E_FAIL;
  437. if (!SystemTimeToFileTime(pTimeB, &fileTimeB))
  438. return E_FAIL;
  439. *pnResult = CompareFileTime(&fileTimeA, &fileTimeB);
  440. break;
  441. }
  442. default:
  443. return E_INVALIDARG;
  444. }
  445. }
  446. else // Not DS objects
  447. {
  448. strA = pUINodeA->GetDisplayString(prdc->nColumn, pColSetA);
  449. strB = pUINodeB->GetDisplayString(prdc->nColumn, pColSetB);
  450. *pnResult = LocaleStrCmp(strA, strB);
  451. }
  452. // TRACE(_T("Compare: %d\n"), *pnResult);
  453. return hr;
  454. }
  455. //+----------------------------------------------------------------------------
  456. //
  457. // Member: CDSEvent::IComponent::CompareObjects
  458. //
  459. // Synopsis: If the data objects belong to the same DS object, then return
  460. // S_OK.
  461. //
  462. //-----------------------------------------------------------------------------
  463. STDMETHODIMP CDSEvent::CompareObjects(LPDATAOBJECT pDataObject1, LPDATAOBJECT pDataObject2)
  464. {
  465. //
  466. // Delegate to the IComponentData implementation.
  467. //
  468. return m_pComponentData->CompareObjects(pDataObject1, pDataObject2);
  469. }
  470. STDMETHODIMP CDSEvent::Notify(IDataObject * pDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  471. {
  472. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  473. HRESULT hr = S_FALSE;
  474. CInternalFormatCracker dobjCracker;
  475. CUINode* pUINode = NULL;
  476. if (pDataObject != NULL)
  477. {
  478. if (FAILED(dobjCracker.Extract(pDataObject)))
  479. {
  480. if ( (event == MMCN_ADD_IMAGES) && !m_pComponentData->m_bRunAsPrimarySnapin )
  481. {
  482. m_pComponentData->FillInIconStrip (m_pRsltImageList);
  483. }
  484. return S_OK;
  485. }
  486. pUINode = dobjCracker.GetCookie();
  487. }
  488. if (event == MMCN_PROPERTY_CHANGE)
  489. {
  490. CWaitCursor cwait;
  491. TRACE(_T("CDSEvent::Notify() - property change, pDataObj = 0x%08x, param = 0x%08x, arg = %d.\n"),
  492. pDataObject, param, arg);
  493. if (param != 0)
  494. {
  495. hr = m_pComponentData->_OnPropertyChange((LPDATAOBJECT)param, FALSE);
  496. if (FAILED(hr))
  497. {
  498. hr = S_FALSE;
  499. }
  500. }
  501. return S_OK;
  502. }
  503. // some of the MMCN_VIEW_CHANGE, MMCN_CUTORMOVE messages have a NULL data object
  504. if ((event != MMCN_VIEW_CHANGE) && (event != MMCN_CUTORMOVE) && (pUINode == NULL))
  505. return S_FALSE;
  506. switch (event)
  507. {
  508. case MMCN_SHOW:
  509. if (arg == TRUE)
  510. { // Show
  511. CWaitCursor cwait;
  512. _EnumerateCookie(pUINode,(HSCOPEITEM)param,event);
  513. hr = S_OK;
  514. }
  515. break;
  516. case MMCN_MINIMIZED:
  517. hr = S_FALSE;
  518. break;
  519. case MMCN_SELECT:
  520. {
  521. BOOL bScope = LOWORD(arg);
  522. BOOL bSelect = HIWORD(arg);
  523. CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData);
  524. if (pMenuVerbs == NULL)
  525. {
  526. ASSERT(FALSE);
  527. return S_FALSE;
  528. }
  529. pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb,
  530. bScope/*bScope*/,
  531. bSelect/*bSelect*/,
  532. pUINode,
  533. pDataObject);
  534. hr = S_OK;
  535. }
  536. break;
  537. case MMCN_DELETE:
  538. {
  539. CWaitCursor cwait;
  540. _Delete(pDataObject, &dobjCracker);
  541. hr = S_OK;
  542. }
  543. break;
  544. case MMCN_QUERY_PASTE:
  545. {
  546. hr = _QueryPaste(pUINode, (IDataObject*)(arg));
  547. if (FAILED(hr))
  548. {
  549. hr = S_FALSE;
  550. }
  551. }
  552. break;
  553. case MMCN_PASTE:
  554. {
  555. CWaitCursor cwait;
  556. _Paste(pUINode, (IDataObject*)(arg), (LPDATAOBJECT*)param);
  557. hr = S_OK;
  558. }
  559. break;
  560. case MMCN_CUTORMOVE:
  561. {
  562. CWaitCursor cwait;
  563. ASSERT(pUINode == NULL);
  564. _CutOrMove((IDataObject*)(arg));
  565. hr = S_OK;
  566. }
  567. break;
  568. case MMCN_RENAME:
  569. {
  570. CWaitCursor cwait;
  571. hr = m_pComponentData->_Rename (pUINode,
  572. (LPWSTR) param);
  573. if (SUCCEEDED(hr))
  574. {
  575. m_pFrame->UpdateAllViews (pDataObject,
  576. (LPARAM)pUINode,
  577. DS_RENAME_OCCURRED);
  578. MMC_SORT_SET_DATA* pColumnData = NULL;
  579. CDSColumnSet* pColumnSet = pUINode->GetParent()->GetColumnSet(m_pComponentData);
  580. if (pColumnSet == NULL)
  581. break;
  582. LPCWSTR lpszID = pColumnSet->GetColumnID();
  583. size_t iLen = wcslen(lpszID);
  584. //
  585. // allocate enough memory for the struct and the guid
  586. //
  587. SColumnSetID* pNodeID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  588. if (pNodeID != NULL)
  589. {
  590. memset(pNodeID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  591. pNodeID->cBytes = static_cast<ULONG>(iLen * sizeof(WCHAR));
  592. memcpy(pNodeID->id, lpszID, (iLen * sizeof(WCHAR)));
  593. CComPtr<IColumnData> spColumnData;
  594. hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData);
  595. if (spColumnData != NULL)
  596. {
  597. hr = spColumnData->GetColumnSortData(pNodeID, &pColumnData);
  598. }
  599. if (SUCCEEDED(hr))
  600. {
  601. if (pColumnData != NULL)
  602. {
  603. if (pColumnData->pSortData[0].nColIndex == 0)
  604. {
  605. m_pFrame->UpdateAllViews(NULL,
  606. (LPARAM)pUINode->GetParent(),
  607. DS_SORT_RESULT_PANE);
  608. }
  609. CoTaskMemFree(pColumnData);
  610. }
  611. }
  612. else
  613. {
  614. hr = S_FALSE;
  615. }
  616. free(pNodeID);
  617. }
  618. }
  619. else
  620. {
  621. hr = S_FALSE;
  622. }
  623. }
  624. break;
  625. case MMCN_VIEW_CHANGE:
  626. {
  627. CWaitCursor cwait;
  628. TRACE (_T("CDSEvent::Notify() - view change message.\n"));
  629. HandleViewChange (pDataObject, arg, param);
  630. hr = S_OK;
  631. }
  632. break;
  633. case MMCN_ADD_IMAGES:
  634. {
  635. CWaitCursor cwait;
  636. m_pComponentData->FillInIconStrip (m_pRsltImageList);
  637. hr = S_OK;
  638. }
  639. break;
  640. case MMCN_REFRESH:
  641. {
  642. CWaitCursor cwait;
  643. m_pComponentData->Refresh(pUINode);
  644. hr = S_OK;
  645. }
  646. break;
  647. case MMCN_DBLCLICK:
  648. hr = S_FALSE;
  649. break;
  650. case MMCN_COLUMN_CLICK:
  651. hr = S_OK;
  652. break;
  653. case MMCN_COLUMNS_CHANGED:
  654. {
  655. CWaitCursor cwait;
  656. MMC_VISIBLE_COLUMNS* pVisibleColumns = reinterpret_cast<MMC_VISIBLE_COLUMNS*>(param);
  657. // Delegate to IComponentData
  658. hr = m_pComponentData->ColumnsChanged(this, pUINode, pVisibleColumns, TRUE);
  659. if (FAILED(hr))
  660. {
  661. hr = S_FALSE;
  662. }
  663. }
  664. break;
  665. case MMCN_RESTORE_VIEW :
  666. {
  667. CWaitCursor cwait;
  668. m_pComponentData->ColumnsChanged(this, pUINode, NULL, FALSE);
  669. *((BOOL*)param) = TRUE;
  670. hr = S_OK;
  671. }
  672. break;
  673. case MMCN_CONTEXTHELP:
  674. {
  675. CWaitCursor cwait;
  676. IDisplayHelp * phelp = NULL;
  677. hr = m_pFrame->QueryInterface (IID_IDisplayHelp,
  678. (void **)&phelp);
  679. CString strDefTopic;
  680. if (SUCCEEDED(hr))
  681. {
  682. if (m_pComponentData->QuerySnapinType() == SNAPINTYPE_SITE)
  683. {
  684. strDefTopic = DSSITES_DEFAULT_TOPIC;
  685. }
  686. else
  687. {
  688. strDefTopic = DSADMIN_DEFAULT_TOPIC;
  689. }
  690. phelp->ShowTopic ((LPWSTR)(LPCWSTR)strDefTopic);
  691. phelp->Release();
  692. }
  693. else
  694. {
  695. ReportErrorEx (m_hwnd, IDS_HELPLESS, hr, NULL, 0);
  696. hr = S_FALSE;
  697. }
  698. if (FAILED(hr))
  699. {
  700. hr = S_FALSE;
  701. }
  702. }
  703. break;
  704. default:
  705. hr = S_FALSE;
  706. }
  707. return hr;
  708. }
  709. /////////////////////////////////////////////////////////////////////////////
  710. // IExtendContextMenu
  711. STDMETHODIMP CDSEvent::AddMenuItems(IDataObject* piDataObject,
  712. IContextMenuCallback* piCallback,
  713. long *pInsertionAllowed)
  714. {
  715. TRACE(_T("CDSEvent::AddExtensionContextMenuItems()\n"));
  716. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  717. HRESULT hr;
  718. CWaitCursor cwait;
  719. CInternalFormatCracker dobjCracker;
  720. hr = dobjCracker.Extract(piDataObject);
  721. if (FAILED(hr))
  722. {
  723. return hr;
  724. }
  725. DATA_OBJECT_TYPES dotType = dobjCracker.GetType();
  726. CUINode* pUINode = dobjCracker.GetCookie();
  727. //
  728. // Retrieve the verb handler from the node
  729. // NOTE: multi-selection is handled by cracking the dataobject not by which node
  730. // is called to retrieve the CContextMenuVerbs object
  731. //
  732. CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData);
  733. if (pMenuVerbs == NULL)
  734. {
  735. ASSERT(FALSE);
  736. return E_FAIL;
  737. }
  738. CComPtr<IContextMenuCallback2> spContextMenuCallback2;
  739. hr = piCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spContextMenuCallback2);
  740. if (FAILED(hr))
  741. {
  742. ASSERT(FALSE && L"Unable to QI for the IContextMenuCallback2 interface.");
  743. return hr;
  744. }
  745. if (dotType == CCT_RESULT)
  746. {
  747. pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, FALSE/*bScope*/, TRUE /*bSelect*/, pUINode, piDataObject);
  748. //
  749. // Create the main menu, if allowed
  750. //
  751. if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP)
  752. {
  753. hr = pMenuVerbs->LoadMainMenu(spContextMenuCallback2,piDataObject,pUINode);
  754. hr = pMenuVerbs->LoadMenuExtensions(spContextMenuCallback2,
  755. m_pComponentData->m_pShlInit,
  756. piDataObject,
  757. pUINode);
  758. }
  759. if (SUCCEEDED(hr))
  760. {
  761. // create the task menu
  762. if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK)
  763. {
  764. hr = pMenuVerbs->LoadTaskMenu(spContextMenuCallback2,pUINode);
  765. }
  766. }
  767. }
  768. else if (dotType == CCT_SCOPE)
  769. {
  770. pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb, TRUE/*bScope*/, TRUE /*bSelect*/, pUINode, piDataObject);
  771. hr = m_pComponentData->AddMenuItems (piDataObject,
  772. piCallback,
  773. pInsertionAllowed);
  774. }
  775. else // CCT_UNINITIALIZED
  776. {
  777. if (dobjCracker.GetCookieCount() > 1)
  778. {
  779. hr = pMenuVerbs->LoadMenuExtensions(spContextMenuCallback2,
  780. m_pComponentData->m_pShlInit,
  781. piDataObject,
  782. pUINode);
  783. }
  784. }
  785. ASSERT( SUCCEEDED(hr) );
  786. return hr;
  787. }
  788. STDMETHODIMP CDSEvent::Command(long lCommandID, IDataObject * pDataObject)
  789. {
  790. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  791. TRACE(_T("CDSEvent::Command()\n"));
  792. CWaitCursor CWait;
  793. // crack data object
  794. CInternalFormatCracker dobjCracker;
  795. HRESULT hr = dobjCracker.Extract(pDataObject);
  796. if (FAILED(hr))
  797. {
  798. ASSERT(FALSE); // not our data object
  799. return hr;
  800. }
  801. DATA_OBJECT_TYPES dotType = dobjCracker.GetType();
  802. if (dotType == CCT_SCOPE)
  803. {
  804. // if called from the tree view context, delegate to ComponentData
  805. return m_pComponentData->Command(lCommandID, pDataObject);
  806. }
  807. // context menu shell extensions
  808. if ((lCommandID >= MENU_MERGE_BASE) && (lCommandID <= MENU_MERGE_LIMIT))
  809. {
  810. return _CommandShellExtension(lCommandID, pDataObject);
  811. }
  812. // standard commands
  813. CUINode* pUINode = dobjCracker.GetCookie();
  814. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  815. if ( (pUINode == NULL) ||(pCookie==NULL) )
  816. {
  817. ASSERT(FALSE); // Invalid Cookie
  818. return E_INVALIDARG;
  819. }
  820. switch (lCommandID)
  821. {
  822. case IDM_GEN_TASK_MOVE:
  823. {
  824. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(pUINode);
  825. ASSERT(pDSUINode != NULL);
  826. CDSCookie* pMoveCookie = pDSUINode->GetCookie();
  827. hr = m_pComponentData->GetActiveDS()->MoveObject(pMoveCookie);
  828. if (hr == S_OK)
  829. {
  830. CUINode* pNewParentNode = NULL;
  831. hr = m_pComponentData->FindParentCookie(pMoveCookie->GetPath(), &pNewParentNode);
  832. if ((hr == S_OK) && (pNewParentNode->GetFolderInfo()->IsExpanded()))
  833. {
  834. pNewParentNode->GetFolderInfo()->AddNode(pUINode);
  835. }
  836. m_pFrame->UpdateAllViews(pDataObject, (LPARAM)pUINode, DS_MOVE_OCCURRED);
  837. }
  838. }
  839. break;
  840. default:
  841. ;
  842. } // switch
  843. return S_OK;
  844. }
  845. HRESULT CDSEvent::_CommandShellExtension(long nCommandID, LPDATAOBJECT pDataObject)
  846. {
  847. CWaitCursor wait;
  848. // initialize shell code with data object
  849. IShellExtInit* pShlInit = m_pComponentData->m_pShlInit; // local copy, no addref
  850. HRESULT hr = pShlInit->Initialize(NULL, pDataObject, 0);
  851. if (FAILED(hr))
  852. {
  853. TRACE(TEXT("pShlInit->Initialize failed, hr: 0x%x\n"), hr);
  854. return hr;
  855. }
  856. // get the context menu specific interface
  857. CComPtr<IContextMenu> spICM;
  858. hr = pShlInit->QueryInterface(IID_IContextMenu, (void **)&spICM);
  859. if (FAILED(hr))
  860. {
  861. TRACE(TEXT("pShlInit->QueryInterface(IID_IContextMenu, ...) failed, hr: 0x%x\n"), hr);
  862. return hr;
  863. }
  864. // invoke the shell extension command
  865. HWND hwnd;
  866. CMINVOKECOMMANDINFO cmiCommand;
  867. hr = m_pFrame->GetMainWindow (&hwnd);
  868. ASSERT (hr == S_OK);
  869. cmiCommand.hwnd = hwnd;
  870. cmiCommand.cbSize = sizeof (CMINVOKECOMMANDINFO);
  871. cmiCommand.fMask = SEE_MASK_ASYNCOK;
  872. cmiCommand.lpVerb = MAKEINTRESOURCEA(nCommandID - MENU_MERGE_BASE);
  873. spICM->InvokeCommand (&cmiCommand);
  874. CInternalFormatCracker dobjCracker;
  875. hr = dobjCracker.Extract(pDataObject);
  876. if (FAILED(hr))
  877. {
  878. ASSERT(FALSE); // not our data object
  879. return hr;
  880. }
  881. // -----------------------------------------------------------------
  882. // code to update the views if the extension says it moved items
  883. //
  884. TRACE(_T("Command: returned from extension commdand\n"));
  885. CUINodeList nodesMoved;
  886. HSCOPEITEM ItemID;
  887. CUINode* pCurrentParentNode = NULL;
  888. CUINode* pNewParentNode = NULL;
  889. for (UINT index = 0; index < dobjCracker.GetCookieCount(); index ++)
  890. {
  891. CUINode* pUINode = dobjCracker.GetCookie(index);
  892. // make sure the node moved is of the right type: for the time
  893. // being we just deal with DS objects
  894. if (!IS_CLASS(*pUINode, CDSUINode))
  895. {
  896. ASSERT(FALSE); // should not get here
  897. continue;
  898. }
  899. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  900. if (pUINode->GetExtOp() & OPCODE_MOVE)
  901. {
  902. if (pNewParentNode == NULL)
  903. {
  904. // get the parent from the first node
  905. // assume that all have the same parent
  906. m_pComponentData->FindParentCookie(pCookie->GetPath(), &pNewParentNode);
  907. }
  908. pCurrentParentNode = pUINode->GetParent();
  909. if (pCurrentParentNode &&
  910. IS_CLASS(*pCurrentParentNode, CDSUINode))
  911. {
  912. if (pUINode->IsContainer())
  913. {
  914. ItemID = pUINode->GetFolderInfo()->GetScopeItem();
  915. // delete the scope item in MMC
  916. hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE);
  917. ASSERT(SUCCEEDED(hr));
  918. #ifdef DBG
  919. if (FAILED(hr))
  920. {
  921. TRACE(_T("DeleteItem failed on %lx (%s).\n"),
  922. ItemID, pUINode->GetName());
  923. }
  924. TRACE(_T("Move postprocessing - deleted scope node: %x (%s)\n"),
  925. ItemID, pUINode->GetName());
  926. #endif
  927. if (pCurrentParentNode)
  928. {
  929. pCurrentParentNode->GetFolderInfo()->RemoveNode(pUINode);
  930. }
  931. if ((pNewParentNode) && pNewParentNode->GetFolderInfo()->IsExpanded())
  932. {
  933. pUINode->ClearParent();
  934. pNewParentNode->GetFolderInfo()->AddNode(pUINode);
  935. hr = m_pComponentData->_AddScopeItem(pUINode, pNewParentNode->GetFolderInfo()->GetScopeItem());
  936. #ifdef DBG
  937. if (FAILED(hr))
  938. {
  939. TRACE(_T("AddItem failed on %lx (%s).\n"),
  940. ItemID, pUINode->GetName());
  941. }
  942. TRACE(_T("Move postprocessing - added scope node: %s\n"),
  943. pUINode->GetName());
  944. #endif
  945. }
  946. else
  947. {
  948. // not expanded
  949. delete pCookie;
  950. pCookie = NULL;
  951. }
  952. }
  953. else
  954. {
  955. // not a container
  956. if ((pNewParentNode) &&
  957. (pNewParentNode->GetFolderInfo()->IsExpanded()))
  958. {
  959. pUINode->ClearParent();
  960. pNewParentNode->GetFolderInfo()->AddNode(pUINode);
  961. }
  962. nodesMoved.AddTail(pUINode);
  963. }
  964. }
  965. if (pUINode)
  966. {
  967. pUINode->SetExtOp(NULL);
  968. }
  969. }
  970. } // for items in multiple selection
  971. if (!nodesMoved.IsEmpty())
  972. {
  973. m_pFrame->UpdateAllViews(NULL, (LPARAM)&nodesMoved, DS_MULTIPLE_MOVE_OCCURRED);
  974. }
  975. //------------------------------ends here--------------------------------------
  976. m_pComponentData->SortResultPane(pNewParentNode);
  977. return S_OK;
  978. }
  979. HRESULT CDSEvent::_InitView(CUINode* pUINode)
  980. {
  981. CWaitCursor wait;
  982. HRESULT hr=S_OK;
  983. //
  984. // This is more a suggestion than anything so its OK to ignore the return value but
  985. // we will ASSERT for testing purposes
  986. //
  987. hr = m_pResultData->ModifyViewStyle(MMC_ENSUREFOCUSVISIBLE, (MMC_RESULT_VIEW_STYLE)0);
  988. ASSERT(SUCCEEDED(hr));
  989. hr=_SetColumns(pUINode);
  990. m_pSelectedFolderNode = pUINode;
  991. return hr;
  992. }
  993. HRESULT CDSEvent::_EnumerateCookie(CUINode* pUINode, HSCOPEITEM hParent, MMC_NOTIFY_TYPE event)
  994. {
  995. TRACE(_T("CDSEvent::_EnumerateCookie()\n"));
  996. HRESULT hr = S_OK;
  997. CWaitCursor cwait;
  998. if ( (pUINode == NULL) || (!pUINode->IsContainer()) )
  999. {
  1000. ASSERT(FALSE); // Invalid Arguments
  1001. return E_INVALIDARG;
  1002. }
  1003. if (MMCN_SHOW == event)
  1004. {
  1005. _InitView(pUINode);
  1006. if (!pUINode->GetFolderInfo()->IsExpanded())
  1007. {
  1008. m_pComponentData->_OnExpand(pUINode, hParent, event);
  1009. }
  1010. _DisplayCachedNodes(pUINode);
  1011. pUINode->GetFolderInfo()->UpdateSerialNumber(m_pComponentData);
  1012. if (pUINode->GetFolderInfo()->GetSortOnNextSelect())
  1013. {
  1014. m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_SORT_RESULT_PANE);
  1015. pUINode->GetFolderInfo()->SetSortOnNextSelect(FALSE);
  1016. }
  1017. }
  1018. return hr;
  1019. }
  1020. HRESULT CDSEvent::_DisplayCachedNodes(CUINode* pUINode)
  1021. {
  1022. if ( (pUINode == NULL) || (!pUINode->IsContainer()) )
  1023. {
  1024. ASSERT(FALSE); // Invalid Arguments
  1025. return E_INVALIDARG;
  1026. }
  1027. HRESULT hr = S_OK;
  1028. // Add the leaf nodes
  1029. CUINodeList* pLeafList = pUINode->GetFolderInfo()->GetLeafList();
  1030. for (POSITION pos = pLeafList->GetHeadPosition(); pos != NULL; )
  1031. {
  1032. POSITION prevPos = pos;
  1033. CUINode* pCurrChildUINode = pLeafList->GetNext(pos);
  1034. ASSERT(pCurrChildUINode != NULL);
  1035. if (pCurrChildUINode->GetExtOp() & OPCODE_MOVE)
  1036. {
  1037. pLeafList->RemoveAt(prevPos);
  1038. pCurrChildUINode->SetExtOp(NULL);
  1039. delete pCurrChildUINode;
  1040. }
  1041. else
  1042. {
  1043. hr = _AddResultItem(pCurrChildUINode);
  1044. }
  1045. }
  1046. _UpdateObjectCount(FALSE /* set count to 0?*/);
  1047. return S_OK;
  1048. }
  1049. HRESULT CDSEvent::_AddResultItem(CUINode* pUINode, BOOL bSetSelect)
  1050. {
  1051. if (pUINode == NULL)
  1052. {
  1053. ASSERT(FALSE); // Invalid Arguments
  1054. return E_INVALIDARG;
  1055. }
  1056. HRESULT hr = S_OK;
  1057. RESULTDATAITEM rdiListView;
  1058. ZeroMemory(&rdiListView, sizeof(RESULTDATAITEM));
  1059. rdiListView.lParam = reinterpret_cast<LPARAM>(pUINode);
  1060. rdiListView.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  1061. rdiListView.str = MMC_CALLBACK;
  1062. rdiListView.nImage = MMC_IMAGECALLBACK;
  1063. if (bSetSelect)
  1064. {
  1065. rdiListView.mask |= RDI_STATE;
  1066. rdiListView.nState = LVIS_SELECTED | LVIS_FOCUSED;
  1067. }
  1068. return hr = m_pResultData->InsertItem(&rdiListView);
  1069. }
  1070. HRESULT CDSEvent::SelectResultNode(CUINode* pUINode)
  1071. {
  1072. HRESULTITEM ItemID = 0;
  1073. HRESULT hr = m_pResultData->FindItemByLParam ((LPARAM)pUINode, &ItemID);
  1074. if (SUCCEEDED(hr))
  1075. {
  1076. hr = m_pResultData->ModifyItemState(0 /*unused*/,
  1077. ItemID,
  1078. LVIS_FOCUSED | LVIS_SELECTED,
  1079. 0 /*no removing*/);
  1080. }
  1081. return hr;
  1082. }
  1083. void CDSEvent::_DeleteSingleSel(IDataObject* pDataObject, CUINode* pUINode)
  1084. {
  1085. ASSERT(!pUINode->IsContainer());
  1086. HRESULT hr = S_OK;
  1087. //
  1088. // Get the parent container for later use
  1089. //
  1090. CUINode* pParentNode = pUINode->GetParent();
  1091. ASSERT(pParentNode != NULL);
  1092. CDSCookie* pCookie = NULL;
  1093. if (IS_CLASS(*pUINode, CDSUINode))
  1094. {
  1095. pCookie = GetDSCookieFromUINode(pUINode);
  1096. if (pCookie == NULL)
  1097. {
  1098. return;
  1099. }
  1100. //
  1101. // delete from the back end
  1102. // this call will handle the notifification to extensions
  1103. //
  1104. hr = m_pComponentData->_DeleteFromBackEnd(pDataObject, pCookie);
  1105. }
  1106. else
  1107. {
  1108. hr = pUINode->Delete(m_pComponentData);
  1109. }
  1110. //
  1111. // update the result pane
  1112. //
  1113. if (SUCCEEDED(hr) && (hr != S_FALSE))
  1114. {
  1115. m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_DELETE_OCCURRED);
  1116. }
  1117. //
  1118. // Remove the '+' next to the parent in the UI if this is the last container
  1119. // object in this container
  1120. //
  1121. if (pParentNode != NULL &&
  1122. pParentNode->GetFolderInfo()->GetContainerList()->GetCount() == 0)
  1123. {
  1124. SCOPEDATAITEM sdi;
  1125. memset(&sdi, 0, sizeof(SCOPEDATAITEM));
  1126. sdi.ID = pParentNode->GetFolderInfo()->GetScopeItem();
  1127. sdi.mask |= SDI_CHILDREN;
  1128. sdi.cChildren = 0;
  1129. hr = m_pScopeData->SetItem(&sdi);
  1130. }
  1131. }
  1132. ///////////////////////////////////////////////////////////////////////////
  1133. // CResultPaneMultipleDeleteHandler
  1134. class CResultPaneMultipleDeleteHandler : public CMultipleDeleteHandlerBase
  1135. {
  1136. public:
  1137. CResultPaneMultipleDeleteHandler(CDSComponentData* pComponentData, HWND hwnd,
  1138. IDataObject* pDataObject,
  1139. CInternalFormatCracker* pObjCracker,
  1140. CUINodeList* pNodesDeletedList)
  1141. : CMultipleDeleteHandlerBase(pComponentData, hwnd)
  1142. {
  1143. m_pDataObject = pDataObject;
  1144. m_pObjCracker = pObjCracker;
  1145. m_pNodesDeletedList = pNodesDeletedList;
  1146. }
  1147. protected:
  1148. virtual UINT GetItemCount() { return m_pObjCracker->GetCookieCount();}
  1149. virtual HRESULT BeginTransaction()
  1150. {
  1151. return GetTransaction()->Begin(m_pDataObject, NULL, NULL, FALSE);
  1152. }
  1153. virtual HRESULT DeleteObject(UINT i)
  1154. {
  1155. CUINode* pUINode = m_pObjCracker->GetCookie(i);
  1156. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1157. if (pCookie != NULL)
  1158. {
  1159. // need to pass full ADSI path to ObjectDeletionCheck
  1160. CString strPath;
  1161. GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(
  1162. strPath, pCookie->GetPath());
  1163. bool fAlternateDeleteMethod = false;
  1164. HRESULT hr = ObjectDeletionCheck(
  1165. strPath,
  1166. pCookie->GetName(),
  1167. pCookie->GetClass(),
  1168. fAlternateDeleteMethod );
  1169. if ( FAILED(hr)
  1170. || HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr
  1171. || fAlternateDeleteMethod )
  1172. return hr;
  1173. }
  1174. return GetComponentData()->GetActiveDS()->DeleteObject(pCookie,
  1175. FALSE); //raise UI for error?
  1176. }
  1177. virtual HRESULT DeleteSubtree(UINT i)
  1178. {
  1179. CUINode* pUINode = m_pObjCracker->GetCookie(i);
  1180. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1181. return GetComponentData()->_DeleteSubtreeFromBackEnd(pCookie);
  1182. }
  1183. virtual void OnItemDeleted(UINT i)
  1184. {
  1185. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(m_pObjCracker->GetCookie(i));
  1186. ASSERT(pDSUINode != NULL);
  1187. m_pNodesDeletedList->AddTail(pDSUINode);
  1188. }
  1189. virtual void GetItemName(IN UINT i, OUT CString& szName)
  1190. {
  1191. CUINode* pUINode = m_pObjCracker->GetCookie(i);
  1192. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1193. if (pCookie != NULL)
  1194. {
  1195. szName = pCookie->GetName();
  1196. }
  1197. }
  1198. virtual void GetItemPath(UINT i, CString& szPath)
  1199. {
  1200. CUINode* pUINode = m_pObjCracker->GetCookie(i);
  1201. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1202. if (pCookie != NULL)
  1203. {
  1204. GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(szPath, pCookie->GetPath());
  1205. }
  1206. }
  1207. virtual PCWSTR GetItemClass(UINT i)
  1208. {
  1209. CUINode* pUINode = m_pObjCracker->GetCookie(i);
  1210. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1211. PCWSTR pszClass = NULL;
  1212. if (pCookie != NULL)
  1213. {
  1214. pszClass = pCookie->GetClass();
  1215. }
  1216. return pszClass;
  1217. }
  1218. private:
  1219. IDataObject* m_pDataObject;
  1220. CInternalFormatCracker* m_pObjCracker;
  1221. CUINodeList* m_pNodesDeletedList;
  1222. };
  1223. void CDSEvent::_DeleteNodeListFromUI(CUINodeList* pNodesDeletedList)
  1224. {
  1225. // finally, we have to update the UI
  1226. if (pNodesDeletedList->GetCount() == 0)
  1227. {
  1228. return;
  1229. }
  1230. TIMER(_T("updating UI after delete, containers first.\n"));
  1231. //walk this cookie list and take
  1232. //care of the containers (scope pane items)
  1233. for (POSITION pos = pNodesDeletedList->GetHeadPosition(); pos != NULL; )
  1234. {
  1235. POSITION posCurrNode = pos;
  1236. CUINode* pCurrNode = pNodesDeletedList->GetNext(pos);
  1237. ASSERT(pCurrNode != NULL);
  1238. HSCOPEITEM ItemID, ParentItemID;
  1239. if (pCurrNode->IsContainer())
  1240. {
  1241. ItemID = pCurrNode->GetFolderInfo()->GetScopeItem();
  1242. CUINode* pParentNode = NULL;
  1243. HRESULT hr = m_pComponentData->m_pScope->GetParentItem(ItemID,
  1244. &ParentItemID,
  1245. (MMC_COOKIE *)&pParentNode);
  1246. m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE);
  1247. if (SUCCEEDED(hr))
  1248. {
  1249. pParentNode->GetFolderInfo()->DeleteNode(pCurrNode);
  1250. pNodesDeletedList->RemoveAt(posCurrNode);
  1251. }
  1252. } // container
  1253. } // for
  1254. TIMER(_T("updating UI after delete, now the leaf items.\n"));
  1255. // now update all the views to take care of result pane items
  1256. m_pFrame->UpdateAllViews(NULL,
  1257. (LPARAM)pNodesDeletedList,
  1258. DS_MULTIPLE_DELETE_OCCURRED);
  1259. TIMER(_T("updating UI after delete, done.\n"));
  1260. }
  1261. void CDSEvent::_DeleteMultipleSel(IDataObject* pDataObject, CInternalFormatCracker* pObjCracker)
  1262. {
  1263. // handle the deletion in the back end involving the extensions
  1264. // by calling the delete handler
  1265. //
  1266. // Get the parent container
  1267. //
  1268. CUINode* pContainerNode = NULL;
  1269. CUINode* pUINode = pObjCracker->GetCookie();
  1270. if (pUINode != NULL)
  1271. {
  1272. pContainerNode = pUINode->GetParent();
  1273. }
  1274. else
  1275. {
  1276. ASSERT(FALSE);
  1277. }
  1278. // REVIEW_MARCOC_PORT: for the time being we assume that all the
  1279. // items in the multiple selection are of DS type
  1280. if (!AreAllNodesOfType<CDSUINode>(pObjCracker))
  1281. {
  1282. //
  1283. // Delegate the delete to the container object
  1284. //
  1285. if (pContainerNode != NULL)
  1286. {
  1287. pContainerNode->DeleteMultiselect(m_pComponentData, pObjCracker);
  1288. }
  1289. else
  1290. {
  1291. ASSERT(FALSE);
  1292. }
  1293. }
  1294. else // All are DS nodes
  1295. {
  1296. CUINodeList nodesDeletedList;
  1297. CResultPaneMultipleDeleteHandler deleteHandler(m_pComponentData, m_hwnd,
  1298. pDataObject, pObjCracker, &nodesDeletedList);
  1299. deleteHandler.Delete();
  1300. _DeleteNodeListFromUI(&nodesDeletedList);
  1301. }
  1302. //
  1303. // Remove the '+' sign in the UI if this was the last container child in this container
  1304. //
  1305. if (pContainerNode != NULL &&
  1306. pContainerNode->GetFolderInfo()->GetContainerList()->GetCount() == 0)
  1307. {
  1308. SCOPEDATAITEM sdi;
  1309. memset(&sdi, 0, sizeof(SCOPEDATAITEM));
  1310. sdi.ID = pContainerNode->GetFolderInfo()->GetScopeItem();
  1311. sdi.mask |= SDI_CHILDREN;
  1312. sdi.cChildren = 0;
  1313. m_pComponentData->m_pScope->SetItem(&sdi);
  1314. }
  1315. }
  1316. void CDSEvent::_Delete(IDataObject* pDataObject, CInternalFormatCracker* pObjCracker)
  1317. {
  1318. CWaitCursor cwait;
  1319. // protect against deletion with sheets up
  1320. if (m_pComponentData->_WarningOnSheetsUp(pObjCracker))
  1321. return;
  1322. // do the actual deletion
  1323. if (pObjCracker->GetCookieCount() == 1)
  1324. {
  1325. _DeleteSingleSel(pDataObject, pObjCracker->GetCookie());
  1326. }
  1327. else
  1328. {
  1329. _DeleteMultipleSel(pDataObject, pObjCracker);
  1330. }
  1331. }
  1332. BOOL AllObjectsHaveTheSameServerName(IN LPCWSTR lpszServerName,
  1333. IN CObjectNamesFormatCracker* pObjectNamesFormatPaste)
  1334. {
  1335. if (lpszServerName == NULL)
  1336. {
  1337. ASSERT(FALSE);
  1338. return FALSE;
  1339. }
  1340. CComBSTR bstrCurrServerName;
  1341. for (UINT k=0; k<pObjectNamesFormatPaste->GetCount(); k++)
  1342. {
  1343. HRESULT hr = GetServerFromLDAPPath(pObjectNamesFormatPaste->GetName(k),
  1344. &bstrCurrServerName);
  1345. if (FAILED(hr) || (&bstrCurrServerName == NULL))
  1346. {
  1347. // something was wrong
  1348. return FALSE;
  1349. }
  1350. if (_wcsicmp(lpszServerName, bstrCurrServerName) != 0)
  1351. {
  1352. // got something different
  1353. return FALSE;
  1354. }
  1355. }
  1356. return TRUE; // all are the same
  1357. }
  1358. BOOL HasSameObject(IN CUINode* pUINode, IN IDataObject* pPasteData)
  1359. {
  1360. if (pUINode == NULL)
  1361. {
  1362. ASSERT(FALSE);
  1363. return FALSE;
  1364. }
  1365. //
  1366. // Check to see if the target is a DS node
  1367. //
  1368. CDSUINode* pDSTargetNode = NULL;
  1369. BOOL bCookieIsDSUINode = FALSE;
  1370. if(IS_CLASS(*pUINode, CDSUINode))
  1371. {
  1372. bCookieIsDSUINode = TRUE;
  1373. pDSTargetNode = dynamic_cast<CDSUINode*>(pUINode);
  1374. }
  1375. CInternalFormatCracker ifc;
  1376. HRESULT hr = ifc.Extract(pPasteData);
  1377. if (SUCCEEDED(hr))
  1378. {
  1379. for (UINT k=0; k < ifc.GetCookieCount(); k++)
  1380. {
  1381. //
  1382. // If the cookies are the same return TRUE
  1383. //
  1384. if (ifc.GetCookie(k) == pUINode)
  1385. {
  1386. return TRUE;
  1387. }
  1388. if (bCookieIsDSUINode && pDSTargetNode != NULL)
  1389. {
  1390. //
  1391. // If its a DS node and their DNs are the same return TRUE
  1392. //
  1393. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(ifc.GetCookie(k));
  1394. if (pDSUINode != NULL)
  1395. {
  1396. if (_wcsicmp(pDSUINode->GetName(), pDSTargetNode->GetName()) == 0)
  1397. {
  1398. return TRUE;
  1399. }
  1400. }
  1401. }
  1402. }
  1403. }
  1404. return FALSE; // all are the different
  1405. }
  1406. HRESULT CDSEvent::_QueryPaste(IN CUINode* pUINode, // paste target data object (container)
  1407. IN IDataObject* pPasteData // paste argument data object
  1408. )
  1409. {
  1410. TRACE(L"CDSEvent::_QueryPaste()\n");
  1411. HRESULT hr = S_OK;
  1412. ASSERT(pUINode != NULL);
  1413. ASSERT(pUINode->IsContainer());
  1414. TRACE(L"MMCN_QUERY_PASTE on %s\n", pUINode->GetName());
  1415. // First lets make sure we are talking within the same snapin type
  1416. // For instance we will allow paste between instances of AD U&C
  1417. // but we will not allow paste between AD S&S and AD U&C
  1418. CInternalFormatCracker ifc;
  1419. hr = ifc.Extract(pPasteData);
  1420. if (FAILED(hr) || !ifc.HasData())
  1421. {
  1422. return S_FALSE;
  1423. }
  1424. if (m_pComponentData->QuerySnapinType() != ifc.GetSnapinType())
  1425. {
  1426. // The snapins are not of the same type so fail
  1427. return S_FALSE;
  1428. }
  1429. if (!IS_CLASS(*pUINode, CDSUINode))
  1430. {
  1431. //
  1432. // For non DS nodes we will delegate the operation to the node itself
  1433. //
  1434. hr = pUINode->QueryPaste(pPasteData, m_pComponentData);
  1435. return hr;
  1436. }
  1437. // it is a DS object, extract the cookie
  1438. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1439. ASSERT(pCookie != NULL);
  1440. TRACE(L"MMCN_QUERY_PASTE on %s\n",pCookie->GetPath());
  1441. CObjectNamesFormatCracker objectNamesFormatPaste;
  1442. hr = objectNamesFormatPaste.Extract(pPasteData);
  1443. if (!objectNamesFormatPaste.HasData() || (objectNamesFormatPaste.GetCount() < 1))
  1444. {
  1445. // we have something that does not contain the
  1446. // data format for DS operations
  1447. return S_FALSE;
  1448. }
  1449. if (SNAPINTYPE_SITE == m_pComponentData->QuerySnapinType())
  1450. {
  1451. //
  1452. // DSSite
  1453. //
  1454. if (_wcsicmp(pCookie->GetClass(), L"serversContainer") != 0)
  1455. {
  1456. //
  1457. // Drops only allowed on sites
  1458. //
  1459. return S_FALSE;
  1460. }
  1461. //
  1462. // We only allow servers to be moved between sites
  1463. //
  1464. for (UINT idx = 0; idx < objectNamesFormatPaste.GetCount(); idx++)
  1465. {
  1466. if (_wcsicmp(objectNamesFormatPaste.GetClass(idx), L"server") != 0)
  1467. {
  1468. return S_FALSE;
  1469. }
  1470. }
  1471. // make sure all items have the same server in the LDAP path
  1472. if (!AllObjectsHaveTheSameServerName(
  1473. m_pComponentData->GetBasePathsInfo()->GetServerName(),
  1474. &objectNamesFormatPaste))
  1475. {
  1476. return S_FALSE;
  1477. }
  1478. return S_OK;
  1479. }
  1480. //
  1481. // DSAdmin
  1482. //
  1483. // we do not allow drops on users, contacts,
  1484. // but we do allow drops on computers
  1485. // NTRAID#NTBUG9-342116-2001/05/07-sburns
  1486. // NOTICE: we allow groups because we allow add to group semantics
  1487. if ((_wcsicmp(pCookie->GetClass(), L"user") == 0) ||
  1488. #ifdef INETORGPERSON
  1489. (_wcsicmp(pCookie->GetClass(), L"inetOrgPerson") == 0) ||
  1490. #endif
  1491. (_wcsicmp(pCookie->GetClass(), L"contact") == 0))
  1492. {
  1493. return S_FALSE;
  1494. }
  1495. // make sure all items have the same server in the LDAP path
  1496. if (!AllObjectsHaveTheSameServerName(
  1497. m_pComponentData->GetBasePathsInfo()->GetServerName(),
  1498. &objectNamesFormatPaste))
  1499. {
  1500. return S_FALSE;
  1501. }
  1502. //
  1503. // make sure we are not dropping an object on itself
  1504. //
  1505. if (HasSameObject(pUINode, pPasteData))
  1506. {
  1507. return S_FALSE;
  1508. }
  1509. if (_wcsicmp(pCookie->GetClass(), L"group") == 0)
  1510. {
  1511. //
  1512. // Check to see if we are trying to add a group type to this group
  1513. // that is illegal
  1514. //
  1515. //
  1516. // Retrieve the group type
  1517. //
  1518. INT iGroupType = -1;
  1519. CDSCookieInfoGroup* pExtraInfo = dynamic_cast<CDSCookieInfoGroup*>(pCookie->GetExtraInfo());
  1520. if (pExtraInfo != NULL)
  1521. {
  1522. iGroupType = pExtraInfo->m_GroupType;
  1523. }
  1524. else
  1525. {
  1526. //
  1527. // Couldn't retrieve the group type so don't allow anything to be added
  1528. //
  1529. return S_FALSE;
  1530. }
  1531. //
  1532. // See if we are in native mode or mixed mode
  1533. //
  1534. BOOL bMixedMode = TRUE;
  1535. CString szDomainRoot;
  1536. m_pComponentData->GetBasePathsInfo()->GetDefaultRootPath(szDomainRoot);
  1537. if (!szDomainRoot.IsEmpty())
  1538. {
  1539. //
  1540. // bind to the domain object
  1541. //
  1542. CComPtr<IADs> spDomainObj;
  1543. hr = DSAdminOpenObject(szDomainRoot,
  1544. IID_IADs,
  1545. (void **) &spDomainObj,
  1546. TRUE /*bServer*/);
  1547. if (SUCCEEDED(hr))
  1548. {
  1549. //
  1550. // retrieve the mixed node attribute
  1551. //
  1552. CComVariant Mixed;
  1553. CComBSTR bsMixed(L"nTMixedDomain");
  1554. spDomainObj->Get(bsMixed, &Mixed);
  1555. bMixedMode = (BOOL)Mixed.bVal;
  1556. }
  1557. }
  1558. //
  1559. // Loop through the objects passed by the data object
  1560. // looking for groups
  1561. //
  1562. for (UINT k=0; k < ifc.GetCookieCount(); k++)
  1563. {
  1564. CUINode* pNode = ifc.GetCookie(k);
  1565. if (pNode != NULL)
  1566. {
  1567. //
  1568. // Must be a DS node to be added to a group
  1569. //
  1570. if (!IS_CLASS(*pNode, CDSUINode))
  1571. {
  1572. return S_FALSE;
  1573. }
  1574. CDSCookie* pTempCookie = dynamic_cast<CDSCookie*>(pNode->GetNodeData());
  1575. if (pTempCookie)
  1576. {
  1577. if (!m_pComponentData->CanAddCookieToGroup(pTempCookie, iGroupType, bMixedMode))
  1578. {
  1579. return S_FALSE;
  1580. }
  1581. }
  1582. }
  1583. }
  1584. }
  1585. return S_OK; // we allow to paste
  1586. }
  1587. // given an LDAP path, it returns
  1588. // the LDAP path and the class of the container
  1589. // e.g. given "LDAP://foo.com/cn=a,cn=b,..."
  1590. // it returns "LDAP://foo.com/cn=b,..." and "b_class"
  1591. HRESULT GetContainerLdapPathAndClass(IN LPCWSTR lpszLdapPath,
  1592. OUT BSTR* pbstrSourceContainerPath,
  1593. OUT BSTR* pbstrSourceContainerClass)
  1594. {
  1595. if (*pbstrSourceContainerPath != NULL)
  1596. {
  1597. ::SysFreeString(*pbstrSourceContainerPath);
  1598. *pbstrSourceContainerPath = NULL;
  1599. }
  1600. if (*pbstrSourceContainerClass != NULL)
  1601. {
  1602. ::SysFreeString(*pbstrSourceContainerClass);
  1603. *pbstrSourceContainerClass = NULL;
  1604. }
  1605. // remove leaf element from path
  1606. CPathCracker pathCracker;
  1607. HRESULT hr = pathCracker.Set((LPWSTR)lpszLdapPath, ADS_SETTYPE_FULL);
  1608. RETURN_IF_FAILED(hr);
  1609. hr = pathCracker.RemoveLeafElement();
  1610. RETURN_IF_FAILED(hr);
  1611. CComBSTR bstrParentLdapPath;
  1612. hr = pathCracker.Retrieve(ADS_FORMAT_X500, pbstrSourceContainerPath);
  1613. RETURN_IF_FAILED(hr);
  1614. // now try to bind and determine the class of the object
  1615. CComPtr<IADs> spParentIADs;
  1616. hr = DSAdminOpenObject(*pbstrSourceContainerPath,
  1617. IID_IADs,
  1618. (void **)&spParentIADs,
  1619. TRUE /*bServer*/);
  1620. RETURN_IF_FAILED(hr);
  1621. CComBSTR bstrParentClass;
  1622. hr = spParentIADs->get_Class(pbstrSourceContainerClass);
  1623. RETURN_IF_FAILED(hr);
  1624. return S_OK;
  1625. }
  1626. // given an LDAP path, it returns
  1627. // the DN of the container
  1628. // e.g. given "LDAP://foo.com/cn=a,cn=b,..."
  1629. // it returns "cn=b,..."
  1630. HRESULT GetContainerDN(IN LPCWSTR lpszLdapPath,
  1631. OUT BSTR* pbstrSourceContainerDN)
  1632. {
  1633. if (*pbstrSourceContainerDN != NULL)
  1634. {
  1635. ::SysFreeString(*pbstrSourceContainerDN);
  1636. *pbstrSourceContainerDN = NULL;
  1637. }
  1638. CPathCracker pathCracker;
  1639. HRESULT hr = pathCracker.Set((LPWSTR)lpszLdapPath, ADS_SETTYPE_FULL);
  1640. RETURN_IF_FAILED(hr);
  1641. hr = pathCracker.RemoveLeafElement();
  1642. RETURN_IF_FAILED(hr);
  1643. return pathCracker.Retrieve(ADS_FORMAT_X500_DN, pbstrSourceContainerDN);
  1644. }
  1645. void CDSEvent::_Paste(
  1646. IN CUINode* pUINode, // paste target (container)
  1647. IN IDataObject* pPasteData, // paste argument data object
  1648. OUT LPDATAOBJECT* ppCutDataObj // data object to return for a cut operation
  1649. )
  1650. {
  1651. TRACE(L"CDSEvent::_Paste()\n");
  1652. ASSERT(pUINode != NULL);
  1653. ASSERT(pUINode->IsContainer());
  1654. TRACE(L"MMCN_PASTE on %s\n", pUINode->GetName());
  1655. if (ppCutDataObj == NULL)
  1656. {
  1657. //
  1658. // We only support copy in the Saved Queries tree
  1659. //
  1660. pUINode->Paste(pPasteData, m_pComponentData, NULL);
  1661. return;
  1662. }
  1663. TRACE(L"ppCutDataObj != NULL, cut\n");
  1664. *ppCutDataObj = NULL;
  1665. if (!IS_CLASS(*pUINode, CDSUINode))
  1666. {
  1667. //
  1668. // Delegate the paste for non DS nodes to the node itself
  1669. //
  1670. pUINode->Paste(pPasteData, m_pComponentData, ppCutDataObj);
  1671. return;
  1672. }
  1673. // it is a DS object, extract the cookie
  1674. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1675. ASSERT(pCookie != NULL);
  1676. TRACE(L"MMCN_PASTE on %s\n",pCookie->GetPath());
  1677. CObjectNamesFormatCracker objectNamesFormatPaste;
  1678. HRESULT hr = objectNamesFormatPaste.Extract(pPasteData);
  1679. if (!objectNamesFormatPaste.HasData() || (objectNamesFormatPaste.GetCount() < 1))
  1680. {
  1681. // we have something that does not contain the
  1682. // data format for DS operations
  1683. ASSERT(FALSE);
  1684. return;
  1685. }
  1686. UINT nPasteCount = objectNamesFormatPaste.GetCount();
  1687. #ifdef DBG
  1688. // see what we are pasting
  1689. for (UINT kTest=0; kTest<nPasteCount; kTest++)
  1690. {
  1691. TRACE(L"Pasting = %s\n", objectNamesFormatPaste.GetName(kTest));
  1692. }
  1693. #endif
  1694. // short circuit if the source container
  1695. // is the same as this container (drop onto itself)
  1696. CComBSTR bstrContainerDN;
  1697. hr = GetContainerDN(objectNamesFormatPaste.GetName(0), &bstrContainerDN);
  1698. if (FAILED(hr))
  1699. {
  1700. // something is really bad here...
  1701. ASSERT(FALSE);
  1702. return;
  1703. }
  1704. if (_wcsicmp(pCookie->GetPath(), bstrContainerDN) == 0)
  1705. {
  1706. TRACE(L"Dropping on the same container, short circuiting\n");
  1707. return;
  1708. }
  1709. // make sure all items have the same server in the LDAP path
  1710. if (!AllObjectsHaveTheSameServerName(
  1711. m_pComponentData->GetBasePathsInfo()->GetServerName(),
  1712. &objectNamesFormatPaste))
  1713. {
  1714. ASSERT(FALSE);
  1715. return;
  1716. }
  1717. // we do not allow drops on users,
  1718. // but we do allow drops on computers
  1719. // NTRAID#NTBUG9-342116-2001/05/07-sburns
  1720. if ((_wcsicmp(pCookie->GetClass(), L"user") == 0) ||
  1721. #ifdef INETORGPERSON
  1722. (_wcsicmp(pCookie->GetClass(), L"inetOrgPerson") == 0))
  1723. #endif
  1724. {
  1725. return;
  1726. }
  1727. // if it is a group, dropping means adding to group
  1728. if (_wcsicmp(pCookie->GetClass(), L"group") == 0)
  1729. {
  1730. _PasteAddToGroup(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, ppCutDataObj);
  1731. return;
  1732. }
  1733. //
  1734. // We also want the internal clipboard format so that we can change the path of
  1735. // object(s) that was/were the source of the move
  1736. //
  1737. CInternalFormatCracker ifc;
  1738. hr = ifc.Extract(pPasteData);
  1739. if (SUCCEEDED(hr))
  1740. {
  1741. _PasteDoMove(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, &ifc, ppCutDataObj);
  1742. }
  1743. else
  1744. {
  1745. //
  1746. // The move can succeed without the internal clipboard format but if the source
  1747. // was from a saved query then it will not be updated with the new path.
  1748. //
  1749. _PasteDoMove(dynamic_cast<CDSUINode*>(pUINode), &objectNamesFormatPaste, NULL, ppCutDataObj);
  1750. }
  1751. }
  1752. void CDSEvent::_PasteDoMove(CDSUINode* pTargetUINode,
  1753. CObjectNamesFormatCracker* pObjectNamesFormatPaste,
  1754. CInternalFormatCracker* pInternalFC,
  1755. LPDATAOBJECT* ppCutDataObj)
  1756. {
  1757. //
  1758. // Get the UI source node
  1759. //
  1760. CUINode* pSourceNode = NULL;
  1761. if (pInternalFC != NULL)
  1762. {
  1763. pSourceNode = pInternalFC->GetCookie()->GetParent();
  1764. }
  1765. //
  1766. // Get the actual source containers from the DS
  1767. // There can be more than one source node especially if the move is from a
  1768. // Saved Query so make a list of all the parents
  1769. //
  1770. CUINodeList possibleMovedObjectList;
  1771. for (UINT idx = 0; idx < pObjectNamesFormatPaste->GetCount(); idx++)
  1772. {
  1773. CUINode* pTempChildNode = NULL;
  1774. CString szDN;
  1775. StripADsIPath(pObjectNamesFormatPaste->GetName(idx), szDN);
  1776. if (m_pComponentData->FindUINodeByDN(m_pComponentData->GetRootNode(),
  1777. szDN,
  1778. &pTempChildNode))
  1779. {
  1780. if (pTempChildNode != NULL)
  1781. {
  1782. possibleMovedObjectList.AddTail(pTempChildNode);
  1783. }
  1784. }
  1785. }
  1786. // bind to the first item in the paste selection and
  1787. // try to get to the container object
  1788. CComBSTR bstrSourceContainerPath;
  1789. CComBSTR bstrSourceContainerClass;
  1790. HRESULT hr = GetContainerLdapPathAndClass(pObjectNamesFormatPaste->GetName(0),
  1791. &bstrSourceContainerPath,
  1792. &bstrSourceContainerClass);
  1793. if (FAILED(hr))
  1794. {
  1795. ASSERT(FALSE);
  1796. return;
  1797. }
  1798. // create a data object to specify the source container
  1799. // the objects are moved from
  1800. CComPtr<IDataObject> spDataObjectContainer;
  1801. hr = CDSNotifyHandlerTransaction::BuildTransactionDataObject(
  1802. bstrSourceContainerPath,
  1803. bstrSourceContainerClass,
  1804. TRUE /*bContainer*/,
  1805. m_pComponentData,
  1806. &spDataObjectContainer);
  1807. if (FAILED(hr))
  1808. {
  1809. ASSERT(FALSE);
  1810. return;
  1811. }
  1812. CMultiselectMoveHandler moveHandler(m_pComponentData, m_hwnd, NULL);
  1813. hr = moveHandler.Initialize(spDataObjectContainer,
  1814. pObjectNamesFormatPaste,
  1815. pInternalFC);
  1816. ASSERT(SUCCEEDED(hr));
  1817. CString szTargetContainer;
  1818. m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szTargetContainer, pTargetUINode->GetCookie()->GetPath());
  1819. moveHandler.Move(szTargetContainer);
  1820. *ppCutDataObj = NULL;
  1821. CUINodeList nodesMoved;
  1822. // -----------------------------------------------------------------
  1823. // code to update the views if the extension says it moved items
  1824. //
  1825. TRACE(_T("Command: returned from extension commdand\n"));
  1826. if (pSourceNode != NULL &&
  1827. IS_CLASS(*pSourceNode, CDSUINode))
  1828. {
  1829. for (UINT index = 0; index < pInternalFC->GetCookieCount(); index ++)
  1830. {
  1831. CUINode* pUINode = pInternalFC->GetCookie(index);
  1832. // make sure the node moved is of the right type: for the time
  1833. // being we just deal with DS objects
  1834. if (!IS_CLASS(*pUINode, CDSUINode))
  1835. {
  1836. ASSERT(FALSE); // should not get here
  1837. continue;
  1838. }
  1839. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  1840. if (pUINode->GetExtOp() & OPCODE_MOVE)
  1841. {
  1842. if (pTargetUINode == NULL)
  1843. {
  1844. // get the parent from the first node
  1845. // assume that all have the same parent
  1846. CUINode* pPossibleTargetNode = NULL;
  1847. m_pComponentData->FindParentCookie(pCookie->GetPath(), &pPossibleTargetNode);
  1848. if (pPossibleTargetNode != NULL)
  1849. {
  1850. pTargetUINode = dynamic_cast<CDSUINode*>(pPossibleTargetNode);
  1851. }
  1852. }
  1853. if (pUINode->IsContainer())
  1854. {
  1855. HSCOPEITEM ItemID = 0, ParentItemID = 0;
  1856. ItemID = pUINode->GetFolderInfo()->GetScopeItem();
  1857. if (pSourceNode == NULL)
  1858. {
  1859. // do it once for the first node, all the same
  1860. hr = m_pComponentData->m_pScope->GetParentItem (ItemID,
  1861. &ParentItemID,
  1862. (MMC_COOKIE *)&pSourceNode);
  1863. }
  1864. // delete the scope item in MMC
  1865. hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE);
  1866. ASSERT(SUCCEEDED(hr));
  1867. #ifdef DBG
  1868. if (FAILED(hr))
  1869. {
  1870. TRACE(_T("DeleteItem failed on %lx (%s).\n"),
  1871. ItemID, pUINode->GetName());
  1872. }
  1873. TRACE(_T("Move postprocessing - deleted scope node: %x (%s)\n"),
  1874. ItemID, pUINode->GetName());
  1875. #endif
  1876. if (pSourceNode)
  1877. {
  1878. pSourceNode->GetFolderInfo()->RemoveNode(pUINode);
  1879. }
  1880. //
  1881. // Remove all children and mark it as unexpanded so that it will be expanded
  1882. // when selected
  1883. //
  1884. pUINode->GetFolderInfo()->DeleteAllContainerNodes();
  1885. pUINode->GetFolderInfo()->DeleteAllLeafNodes();
  1886. pUINode->GetFolderInfo()->ReSetExpanded();
  1887. if ((pTargetUINode) && pTargetUINode->GetFolderInfo()->IsExpanded())
  1888. {
  1889. pUINode->ClearParent();
  1890. pTargetUINode->GetFolderInfo()->AddNode(pUINode);
  1891. hr = m_pComponentData->_AddScopeItem(pUINode, pTargetUINode->GetFolderInfo()->GetScopeItem());
  1892. #ifdef DBG
  1893. if (FAILED(hr))
  1894. {
  1895. TRACE(_T("AddItem failed on %lx (%s).\n"),
  1896. ItemID, pUINode->GetName());
  1897. }
  1898. TRACE(_T("Move postprocessing - added scope node: %s\n"),
  1899. pUINode->GetName());
  1900. #endif
  1901. }
  1902. else
  1903. {
  1904. //
  1905. // This object was created during the enumeration of the source container.
  1906. // Since the target container hasn't been expanded yet we can just throw
  1907. // this node away and it will be recreated if the target node ever gets
  1908. // expanded
  1909. //
  1910. delete pUINode;
  1911. pUINode = NULL;
  1912. }
  1913. }
  1914. else
  1915. {
  1916. // not a container
  1917. if ((pTargetUINode) &&
  1918. (pTargetUINode->GetFolderInfo()->IsExpanded()))
  1919. {
  1920. pUINode->ClearParent();
  1921. pTargetUINode->GetFolderInfo()->AddNode(pUINode);
  1922. }
  1923. //
  1924. // If the folder is not select (like on cut/paste)
  1925. // the FindItemByLParam() in UpdateAllViews will fail
  1926. // and the node will not be removed from the UI.
  1927. // So just remove it from the node list of the source
  1928. // container.
  1929. //
  1930. if (pSourceNode && m_pSelectedFolderNode != pSourceNode)
  1931. {
  1932. pSourceNode->GetFolderInfo()->RemoveNode(pUINode);
  1933. }
  1934. nodesMoved.AddTail(pUINode);
  1935. }
  1936. if (pUINode)
  1937. {
  1938. pUINode->SetExtOp(NULL);
  1939. }
  1940. }
  1941. }
  1942. }
  1943. else if (pSourceNode != NULL &&
  1944. IS_CLASS(*pSourceNode, CSavedQueryNode))
  1945. {
  1946. //
  1947. // Refresh the target node so that we get new cookies
  1948. // for all the moved objects. It would just be too
  1949. // difficult to do a deep copy of the cookies in the
  1950. // saved query tree
  1951. //
  1952. if (pTargetUINode &&
  1953. pTargetUINode->GetFolderInfo()->IsExpanded())
  1954. {
  1955. m_pComponentData->Refresh(pTargetUINode);
  1956. }
  1957. //
  1958. // Mark the moved leaf objects with the opcode. Simply remove containers from
  1959. // the UI and the list. The move handler only marks the
  1960. // selected items, not those found using FindUINodeByDN.
  1961. //
  1962. POSITION posPossible = possibleMovedObjectList.GetHeadPosition();
  1963. while (posPossible)
  1964. {
  1965. CUINode* pPossibleMoved = possibleMovedObjectList.GetNext(posPossible);
  1966. if (pPossibleMoved)
  1967. {
  1968. if (pPossibleMoved->IsContainer())
  1969. {
  1970. HSCOPEITEM ItemID = 0;
  1971. ItemID = pPossibleMoved->GetFolderInfo()->GetScopeItem();
  1972. // delete the scope item in MMC
  1973. hr = m_pComponentData->m_pScope->DeleteItem(ItemID, TRUE);
  1974. if (SUCCEEDED(hr))
  1975. {
  1976. hr = pPossibleMoved->GetParent()->GetFolderInfo()->RemoveNode(pPossibleMoved);
  1977. }
  1978. }
  1979. else
  1980. {
  1981. pPossibleMoved->SetExtOp(OPCODE_MOVE);
  1982. }
  1983. }
  1984. }
  1985. //
  1986. // Now reset the opcode for all the nodes in the saved query tree so
  1987. // that they will still show up the next time the saved query node is selected
  1988. //
  1989. for (UINT index = 0; index < pInternalFC->GetCookieCount(); index ++)
  1990. {
  1991. CUINode* pUINode = pInternalFC->GetCookie(index);
  1992. if (pUINode)
  1993. {
  1994. pUINode->SetExtOp(NULL);
  1995. }
  1996. } // for
  1997. } // IS_CLASS
  1998. if (!nodesMoved.IsEmpty())
  1999. {
  2000. m_pFrame->UpdateAllViews(NULL, (LPARAM)&nodesMoved, DS_MULTIPLE_MOVE_OCCURRED);
  2001. }
  2002. //------------------------------ends here--------------------------------------
  2003. m_pComponentData->SortResultPane(pTargetUINode);
  2004. }
  2005. void CDSEvent::_PasteAddToGroup(CDSUINode* pUINode,
  2006. CObjectNamesFormatCracker* pObjectNamesFormatPaste,
  2007. LPDATAOBJECT*)
  2008. {
  2009. if (_wcsicmp(pUINode->GetCookie()->GetClass(), L"group") != 0)
  2010. {
  2011. ASSERT(FALSE);
  2012. return;
  2013. }
  2014. // get the LDAP path of the group we want to add to
  2015. CString szGroupLdapPath;
  2016. m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szGroupLdapPath,
  2017. pUINode->GetCookie()->GetPath());
  2018. AddDataObjListToGivenGroup(pObjectNamesFormatPaste,
  2019. szGroupLdapPath,
  2020. pUINode->GetCookie()->GetName(),
  2021. m_pComponentData->GetHWnd(),
  2022. m_pComponentData);
  2023. }
  2024. BOOL FindDSUINodeInListByDN(IN LPCWSTR lpszDN,
  2025. IN CUINodeList* pNodeList,
  2026. OUT CDSUINode** ppNode)
  2027. {
  2028. *ppNode = NULL;
  2029. for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; )
  2030. {
  2031. CUINode* pCurrentNode = pNodeList->GetNext(pos);
  2032. CDSUINode* pCurrDSUINode = dynamic_cast<CDSUINode*>(pCurrentNode);
  2033. if (pCurrDSUINode == NULL)
  2034. {
  2035. // not a node with a cookie, just skip
  2036. continue;
  2037. }
  2038. // get the cookie from the node
  2039. if (_wcsicmp(lpszDN, pCurrDSUINode->GetCookie()->GetPath()) == 0)
  2040. {
  2041. *ppNode = pCurrDSUINode;
  2042. return TRUE;
  2043. }
  2044. }// for
  2045. return FALSE;
  2046. }
  2047. void FindListOfChildNodes(IN CDSUINode* pDSUIContainerNode,
  2048. IN CObjectNamesFormatCracker* pObjectNamesFormat,
  2049. INOUT CUINodeList* pNodesDeletedList)
  2050. {
  2051. ASSERT(pDSUIContainerNode != NULL);
  2052. ASSERT(pDSUIContainerNode->IsContainer());
  2053. // it is a DS object, extract the cookie
  2054. CDSCookie* pContainerCookie = pDSUIContainerNode->GetCookie();
  2055. ASSERT(pContainerCookie != NULL);
  2056. TRACE(L"FindListOfChildNodes(%s,...)\n",pContainerCookie->GetPath());
  2057. //for each item in the list of paths, find it into the list
  2058. // of children
  2059. CPathCracker pathCracker;
  2060. UINT nCount = pObjectNamesFormat->GetCount();
  2061. for (UINT k=0; k<nCount; k++)
  2062. {
  2063. // from the LDAP path, get the DN
  2064. HRESULT hr = pathCracker.Set((LPWSTR)pObjectNamesFormat->GetName(k), ADS_SETTYPE_FULL);
  2065. ASSERT(SUCCEEDED(hr));
  2066. CComBSTR bstrDN;
  2067. hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrDN);
  2068. ASSERT(SUCCEEDED(hr));
  2069. // find it into the lists of children
  2070. CDSUINode* pFoundNode = NULL;
  2071. if (FindDSUINodeInListByDN(bstrDN,
  2072. pDSUIContainerNode->GetFolderInfo()->GetContainerList(),
  2073. &pFoundNode))
  2074. {
  2075. ASSERT(pFoundNode != NULL);
  2076. pNodesDeletedList->AddTail(pFoundNode);
  2077. continue;
  2078. }
  2079. if (FindDSUINodeInListByDN(bstrDN,
  2080. pDSUIContainerNode->GetFolderInfo()->GetLeafList(),
  2081. &pFoundNode))
  2082. {
  2083. ASSERT(pFoundNode != NULL);
  2084. pNodesDeletedList->AddTail(pFoundNode);
  2085. continue;
  2086. }
  2087. } // for
  2088. }
  2089. void CDSEvent::_CutOrMove(IN IDataObject* pCutOrMoveData)
  2090. {
  2091. TRACE(L"CDSEvent::_CutOrMove()\n");
  2092. if (pCutOrMoveData == NULL)
  2093. {
  2094. //
  2095. // With a single pass move operation we return a NULL data object
  2096. // but the move was still successful
  2097. //
  2098. return;
  2099. }
  2100. CInternalFormatCracker ifc;
  2101. HRESULT hr = ifc.Extract(pCutOrMoveData);
  2102. if (SUCCEEDED(hr))
  2103. {
  2104. //
  2105. // Non DS nodes
  2106. //
  2107. //
  2108. // Build a list of the nodes to be deleted
  2109. //
  2110. CUINodeList nodesDeletedList;
  2111. for (UINT nCount = 0; nCount < ifc.GetCookieCount(); nCount++)
  2112. {
  2113. CUINode* pUINode = ifc.GetCookie(nCount);
  2114. if (pUINode != NULL)
  2115. {
  2116. nodesDeletedList.AddTail(pUINode);
  2117. }
  2118. }
  2119. //
  2120. // finally, delete the nodes from the UI
  2121. //
  2122. _DeleteNodeListFromUI(&nodesDeletedList);
  2123. }
  2124. else
  2125. {
  2126. //
  2127. // DS Objects
  2128. //
  2129. CObjectNamesFormatCracker objectNamesFormatCutOrMove;
  2130. hr = objectNamesFormatCutOrMove.Extract(pCutOrMoveData);
  2131. if (SUCCEEDED(hr))
  2132. {
  2133. if (!objectNamesFormatCutOrMove.HasData() || (objectNamesFormatCutOrMove.GetCount() < 1))
  2134. {
  2135. // we have something that does not contain the
  2136. // data format for DS operations
  2137. ASSERT(FALSE);
  2138. return;
  2139. }
  2140. // make sure all items have the same server in the LDAP path
  2141. if (!AllObjectsHaveTheSameServerName(
  2142. m_pComponentData->GetBasePathsInfo()->GetServerName(),
  2143. &objectNamesFormatCutOrMove))
  2144. {
  2145. ASSERT(FALSE);
  2146. return;
  2147. }
  2148. // find the source container the objects are moved from
  2149. // (we assume they all come from the same container)
  2150. TRACE(L"GetName(0) = %s\n", objectNamesFormatCutOrMove.GetName(0));
  2151. CComBSTR bstrContainerDN;
  2152. hr = GetContainerDN(objectNamesFormatCutOrMove.GetName(0), &bstrContainerDN);
  2153. if (FAILED(hr))
  2154. {
  2155. ASSERT(FALSE);
  2156. return;
  2157. }
  2158. TRACE(L"GetContainerDN() bstrContainerDN = %s\n", bstrContainerDN);
  2159. // find the container object in the folders
  2160. // NOTICE: for the time being we ignore the query folders
  2161. CUINode* pUINode = NULL;
  2162. if (!FindCookieInSubtree(m_pComponentData->GetRootNode(),
  2163. bstrContainerDN,
  2164. m_pComponentData->QuerySnapinType(),
  2165. &pUINode))
  2166. {
  2167. // should never happen...
  2168. return;
  2169. }
  2170. // found the container node
  2171. ASSERT(pUINode != NULL);
  2172. ASSERT(pUINode->IsContainer());
  2173. if (!IS_CLASS(*pUINode, CDSUINode))
  2174. {
  2175. // we do not allow paste on non DS nodes,
  2176. // so we should never get here...
  2177. ASSERT(FALSE);
  2178. return;
  2179. }
  2180. ASSERT(pUINode->GetFolderInfo()->IsExpanded());
  2181. // need to remove the items that are in the data object
  2182. // from the pUINode container: find the list of nodes
  2183. // to be deleted in the
  2184. CUINodeList nodesDeletedList;
  2185. FindListOfChildNodes(dynamic_cast<CDSUINode*>(pUINode),
  2186. &objectNamesFormatCutOrMove,
  2187. &nodesDeletedList);
  2188. // finally, delete the nodes from the UI
  2189. _DeleteNodeListFromUI(&nodesDeletedList);
  2190. }
  2191. }
  2192. }
  2193. void CDSEvent::HandleViewChange(LPDATAOBJECT pDataObject,
  2194. LPARAM arg,
  2195. LPARAM Action)
  2196. {
  2197. HRESULT hr = S_OK;
  2198. TRACE(_T("handle view change. action is %lx.\n"), Action);
  2199. switch (Action)
  2200. {
  2201. case DS_DELETE_OCCURRED:
  2202. {
  2203. HRESULTITEM ItemID;
  2204. hr = m_pResultData->FindItemByLParam(arg, &ItemID);
  2205. if (!SUCCEEDED(hr))
  2206. {
  2207. break;
  2208. }
  2209. hr = m_pResultData->DeleteItem(ItemID, 0);
  2210. #ifdef DBG
  2211. if (FAILED(hr)) {
  2212. TRACE (_T("Delete Item Failed on IResultData. Item %lx, hr = %lx\n"),
  2213. ItemID, hr);
  2214. }
  2215. #endif
  2216. // this will fail for all but the first update, we don't care
  2217. hr = m_pSelectedFolderNode->GetFolderInfo()->DeleteNode(reinterpret_cast<CUINode*>(arg));
  2218. _UpdateObjectCount(FALSE);
  2219. break;
  2220. }
  2221. case DS_MULTIPLE_DELETE_OCCURRED:
  2222. {
  2223. TIMER(_T("updating result pane for mult. delete ..."));
  2224. CUINodeList* pNodesDeletedList = reinterpret_cast<CUINodeList*>(arg); // gross
  2225. for (POSITION pos = pNodesDeletedList->GetHeadPosition(); pos != NULL; )
  2226. {
  2227. CUINode* pCurrNode = pNodesDeletedList->GetNext(pos);
  2228. ASSERT(pCurrNode != NULL);
  2229. HRESULTITEM ItemID;
  2230. hr = m_pResultData->FindItemByLParam((LPARAM)pCurrNode,
  2231. &ItemID);
  2232. if (FAILED(hr))
  2233. {
  2234. //
  2235. // We cannot find the item by lParam if the node is not selected so
  2236. // just delete the node from the container
  2237. //
  2238. CUIFolderInfo* pFolderInfo = pCurrNode->GetParent()->GetFolderInfo();
  2239. if (pFolderInfo != NULL)
  2240. {
  2241. hr = pFolderInfo->DeleteNode(pCurrNode);
  2242. }
  2243. continue;
  2244. }
  2245. hr = m_pResultData->DeleteItem(ItemID, 0);
  2246. CUIFolderInfo* pSelectedFolderInfo = m_pSelectedFolderNode->GetFolderInfo();
  2247. if (pSelectedFolderInfo != NULL)
  2248. {
  2249. // this will fail for all but the first update, we don't care
  2250. hr = m_pSelectedFolderNode->GetFolderInfo()->DeleteNode(pCurrNode);
  2251. }
  2252. }
  2253. _UpdateObjectCount(FALSE);
  2254. TIMER(_T("updating result pane for mult. delete, done"));
  2255. }
  2256. break;
  2257. case DS_RENAME_OCCURRED:
  2258. case DS_UPDATE_OCCURRED:
  2259. {
  2260. HRESULTITEM ItemID;
  2261. hr = m_pResultData->FindItemByLParam (arg, &ItemID);
  2262. if (SUCCEEDED(hr)) {
  2263. m_pResultData->UpdateItem (ItemID);
  2264. }
  2265. break;
  2266. }
  2267. case DS_MOVE_OCCURRED:
  2268. {
  2269. CDSUINode* pDSUINode = reinterpret_cast<CDSUINode*>(arg);
  2270. CDSUINode* pDSSelectedFolderNode = dynamic_cast<CDSUINode*>(m_pSelectedFolderNode);
  2271. // REVIEW_MARCOC_PORT: this is working for DS objects only
  2272. // need to generalize for all folder types
  2273. ASSERT(pDSUINode != NULL);
  2274. ASSERT(pDSSelectedFolderNode != NULL);
  2275. if ((pDSUINode == NULL) || (pDSSelectedFolderNode == NULL))
  2276. break;
  2277. // remove the result pane item
  2278. HRESULTITEM ItemID;
  2279. hr = m_pResultData->FindItemByLParam (arg, &ItemID);
  2280. if (SUCCEEDED(hr))
  2281. {
  2282. hr = m_pSelectedFolderNode->GetFolderInfo()->RemoveNode(pDSUINode);
  2283. hr = m_pResultData->DeleteItem(ItemID, 0);
  2284. }
  2285. CString szParent;
  2286. hr = m_pComponentData->GetActiveDS()->GetParentDN(pDSUINode->GetCookie(), szParent);
  2287. if (SUCCEEDED(hr))
  2288. {
  2289. if (szParent.CompareNoCase(pDSSelectedFolderNode->GetCookie()->GetPath()) == 0)
  2290. {
  2291. _AddResultItem(pDSUINode);
  2292. m_pComponentData->SortResultPane(pDSUINode->GetParent());
  2293. _UpdateObjectCount(FALSE);
  2294. }
  2295. }
  2296. break;
  2297. }
  2298. case DS_MULTIPLE_MOVE_OCCURRED:
  2299. {
  2300. CUINodeList* pNodesMovedList = reinterpret_cast<CUINodeList*>(arg); // gross
  2301. //
  2302. // If the selected folder is not a DS node then its probably a saved query
  2303. // in which case we just want to break because we don't want to delete the results
  2304. // of the saved query just change its path
  2305. //
  2306. CDSUINode* pDSSelectedFolderNode = dynamic_cast<CDSUINode*>(m_pSelectedFolderNode);
  2307. if (pDSSelectedFolderNode == NULL)
  2308. break;
  2309. CString ObjPath;
  2310. CString szParent = L"";
  2311. BOOL fInThisContainer = FALSE;
  2312. for (POSITION pos = pNodesMovedList->GetHeadPosition(); pos != NULL; )
  2313. {
  2314. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(pNodesMovedList->GetNext(pos));
  2315. // REVIEW_MARCOC_PORT: this is working for DS objects only
  2316. // need to generalize for all folder types
  2317. if (pDSUINode == NULL)
  2318. {
  2319. ASSERT(FALSE);
  2320. break; // can't do it, should be doing it in the future
  2321. }
  2322. if (!pDSUINode->IsContainer())
  2323. {
  2324. // it s a leaf node, delete from result pane
  2325. HRESULTITEM ItemID;
  2326. hr = m_pResultData->FindItemByLParam ((LPARAM)pDSUINode, &ItemID);
  2327. if (SUCCEEDED(hr))
  2328. {
  2329. hr = m_pSelectedFolderNode->GetFolderInfo()->RemoveNode(pDSUINode);
  2330. hr = m_pResultData->DeleteItem(ItemID, 0);
  2331. }
  2332. if (szParent.IsEmpty())
  2333. {
  2334. hr = m_pComponentData->GetActiveDS()->GetParentDN(pDSUINode->GetCookie(), szParent);
  2335. if (SUCCEEDED(hr))
  2336. {
  2337. if (szParent.CompareNoCase(pDSSelectedFolderNode->GetCookie()->GetPath()) == 0)
  2338. {
  2339. fInThisContainer = TRUE;
  2340. }
  2341. }
  2342. }
  2343. if (fInThisContainer)
  2344. {
  2345. _AddResultItem(pDSUINode);
  2346. }
  2347. }
  2348. }
  2349. _UpdateObjectCount(FALSE);
  2350. break;
  2351. }
  2352. case DS_CREATE_OCCURRED_RESULT_PANE:
  2353. case DS_CREATE_OCCURRED:
  2354. {
  2355. CUINode* pParent = NULL;
  2356. CUINode* pTmpNode = NULL;
  2357. if (pDataObject)
  2358. {
  2359. CInternalFormatCracker dobjCracker;
  2360. VERIFY(SUCCEEDED(dobjCracker.Extract(pDataObject)));
  2361. pTmpNode = dobjCracker.GetCookie();
  2362. if (Action == DS_CREATE_OCCURRED_RESULT_PANE)
  2363. {
  2364. pParent = pTmpNode->GetParent();
  2365. }
  2366. else
  2367. {
  2368. pParent = pTmpNode;
  2369. }
  2370. }
  2371. else
  2372. {
  2373. pParent = m_pSelectedFolderNode;
  2374. }
  2375. if (pParent == m_pSelectedFolderNode)
  2376. {
  2377. // reset icon list, just in case it was a new type of object
  2378. m_pComponentData->FillInIconStrip (m_pRsltImageList);
  2379. //
  2380. // Add and select the new item
  2381. //
  2382. _AddResultItem(reinterpret_cast<CUINode*>(arg), FALSE);
  2383. m_pComponentData->SortResultPane(pParent);
  2384. // Must select the result node after the sort to ensure visibility
  2385. SelectResultNode(reinterpret_cast<CUINode*>(arg));
  2386. _UpdateObjectCount(FALSE);
  2387. }
  2388. else
  2389. {
  2390. pParent->GetFolderInfo()->SetSortOnNextSelect(TRUE);
  2391. }
  2392. break;
  2393. }
  2394. case DS_HAVE_DATA:
  2395. {
  2396. CInternalFormatCracker dobjCracker;
  2397. VERIFY(SUCCEEDED(dobjCracker.Extract(pDataObject)));
  2398. CUINode* pContainerNode = dobjCracker.GetCookie();
  2399. if (pContainerNode == m_pSelectedFolderNode)
  2400. {
  2401. TIMER(_T("adding leaf items to view\n"));
  2402. CUINodeList* pNodeList = reinterpret_cast<CUINodeList*>(arg);
  2403. for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; )
  2404. {
  2405. CUINode* pNewUINode = pNodeList->GetNext(pos);
  2406. if (!pNewUINode->IsContainer())
  2407. {
  2408. // add to the scope pane
  2409. _AddResultItem(pNewUINode);
  2410. }
  2411. _UpdateObjectCount(FALSE);
  2412. }
  2413. }
  2414. break;
  2415. }
  2416. case DS_REFRESH_REQUESTED:
  2417. {
  2418. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2419. if (pUINode == m_pSelectedFolderNode) {
  2420. m_pResultData->DeleteAllRsltItems();
  2421. _UpdateObjectCount (TRUE);
  2422. }
  2423. break;
  2424. }
  2425. case DS_VERB_UPDATE:
  2426. {
  2427. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2428. if (pUINode == m_pSelectedFolderNode)
  2429. {
  2430. CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(m_pComponentData);
  2431. if (pMenuVerbs == NULL)
  2432. {
  2433. ASSERT(FALSE);
  2434. return;
  2435. }
  2436. pMenuVerbs->LoadStandardVerbs(m_pConsoleVerb,
  2437. TRUE/*bScope*/,
  2438. TRUE /*bSelect*/,
  2439. pUINode,
  2440. pDataObject);
  2441. }
  2442. break;
  2443. }
  2444. case DS_DELAYED_EXPAND:
  2445. {
  2446. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2447. ASSERT(pUINode->IsContainer());
  2448. // if (pCookie == m_pSelectedFolderNode) {
  2449. m_pFrame->Expand (pUINode->GetFolderInfo()->GetScopeItem(),
  2450. TRUE);
  2451. //}
  2452. }
  2453. break;
  2454. case DS_ICON_STRIP_UPDATE:
  2455. {
  2456. // reset icon list, just in case it was a new type of object
  2457. m_pComponentData->FillInIconStrip (m_pRsltImageList);
  2458. }
  2459. break;
  2460. case DS_IS_COOKIE_SELECTION:
  2461. {
  2462. PUINODESELECTION pUINodeSel = reinterpret_cast<PUINODESELECTION>(arg); //gross
  2463. if (pUINodeSel->IsSelection)
  2464. {
  2465. // got the snawer from some other view, just skip
  2466. break;
  2467. }
  2468. if (pUINodeSel->pUINode == m_pSelectedFolderNode)
  2469. {
  2470. // selected folder in this view
  2471. pUINodeSel->IsSelection = TRUE;
  2472. }
  2473. else
  2474. {
  2475. // not selected in this view, but look for the parents
  2476. // of the current selection
  2477. CUINode* pParentNode = m_pSelectedFolderNode->GetParent();
  2478. while (pParentNode)
  2479. {
  2480. if (pUINodeSel->pUINode == pParentNode)
  2481. {
  2482. pUINodeSel->IsSelection = TRUE;
  2483. break;
  2484. }
  2485. else
  2486. {
  2487. pParentNode = pParentNode->GetParent();
  2488. }
  2489. } // while
  2490. }
  2491. } // case
  2492. break;
  2493. case DS_SORT_RESULT_PANE:
  2494. {
  2495. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2496. MMC_SORT_SET_DATA* pColumnData = NULL;
  2497. TIMER(_T("sorting result pane, starting"));
  2498. CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData);
  2499. if (pColumnSet == NULL)
  2500. break;
  2501. LPCWSTR lpszID = pColumnSet->GetColumnID();
  2502. size_t iLen = wcslen(lpszID);
  2503. // allocate enough memory for the struct and the column ID
  2504. SColumnSetID* pNodeID = (SColumnSetID*)malloc(sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  2505. if (pNodeID != NULL)
  2506. {
  2507. memset(pNodeID, 0, sizeof(SColumnSetID) + (iLen * sizeof(WCHAR)));
  2508. pNodeID->cBytes = static_cast<ULONG>(iLen * sizeof(WCHAR));
  2509. memcpy(pNodeID->id, lpszID, (iLen * sizeof(WCHAR)));
  2510. CComPtr<IColumnData> spColumnData;
  2511. hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData);
  2512. if (spColumnData != NULL)
  2513. {
  2514. hr = spColumnData->GetColumnSortData(pNodeID, &pColumnData);
  2515. }
  2516. if (hr == S_OK && pColumnData != NULL)
  2517. {
  2518. m_pResultData->Sort(pColumnData->pSortData->nColIndex, pColumnData->pSortData->dwSortOptions, NULL);
  2519. CoTaskMemFree(pColumnData);
  2520. }
  2521. else
  2522. {
  2523. //
  2524. // Sort by the name column ascending if the user hasn't persisted something else
  2525. //
  2526. m_pResultData->Sort(0, RSI_NOSORTICON, NULL);
  2527. }
  2528. free(pNodeID);
  2529. }
  2530. else
  2531. {
  2532. //
  2533. // Sort by the name column ascending if the user hasn't persisted something else
  2534. //
  2535. m_pResultData->Sort(0, RSI_NOSORTICON, NULL);
  2536. }
  2537. break;
  2538. TIMER(_T("sorting result pane, done"));
  2539. if (pUINode != m_pSelectedFolderNode &&
  2540. pUINode->IsContainer())
  2541. {
  2542. pUINode->GetFolderInfo()->SetSortOnNextSelect(TRUE);
  2543. }
  2544. }
  2545. break;
  2546. case DS_UPDATE_VISIBLE_COLUMNS:
  2547. {
  2548. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2549. if (m_bUpdateAllViewsOrigin)
  2550. {
  2551. // this message originated from this instance,
  2552. // it is handled separately
  2553. break;
  2554. }
  2555. CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData);
  2556. if (pColumnSet == NULL)
  2557. break;
  2558. CComPtr<IColumnData> spColumnData;
  2559. hr = m_pFrame->QueryInterface(IID_IColumnData, (void**)&spColumnData);
  2560. if (spColumnData != NULL)
  2561. hr = pColumnSet->LoadFromColumnData(spColumnData);
  2562. if (FAILED(hr))
  2563. {
  2564. pColumnSet->SetAllColumnsToDefaultVisibility();
  2565. }
  2566. break;
  2567. }
  2568. case DS_UPDATE_OBJECT_COUNT:
  2569. _UpdateObjectCount(FALSE);
  2570. break;
  2571. case DS_UNSELECT_OBJECT:
  2572. {
  2573. CUINode* pUINode = reinterpret_cast<CUINode*>(arg);
  2574. if (pUINode != NULL)
  2575. {
  2576. HRESULTITEM ItemID;
  2577. hr = m_pResultData->FindItemByLParam ((LPARAM)pUINode, &ItemID);
  2578. if (SUCCEEDED(hr))
  2579. {
  2580. VERIFY(SUCCEEDED(m_pResultData->ModifyItemState(0 /*unused*/,
  2581. ItemID,
  2582. 0 /*not adding*/,
  2583. LVIS_FOCUSED | LVIS_SELECTED)));
  2584. }
  2585. }
  2586. }
  2587. break;
  2588. } // switch
  2589. }
  2590. void
  2591. CDSEvent::_UpdateObjectCount(BOOL fZero)
  2592. {
  2593. if (!m_pSelectedFolderNode->IsContainer())
  2594. {
  2595. ASSERT(m_pSelectedFolderNode->IsContainer());
  2596. return;
  2597. }
  2598. UINT cItems = 0;
  2599. if (!fZero)
  2600. {
  2601. CUINodeList* pclFolders = m_pSelectedFolderNode->GetFolderInfo()->GetContainerList();
  2602. CUINodeList* pclLeaves = m_pSelectedFolderNode->GetFolderInfo()->GetLeafList();
  2603. if (pclFolders && pclLeaves)
  2604. {
  2605. cItems = (UINT)(pclFolders->GetCount() + pclLeaves->GetCount());
  2606. }
  2607. }
  2608. else //set the count to 0
  2609. {
  2610. m_pSelectedFolderNode->GetFolderInfo()->SetTooMuchData(FALSE, 0);
  2611. }
  2612. CString csTemp;
  2613. if (IS_CLASS(*m_pSelectedFolderNode, CSavedQueryNode))
  2614. {
  2615. CSavedQueryNode* pSavedQueryNode = dynamic_cast<CSavedQueryNode*>(m_pSelectedFolderNode);
  2616. if (pSavedQueryNode && !pSavedQueryNode->IsValid())
  2617. {
  2618. VERIFY(csTemp.LoadString(IDS_DESCBAR_INVALID_SAVEDQUERY));
  2619. }
  2620. }
  2621. if (csTemp.IsEmpty())
  2622. {
  2623. if (m_pSelectedFolderNode->GetFolderInfo()->HasTooMuchData())
  2624. {
  2625. UINT nApprox = m_pSelectedFolderNode->GetFolderInfo()->GetApproxTotalContained();
  2626. nApprox = __max(nApprox, cItems);
  2627. csTemp.Format(IDS_DESCBAR_TOO_MUCH_DATA,
  2628. nApprox);
  2629. }
  2630. else
  2631. {
  2632. VERIFY(csTemp.LoadString(IDS_OBJECTS));
  2633. }
  2634. }
  2635. CString csDescription;
  2636. csDescription.Format (L"%d%s", cItems, csTemp);
  2637. if (m_pComponentData->m_pQueryFilter &&
  2638. m_pComponentData->m_pQueryFilter->IsFilteringActive())
  2639. {
  2640. CString csFilter;
  2641. csFilter.LoadString (IDS_FILTERING_ON);
  2642. csDescription += csFilter;
  2643. }
  2644. if (m_pResultData)
  2645. {
  2646. m_pResultData->SetDescBarText ((LPWSTR)(LPCWSTR)csDescription);
  2647. }
  2648. }
  2649. HRESULT CDSEvent::_SetColumns(CUINode* pUINode)
  2650. {
  2651. ASSERT(pUINode->IsContainer());
  2652. TRACE(_T("CDSEvent::_SetColumns on container %s\n"),
  2653. (LPWSTR)(LPCWSTR)pUINode->GetName());
  2654. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2655. HRESULT hr = S_OK;
  2656. CDSColumnSet* pColumnSet = pUINode->GetColumnSet(m_pComponentData);
  2657. if (pColumnSet == NULL)
  2658. return hr;
  2659. for (POSITION pos = pColumnSet->GetHeadPosition(); pos != NULL; )
  2660. {
  2661. CDSColumn* pColumn = (CDSColumn*)pColumnSet->GetNext(pos);
  2662. int nWidth = (pColumn->IsVisible()) ? AUTO_WIDTH : HIDE_COLUMN;
  2663. hr = m_pHeader->InsertColumn(pColumn->GetColumnNum(),
  2664. pColumn->GetHeader(),
  2665. pColumn->GetFormat(),
  2666. nWidth);
  2667. ASSERT(SUCCEEDED(hr));
  2668. hr = m_pHeader->SetColumnWidth(pColumn->GetColumnNum(),
  2669. pColumn->GetWidth());
  2670. ASSERT(SUCCEEDED(hr));
  2671. }
  2672. return S_OK;
  2673. }