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.

688 lines
20 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: nodepath.h
  7. *
  8. * Contents: Dynamic node path generation helpers
  9. *
  10. * History: 31-Mar-98 JeffRo Created
  11. *
  12. *
  13. * The persisted format of a node path (aka bookmark) is as follows:
  14. *
  15. * DWORD idStatic; // the MTNODEID of the static root of the node
  16. * DWORD cDynamicBytes; // count of bytes in the dynamic portion of the
  17. * // bookmark
  18. * BYTE rgDynamicBytes[]; // array of bytes representing the dynamic
  19. * // portion of the bookmark
  20. *
  21. *
  22. * For MMC v1.0 consoles, rgDynamicBytes is a double-NULL terminated list
  23. * of Unicode strings representing the names of the dynamic nodes. For a
  24. * tree that looks like this:
  25. *
  26. * Static Node (id == 3)
  27. * Dynamic Node1
  28. * Dynamic Node2
  29. *
  30. * the full bookmark for Dynamic Node 2 would be:
  31. *
  32. * 00000000 03 00 00 00 00 00 00 00 44 00 79 00 6E 00 61 00 ........D.y.n.a.
  33. * 00000010 6D 00 69 00 63 00 20 00 4E 00 6F 00 64 00 65 00 m.i.c. .N.o.d.e.
  34. * 00000020 31 00 00 00 44 00 79 00 6E 00 61 00 6D 00 69 00 1...D.y.n.a.m.i.
  35. * 00000030 63 00 20 00 4E 00 6F 00 64 00 65 00 32 00 00 00 c. .N.o.d.e.2...
  36. * 00000040 00 00 ..
  37. *
  38. *
  39. * For MMC v1.1 and higher consoles, rgDynamic looks like this:
  40. *
  41. * BYTE rgSignature[16]; // "MMCCustomStream"
  42. * DWORD dwStreamVersion; // version number, currently 0x0100
  43. *
  44. * followed by 1 or more dynamic node IDs, each of which looks like:
  45. *
  46. * BYTE byNodeIDType; // NDTYP_STRING (0x01) means the snap-in
  47. * // did not support CCF_NODEID(2) and the
  48. * // ID is the NULL-terminated Unicode name
  49. * // of the node
  50. * // NDTYP_CUSTOM (0x02) means the snap-in
  51. * // supported CCF_NODEID(2) and what follows
  52. * // is the SNodeID structure
  53. *
  54. * BYTE rgNodeIDBytes[]; // bytes for the dynamic node ID
  55. *
  56. *
  57. * For a tree that looks like this:
  58. *
  59. * Static Node (id == 3)
  60. * Dynamic Node1 (doesn't support CCF_NODEID(2))
  61. * Dynamic Node2 (suports CCF_NODEID, returns DWORD 0x12345678)
  62. *
  63. * the full bookmark for Dynamic Node 2 would be:
  64. *
  65. * 00000000 03 00 00 00 3A 00 00 00 4D 4D 43 43 75 73 74 6F ....:...MMCCusto
  66. * 00000010 6D 53 74 72 65 61 6D 00 00 00 01 00 01 44 00 79 mStream......D.y
  67. * 00000020 00 6E 00 61 00 6D 00 69 00 63 00 20 00 4E 00 6F .n.a.m.i.c. .N.o
  68. * 00000030 00 64 00 65 00 31 00 00 00 02 04 00 00 00 78 56 .d.e.1........xV
  69. * 00000040 34 12 4.
  70. *--------------------------------------------------------------------------*/
  71. #include "stdafx.h"
  72. #include "nodepath.h"
  73. #include <comdef.h>
  74. #include "nmtempl.h"
  75. #include "conview.h"
  76. using namespace std;
  77. /*+-------------------------------------------------------------------------*
  78. * class CDynamicPathEntryEx
  79. *
  80. *
  81. * PURPOSE: Adds functionality (but NO MEMBER VARIABLES) to the
  82. * CDynamicPathEntry class, to initialize from an MTNode.
  83. *
  84. *+-------------------------------------------------------------------------*/
  85. class CDynamicPathEntryEx : public CDynamicPathEntry
  86. {
  87. typedef CDynamicPathEntry BC;
  88. public:
  89. // initialize from a node.
  90. SC ScInitialize(CMTNode *pMTNode, bool bFastRetrievalOnly);
  91. // assignment
  92. CDynamicPathEntryEx & operator = (const CDynamicPathEntryEx &rhs)
  93. {
  94. BC::operator =(rhs);
  95. return *this;
  96. }
  97. CDynamicPathEntryEx & operator = (const CDynamicPathEntry &rhs)
  98. {
  99. BC::operator =(rhs);
  100. return *this;
  101. }
  102. private:
  103. CLIPFORMAT GetCustomNodeIDCF ();
  104. CLIPFORMAT GetCustomNodeID2CF();
  105. };
  106. /*+-------------------------------------------------------------------------*
  107. *
  108. * CDynamicPathEntryEx::ScInitialize
  109. *
  110. * PURPOSE: Initializes the CDynamicPathEntryEx structure from the given MTNode.
  111. *
  112. * This handles all the backward compatibility cases. Refer to the
  113. * SDK docs to see how CCF_NODEID and CCF_NODEID2 are handled.
  114. *
  115. * PARAMETERS:
  116. * CMTNode* pMTNode :
  117. * DWORD dwFlags :
  118. *
  119. * RETURNS:
  120. * SC
  121. *
  122. *+-------------------------------------------------------------------------*/
  123. SC
  124. CDynamicPathEntryEx::ScInitialize(CMTNode* pMTNode, bool bFastRetrievalOnly)
  125. {
  126. DECLARE_SC(sc, TEXT("CDynamicPathEntryEx::ScInitialize"));
  127. USES_CONVERSION;
  128. // get the data object for the node
  129. IDataObjectPtr spDataObject;
  130. sc = pMTNode->QueryDataObject (CCT_SCOPE, &spDataObject);
  131. m_type = 0; // initialize
  132. // Got data object then try to get NodeID2 or NodeID
  133. if(!sc.IsError())
  134. {
  135. // extract the CCF_NODEID2 format from the data object
  136. HGLOBAL hGlobal = NULL;
  137. sc = DataObject_GetHGLOBALData (spDataObject, GetCustomNodeID2CF(), &hGlobal);
  138. if(!sc.IsError()) // succeeded
  139. {
  140. // build the DynamicNodeID from the custom node ID struct
  141. SNodeID2 *pNodeID2 = reinterpret_cast<SNodeID2*>(GlobalLock (hGlobal));
  142. sc = ScCheckPointers(pNodeID2);
  143. if(sc)
  144. return sc;
  145. // if the client needs a fast path ONLY but the snapin can't provide one,
  146. // return E_INVALIDARG;
  147. // Bug 175684: this is a "valid" error return, so we don't want to trace it
  148. if ( ( (pNodeID2->dwFlags & MMC_NODEID_SLOW_RETRIEVAL) &&
  149. bFastRetrievalOnly) ||
  150. ( pNodeID2->cBytes <= 0) )
  151. {
  152. SC scNoTrace = E_INVALIDARG;
  153. return (scNoTrace);
  154. }
  155. m_byteVector.insert (m_byteVector.end(),
  156. pNodeID2->id, pNodeID2->id + pNodeID2->cBytes);
  157. m_type |= NDTYP_CUSTOM;
  158. }
  159. else // the CCF_NODEID2 format was not supported. Try CCF_NODEID.
  160. {
  161. sc = DataObject_GetHGLOBALData (spDataObject, GetCustomNodeIDCF(), &hGlobal);
  162. if(!sc)
  163. {
  164. // build the DynamicNodeID from the custom node ID struct
  165. m_type |= NDTYP_CUSTOM;
  166. SNodeID *pNodeID = reinterpret_cast<SNodeID*>(GlobalLock (hGlobal));
  167. sc = ScCheckPointers(pNodeID);
  168. if(sc)
  169. return sc;
  170. // if pNodeID->cBytes is zero, this is a legacy indication that the
  171. // node does not support fast retrieval. But, if the client is OK
  172. // with slow retrieval, we supply the display name instead.
  173. if(pNodeID->cBytes != 0)
  174. {
  175. m_byteVector.insert (m_byteVector.end(),
  176. pNodeID->id, pNodeID->id + pNodeID->cBytes);
  177. }
  178. else
  179. {
  180. // cBytes == 0 here. If the client indicated fast retrieval, must return an error.
  181. // Bug 175684: this is a "valid" error return, so we don't want to trace it
  182. if(bFastRetrievalOnly)
  183. {
  184. SC scNoTrace = E_INVALIDARG;
  185. return (scNoTrace);
  186. }
  187. }
  188. }
  189. };
  190. // let go of the data
  191. if (hGlobal)
  192. {
  193. GlobalUnlock (hGlobal);
  194. GlobalFree (hGlobal);
  195. }
  196. }
  197. // always save the display name as well.
  198. sc.Clear();
  199. m_type |= NDTYP_STRING;
  200. tstring strName = pMTNode->GetDisplayName();
  201. if (!strName.empty())
  202. m_strEntry = T2CW(strName.data());
  203. else
  204. return (sc = E_INVALIDARG);
  205. return sc;
  206. }
  207. /*--------------------------------------------------------------------------*
  208. * CDynamicPathEntryEx::GetCustomNodeIDCF
  209. *
  210. *
  211. *--------------------------------------------------------------------------*/
  212. CLIPFORMAT CDynamicPathEntryEx::GetCustomNodeIDCF()
  213. {
  214. static CLIPFORMAT cfCustomNodeID = 0;
  215. if (cfCustomNodeID == 0)
  216. {
  217. USES_CONVERSION;
  218. cfCustomNodeID = (CLIPFORMAT) RegisterClipboardFormat (W2T (CCF_NODEID));
  219. ASSERT (cfCustomNodeID != 0);
  220. }
  221. return (cfCustomNodeID);
  222. }
  223. /*--------------------------------------------------------------------------*
  224. * CDynamicPathEntryEx::GetCustomNodeID2CF
  225. *
  226. *
  227. *--------------------------------------------------------------------------*/
  228. CLIPFORMAT CDynamicPathEntryEx::GetCustomNodeID2CF()
  229. {
  230. static CLIPFORMAT cfCustomNodeID2 = 0;
  231. if (cfCustomNodeID2 == 0)
  232. {
  233. USES_CONVERSION;
  234. cfCustomNodeID2 = (CLIPFORMAT) RegisterClipboardFormat (W2T (CCF_NODEID2));
  235. ASSERT (cfCustomNodeID2 != 0);
  236. }
  237. return (cfCustomNodeID2);
  238. }
  239. //############################################################################
  240. //############################################################################
  241. //
  242. // Implementation of class CBookmarkEx
  243. //
  244. //############################################################################
  245. //############################################################################
  246. CBookmarkEx::CBookmarkEx(MTNODEID idStatic) : BC(idStatic)
  247. {
  248. }
  249. CBookmarkEx::CBookmarkEx(bool bIsFastBookmark) : BC(bIsFastBookmark)
  250. {
  251. }
  252. /*+-------------------------------------------------------------------------*
  253. * CBookmarkEx::~CBookmarkEx
  254. *
  255. * PURPOSE: Destructor
  256. *
  257. * PARAMETERS:
  258. *
  259. * RETURNS:
  260. *
  261. /*+-------------------------------------------------------------------------*/
  262. CBookmarkEx::~CBookmarkEx()
  263. {
  264. }
  265. /*+-------------------------------------------------------------------------*
  266. *
  267. * CBookmarkEx::ScRetarget
  268. *
  269. * PURPOSE:
  270. *
  271. * PARAMETERS:
  272. * CMTNode * pMTNode :
  273. * bool bFastRetrievalOnly :
  274. *
  275. * RETURNS:
  276. * SC
  277. *
  278. *+-------------------------------------------------------------------------*/
  279. SC
  280. CBookmarkEx::ScRetarget(CMTNode *pMTNode, bool bFastRetrievalOnly)
  281. {
  282. DECLARE_SC(sc, TEXT("CBookmarkEx::ScRetarget"));
  283. if(pMTNode)
  284. {
  285. sc = ScInitialize (pMTNode, NULL, bFastRetrievalOnly);
  286. if(sc)
  287. return sc;
  288. }
  289. else
  290. Reset();
  291. return sc;
  292. }
  293. /*+-------------------------------------------------------------------------*
  294. *
  295. * CBookmarkEx::ResetUI
  296. *
  297. * PURPOSE: Reset's the state of the bookmark. Will put up the Retry/Cancel
  298. * UI if the node is not available.
  299. *
  300. * RETURNS:
  301. * void
  302. *
  303. *+-------------------------------------------------------------------------*/
  304. void
  305. CBookmarkEx::ResetUI()
  306. {
  307. }
  308. /* CBookmarkEx::GetNode
  309. *
  310. * PURPOSE: Returns a CNode corresponding to the bookmark for a particular view.
  311. * NOTE: This will return a new instance every time. To reuse the same
  312. * instance, cache it.
  313. *
  314. * PARAMETERS:
  315. * CViewData * pViewData: The view for which a node is requested
  316. *
  317. * RETURNS:
  318. * CNode * : NULL if the MTNode could not be found.
  319. */
  320. std::auto_ptr<CNode>
  321. CBookmarkEx::GetNode(CViewData *pViewData)
  322. {
  323. DECLARE_SC(sc, TEXT("CBookmarkEx::GetNode"));
  324. CNode * pNode = NULL;
  325. CMTNode * pMTNode = NULL;
  326. // The NULL return value for failure conditions.
  327. std::auto_ptr<CNode> spNodeNull;
  328. // validate parameters
  329. if(NULL == pViewData)
  330. {
  331. sc = E_UNEXPECTED;
  332. return spNodeNull;
  333. }
  334. // Get the target node.
  335. bool bExactMatchFound = false; // out value from ScGetMTNode, unused
  336. sc = ScGetMTNode(true, &pMTNode, bExactMatchFound);
  337. if( sc.IsError() || !pMTNode) // could not find the node - abort.
  338. {
  339. return spNodeNull;
  340. }
  341. // make sure the node is expanded (invisibly) in the tree
  342. CConsoleView* pConsoleView = pViewData->GetConsoleView();
  343. if (pConsoleView == NULL)
  344. {
  345. sc = E_UNEXPECTED;
  346. return spNodeNull;
  347. }
  348. sc = pConsoleView->ScExpandNode (pMTNode->GetID(), true, false);
  349. if(sc)
  350. return spNodeNull;
  351. pNode = pMTNode->GetNode(pViewData, false);
  352. if (pNode == NULL)
  353. {
  354. sc = E_OUTOFMEMORY;
  355. return spNodeNull;
  356. }
  357. if (FAILED (pNode->InitComponents()))
  358. {
  359. delete pNode;
  360. sc = E_UNEXPECTED;
  361. return spNodeNull;
  362. }
  363. return (std::auto_ptr<CNode>(pNode));
  364. }
  365. /*+-------------------------------------------------------------------------*
  366. *
  367. * CBookmarkEx::ScInitialize
  368. *
  369. * PURPOSE:
  370. *
  371. * PARAMETERS:
  372. * CMTNode* pMTNode :
  373. * CMTNode* pMTViewRootNode :
  374. * bool bFastRetrievalOnly : true by default. If true, this
  375. * function returns E_INVALIDARG for
  376. * any node that cannot be quickly
  377. * retrieved.
  378. *
  379. * RETURNS:
  380. * SC
  381. *
  382. *+-------------------------------------------------------------------------*/
  383. SC
  384. CBookmarkEx::ScInitialize (CMTNode* pMTNode, CMTNode* pMTViewRootNode, bool bFastRetrievalOnly)
  385. {
  386. DECLARE_SC(sc, TEXT("CBookmarkEx::ScInitialize"));
  387. // check pointers
  388. sc = ScCheckPointers(pMTNode);
  389. if(sc)
  390. return sc;
  391. BC::Reset();
  392. // 1. Get the static node ID
  393. m_idStatic = pMTNode->GetID();
  394. // If this is a static node, we're done.
  395. if(pMTNode->IsStaticNode())
  396. return sc;
  397. bool fPassedViewRootNode = false;
  398. // get a descriptor for each dynamic node at the end of the branch
  399. // (from leaf to root)
  400. while ((pMTNode != NULL) && !pMTNode->IsStaticNode())
  401. {
  402. CDynamicPathEntryEx entry;
  403. sc = entry.ScInitialize(pMTNode, bFastRetrievalOnly);
  404. if(sc.IsError() && !(sc == E_INVALIDARG) ) // E_INVALIDARG means that fast retrieval was not available.
  405. return sc;
  406. if(sc) // must be E_INVALIDARG
  407. {
  408. // if the node's data object gave us an empty custom node ID,
  409. // we don't want to persist this node or any below it, so purge the list
  410. m_dynamicPath.clear(); // clear the path
  411. sc.Clear();
  412. }
  413. // otherwise, put it this node ID on the front of the list
  414. else
  415. m_dynamicPath.push_front (entry);
  416. /*
  417. * remember if we've passed the node at the root of our view
  418. * on our way up the tree to the first static node
  419. */
  420. if (pMTNode == pMTViewRootNode)
  421. fPassedViewRootNode = true;
  422. /*
  423. * If we've passed the view's root node and the list is empty, it means
  424. * that a node between the view's root node and the first static node
  425. * (specifically, this one) supports CCF_NODEID and has requested
  426. * that the node not be persisted. If a node isn't persisted,
  427. * nothing below it is persisted, either, so we can bail out.
  428. */
  429. if (fPassedViewRootNode && m_dynamicPath.empty())
  430. break;
  431. pMTNode = pMTNode->Parent();
  432. }
  433. // assume success
  434. sc.Clear();
  435. if(!pMTNode || !pMTNode->IsStaticNode())
  436. return (sc = E_UNEXPECTED);
  437. // Get the static node ID of the static parent
  438. m_idStatic = pMTNode->GetID();
  439. // if we don't have a dynamic node path, return so
  440. if (m_dynamicPath.empty ())
  441. return (sc = S_FALSE);
  442. // if we hit the root before we hit a static node, we have an error
  443. if (pMTNode == NULL)
  444. sc = E_FAIL;
  445. return sc;
  446. }
  447. /*+-------------------------------------------------------------------------*
  448. *
  449. * CBookmarkEx::ScGetMTNode
  450. *
  451. * PURPOSE: Returns the MTNode of the node with the given path relative to
  452. * the static node.
  453. *
  454. * PARAMETERS:
  455. * bool bExactMatchRequired: [IN] Do we need exact match?
  456. * CMTNode ** ppMTNode : [OUT]: The MTNode, if found.
  457. * bool bExactMatchFound : [OUT] Did we find exact match?
  458. *
  459. * RETURNS:
  460. * SC
  461. *
  462. *+-------------------------------------------------------------------------*/
  463. SC
  464. CBookmarkEx::ScGetMTNode(bool bExactMatchRequired, CMTNode **ppMTNode, bool& bExactMatchFound)
  465. {
  466. DECLARE_SC(sc, TEXT("CBookmarkEx::ScGetMTNode"));
  467. // check parameters
  468. sc = ScCheckPointers(ppMTNode);
  469. if(sc)
  470. return sc;
  471. // init out param
  472. *ppMTNode = NULL;
  473. bExactMatchFound = false;
  474. CScopeTree *pScopeTree = CScopeTree::GetScopeTree();
  475. if(!pScopeTree)
  476. {
  477. sc = E_POINTER;
  478. return sc;
  479. }
  480. if (m_idStatic == ID_ConsoleRoot)
  481. {
  482. sc = ScRetarget (pScopeTree->GetRoot(), true /*bFastRetrievalOnly*/);
  483. if(sc)
  484. return sc;
  485. }
  486. // find the MTNode of the static node closest to the required node.
  487. CMTNode* pMTNode = NULL;
  488. sc = pScopeTree->Find(m_idStatic, &pMTNode);
  489. if(sc)
  490. return sc;
  491. sc = ScCheckPointers(pMTNode);
  492. if(sc)
  493. return sc;
  494. *ppMTNode = pMTNode; // initialize
  495. CDynamicPath::iterator iter;
  496. for(iter = m_dynamicPath.begin(); iter != m_dynamicPath.end(); iter++)
  497. {
  498. CDynamicPathEntryEx entry;
  499. entry = *iter;
  500. // check the next segment of the path.
  501. sc = ScFindMatchingMTNode(pMTNode, entry, ppMTNode);
  502. // handle the special case of the node not being found but an exact match
  503. // not being needed. In this case, we use the closest ancestor node that
  504. // was available.
  505. if ( (sc == ScFromMMC(IDS_NODE_NOT_FOUND)) && !bExactMatchRequired )
  506. {
  507. // set the output.
  508. *ppMTNode = pMTNode;
  509. sc.Clear();
  510. return sc;
  511. }
  512. // bail on all other errors
  513. if(sc)
  514. return sc;
  515. sc = ScCheckPointers(*ppMTNode);
  516. if(sc)
  517. return sc;
  518. pMTNode = *ppMTNode; //prime the MTNode for the next round, if there is one.
  519. }
  520. // we've found a match if we ran out of entries.
  521. bExactMatchFound = (iter == m_dynamicPath.end());
  522. if(bExactMatchRequired && !bExactMatchFound) // could not find the exact node.
  523. {
  524. *ppMTNode = NULL;
  525. return (sc = ScFromMMC(IDS_NODE_NOT_FOUND));
  526. }
  527. // a NULL pMTNode is not an error, we just need to make sure that
  528. // nodes are initialized before use.
  529. if ((pMTNode != NULL) && !pMTNode->IsInitialized() )
  530. {
  531. sc = pMTNode->Init();
  532. if(sc)
  533. sc.TraceAndClear(); // does not invalidate the locating operation
  534. }
  535. return sc;
  536. }
  537. /*+-------------------------------------------------------------------------*
  538. *
  539. * CBookmarkEx::ScFindMatchingMTNode
  540. *
  541. * PURPOSE: Finds the first child node directly beneath the given parent node
  542. * whose node ID (ie one of CCF_NODEID2, CCF_NODEID, or the display
  543. * name) matches the specified CDynamicPathEntryEx object.
  544. *
  545. * PARAMETERS:
  546. * CMTNode * pMTNodeParent :
  547. * CDynamicPathEntryEx & entry :
  548. * CMTNode ** ppMatchingMTNode : [OUT]: The child node, if found.
  549. *
  550. * RETURNS:
  551. * SC
  552. *
  553. *+-------------------------------------------------------------------------*/
  554. SC
  555. CBookmarkEx::ScFindMatchingMTNode(CMTNode *pMTNodeParent, CDynamicPathEntryEx &entry,
  556. CMTNode **ppMatchingMTNode)
  557. {
  558. DECLARE_SC(sc, TEXT("CBookmarkEx::ScFindMatchingMTNode"));
  559. sc = ScCheckPointers(pMTNodeParent, ppMatchingMTNode);
  560. if(sc)
  561. return sc;
  562. *ppMatchingMTNode = NULL; // initialize
  563. // expand the parent node if not already done so.
  564. if (pMTNodeParent->WasExpandedAtLeastOnce() == FALSE)
  565. {
  566. sc = pMTNodeParent->Expand();
  567. if(sc)
  568. return sc;
  569. }
  570. // see if any of the children of this node match the next segment of the stored path
  571. for (CMTNode *pMTNode = pMTNodeParent->Child(); pMTNode != NULL; pMTNode = pMTNode->Next())
  572. {
  573. CDynamicPathEntryEx entryTemp;
  574. sc = entryTemp.ScInitialize(pMTNode, false /*bFastRetrievalOnly :
  575. at this point, we know the node is created, so we don't care about retrieval speed*/);
  576. if(sc)
  577. return sc;
  578. if(entryTemp == entry) // found it.
  579. {
  580. *ppMatchingMTNode = pMTNode;
  581. return sc;
  582. }
  583. }
  584. // could not find the node.
  585. return (sc = ScFromMMC(IDS_NODE_NOT_FOUND));
  586. }