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.

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