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.

687 lines
19 KiB

  1. /*======================================================================================//
  2. | Process Control //
  3. | //
  4. |Copyright (c) 1998 Sequent Computer Systems, Incorporated. All rights reserved. //
  5. | //
  6. |File Name: RootFolder.cpp //
  7. | //
  8. |Description: Class implemention for the root node //
  9. | //
  10. |Created: Paul Skoglund 07-1998 //
  11. | //
  12. |Rev History: //
  13. | //
  14. |=======================================================================================*/
  15. #include "StdAfx.h"
  16. #include "BaseNode.h"
  17. #include "ProcConLibMsg.h"
  18. #include "RootPages.h"
  19. #include "Container.h"
  20. using std::list<CBaseNode *>;
  21. const GUID CRootFolder::m_GUID = {0xff9baf5f,0x064e,0x11d2,{0x80, 0x14,0x00,0x10,0x4b,0x9a,0x31,0x06} };
  22. const TCHAR *const CRootFolder::m_szGUID = _T("{ff9baf5f-064e-11d2-8014-00104b9a3106}");
  23. ///////////////////////////////////////////////////////////////////////////
  24. // CRootFolder
  25. const CONTEXTMENUITEMBYID CRootFolder::TaskMenuItems[] =
  26. {
  27. { IDS_ROOT_CONNECT, ID_ROOT_CONNECT, ID_ROOT_CONNECT, CCM_INSERTIONPOINTID_PRIMARY_TOP },
  28. { 0, 0, 0, 0 },
  29. };
  30. CRootFolder::CRootFolder() : CBaseNode(ROOT_NODE), m_ID(0), m_ParentID(0), m_NodeList(0),
  31. m_bUseLocalComputer(TRUE),
  32. m_bDirty(FALSE),
  33. m_hPC(0), m_PCLastError(0), m_ipConsole2(NULL)
  34. {
  35. LoadStringHelper(m_name, IDS_ROOT_FOLDER);
  36. m_longname = m_name;
  37. //LoadStringHelper(m_TypeDescriptionStr, IDS_TYPE_DESCRIPTION);
  38. LoadStringHelper(m_DescriptionStr, IDS_DESCRIPTION);
  39. memset(m_Computer, 0, sizeof(m_Computer));
  40. }
  41. CRootFolder::~CRootFolder()
  42. {
  43. ATLTRACE( _T("~CRootFolder <%s>\n"), GetNodeName() );
  44. FreeNodes();
  45. if (m_hPC)
  46. VERIFY( PCClose(m_hPC) );
  47. ATLTRACE( _T("~CRootFolder end\n"));
  48. }
  49. void CRootFolder::FreeNodes()
  50. {
  51. ATLTRACE( _T("CRootFolder::FreeNodes()\n"));
  52. for (list<CBaseNode *>::iterator i = m_NodeList.begin(); i != m_NodeList.end(); ++i)
  53. {
  54. (*i)->Release();
  55. //delete *i;
  56. }
  57. m_NodeList.clear();
  58. }
  59. const PCid CRootFolder::GetPCid()
  60. {
  61. ASSERT(!GetParentNode());
  62. /*
  63. if (
  64. // retry code now in the ProcConLib/service
  65. m_PCLastError == ERROR_NO_DATA ||
  66. m_PCLastError == ERROR_BROKEN_PIPE ||
  67. m_PCLastError == ERROR_BAD_PIPE ||
  68. m_PCLastError == ERROR_PIPE_NOT_CONNECTED ||
  69. m_PCLastError == ERROR_NETNAME_DELETED
  70. )
  71. {
  72. m_PCLastError = 0;
  73. if (m_hPC)
  74. VERIFY( PCClose(m_hPC));
  75. m_hPC = 0;
  76. }
  77. */
  78. if (m_hPC)
  79. return m_hPC;
  80. ATLTRACE(_T("Opening %s.\n"), GetComputerDisplayName());
  81. m_hPC = PCOpen(m_bUseLocalComputer ? NULL : GetComputerName(), NULL, COM_BUFFER_SIZE);
  82. if (!m_hPC)
  83. {
  84. m_PCLastError = PCGetLastError(m_hPC);
  85. ATLTRACE(_T("Unable to open connection to %s, Error(0x%lX).\n"),
  86. GetComputerDisplayName(), m_PCLastError );
  87. }
  88. return m_hPC;
  89. }
  90. BOOL CRootFolder::ReportPCError(PCULONG32 nLastError)
  91. {
  92. TCHAR *pMsgBuf = FormatErrorMessageIntoBuffer(nLastError);
  93. if ( pMsgBuf )
  94. {
  95. int ret = 0;
  96. ATLTRACE( (TCHAR *) pMsgBuf );
  97. ATLTRACE( _T("\n") );
  98. if (m_ipConsole2)
  99. m_ipConsole2->MessageBox(pMsgBuf, NULL, MB_OK | MB_ICONWARNING, &ret);
  100. LocalFree(pMsgBuf);
  101. return TRUE;
  102. }
  103. ATLTRACE(_T("Message Problem: Error (0x%lX).\n"), nLastError );
  104. return FALSE;
  105. }
  106. BOOL CRootFolder::ReportPCError()
  107. {
  108. return ReportPCError( GetLastPCError() );
  109. }
  110. PCULONG32 CRootFolder::GetLastPCError()
  111. {
  112. if (m_hPC) // don't clear an open error...
  113. m_PCLastError = PCGetLastError(m_hPC);
  114. return m_PCLastError;
  115. }
  116. void CRootFolder::GetComputerConnectionInfo(COMPUTER_CONNECTION_INFO &out)
  117. {
  118. out.bLocalComputer = m_bUseLocalComputer;
  119. memcpy(out.RemoteComputer, m_Computer, sizeof(m_Computer));
  120. }
  121. void CRootFolder::SetComputerName(TCHAR Computer[SNAPIN_MAX_COMPUTERNAME_LENGTH + 1])
  122. {
  123. Config((Computer[0] == 0), Computer);
  124. }
  125. void CRootFolder::Config(BOOL bUseLocal, TCHAR Computer[SNAPIN_MAX_COMPUTERNAME_LENGTH + 1])
  126. {
  127. m_bDirty = TRUE;
  128. m_bUseLocalComputer = bUseLocal;
  129. memset(m_Computer, 0, sizeof(m_Computer));
  130. _tcsncpy(m_Computer, Computer, ARRAY_SIZE(m_Computer) - 1);
  131. // change the node's display name...
  132. m_longname = m_name;
  133. if (m_bUseLocalComputer)
  134. {
  135. ITEM_STR tempstr;
  136. LoadStringHelper(tempstr, IDS_LOCAL);
  137. m_machinedisplayname = tempstr;
  138. }
  139. else
  140. {
  141. m_machinedisplayname.reserve((SNAPIN_MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR));
  142. m_machinedisplayname = _T(" (");
  143. m_machinedisplayname+= m_Computer;
  144. m_machinedisplayname+= _T(")");
  145. }
  146. m_longname += m_machinedisplayname;
  147. // finish change node name...
  148. if (m_hPC)
  149. VERIFY( PCClose(m_hPC));
  150. m_hPC = 0;
  151. }
  152. HRESULT CRootFolder::IsDirty() const
  153. {
  154. if (m_bDirty)
  155. return S_OK;
  156. return S_FALSE;
  157. }
  158. HRESULT CRootFolder::Load(IStream *pStm)
  159. {
  160. if (!pStm)
  161. return E_POINTER;
  162. ASSERT(sizeof(WCHAR) == sizeof(TCHAR)); // conversions need to go to single byte characters
  163. ULONG BytesRead = 0;
  164. WCHAR sIn[SNAPIN_MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
  165. HRESULT hr = pStm->Read(sIn, sizeof(sIn), &BytesRead);
  166. if (hr == S_OK && BytesRead)
  167. {
  168. SetComputerName(sIn);
  169. m_bDirty = FALSE;
  170. }
  171. //pStm->Release();
  172. return hr;
  173. }
  174. HRESULT CRootFolder::Save(IStream *pStm, BOOL fClearDirty)
  175. {
  176. if (!pStm)
  177. return E_POINTER;
  178. #ifndef _UNICODE
  179. #error "need to convert output to unicode prior to writing to disk"
  180. #endif
  181. ULONG BytesWritten = 0;
  182. HRESULT hr = pStm->Write(GetComputerName(), ((SNAPIN_MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR)), &BytesWritten);
  183. if (hr == S_OK && fClearDirty)
  184. m_bDirty = FALSE;
  185. // pStm->Release();
  186. return hr;
  187. }
  188. HRESULT CRootFolder::GetSizeMax(ULARGE_INTEGER *pcbSize)
  189. {
  190. if (!pcbSize)
  191. return E_POINTER;
  192. (*pcbSize).LowPart = (SNAPIN_MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
  193. (*pcbSize).HighPart = 0;
  194. return S_OK;
  195. }
  196. LPCTSTR CRootFolder::GetNodeName()
  197. {
  198. if (!m_ParentID)
  199. return m_longname.c_str();
  200. else
  201. return m_name;
  202. }
  203. HRESULT CRootFolder::GetDisplayInfo(RESULTDATAITEM &ResultItem)
  204. {
  205. if (ResultItem.bScopeItem)
  206. {
  207. if( ResultItem.mask & RDI_STR )
  208. {
  209. if (0 == ResultItem.nCol)
  210. ResultItem.str = const_cast<LPOLESTR>(GetNodeName());
  211. //else if (m_ParentID && 1 == ResultItem.nCol)
  212. // ResultItem.Str = m_TypeDescriptionStr;
  213. else if (2 == ResultItem.nCol)
  214. ResultItem.str = m_DescriptionStr;
  215. else
  216. ResultItem.str = _T("");
  217. }
  218. if (ResultItem.mask & RDI_IMAGE)
  219. ResultItem.nImage = sImage();
  220. return S_OK;
  221. }
  222. return E_UNEXPECTED;
  223. }
  224. LPCTSTR CRootFolder::GetComputerName() const
  225. {
  226. return m_Computer;
  227. }
  228. LPCTSTR CRootFolder::GetComputerDisplayName() const
  229. {
  230. return m_machinedisplayname.c_str();
  231. }
  232. HRESULT CRootFolder::OnHelpCmd(IDisplayHelp *ipDisplayHelp)
  233. {
  234. if (!ipDisplayHelp)
  235. return E_UNEXPECTED;
  236. ipDisplayHelp->ShowTopic(const_cast<TCHAR *>(HELP_overview));
  237. return S_OK;
  238. }
  239. //IComponentData::Notify -- MNCN_EXPAND
  240. HRESULT CRootFolder::OnParentExpand(
  241. BOOL bExpanded, // [in] TRUE is we are expanding
  242. HSCOPEITEM hID, // [in] Points to the HSCOPEITEM
  243. IConsoleNameSpace2 *ipConsoleNameSpace2
  244. )
  245. {
  246. ASSERT(ipConsoleNameSpace2);
  247. if(!ipConsoleNameSpace2)
  248. return E_UNEXPECTED;
  249. if (bExpanded)
  250. {
  251. ASSERT(m_NodeList.size() == 0);
  252. ASSERT(m_ID == 0);
  253. m_ParentID = hID;
  254. SCOPEDATAITEM sdi = {0};
  255. sdi.mask = SDI_STR |
  256. SDI_PARAM | // lParam is valid
  257. SDI_IMAGE | // nImage is valid
  258. SDI_OPENIMAGE | // nOpenImage is valid
  259. SDI_CHILDREN | // cChildren is valid
  260. SDI_PARENT;
  261. sdi.displayname = (LPOLESTR)MMC_CALLBACK;
  262. sdi.nImage = sImage();
  263. sdi.nOpenImage = sOpenImage();
  264. sdi.cChildren = GetChildrenCount();
  265. sdi.lParam = reinterpret_cast <LPARAM> (this);
  266. sdi.relativeID = hID;
  267. HRESULT hr = ipConsoleNameSpace2->InsertItem(&sdi);
  268. if (hr == S_OK)
  269. m_ID = sdi.ID;
  270. }
  271. return S_OK; // return has no meaning to MMC
  272. } // end OnParentExpand()
  273. //IComponentData::Notify -- MNCN_EXPAND
  274. HRESULT CRootFolder::OnExpand(
  275. BOOL bExpanded, // [in] TRUE is we are expanding
  276. HSCOPEITEM hID, // [in] Points to the HSCOPEITEM
  277. IConsoleNameSpace2 *ipConsoleNameSpace2
  278. )
  279. {
  280. ASSERT(ipConsoleNameSpace2);
  281. if(!ipConsoleNameSpace2)
  282. return E_UNEXPECTED;
  283. if (bExpanded)
  284. {
  285. ASSERT(m_NodeList.size() == 0);
  286. ASSERT(m_ID == 0 || m_ID == hID);
  287. m_ID = hID; // Cache the root node handle
  288. // 3/7/2001 (PAS)
  289. // around 2410 MMC behavior changed and the proccon folder icon
  290. // wasn't always displayed correctly...the root node image used to be
  291. // handled differently (ISnapinAbout::GetStaticFolderImage()) but
  292. // possibly is now handled like other scope items.
  293. SCOPEDATAITEM sdi = {0};
  294. sdi.mask = SDI_STR |
  295. SDI_IMAGE | // nImage is valid
  296. SDI_OPENIMAGE; // nOpenImage is valid
  297. sdi.ID = hID;
  298. sdi.displayname = (LPOLESTR)MMC_CALLBACK;
  299. sdi.nImage = sImage();
  300. sdi.nOpenImage = sOpenImage();
  301. VERIFY( S_OK == ipConsoleNameSpace2->SetItem(&sdi) );
  302. VERIFY( S_OK == AddNodes(ipConsoleNameSpace2) );
  303. }
  304. return S_OK; // return has no meaning to MMC
  305. } // end OnExpand()
  306. HRESULT CRootFolder::AddNodes(IConsoleNameSpace2 *ipConsoleNameSpace2)
  307. {
  308. VERIFY( S_OK == AddNode(ipConsoleNameSpace2, new CRuleFolder(this) ) );
  309. VERIFY( S_OK == AddNode(ipConsoleNameSpace2, new CProcessFolder(this) ) );
  310. VERIFY( S_OK == AddNode(ipConsoleNameSpace2, new CJobFolder(this) ) );
  311. return S_OK;
  312. }
  313. HRESULT CRootFolder::AddNode(IConsoleNameSpace2 *ipConsoleNameSpace2, CBaseNode *pSubNode)
  314. {
  315. HRESULT hr = S_OK;
  316. SCOPEDATAITEM sdi = {0};
  317. if (!pSubNode)
  318. return E_OUTOFMEMORY;
  319. // Place folder into the scope pane
  320. sdi.mask = SDI_STR | // Displayname is valid
  321. SDI_PARAM | // lParam is valid
  322. SDI_IMAGE | // nImage is valid
  323. SDI_OPENIMAGE | // nOpenImage is valid
  324. SDI_CHILDREN | // cChildren is valid
  325. SDI_PARENT;
  326. sdi.displayname = (LPOLESTR)MMC_CALLBACK;
  327. sdi.nImage = pSubNode->sImage();
  328. sdi.nOpenImage = pSubNode->sOpenImage();
  329. //sdi.nState
  330. sdi.cChildren = pSubNode->GetChildrenCount();
  331. sdi.lParam = reinterpret_cast <LPARAM> (pSubNode);
  332. sdi.relativeID = m_ID;
  333. hr = ipConsoleNameSpace2->InsertItem( &sdi );
  334. if (SUCCEEDED(hr))
  335. {
  336. pSubNode->SetID(sdi.ID);
  337. m_NodeList.push_front( pSubNode );
  338. }
  339. else
  340. {
  341. pSubNode->Release();
  342. //delete pSubNode;
  343. }
  344. return hr;
  345. }
  346. //IComponentData::Notify -- MNCN_REMOVE_CHILDREN
  347. HRESULT CRootFolder::OnParentRemoveChildren(HSCOPEITEM hID)
  348. {
  349. ASSERT(hID == m_ParentID);
  350. if (hID == m_ParentID)
  351. return OnRemoveChildren(m_ID);
  352. return E_UNEXPECTED;
  353. }
  354. HRESULT CRootFolder::OnRemoveChildren(HSCOPEITEM hID)
  355. {
  356. ASSERT(m_ID == hID);
  357. FreeNodes();
  358. m_ID = 0;
  359. return S_OK;
  360. }
  361. HRESULT CRootFolder::AddMenuItems(LPCONTEXTMENUCALLBACK piCallback, long * pInsertionAllowed)
  362. {
  363. HRESULT hr = S_OK;
  364. // 10/2/1998 PAS
  365. // when the snapin is first loaded and the root node has not yet been expanded or
  366. // selected than we haven't yet been able to save the ID.
  367. // The right click context menu can be invoked when the node has no yet been expanded or
  368. // selected, if we haven't yet gotten the ID we have no way to change the selection
  369. // node so the menu command can't be supported yet.
  370. if (!m_ID)
  371. return S_FALSE;
  372. ITEM_STR name;
  373. ITEM_STR status;
  374. if( *pInsertionAllowed & CCM_INSERTIONALLOWED_TOP )
  375. {
  376. CONTEXTMENUITEM m = { 0 };
  377. for (const CONTEXTMENUITEMBYID *M = TaskMenuItems; M->lCommandID; M++)
  378. {
  379. m.strName = const_cast<TCHAR *>(LoadStringHelper(name, M->strNameID));
  380. m.strStatusBarText = const_cast<TCHAR *>(LoadStringHelper(status, M->strStatusBarTextID));
  381. m.lCommandID = M->lCommandID;
  382. m.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
  383. m.fFlags = MF_ENABLED;
  384. //m.fSpecialFlags = 0; // currently always 0, initialized to 0
  385. if (m.lCommandID == ID_ROOT_CONNECT && m_ParentID)
  386. continue;
  387. hr = piCallback->AddItem(&m);
  388. if (FAILED(hr))
  389. break;
  390. }
  391. }
  392. if( *pInsertionAllowed & CCM_INSERTIONALLOWED_TASK )
  393. {
  394. CONTEXTMENUITEM m = { 0 };
  395. for (const CONTEXTMENUITEMBYID *M = TaskMenuItems; M->lCommandID; M++)
  396. {
  397. m.strName = const_cast<TCHAR *>(LoadStringHelper(name, M->strNameID));
  398. m.strStatusBarText = const_cast<TCHAR *>(LoadStringHelper(status, M->strStatusBarTextID));
  399. m.lCommandID = M->lCommandID;
  400. m.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TASK;
  401. m.fFlags = MF_ENABLED;
  402. //m.fSpecialFlags = 0; // currently always 0, initialized to 0
  403. if (m.lCommandID == ID_ROOT_CONNECT && m_ParentID)
  404. continue;
  405. hr = piCallback->AddItem(&m);
  406. if (FAILED(hr))
  407. break;
  408. }
  409. }
  410. return hr;
  411. }
  412. HRESULT CRootFolder::OnMenuCommand(IConsole2 *ipConsole2, long nCommandID )
  413. {
  414. HRESULT hr = S_FALSE;
  415. switch(nCommandID)
  416. {
  417. case ID_ROOT_CONNECT:
  418. ATLTRACE(_T("CRootFolder(%s)-OnMenuCommand Connect to another computer\n"), GetNodeName());
  419. hr = OnChangeComputerConnection();
  420. break;
  421. default:
  422. ATLTRACE(_T("CRootFolder(%s)-OnMenuCommand Unrecognized command 0x%lX\n"), GetNodeName(), nCommandID);
  423. break;
  424. }
  425. return hr;
  426. }
  427. HRESULT CRootFolder::OnMenuCommand(IConsole2 *ipConsole2, long nCommandID, LPARAM Cookie)
  428. {
  429. ATLTRACE(_T("CRootFolder(%s)-OnMenuCommand Unrecognized command 0x%lX\n"), GetNodeName(), nCommandID);
  430. return E_UNEXPECTED;
  431. }
  432. HRESULT CRootFolder::OnChangeComputerConnection()
  433. {
  434. CRootWizard2 *pPage2 = new CRootWizard2(CRootWizard2::LASTANDONLY_PAGE, IDS_CONNECT_TITLE, this);
  435. if (!pPage2)
  436. return S_FALSE;
  437. PROPSHEETHEADER sheet;
  438. memset(&sheet, 0, sizeof(PROPSHEETHEADER));
  439. sheet.dwSize = sizeof(PROPSHEETHEADER);
  440. sheet.dwFlags = PSH_WIZARD | PSH_WIZARDCONTEXTHELP;
  441. sheet.hwndParent = ::GetActiveWindow();
  442. sheet.hInstance = _Module.GetResourceInstance();
  443. sheet.pszIcon = 0;
  444. sheet.pszCaption = 0;
  445. sheet.nPages = 1;
  446. sheet.nStartPage = 0;
  447. #if USE_WIZARD97_WATERMARKS
  448. sheet.dwFlags |= PSH_WIZARD97 | PSH_WATERMARK;
  449. sheet.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK1);
  450. #endif
  451. #if USE_WIZARD97_HEADERS
  452. sheet.dwFlags |= PSH_WIZARD97 | PSH_HEADER;
  453. sheet.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER1);
  454. #endif
  455. HPROPSHEETPAGE hPages[1];
  456. hPages[0] = pPage2->Create();
  457. sheet.phpage = &hPages[0];
  458. sheet.pfnCallback = NULL;
  459. PropertySheet(&sheet);
  460. return S_OK;
  461. }
  462. // folder selection...
  463. HRESULT CRootFolder::OnSelect(BOOL bScope, BOOL bSelect, IConsoleVerb* ipConsoleVerb)
  464. {
  465. ASSERT(bScope);
  466. if (bSelect)
  467. {
  468. // allow properties verb to work when context menu is used in scope or result pane
  469. VERIFY( ipConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, TRUE ) == S_OK);
  470. if (!bScope) // incase the rules are changed again leave !bScope test
  471. {
  472. VERIFY( ipConsoleVerb->SetVerbState( MMC_VERB_OPEN, ENABLED, TRUE ) == S_OK);
  473. VERIFY( ipConsoleVerb->SetDefaultVerb( MMC_VERB_OPEN ) == S_OK );
  474. }
  475. }
  476. return S_OK;
  477. }
  478. HRESULT CRootFolder::OnSelect(BOOL bScope, BOOL bSelect, IConsoleVerb* ipConsoleVerb, LPARAM Cookie)
  479. {
  480. ASSERT(!bScope);
  481. if (bSelect)
  482. {
  483. // allow properties verb to work when context menu is used in scope or result pane
  484. VERIFY( ipConsoleVerb->SetVerbState( MMC_VERB_PROPERTIES, ENABLED, TRUE ) == S_OK);
  485. // why this seems to be a meaningless test
  486. // changes between MMC 1.1 vs MMC 1.2 (as least in the documentation)
  487. // as to whether bScope mean scope pane or scope item
  488. // leave this in for the time being
  489. if (!bScope) // incase the rules are changed again leave !bScope test
  490. {
  491. VERIFY( ipConsoleVerb->SetVerbState( MMC_VERB_OPEN, ENABLED, TRUE ) == S_OK);
  492. VERIFY( ipConsoleVerb->SetDefaultVerb( MMC_VERB_OPEN ) == S_OK );
  493. }
  494. }
  495. return S_OK;
  496. }
  497. HRESULT CRootFolder::QueryPagesFor()
  498. {
  499. return S_OK;
  500. }
  501. HRESULT CRootFolder::OnCreatePropertyPages( LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, DATA_OBJECT_TYPES context)
  502. {
  503. if (context == CCT_SNAPIN_MANAGER)
  504. {
  505. CRootWizard1 *pPage1 = new CRootWizard1(CRootWizard1::FIRST_PAGE, IDS_ADDSNAPIN_TITLE);
  506. CRootWizard2 *pPage2 = new CRootWizard2(CRootWizard2::LAST_PAGE, IDS_ADDSNAPIN_TITLE, this);
  507. if (!pPage1 || !pPage2)
  508. return S_FALSE;
  509. ASSERT(handle == NULL); // $$ behavior change, better see what's going on...
  510. // previously context of CCT_SNAPIN_MANAGER, the handle was always null so
  511. // ...access the the folder object directly was assumed to be a valid operation
  512. VERIFY(lpProvider->AddPage(pPage1->Create()) == S_OK);
  513. return lpProvider->AddPage(pPage2->Create());
  514. }
  515. else
  516. {
  517. COMPUTER_CONNECTION_INFO ConnInfo;
  518. GetComputerConnectionInfo(ConnInfo);
  519. CRootGeneralPage *pPage1 = new CRootGeneralPage(NULL);
  520. if (pPage1)
  521. lpProvider->AddPage(pPage1->Create());
  522. CRootVersionPage *pPage2 = new CRootVersionPage(NULL);
  523. if (pPage2)
  524. lpProvider->AddPage(pPage2->Create());
  525. PCSystemInfo sysInfo;
  526. PCid hID = GetPCid();
  527. if (PCGetServiceInfo( hID, &sysInfo, sizeof(sysInfo) ))
  528. {
  529. CServicePageContainer *pContainer = new CServicePageContainer(sysInfo.sysParms, this, handle, hID, ConnInfo, 0, TRUE, -1);
  530. if (pContainer)
  531. {
  532. CRootServicePage *pPage3 = new CRootServicePage(NULL, pContainer);
  533. if (pPage3)
  534. {
  535. pPage3->PCInfo = sysInfo;
  536. lpProvider->AddPage(pPage3->Create());
  537. }
  538. pContainer->Release();
  539. pContainer = NULL;
  540. }
  541. }
  542. else
  543. {
  544. VERIFY(S_OK == MMCFreeNotifyHandle(handle));
  545. }
  546. return S_OK;
  547. }
  548. return S_FALSE;
  549. }
  550. HRESULT CRootFolder::OnPropertyChange(PROPERTY_CHANGE_HDR *pUpdate, IConsole2 *ipConsole2)
  551. {
  552. ATLTRACE(_T("Service Info updated via property page...\n"));
  553. return S_OK;
  554. }