Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1171 lines
28 KiB

  1. //
  2. // cmponent.cpp : Declaration of Component.
  3. //
  4. // This COM object is primarily concerned with
  5. // the result pane items.
  6. //
  7. // Cory West <[email protected]>
  8. // Copyright (c) Microsoft Corporation 1997
  9. //
  10. #include "stdafx.h"
  11. #include "macros.h"
  12. USE_HANDLE_MACROS("SCHMMGMT(cmponent.cpp)")
  13. #include "dataobj.h"
  14. #include "cmponent.h" // Component
  15. #include "compdata.h" // ComponentData
  16. #include "schmutil.h"
  17. #include "attrgen.hpp"
  18. #include "stdcmpnt.cpp" // CComponent
  19. //
  20. // These arrays describe the result pane layout for when
  21. // any particular object is selected.
  22. //
  23. UINT
  24. g_aColumns0[5] = {
  25. IDS_COLUMN_NAME,
  26. IDS_COLUMN_TYPE,
  27. IDS_COLUMN_STATUS,
  28. IDS_COLUMN_DESCRIPTION,
  29. 0
  30. };
  31. UINT
  32. g_aColumns1[5] = {
  33. IDS_COLUMN_NAME,
  34. IDS_COLUMN_SYNTAX,
  35. IDS_COLUMN_STATUS,
  36. IDS_COLUMN_DESCRIPTION,
  37. 0
  38. };
  39. UINT
  40. g_aColumns2[6] = {
  41. IDS_COLUMN_NAME,
  42. IDS_COLUMN_TYPE,
  43. IDS_COLUMN_SYSTEM,
  44. IDS_COLUMN_DESCRIPTION,
  45. IDS_COLUMN_PARENT,
  46. 0
  47. };
  48. UINT
  49. g_aColumns3[2] =
  50. {
  51. IDS_COLUMN_NAME,
  52. 0
  53. };
  54. UINT*
  55. g_Columns[SCHMMGMT_NUMTYPES] = {
  56. g_aColumns3, // SCHMMGMT_SCHMMGMT
  57. g_aColumns0, // SCHMMGMT_CLASSES
  58. g_aColumns1, // SCHMMGMT_ATTRIBUTES
  59. g_aColumns2, // SCHMMGMT_CLASS
  60. g_aColumns0, // SCHMMGMT_ATTRIBUTE // @@ Is this used?
  61. };
  62. UINT** g_aColumns = g_Columns;
  63. //
  64. // These control the column widths, which I will not change.
  65. //
  66. int g_aColumnWidths0[4] = {150,150,75,150};
  67. int g_aColumnWidths1[5] = {150,75,75,150,150};
  68. int g_aColumnWidths2[1] = {150};
  69. int* g_ColumnWidths[SCHMMGMT_NUMTYPES] = {
  70. g_aColumnWidths2, // SCHMMGMT_SCHMMGMT
  71. g_aColumnWidths0, // SCHMMGMT_CLASSES
  72. g_aColumnWidths0, // SCHMMGMT_ATTRIBUTES
  73. g_aColumnWidths1, // SCHMMGMT_CLASS
  74. g_aColumnWidths0, // SCHMMGMT_ATTRIBUTE
  75. };
  76. int** g_aColumnWidths = g_ColumnWidths;
  77. //
  78. // Constructors and destructors.
  79. //
  80. Component::Component()
  81. : m_pSvcMgmtToolbar( NULL ),
  82. m_pSchmMgmtToolbar( NULL ),
  83. m_pControlbar( NULL )
  84. {
  85. AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
  86. m_pViewedCookie = NULL;
  87. }
  88. Component::~Component()
  89. {
  90. TRACE_METHOD(Component,Destructor);
  91. VERIFY( SUCCEEDED(ReleaseAll()) );
  92. }
  93. HRESULT Component::ReleaseAll()
  94. {
  95. MFC_TRY;
  96. TRACE_METHOD(Component,ReleaseAll);
  97. SAFE_RELEASE(m_pSvcMgmtToolbar);
  98. SAFE_RELEASE(m_pSchmMgmtToolbar);
  99. SAFE_RELEASE(m_pControlbar);
  100. return CComponent::ReleaseAll();
  101. MFC_CATCH;
  102. }
  103. //
  104. // Support routines in ISchmMgmtComponent.
  105. //
  106. HRESULT
  107. Component::LoadColumns(
  108. Cookie* pcookie
  109. ) {
  110. TEST_NONNULL_PTR_PARAM(pcookie);
  111. return LoadColumnsFromArrays( (INT)(pcookie->m_objecttype) );
  112. }
  113. HRESULT
  114. Component::OnViewChange(
  115. LPDATAOBJECT,
  116. LPARAM data,
  117. LPARAM function
  118. )
  119. /***
  120. This is called when IConsole->UpdateAllViews() is called.
  121. The data is a schema object type as follows:
  122. if function == 0 (SCHMMGMT_UPDATEVIEW_REFRESH)
  123. SCHMMGMT_ATTIBUTES - We need to refresh the attributes
  124. folder displays.
  125. SCHMMGMT_CLASS - We need to refresh _ALL_ class attribute
  126. displays. We don't try and trace the inheritance
  127. graphs and do a selective refresh, that's too complicated.
  128. SCHMMGMT_SCHMMGMT - Refresh EVERYTHING because we reloaded
  129. the schema cache.
  130. else if function == 1 (SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM)
  131. data is the Cookie pointer
  132. ***/
  133. {
  134. //
  135. // Refresh this result view.
  136. //
  137. if ( function == SCHMMGMT_UPDATEVIEW_REFRESH )
  138. {
  139. if ( m_pViewedCookie ) {
  140. if ( ( data == m_pViewedCookie->m_objecttype ) ||
  141. ( data == SCHMMGMT_SCHMMGMT ) ) {
  142. m_pResultData->DeleteAllRsltItems();
  143. PopulateListbox( m_pViewedCookie );
  144. }
  145. }
  146. }
  147. else if ( function == SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM )
  148. {
  149. HRESULTITEM item;
  150. ZeroMemory( &item, sizeof(HRESULTITEM) );
  151. HRESULT hr = m_pResultData->FindItemByLParam( data, &item );
  152. if ( SUCCEEDED(hr) )
  153. {
  154. hr = m_pResultData->DeleteItem( item, 0 );
  155. ASSERT( SUCCEEDED(hr) );
  156. }
  157. }
  158. return S_OK;
  159. }
  160. HRESULT
  161. Component::OnNotifySelect( LPDATAOBJECT lpDataObject, BOOL )
  162. /***
  163. This called in response to MMCN_SELECT.
  164. This routine will set the default verb and enable the toolbar buttons.
  165. ***/
  166. {
  167. CCookie* pBaseParentCookie = NULL;
  168. HRESULT hr = ExtractData( lpDataObject,
  169. CSchmMgmtDataObject::m_CFRawCookie,
  170. OUT reinterpret_cast<PBYTE>(&pBaseParentCookie),
  171. sizeof(pBaseParentCookie) );
  172. ASSERT( SUCCEEDED(hr) );
  173. Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
  174. ASSERT( NULL != pParentCookie );
  175. switch ( pParentCookie->m_objecttype ) {
  176. case SCHMMGMT_CLASSES:
  177. case SCHMMGMT_ATTRIBUTES:
  178. break;
  179. case SCHMMGMT_CLASS:
  180. {
  181. //
  182. // Set the default verb to display the properties of the selected object.
  183. //
  184. m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
  185. m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
  186. // if the schema class is defunct and the forest version is Whistler or higher
  187. // then allow delete
  188. /* Feature was removed for Whistler
  189. ComponentData& Scope = QueryComponentDataRef();
  190. if ( Scope.GetBasePathsInfo()->GetForestBehaviorVersion() >= 2)
  191. {
  192. SchemaObject *pSchemaObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
  193. pParentCookie->strSchemaObject,
  194. SCHMMGMT_CLASS );
  195. if ( pSchemaObject &&
  196. pSchemaObject->isDefunct )
  197. {
  198. m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
  199. }
  200. }
  201. */
  202. }
  203. break;
  204. case SCHMMGMT_ATTRIBUTE:
  205. if ( ( pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE ) &&
  206. ( pParentCookie->pParentCookie ) &&
  207. ( pParentCookie->pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTES ) ) {
  208. //
  209. // Set the default verb to display the properties of the selected object.
  210. //
  211. m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
  212. m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
  213. // if the schema class is defunct and the forest version is Whistler or higher
  214. // then allow delete
  215. /* Feature was removed for Whistler
  216. ComponentData& Scope = QueryComponentDataRef();
  217. if ( Scope.GetBasePathsInfo()->GetForestBehaviorVersion() >= 2)
  218. {
  219. SchemaObject *pSchemaObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
  220. pParentCookie->strSchemaObject,
  221. SCHMMGMT_ATTRIBUTE );
  222. if ( pSchemaObject &&
  223. pSchemaObject->isDefunct )
  224. {
  225. m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
  226. }
  227. }
  228. */
  229. } else {
  230. m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, TRUE);
  231. }
  232. break;
  233. default:
  234. //
  235. // Otherwise set the default verb to open/expand the folder.
  236. //
  237. m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
  238. break;
  239. }
  240. return S_OK;
  241. }
  242. HRESULT
  243. Component::Show(
  244. CCookie* pcookie,
  245. LPARAM arg,
  246. HSCOPEITEM hScopeItem
  247. )
  248. /***
  249. This is called in response to MMCN_SHOW.
  250. ***/
  251. {
  252. TEST_NONNULL_PTR_PARAM(pcookie);
  253. HRESULT hr = S_OK;
  254. do
  255. {
  256. if ( TRUE == arg ) // showing...
  257. {
  258. if( QueryComponentDataRef().IsSetDelayedRefreshOnShow() )
  259. {
  260. HSCOPEITEM hItem = QueryComponentDataRef().GetDelayedRefreshOnShowItem();
  261. ASSERT( hItem == hScopeItem );
  262. QueryComponentDataRef().SetDelayedRefreshOnShow( NULL );
  263. hr = m_pConsole->SelectScopeItem( hItem ); // will call GetResultViewType & Show
  264. ASSERT_BREAK_ON_FAILED_HRESULT(hr);
  265. }
  266. else if( QueryComponentDataRef().IsErrorSet() )
  267. {
  268. CComPtr<IUnknown> pUnknown;
  269. CComPtr<IMessageView> pMessageView;
  270. hr = m_pConsole->QueryResultView(&pUnknown);
  271. ASSERT_BREAK_ON_FAILED_HRESULT(hr);
  272. hr = pUnknown->QueryInterface(IID_IMessageView, (PVOID*)&pMessageView);
  273. ASSERT_BREAK_ON_FAILED_HRESULT(hr);
  274. pMessageView->SetTitleText( CComBSTR( QueryComponentDataRef().GetErrorTitle() ) );
  275. pMessageView->SetBodyText( CComBSTR( QueryComponentDataRef().GetErrorText() ) );
  276. pMessageView->SetIcon(Icon_Error);
  277. }
  278. else
  279. {
  280. m_pViewedCookie = (Cookie*)pcookie;
  281. LoadColumns( m_pViewedCookie );
  282. hr = PopulateListbox( m_pViewedCookie );
  283. }
  284. }
  285. else // hiding...
  286. {
  287. if( !QueryComponentDataRef().IsErrorSet() )
  288. {
  289. if ( NULL == m_pResultData )
  290. {
  291. ASSERT( FALSE );
  292. hr = E_UNEXPECTED;
  293. break;
  294. }
  295. m_pViewedCookie = NULL;
  296. }
  297. }
  298. } while( FALSE );
  299. return hr;
  300. }
  301. HRESULT
  302. Component::OnNotifyAddImages(
  303. LPDATAOBJECT,
  304. LPIMAGELIST lpImageList,
  305. HSCOPEITEM
  306. )
  307. /***
  308. This routine is called in response to MMCN_ADD_IMAGES. Here's
  309. what mmc.idl says about this:
  310. Sent to IComponent to add images for the result pane. The
  311. primary snapin should add images for both folders and leaf items.
  312. arg = ptr to result panes IImageList.
  313. param = HSCOPEITEM of selected/deselected item
  314. ***/
  315. {
  316. return QueryComponentDataRef().LoadIcons(lpImageList,TRUE);
  317. }
  318. HRESULT
  319. Component::OnNotifyDelete(
  320. LPDATAOBJECT lpDataObject)
  321. {
  322. CCookie* pBaseParentCookie = NULL;
  323. HRESULT hr = ExtractData( lpDataObject,
  324. CSchmMgmtDataObject::m_CFRawCookie,
  325. reinterpret_cast<PBYTE>(&pBaseParentCookie),
  326. sizeof(pBaseParentCookie) );
  327. ASSERT( SUCCEEDED(hr) );
  328. Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
  329. ASSERT( NULL != pParentCookie );
  330. UINT promptID = 0;
  331. LPARAM updateType = SCHMMGMT_CLASS;
  332. if (pParentCookie->m_objecttype == SCHMMGMT_CLASS)
  333. {
  334. promptID = IDS_DELETE_CLASS_PROMPT;
  335. updateType = SCHMMGMT_CLASS;
  336. }
  337. else if (pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE)
  338. {
  339. promptID = IDS_DELETE_ATTR_PROMPT;
  340. updateType = SCHMMGMT_ATTRIBUTES;
  341. }
  342. else
  343. {
  344. // We should never get called to delete anything but
  345. // class and attribute nodes
  346. ASSERT(FALSE);
  347. return E_FAIL;
  348. }
  349. if( IDYES == AfxMessageBox( promptID, MB_YESNO | MB_ICONWARNING ))
  350. {
  351. hr = DeleteAttribute(pParentCookie);
  352. if ( SUCCEEDED(hr) )
  353. {
  354. // Remove the node from the UI
  355. hr = m_pConsole->UpdateAllViews( lpDataObject,
  356. (LPARAM)pParentCookie,
  357. SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM );
  358. ASSERT( SUCCEEDED(hr) );
  359. }
  360. else
  361. {
  362. CString szDeleteError;
  363. szDeleteError.Format(IDS_ERRMSG_DELETE_FAILED_ATTRIBUTE, GetErrorMessage(hr, TRUE));
  364. DoErrMsgBox( ::GetActiveWindow(), TRUE, szDeleteError );
  365. }
  366. }
  367. return hr;
  368. }
  369. HRESULT
  370. Component::DeleteAttribute(
  371. Cookie* pcookie
  372. )
  373. /***
  374. This deletes an attribute from the schema
  375. ***/
  376. {
  377. HRESULT hr = S_OK;
  378. do
  379. {
  380. if ( !pcookie )
  381. {
  382. hr = E_INVALIDARG;
  383. break;
  384. }
  385. ComponentData& Scope = QueryComponentDataRef();
  386. SchemaObject* pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
  387. pcookie->strSchemaObject,
  388. SCHMMGMT_ATTRIBUTE );
  389. if ( !pObject )
  390. {
  391. hr = E_FAIL;
  392. break;
  393. }
  394. CString szAdsPath;
  395. Scope.GetSchemaObjectPath( pObject->commonName, szAdsPath );
  396. hr = DeleteObject( szAdsPath, pcookie, g_AttributeFilter );
  397. } while (false);
  398. return hr;
  399. }
  400. HRESULT
  401. Component::PopulateListbox(
  402. Cookie* pcookie
  403. )
  404. /***
  405. This populates the result pane when the result pane
  406. contains data that is not directly derived from the
  407. data in the scope pane.
  408. ***/
  409. {
  410. switch ( pcookie->m_objecttype ) {
  411. case SCHMMGMT_SCHMMGMT:
  412. case SCHMMGMT_CLASSES:
  413. //
  414. // We don't care about these - the result
  415. // pane contains only scope items.
  416. //
  417. break;
  418. case SCHMMGMT_ATTRIBUTES:
  419. //
  420. // List the specified items in the result pane
  421. // with some informational data.
  422. //
  423. return FastInsertAttributeResultCookies(
  424. pcookie );
  425. break;
  426. case SCHMMGMT_CLASS:
  427. //
  428. // This results in the attributes used in this
  429. // class and other class data being displayed.
  430. //
  431. return FastInsertClassAttributesResults( pcookie );
  432. break;
  433. case SCHMMGMT_ATTRIBUTE:
  434. //
  435. // This is not a scope pane item and can have no
  436. // corresponding result pane data!!
  437. //
  438. ASSERT(FALSE);
  439. break;
  440. }
  441. return S_OK;
  442. }
  443. HRESULT
  444. Component::FastInsertAttributeResultCookies(
  445. Cookie* pParentCookie
  446. )
  447. /***
  448. When the "Attributes" folder is selected, this puts
  449. the attributes in the result pane.
  450. pParentCookie is the cookie for the parent object.
  451. This routine is similar to
  452. ComponentData::FastInsertClassScopeCookies.
  453. ****/
  454. {
  455. HRESULT hr;
  456. SchemaObject *pObject, *pHead;
  457. Cookie *pNewCookie;
  458. RESULTDATAITEM ResultItem;
  459. LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName();
  460. ComponentData& Scope = QueryComponentDataRef();
  461. //
  462. // Initialize the result item.
  463. //
  464. ::ZeroMemory( &ResultItem, sizeof( ResultItem ) );
  465. ResultItem.nCol = 0;
  466. ResultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  467. ResultItem.str = MMC_CALLBACK;
  468. ResultItem.nImage = iIconAttribute;
  469. //
  470. // Rather than having a clean class interface to the cache, we
  471. // walk the cache data structures ourselves. This isn't super
  472. // clean, but it's simple.
  473. //
  474. // Since we do this, we have to make sure that the cache is loaded.
  475. //
  476. Scope.g_SchemaCache.LoadCache();
  477. pObject = Scope.g_SchemaCache.pSortedAttribs;
  478. //
  479. // If there's no sorted list, we can't insert anything!!!!
  480. //
  481. if ( !pObject ) {
  482. ASSERT( FALSE );
  483. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_PATH );
  484. return S_OK;
  485. }
  486. //
  487. // Delete whatever was in the view before
  488. // and do the insert.
  489. //
  490. pHead = pObject;
  491. do {
  492. //
  493. // Insert this result.
  494. //
  495. pNewCookie= new Cookie( SCHMMGMT_ATTRIBUTE,
  496. lpcszMachineName );
  497. if ( pNewCookie ) {
  498. pNewCookie->pParentCookie = pParentCookie;
  499. pNewCookie->strSchemaObject = pObject->commonName;
  500. pParentCookie->m_listScopeCookieBlocks.AddHead(
  501. (CBaseCookieBlock*)pNewCookie
  502. );
  503. ResultItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pNewCookie);
  504. hr = m_pResultData->InsertItem( &ResultItem );
  505. if ( SUCCEEDED(hr) ) {
  506. pNewCookie->SetResultHandle( ResultItem.itemID );
  507. } else {
  508. delete pNewCookie;
  509. }
  510. }
  511. pObject = pObject->pSortedListFlink;
  512. } while ( pObject != pHead );
  513. return S_OK;
  514. }
  515. HRESULT
  516. Component::FastInsertClassAttributesResults(
  517. Cookie* pClassCookie
  518. )
  519. /***
  520. This routine displays all the attributes for a class.
  521. ***/
  522. {
  523. HRESULT hr = S_OK;
  524. SchemaObject *pObject, *pTop;
  525. CString top = L"top";
  526. ComponentData& Scope = QueryComponentDataRef();
  527. //
  528. // Call the attribute display routine. This routine
  529. // will call itself recursively to display the
  530. // inheritance structure of the class.
  531. //
  532. pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
  533. pClassCookie->strSchemaObject,
  534. SCHMMGMT_CLASS );
  535. if ( pObject ) {
  536. CStringList szProcessedList;
  537. hr = RecursiveDisplayClassAttributesResults(
  538. pClassCookie,
  539. pObject,
  540. szProcessedList);
  541. Scope.g_SchemaCache.ReleaseRef( pObject );
  542. }
  543. //
  544. // Process "top" just once.
  545. //
  546. pTop = Scope.g_SchemaCache.LookupSchemaObject( top, SCHMMGMT_CLASS );
  547. if ( pTop ) {
  548. ProcessResultList( pClassCookie, pTop->systemMayContain, TRUE, TRUE, pTop );
  549. ProcessResultList( pClassCookie, pTop->mayContain, TRUE, FALSE, pTop );
  550. ProcessResultList( pClassCookie, pTop->systemMustContain, FALSE, TRUE, pTop );
  551. ProcessResultList( pClassCookie, pTop->mustContain, FALSE, FALSE, pTop );
  552. Scope.g_SchemaCache.ReleaseRef( pTop );
  553. }
  554. return hr;
  555. }
  556. HRESULT
  557. Component::RecursiveDisplayClassAttributesResults(
  558. Cookie *pParentCookie,
  559. SchemaObject* pObject,
  560. CStringList& szProcessedList
  561. )
  562. /***
  563. Display all the attributes for this class.
  564. ***/
  565. {
  566. ListEntry *pList;
  567. SchemaObject *pInheritFrom;
  568. ComponentData& Scope = QueryComponentDataRef();
  569. //
  570. // Don't process "top" here since everyone inherits from it.
  571. //
  572. if ( pObject->ldapDisplayName == L"top" ) {
  573. return S_OK;
  574. }
  575. DebugTrace( L"RecursiveDisplayClassAttributesResults: %ls\n",
  576. const_cast<LPWSTR>((LPCTSTR)pObject->ldapDisplayName) );
  577. //
  578. // Insert all the attributes for this class.
  579. // The second parameter dictates whether these
  580. // are optional or not. The third parameter
  581. // is the source of the attribute.
  582. //
  583. ProcessResultList( pParentCookie, pObject->systemMayContain, TRUE, TRUE, pObject );
  584. ProcessResultList( pParentCookie, pObject->mayContain, TRUE, FALSE, pObject );
  585. ProcessResultList( pParentCookie, pObject->systemMustContain, FALSE, TRUE, pObject );
  586. ProcessResultList( pParentCookie, pObject->mustContain, FALSE, FALSE, pObject );
  587. //
  588. // For each auxiliary class, insert those attributes.
  589. //
  590. pList = pObject->systemAuxiliaryClass;
  591. while ( pList ) {
  592. pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
  593. SCHMMGMT_CLASS );
  594. //
  595. // Don't recursively process the item if we already processed it
  596. //
  597. if ( pInheritFrom && szProcessedList.Find(pList->Attribute) == NULL) {
  598. RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
  599. szProcessedList.AddTail(pList->Attribute);
  600. Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
  601. }
  602. pList = pList->pNext;
  603. }
  604. pList = pObject->auxiliaryClass;
  605. while ( pList ) {
  606. pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
  607. SCHMMGMT_CLASS );
  608. //
  609. // Don't recursively process the item if we already processed it
  610. //
  611. if ( pInheritFrom && szProcessedList.Find(pList->Attribute) == NULL ) {
  612. RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
  613. szProcessedList.AddTail(pList->Attribute);
  614. Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
  615. }
  616. pList = pList->pNext;
  617. }
  618. //
  619. // If this is an inherited class, insert those attributes.
  620. //
  621. pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pObject->subClassOf,
  622. SCHMMGMT_CLASS );
  623. if ( pInheritFrom ) {
  624. RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
  625. Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
  626. }
  627. return S_OK;
  628. }
  629. HRESULT
  630. Component::ProcessResultList(
  631. Cookie *pParentCookie,
  632. ListEntry *pList,
  633. BOOLEAN fOptional,
  634. BOOLEAN fSystem,
  635. SchemaObject* pSrcObject
  636. ) {
  637. HRESULT hr;
  638. Cookie *pNewCookie;
  639. RESULTDATAITEM ResultItem;
  640. LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName();
  641. ListEntry *pCurrent = pList;
  642. SchemaObject *pAttribute;
  643. ComponentData& Scope = QueryComponentDataRef();
  644. //
  645. // Initialize the result item.
  646. //
  647. ::ZeroMemory( &ResultItem, sizeof( ResultItem ) );
  648. ResultItem.nCol = 0;
  649. ResultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
  650. ResultItem.str = MMC_CALLBACK;
  651. ResultItem.nImage = iIconAttribute;
  652. while ( pCurrent ) {
  653. //
  654. // Make a new cookie.
  655. //
  656. pNewCookie = new Cookie( SCHMMGMT_ATTRIBUTE,
  657. lpcszMachineName );
  658. if ( pNewCookie ) {
  659. //
  660. // Record the optional status and the source.
  661. //
  662. if ( fOptional ) {
  663. pNewCookie->Mandatory = FALSE;
  664. } else {
  665. pNewCookie->Mandatory = TRUE;
  666. }
  667. if ( fSystem ) {
  668. pNewCookie->System = TRUE;
  669. } else {
  670. pNewCookie->System = FALSE;
  671. }
  672. pNewCookie->strSrcSchemaObject = pSrcObject->commonName;
  673. pNewCookie->pParentCookie = pParentCookie;
  674. //
  675. // Point to the actual attribute.
  676. //
  677. pAttribute = Scope.g_SchemaCache.LookupSchemaObject(
  678. pCurrent->Attribute,
  679. SCHMMGMT_ATTRIBUTE );
  680. if ( pAttribute ) {
  681. pNewCookie->strSchemaObject = pAttribute->commonName;
  682. Scope.g_SchemaCache.ReleaseRef( pAttribute );
  683. }
  684. //
  685. // Insert the result pane item.
  686. //
  687. pParentCookie->m_listScopeCookieBlocks.AddHead(
  688. (CBaseCookieBlock*)pNewCookie
  689. );
  690. ResultItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pNewCookie);
  691. hr = m_pResultData->InsertItem( &ResultItem );
  692. if ( SUCCEEDED(hr) ) {
  693. pNewCookie->SetResultHandle( ResultItem.itemID );
  694. } else {
  695. delete pNewCookie;
  696. }
  697. }
  698. pCurrent = pCurrent->pNext;
  699. }
  700. return S_OK;
  701. }
  702. STDMETHODIMP
  703. Component::AddMenuItems(
  704. LPDATAOBJECT,
  705. LPCONTEXTMENUCALLBACK,
  706. long*
  707. ) {
  708. return S_OK;
  709. }
  710. STDMETHODIMP
  711. Component::Command(
  712. long,
  713. LPDATAOBJECT
  714. ) {
  715. return S_OK;
  716. }
  717. HRESULT Component::OnNotifySnapinHelp (LPDATAOBJECT)
  718. {
  719. // return ShowHelpTopic( L"sag_adschema.htm" );
  720. CComQIPtr<IDisplayHelp,&IID_IDisplayHelp> spDisplayHelp = m_pConsole;
  721. if ( !spDisplayHelp )
  722. {
  723. ASSERT(FALSE);
  724. return E_UNEXPECTED;
  725. }
  726. CString strHelpTopic = L"ADConcepts.chm::/sag_adschema.htm";
  727. HRESULT hr = spDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR) strHelpTopic));
  728. ASSERT (SUCCEEDED (hr));
  729. return hr;
  730. }
  731. HRESULT Component::OnNotifyContextHelp (LPDATAOBJECT)
  732. {
  733. // return ShowHelpTopic( L"schmmgmt_top.htm" );
  734. CComQIPtr<IDisplayHelp,&IID_IDisplayHelp> spDisplayHelp = m_pConsole;
  735. if ( !spDisplayHelp )
  736. {
  737. ASSERT(FALSE);
  738. return E_UNEXPECTED;
  739. }
  740. CString strHelpTopic = L"ADConcepts.chm::/schmmgmt_top.htm";
  741. HRESULT hr = spDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR) strHelpTopic));
  742. ASSERT (SUCCEEDED (hr));
  743. return hr;
  744. }
  745. STDMETHODIMP
  746. Component::QueryPagesFor(
  747. LPDATAOBJECT pDataObject )
  748. {
  749. MFC_TRY;
  750. if ( NULL == pDataObject ) {
  751. ASSERT(FALSE);
  752. return E_POINTER;
  753. }
  754. HRESULT hr;
  755. CCookie* pBaseParentCookie = NULL;
  756. hr = ExtractData( pDataObject,
  757. CSchmMgmtDataObject::m_CFRawCookie,
  758. reinterpret_cast<PBYTE>(&pBaseParentCookie),
  759. sizeof(pBaseParentCookie) );
  760. ASSERT( SUCCEEDED(hr) );
  761. Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
  762. ASSERT( NULL != pParentCookie );
  763. if ( ( pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE ) &&
  764. ( pParentCookie->pParentCookie ) &&
  765. ( pParentCookie->pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTES ) ) {
  766. return S_OK;
  767. }
  768. return S_FALSE;
  769. MFC_CATCH;
  770. }
  771. //
  772. // This adds pages to the property sheet if appropriate.
  773. // The handle parameter must be saved in the property page
  774. // object to notify the parent when modified.
  775. //
  776. STDMETHODIMP
  777. Component::CreatePropertyPages(
  778. LPPROPERTYSHEETCALLBACK pCallBack,
  779. LONG_PTR,
  780. LPDATAOBJECT pDataObject )
  781. {
  782. MFC_TRY;
  783. CWaitCursor wait;
  784. //
  785. // Validate the parameters.
  786. //
  787. if ( ( NULL == pCallBack ) ||
  788. ( NULL == pDataObject ) ) {
  789. ASSERT(FALSE);
  790. return E_POINTER;
  791. }
  792. //
  793. // Make sure this is a class object that we are calling up.
  794. //
  795. CCookie* pBaseParentCookie = NULL;
  796. HRESULT hr = ExtractData( pDataObject,
  797. CSchmMgmtDataObject::m_CFRawCookie,
  798. reinterpret_cast<PBYTE>(&pBaseParentCookie),
  799. sizeof(pBaseParentCookie) );
  800. ASSERT( SUCCEEDED(hr) );
  801. Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
  802. ASSERT( NULL != pParentCookie );
  803. ASSERT( pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE );
  804. //
  805. // Create the page.
  806. //
  807. HPROPSHEETPAGE hPage;
  808. AttributeGeneralPage *pGeneralPage =
  809. new AttributeGeneralPage( this, pDataObject );
  810. if ( pGeneralPage )
  811. {
  812. pGeneralPage->Load( *pParentCookie );
  813. MMCPropPageCallback( &pGeneralPage->m_psp );
  814. hPage= CreatePropertySheetPage( &pGeneralPage->m_psp );
  815. hr = pCallBack->AddPage( hPage );
  816. }
  817. return S_OK;
  818. MFC_CATCH;
  819. }
  820. HRESULT __stdcall
  821. Component::Compare(
  822. LPARAM,
  823. MMC_COOKIE cookieA,
  824. MMC_COOKIE cookieB,
  825. int* result)
  826. {
  827. if (!result)
  828. {
  829. return E_INVALIDARG;
  830. }
  831. if (!m_pViewedCookie)
  832. {
  833. ASSERT(false);
  834. *result = 0;
  835. return S_OK;
  836. }
  837. Cookie* c1 =
  838. (Cookie*) ActiveBaseCookie(reinterpret_cast<CCookie*>(cookieA));
  839. Cookie* c2 =
  840. (Cookie*) ActiveBaseCookie(reinterpret_cast<CCookie*>(cookieB));
  841. PWSTR t1 = QueryBaseComponentDataRef().QueryResultColumnText(*c1, *result);
  842. PWSTR t2 = QueryBaseComponentDataRef().QueryResultColumnText(*c2, *result);
  843. // All columns use a case-insensitive comparison, as many columns contain
  844. // display names from the directory (which are case-insensitive). That we
  845. // also use a case insensitive compare for the other columns is harmless.
  846. // another trick: we are inverting the results from the compare. This is
  847. // because we initially insert the items in the list in sorted order. So
  848. // the first sort request from the user really is intended to reverse-sort
  849. // the list.
  850. *result = -(_wcsicmp(t1, t2));
  851. return S_OK;
  852. }
  853. STDMETHODIMP Component::GetResultViewType(MMC_COOKIE cookie,
  854. BSTR* ppViewType,
  855. long* pViewOptions)
  856. {
  857. MFC_TRY;
  858. if( QueryComponentDataRef().IsErrorSet() )
  859. {
  860. *pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
  861. LPOLESTR psz = NULL;
  862. StringFromCLSID(CLSID_MessageView, &psz);
  863. USES_CONVERSION;
  864. if (psz != NULL)
  865. {
  866. *ppViewType = psz;
  867. return S_OK;
  868. }
  869. else
  870. {
  871. return S_FALSE;
  872. }
  873. }
  874. else
  875. {
  876. return CComponent::GetResultViewType( cookie, ppViewType, pViewOptions );
  877. }
  878. MFC_CATCH;
  879. }