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.

2218 lines
68 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // BasePage.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the CBasePropertyPage class.
  10. //
  11. // Author:
  12. // David Potter (davidp) June 28, 1996
  13. //
  14. // Revision History:
  15. // 1. Removed the calls to UpdateData from OnWizardNext and OnApply
  16. // since OnKillActive, called before both these functions does a
  17. // data update anyway.
  18. //
  19. // Notes:
  20. //
  21. /////////////////////////////////////////////////////////////////////////////
  22. #include "stdafx.h"
  23. #include "CluAdmX.h"
  24. #include "ExtObj.h"
  25. #include "BasePage.h"
  26. #include "BasePage.inl"
  27. #include "PropList.h"
  28. #include "ExcOper.h"
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CBasePropertyPage property page
  36. /////////////////////////////////////////////////////////////////////////////
  37. IMPLEMENT_DYNCREATE( CBasePropertyPage, CPropertyPage )
  38. /////////////////////////////////////////////////////////////////////////////
  39. // Message Maps
  40. BEGIN_MESSAGE_MAP( CBasePropertyPage, CPropertyPage )
  41. //{{AFX_MSG_MAP(CBasePropertyPage)
  42. ON_WM_CREATE()
  43. ON_WM_DESTROY()
  44. ON_WM_HELPINFO()
  45. ON_WM_CONTEXTMENU()
  46. ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  47. //}}AFX_MSG_MAP
  48. END_MESSAGE_MAP()
  49. /////////////////////////////////////////////////////////////////////////////
  50. //++
  51. //
  52. // CBasePropertyPage::CBasePropertyPage
  53. //
  54. // Routine Description:
  55. // Default constructor.
  56. //
  57. // Arguments:
  58. // None.
  59. //
  60. // Return Value:
  61. // None.
  62. //
  63. //--
  64. /////////////////////////////////////////////////////////////////////////////
  65. CBasePropertyPage::CBasePropertyPage( void )
  66. {
  67. CommonConstruct();
  68. } //*** CBasePropertyPage::CBasePropertyPage()
  69. /////////////////////////////////////////////////////////////////////////////
  70. //++
  71. //
  72. // CBasePropertyPage::CBasePropertyPage
  73. //
  74. // Routine Description:
  75. // Default constructor.
  76. //
  77. // Arguments:
  78. // pdwHelpMap [IN] Control-to-help ID map.
  79. // pdwWizardHelpMap [IN] Control-to-help ID map if this is a wizard page.
  80. //
  81. // Return Value:
  82. // None.
  83. //
  84. //--
  85. /////////////////////////////////////////////////////////////////////////////
  86. CBasePropertyPage::CBasePropertyPage(
  87. IN const DWORD * pdwHelpMap,
  88. IN const DWORD * pdwWizardHelpMap
  89. )
  90. : m_dlghelp( pdwHelpMap, 0 )
  91. {
  92. CommonConstruct();
  93. m_pdwWizardHelpMap = pdwWizardHelpMap;
  94. } //*** CBasePropertyPage::CBasePropertyPage()
  95. /////////////////////////////////////////////////////////////////////////////
  96. //++
  97. //
  98. // CBasePropertyPage::CBasePropertyPage
  99. //
  100. // Routine Description:
  101. // Default constructor.
  102. //
  103. // Arguments:
  104. // idd [IN] Dialog template resource ID.
  105. // pdwHelpMap [IN] Control-to-help ID map.
  106. // pdwWizardHelpMap [IN] Control-to-help ID map if this is a wizard page.
  107. // nIDCaption [IN] Caption string resource ID.
  108. //
  109. // Return Value:
  110. // None.
  111. //
  112. //--
  113. /////////////////////////////////////////////////////////////////////////////
  114. CBasePropertyPage::CBasePropertyPage(
  115. IN UINT idd,
  116. IN const DWORD * pdwHelpMap,
  117. IN const DWORD * pdwWizardHelpMap,
  118. IN UINT nIDCaption
  119. )
  120. : CPropertyPage( idd, nIDCaption )
  121. , m_dlghelp( pdwHelpMap, idd )
  122. {
  123. CommonConstruct();
  124. m_pdwWizardHelpMap = pdwWizardHelpMap;
  125. } //*** CBasePropertyPage::CBasePropertyPage(UINT, UINT)
  126. /////////////////////////////////////////////////////////////////////////////
  127. //++
  128. //
  129. // CBasePropertyPage::CommonConstruct
  130. //
  131. // Routine Description:
  132. // Common construction.
  133. //
  134. // Arguments:
  135. // None.
  136. //
  137. // Return Value:
  138. // None.
  139. //
  140. //--
  141. /////////////////////////////////////////////////////////////////////////////
  142. void CBasePropertyPage::CommonConstruct( void )
  143. {
  144. //{{AFX_DATA_INIT(CBasePropertyPage)
  145. //}}AFX_DATA_INIT
  146. m_peo = NULL;
  147. m_hpage = NULL;
  148. m_bBackPressed = FALSE;
  149. m_bSaved = FALSE;
  150. m_iddPropertyPage = NULL;
  151. m_iddWizardPage = NULL;
  152. m_idsCaption = NULL;
  153. m_pdwWizardHelpMap = NULL;
  154. m_bDoDetach = FALSE;
  155. } //*** CBasePropertyPage::CommonConstruct()
  156. /////////////////////////////////////////////////////////////////////////////
  157. //++
  158. //
  159. // CBasePropertyPage::HrInit
  160. //
  161. // Routine Description:
  162. // Initialize the page.
  163. //
  164. // Arguments:
  165. // peo [IN OUT] Pointer to the extension object.
  166. //
  167. // Return Value:
  168. // S_OK Page initialized successfully.
  169. // hr Error initializing the page.
  170. //
  171. //--
  172. /////////////////////////////////////////////////////////////////////////////
  173. HRESULT CBasePropertyPage::HrInit( IN OUT CExtObject * peo )
  174. {
  175. ASSERT( peo != NULL );
  176. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  177. HRESULT hr = S_OK;
  178. CWaitCursor wc;
  179. m_peo = peo;
  180. // Change the help map if this is a wizard page.
  181. if ( Peo()->BWizard() )
  182. {
  183. m_dlghelp.SetMap( m_pdwWizardHelpMap );
  184. } // if: on wizard page
  185. // Don't display a help button.
  186. m_psp.dwFlags &= ~PSP_HASHELP;
  187. // Construct the property page.
  188. if ( Peo()->BWizard() )
  189. {
  190. ASSERT( IddWizardPage() != NULL );
  191. Construct( IddWizardPage(), IdsCaption() );
  192. m_dlghelp.SetHelpMask( IddWizardPage() );
  193. } // if: adding page to wizard
  194. else
  195. {
  196. ASSERT( IddPropertyPage() != NULL );
  197. Construct( IddPropertyPage(), IdsCaption() );
  198. m_dlghelp.SetHelpMask( IddPropertyPage() );
  199. } // else: adding page to property sheet
  200. // Read the properties private to this resource and parse them.
  201. {
  202. DWORD sc;
  203. CClusPropList cpl;
  204. ASSERT( Peo() != NULL );
  205. ASSERT( Peo()->PrdResData() != NULL );
  206. ASSERT( Peo()->PrdResData()->m_hresource != NULL );
  207. // Get the read-write private properties.
  208. sc = cpl.ScGetResourceProperties(
  209. Peo()->PrdResData()->m_hresource,
  210. CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES
  211. );
  212. // Parse the properties.
  213. if ( sc == ERROR_SUCCESS )
  214. {
  215. // Parse the properties.
  216. try
  217. {
  218. sc = ScParseProperties( cpl );
  219. } // try
  220. catch ( CMemoryException * pme )
  221. {
  222. sc = ERROR_NOT_ENOUGH_MEMORY;
  223. pme->Delete();
  224. } // catch: CMemoryException
  225. } // if: Properties read successfully.
  226. if ( sc != ERROR_SUCCESS )
  227. {
  228. CNTException nte( sc, IDS_ERROR_GETTING_PROPERTIES, NULL, NULL, FALSE );
  229. nte.ReportError();
  230. hr = HRESULT_FROM_WIN32( sc );
  231. goto Cleanup;
  232. } // if: Error getting or parsing properties.
  233. // Get the read-only private properties.
  234. sc = cpl.ScGetResourceProperties(
  235. Peo()->PrdResData()->m_hresource,
  236. CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES
  237. );
  238. // Parse the properties.
  239. if ( sc == ERROR_SUCCESS )
  240. {
  241. // Parse the properties.
  242. try
  243. {
  244. sc = ScParseProperties( cpl );
  245. } // try
  246. catch ( CMemoryException * pme )
  247. {
  248. sc = ERROR_NOT_ENOUGH_MEMORY;
  249. pme->Delete();
  250. } // catch: CMemoryException
  251. } // if: Properties read successfully.
  252. if ( sc != ERROR_SUCCESS )
  253. {
  254. CNTException nte( sc, IDS_ERROR_GETTING_PROPERTIES, NULL, NULL, FALSE );
  255. nte.ReportError();
  256. hr = HRESULT_FROM_WIN32( sc );
  257. goto Cleanup;
  258. } // if: Error getting or parsing properties.
  259. } // Read the properties private to this resource and parse them.
  260. Cleanup:
  261. return hr;
  262. } //*** CBasePropertyPage::HrInit()
  263. /////////////////////////////////////////////////////////////////////////////
  264. //++
  265. //
  266. // CBasePropertyPage::ScParseProperties
  267. //
  268. // Routine Description:
  269. // Parse the properties of the resource. This is in a separate function
  270. // from HrInit so that the optimizer can do a better job.
  271. //
  272. // Arguments:
  273. // rcpl [IN] Cluster property list to parse.
  274. //
  275. // Return Value:
  276. // ERROR_SUCCESS Properties were parsed successfully.
  277. // Any error returns from ScParseUnknownProperty().
  278. //
  279. // Exceptions Thrown:
  280. // Any exceptions from CString::operator=().
  281. //
  282. //--
  283. /////////////////////////////////////////////////////////////////////////////
  284. DWORD CBasePropertyPage::ScParseProperties( IN CClusPropList & rcpl )
  285. {
  286. DWORD sc;
  287. DWORD cprop;
  288. const CObjectProperty * pprop;
  289. ASSERT( rcpl.PbPropList() != NULL );
  290. sc = rcpl.ScMoveToFirstProperty();
  291. while ( sc == ERROR_SUCCESS )
  292. {
  293. //
  294. // Parse known properties.
  295. //
  296. for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
  297. {
  298. if ( ClRtlStrNICmp( rcpl.PszCurrentPropertyName(), pprop->m_pwszName, rcpl.CbhCurrentPropertyName().pValue->cbLength / sizeof( WCHAR ) ) == 0 )
  299. {
  300. ASSERT( rcpl.CpfCurrentValueFormat() == pprop->m_propFormat );
  301. switch ( pprop->m_propFormat )
  302. {
  303. case CLUSPROP_FORMAT_SZ:
  304. case CLUSPROP_FORMAT_EXPAND_SZ:
  305. ASSERT( ( rcpl.CbCurrentValueLength() == (wcslen( rcpl.CbhCurrentValue().pStringValue->sz ) + 1) * sizeof( WCHAR ) )
  306. || ( ( rcpl.CbCurrentValueLength() == 0 )
  307. && ( rcpl.CbhCurrentValue().pStringValue->sz[ 0 ] == L'\0' )
  308. )
  309. );
  310. *pprop->m_value.pstr = rcpl.CbhCurrentValue().pStringValue->sz;
  311. *pprop->m_valuePrev.pstr = rcpl.CbhCurrentValue().pStringValue->sz;
  312. break;
  313. case CLUSPROP_FORMAT_DWORD:
  314. case CLUSPROP_FORMAT_LONG:
  315. ASSERT( rcpl.CbCurrentValueLength() == sizeof( DWORD ) );
  316. *pprop->m_value.pdw = rcpl.CbhCurrentValue().pDwordValue->dw;
  317. *pprop->m_valuePrev.pdw = rcpl.CbhCurrentValue().pDwordValue->dw;
  318. break;
  319. case CLUSPROP_FORMAT_BINARY:
  320. case CLUSPROP_FORMAT_MULTI_SZ:
  321. delete [] *pprop->m_value.ppb;
  322. *pprop->m_value.ppb = new BYTE[ rcpl.CbhCurrentValue().pBinaryValue->cbLength ];
  323. if ( *pprop->m_value.ppb == NULL )
  324. {
  325. AfxThrowMemoryException();
  326. } // if:
  327. CopyMemory( *pprop->m_value.ppb, rcpl.CbhCurrentValue().pBinaryValue->rgb, rcpl.CbhCurrentValue().pBinaryValue->cbLength );
  328. *pprop->m_value.pcb = rcpl.CbhCurrentValue().pBinaryValue->cbLength;
  329. delete [] *pprop->m_valuePrev.ppb;
  330. *pprop->m_valuePrev.ppb = new BYTE[ rcpl.CbhCurrentValue().pBinaryValue->cbLength ];
  331. if ( *pprop->m_valuePrev.ppb == NULL )
  332. {
  333. AfxThrowMemoryException();
  334. } // if:
  335. CopyMemory( *pprop->m_valuePrev.ppb, rcpl.CbhCurrentValue().pBinaryValue->rgb, rcpl.CbhCurrentValue().pBinaryValue->cbLength );
  336. *pprop->m_valuePrev.pcb = rcpl.CbhCurrentValue().pBinaryValue->cbLength;
  337. break;
  338. default:
  339. ASSERT( 0 ); // don't know how to deal with this type
  340. } // switch: property format
  341. // Exit the loop since we found the parameter.
  342. break;
  343. } // if: found a match
  344. } // for: each property that we know about
  345. //
  346. // If the property wasn't known, ask the derived class to parse it.
  347. //
  348. if ( cprop == 0 )
  349. {
  350. sc = ScParseUnknownProperty(
  351. rcpl.CbhCurrentPropertyName().pName->sz,
  352. rcpl.CbhCurrentValue(),
  353. static_cast< DWORD >( rcpl.RPvlPropertyValue().CbDataLeft() )
  354. );
  355. if ( sc != ERROR_SUCCESS )
  356. {
  357. return sc;
  358. } // if: error parsing the unknown property
  359. } // if: property not parsed
  360. //
  361. // Advance the buffer pointer past the value in the value list.
  362. //
  363. sc = rcpl.ScMoveToNextProperty();
  364. } // while: more properties to parse
  365. //
  366. // If we reached the end of the properties, fix the return code.
  367. //
  368. if ( sc == ERROR_NO_MORE_ITEMS )
  369. {
  370. sc = ERROR_SUCCESS;
  371. } // if: ended loop after parsing all properties
  372. return sc;
  373. } //*** CBasePropertyPage::ScParseProperties()
  374. /////////////////////////////////////////////////////////////////////////////
  375. //++
  376. //
  377. // CBasePropertyPage::OnCreate
  378. //
  379. // Routine Description:
  380. // Handler for the WM_CREATE message.
  381. //
  382. // Arguments:
  383. // lpCreateStruct [IN OUT] Window create structure.
  384. //
  385. // Return Value:
  386. // -1 Error.
  387. // 0 Success.
  388. //
  389. //--
  390. /////////////////////////////////////////////////////////////////////////////
  391. int CBasePropertyPage::OnCreate( LPCREATESTRUCT lpCreateStruct )
  392. {
  393. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  394. // Attach the window to the property page structure.
  395. // This has been done once already in the main application, since the
  396. // main application owns the property sheet. It needs to be done here
  397. // so that the window handle can be found in the DLL's handle map.
  398. if ( FromHandlePermanent( m_hWnd ) == NULL ) // is the window handle already in the handle map
  399. {
  400. HWND hWnd = m_hWnd;
  401. m_hWnd = NULL;
  402. Attach( hWnd );
  403. m_bDoDetach = TRUE;
  404. } // if: is the window handle in the handle map
  405. return CPropertyPage::OnCreate( lpCreateStruct );
  406. } //*** CBasePropertyPage::OnCreate()
  407. /////////////////////////////////////////////////////////////////////////////
  408. //++
  409. //
  410. // CBasePropertyPage::OnDestroy
  411. //
  412. // Routine Description:
  413. // Handler for the WM_DESTROY message.
  414. //
  415. // Arguments:
  416. // None.
  417. //
  418. // Return Value:
  419. // None.
  420. //
  421. //--
  422. /////////////////////////////////////////////////////////////////////////////
  423. void CBasePropertyPage::OnDestroy( void )
  424. {
  425. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  426. // Detach the window from the property page structure.
  427. // This will be done again by the main application, since it owns the
  428. // property sheet. It needs to be done here so that the window handle
  429. // can be removed from the DLL's handle map.
  430. if ( m_bDoDetach )
  431. {
  432. if ( m_hWnd != NULL )
  433. {
  434. HWND hWnd = m_hWnd;
  435. Detach();
  436. m_hWnd = hWnd;
  437. } // if: do we have a window handle?
  438. } // if: do we need to balance the attach we did with a detach?
  439. CPropertyPage::OnDestroy();
  440. } //*** CBasePropertyPage::OnDestroy()
  441. /////////////////////////////////////////////////////////////////////////////
  442. //++
  443. //
  444. // CBasePropertyPage::DoDataExchange
  445. //
  446. // Routine Description:
  447. // Do data exchange between the dialog and the class.
  448. //
  449. // Arguments:
  450. // pDX [IN OUT] Data exchange object
  451. //
  452. // Return Value:
  453. // None.
  454. //
  455. //--
  456. /////////////////////////////////////////////////////////////////////////////
  457. void CBasePropertyPage::DoDataExchange( CDataExchange * pDX )
  458. {
  459. if ( ! pDX->m_bSaveAndValidate || !BSaved() )
  460. {
  461. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  462. //{{AFX_DATA_MAP(CBasePropertyPage)
  463. // NOTE: the ClassWizard will add DDX and DDV calls here
  464. //}}AFX_DATA_MAP
  465. DDX_Control( pDX, IDC_PP_ICON, m_staticIcon );
  466. DDX_Control( pDX, IDC_PP_TITLE, m_staticTitle );
  467. if ( pDX->m_bSaveAndValidate )
  468. {
  469. if ( ! BBackPressed() )
  470. {
  471. CWaitCursor wc;
  472. // Validate the data.
  473. if ( ! BSetPrivateProps( TRUE /*bValidateOnly*/ ) )
  474. {
  475. pDX->Fail();
  476. } // if: error setting private properties
  477. } // if: Back button not pressed
  478. } // if: saving data from dialog
  479. else
  480. {
  481. // Set the title.
  482. DDX_Text( pDX, IDC_PP_TITLE, m_strTitle );
  483. } // if: not saving data
  484. } // if: not saving or haven't saved yet
  485. CPropertyPage::DoDataExchange( pDX );
  486. } //*** CBasePropertyPage::DoDataExchange()
  487. /////////////////////////////////////////////////////////////////////////////
  488. //++
  489. //
  490. // CBasePropertyPage::OnInitDialog
  491. //
  492. // Routine Description:
  493. // Handler for the WM_INITDIALOG message.
  494. //
  495. // Arguments:
  496. // None.
  497. //
  498. // Return Value:
  499. // TRUE We need the focus to be set for us.
  500. // FALSE We already set the focus to the proper control.
  501. //
  502. //--
  503. /////////////////////////////////////////////////////////////////////////////
  504. BOOL CBasePropertyPage::OnInitDialog( void )
  505. {
  506. ASSERT( Peo() != NULL );
  507. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  508. // Set the title string.
  509. m_strTitle = Peo()->RrdResData().m_strName;
  510. // Call the base class method.
  511. CPropertyPage::OnInitDialog();
  512. // Display an icon for the object.
  513. if ( Peo()->Hicon() != NULL )
  514. {
  515. m_staticIcon.SetIcon( Peo()->Hicon() );
  516. } // if: icon was specified
  517. return TRUE; // return TRUE unless you set the focus to a control
  518. // EXCEPTION: OCX Property Pages should return FALSE
  519. } //*** CBasePropertyPage::OnInitDialog()
  520. /////////////////////////////////////////////////////////////////////////////
  521. //++
  522. //
  523. // CBasePropertyPage::OnSetActive
  524. //
  525. // Routine Description:
  526. // Handler for the PSN_SETACTIVE message.
  527. //
  528. // Arguments:
  529. // None.
  530. //
  531. // Return Value:
  532. // TRUE Page successfully initialized.
  533. // FALSE Page not initialized.
  534. //
  535. //--
  536. /////////////////////////////////////////////////////////////////////////////
  537. BOOL CBasePropertyPage::OnSetActive( void )
  538. {
  539. HRESULT hr;
  540. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  541. // Reread the data.
  542. hr = Peo()->HrGetObjectInfo();
  543. if ( hr != NOERROR )
  544. {
  545. return FALSE;
  546. } // if: error getting object info
  547. // Set the title string.
  548. m_strTitle = Peo()->RrdResData().m_strName;
  549. m_bBackPressed = FALSE;
  550. m_bSaved = FALSE;
  551. return CPropertyPage::OnSetActive();
  552. } //*** CBasePropertyPage::OnSetActive()
  553. /////////////////////////////////////////////////////////////////////////////
  554. //++
  555. //
  556. // CBasePropertyPage::OnApply
  557. //
  558. // Routine Description:
  559. // Handler for the PSM_APPLY message.
  560. //
  561. // Arguments:
  562. // None.
  563. //
  564. // Return Value:
  565. // TRUE Page successfully applied.
  566. // FALSE Error applying page.
  567. //
  568. //--
  569. /////////////////////////////////////////////////////////////////////////////
  570. BOOL CBasePropertyPage::OnApply( void )
  571. {
  572. ASSERT( ! BWizard() );
  573. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  574. CWaitCursor wc;
  575. if ( ! BApplyChanges() )
  576. {
  577. return FALSE;
  578. } // if: error applying changes
  579. return CPropertyPage::OnApply();
  580. } //*** CBasePropertyPage::OnApply()
  581. /////////////////////////////////////////////////////////////////////////////
  582. //++
  583. //
  584. // CBasePropertyPage::OnWizardBack
  585. //
  586. // Routine Description:
  587. // Handler for the PSN_WIZBACK message.
  588. //
  589. // Arguments:
  590. // None.
  591. //
  592. // Return Value:
  593. // -1 Don't change the page.
  594. // 0 Change the page.
  595. //
  596. //--
  597. /////////////////////////////////////////////////////////////////////////////
  598. LRESULT CBasePropertyPage::OnWizardBack( void )
  599. {
  600. LRESULT lResult;
  601. ASSERT( BWizard() );
  602. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  603. lResult = CPropertyPage::OnWizardBack();
  604. if ( lResult != -1 )
  605. {
  606. m_bBackPressed = TRUE;
  607. } // if: back processing performed successfully
  608. return lResult;
  609. } //*** CBasePropertyPage::OnWizardBack()
  610. /////////////////////////////////////////////////////////////////////////////
  611. //++
  612. //
  613. // CBasePropertyPage::OnWizardNext
  614. //
  615. // Routine Description:
  616. // Handler for the PSN_WIZNEXT message.
  617. //
  618. // Arguments:
  619. // None.
  620. //
  621. // Return Value:
  622. // -1 Don't change the page.
  623. // 0 Change the page.
  624. //
  625. //--
  626. /////////////////////////////////////////////////////////////////////////////
  627. LRESULT CBasePropertyPage::OnWizardNext( void )
  628. {
  629. ASSERT( BWizard() );
  630. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  631. CWaitCursor _wc;
  632. // Update the data in the class from the page.
  633. // This necessary because, while OnKillActive() will call UpdateData(),
  634. // it is called after this method is called, and we need to be sure that
  635. // data has been saved before we apply them.
  636. if ( ! UpdateData( TRUE /*bSaveAndValidate*/ ) )
  637. {
  638. return -1;
  639. } // if: error updating data
  640. // Save the data in the sheet.
  641. if ( ! BApplyChanges() )
  642. {
  643. return -1;
  644. } // if: error applying changes
  645. // Create the object.
  646. return CPropertyPage::OnWizardNext();
  647. } //*** CBasePropertyPage::OnWizardNext()
  648. /////////////////////////////////////////////////////////////////////////////
  649. //++
  650. //
  651. // CBasePropertyPage::OnWizardFinish
  652. //
  653. // Routine Description:
  654. // Handler for the PSN_WIZFINISH message.
  655. //
  656. // Arguments:
  657. // None.
  658. //
  659. // Return Value:
  660. // FALSE Don't change the page.
  661. // TRUE Change the page.
  662. //
  663. //--
  664. /////////////////////////////////////////////////////////////////////////////
  665. BOOL CBasePropertyPage::OnWizardFinish( void )
  666. {
  667. ASSERT( BWizard() );
  668. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  669. CWaitCursor wc;
  670. // BUG! There should be no need to call UpdateData in this function.
  671. // See BUG: Finish Button Fails Data Transfer from Page to Variables
  672. // MSDN Article ID: Q150349
  673. // Update the data in the class from the page.
  674. if ( ! UpdateData( TRUE /*bSaveAndValidate*/ ) )
  675. {
  676. return FALSE;
  677. } // if: error updating data
  678. // Save the data in the sheet.
  679. if ( ! BApplyChanges() )
  680. {
  681. return FALSE;
  682. } // if: error applying changes
  683. return CPropertyPage::OnWizardFinish();
  684. } //*** CBasePropertyPage::OnWizardFinish()
  685. /////////////////////////////////////////////////////////////////////////////
  686. //++
  687. //
  688. // CBasePropertyPage::OnChangeCtrl
  689. //
  690. // Routine Description:
  691. // Handler for the messages sent when a control is changed. This
  692. // method can be specified in a message map if all that needs to be
  693. // done is enable the Apply button.
  694. //
  695. // Arguments:
  696. // None.
  697. //
  698. // Return Value:
  699. // None.
  700. //
  701. //--
  702. /////////////////////////////////////////////////////////////////////////////
  703. void CBasePropertyPage::OnChangeCtrl( void )
  704. {
  705. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  706. SetModified( TRUE );
  707. } //*** CBasePropertyPage::OnChangeCtrl()
  708. /////////////////////////////////////////////////////////////////////////////
  709. //++
  710. //
  711. // CBasePropertyPage::EnableNext
  712. //
  713. // Routine Description:
  714. // Enables or disables the NEXT or FINISH button.
  715. //
  716. // Arguments:
  717. // bEnable [IN] TRUE = enable the button, FALSE = disable the button.
  718. //
  719. // Return Value:
  720. // None.
  721. //
  722. //--
  723. /////////////////////////////////////////////////////////////////////////////
  724. void CBasePropertyPage::EnableNext( IN BOOL bEnable /*TRUE*/ )
  725. {
  726. ASSERT( BWizard() );
  727. ASSERT( PiWizardCallback() );
  728. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  729. PiWizardCallback()->EnableNext( (LONG *) Hpage(), bEnable );
  730. } //*** CBasePropertyPage::EnableNext()
  731. /////////////////////////////////////////////////////////////////////////////
  732. //++
  733. //
  734. // CBasePropertyPage::BApplyChanges
  735. //
  736. // Routine Description:
  737. // Apply changes made on the page.
  738. //
  739. // Arguments:
  740. // None.
  741. //
  742. // Return Value:
  743. // TRUE Page successfully applied.
  744. // FALSE Error applying page.
  745. //
  746. //--
  747. /////////////////////////////////////////////////////////////////////////////
  748. BOOL CBasePropertyPage::BApplyChanges( void )
  749. {
  750. AFX_MANAGE_STATE( AfxGetStaticModuleState() );
  751. BOOL bSuccess;
  752. CWaitCursor wc;
  753. // Make sure required dependencies have been set.
  754. if ( ! BSetPrivateProps() )
  755. {
  756. bSuccess = FALSE;
  757. } // if: all required dependencies are not present
  758. else
  759. {
  760. // Save data.
  761. bSuccess = BRequiredDependenciesPresent();
  762. } // else: all required dependencies are present
  763. return bSuccess;
  764. } //*** CBasePropertyPage::BApplyChanges()
  765. /////////////////////////////////////////////////////////////////////////////
  766. //++
  767. //
  768. // CBasePropertyPage::BBuildPropList
  769. //
  770. // Routine Description:
  771. // Build the property list.
  772. //
  773. // Arguments:
  774. // rcpl [IN OUT] Cluster property list.
  775. // bNoNewProps [IN] TRUE = exclude properties marked with opfNew.
  776. //
  777. // Return Value:
  778. // TRUE Property list built successfully.
  779. // FALSE Error building property list.
  780. //
  781. // Exceptions Thrown:
  782. // Any exceptions thrown by CClusPropList::ScAddProp().
  783. //
  784. //--
  785. /////////////////////////////////////////////////////////////////////////////
  786. BOOL CBasePropertyPage::BBuildPropList(
  787. IN OUT CClusPropList & rcpl,
  788. IN BOOL bNoNewProps // = FALSE
  789. )
  790. {
  791. BOOL bNewPropsFound = FALSE;
  792. DWORD cprop;
  793. const CObjectProperty * pprop;
  794. for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
  795. {
  796. if ( bNoNewProps && ( pprop->m_fFlags & CObjectProperty::opfNew ) )
  797. {
  798. bNewPropsFound = TRUE;
  799. continue;
  800. } // if: no new props allowed and this is a new property
  801. switch ( pprop->m_propFormat )
  802. {
  803. case CLUSPROP_FORMAT_SZ:
  804. rcpl.ScAddProp(
  805. pprop->m_pwszName,
  806. *pprop->m_value.pstr,
  807. *pprop->m_valuePrev.pstr
  808. );
  809. break;
  810. case CLUSPROP_FORMAT_EXPAND_SZ:
  811. rcpl.ScAddExpandSzProp(
  812. pprop->m_pwszName,
  813. *pprop->m_value.pstr,
  814. *pprop->m_valuePrev.pstr
  815. );
  816. break;
  817. case CLUSPROP_FORMAT_DWORD:
  818. rcpl.ScAddProp(
  819. pprop->m_pwszName,
  820. *pprop->m_value.pdw,
  821. *pprop->m_valuePrev.pdw
  822. );
  823. break;
  824. case CLUSPROP_FORMAT_LONG:
  825. rcpl.ScAddProp(
  826. pprop->m_pwszName,
  827. *pprop->m_value.pl,
  828. *pprop->m_valuePrev.pl
  829. );
  830. break;
  831. case CLUSPROP_FORMAT_BINARY:
  832. case CLUSPROP_FORMAT_MULTI_SZ:
  833. rcpl.ScAddProp(
  834. pprop->m_pwszName,
  835. *pprop->m_value.ppb,
  836. *pprop->m_value.pcb,
  837. *pprop->m_valuePrev.ppb,
  838. *pprop->m_valuePrev.pcb
  839. );
  840. break;
  841. default:
  842. ASSERT( 0 ); // don't know how to deal with this type
  843. return FALSE;
  844. } // switch: property format
  845. } // for: each property
  846. return ( ! bNoNewProps || bNewPropsFound );
  847. } //*** CBasePropertyPage::BBuildPropList()
  848. /////////////////////////////////////////////////////////////////////////////
  849. //++
  850. //
  851. // CBasePropertyPage::BSetPrivateProps
  852. //
  853. // Routine Description:
  854. // Set the private properties for this object.
  855. //
  856. // Arguments:
  857. // bValidateOnly [IN] TRUE = only validate the data.
  858. // bNoNewProps [IN] TRUE = exclude properties marked with opfNew.
  859. //
  860. // Return Value:
  861. // ERROR_SUCCESS The operation was completed successfully.
  862. // !0 Failure.
  863. //
  864. //--
  865. /////////////////////////////////////////////////////////////////////////////
  866. BOOL CBasePropertyPage::BSetPrivateProps(
  867. IN BOOL bValidateOnly, // = FALSE
  868. IN BOOL bNoNewProps // = FALSE
  869. )
  870. {
  871. BOOL bSuccess = TRUE;
  872. CClusPropList cpl(BWizard() /*bAlwaysAddProp*/);
  873. ASSERT( Peo() != NULL );
  874. ASSERT( Peo()->PrdResData() );
  875. ASSERT( Peo()->PrdResData()->m_hresource );
  876. // Build the property list.
  877. try
  878. {
  879. bSuccess = BBuildPropList( cpl, bNoNewProps );
  880. } // try
  881. catch ( CException * pe )
  882. {
  883. pe->ReportError();
  884. pe->Delete();
  885. bSuccess = FALSE;
  886. } // catch: CException
  887. // Set the data.
  888. if ( bSuccess )
  889. {
  890. if ( ( cpl.PbPropList() != NULL ) && ( cpl.CbPropList() > 0 ) )
  891. {
  892. DWORD sc;
  893. DWORD dwControlCode;
  894. DWORD cbProps;
  895. // Determine which control code to use.
  896. if ( bValidateOnly )
  897. {
  898. dwControlCode = CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES;
  899. } // if: only validating
  900. else
  901. {
  902. dwControlCode = CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES;
  903. } // else: not just validating
  904. // Set private properties.
  905. sc = ClusterResourceControl(
  906. Peo()->PrdResData()->m_hresource,
  907. NULL, // hNode
  908. dwControlCode,
  909. cpl.PbPropList(),
  910. static_cast< DWORD >( cpl.CbPropList() ),
  911. NULL, // lpOutBuffer
  912. 0, // nOutBufferSize
  913. &cbProps
  914. );
  915. if ( sc != ERROR_SUCCESS )
  916. {
  917. if ( sc == ERROR_INVALID_PARAMETER )
  918. {
  919. if ( ! bNoNewProps )
  920. {
  921. bSuccess = BSetPrivateProps( bValidateOnly, TRUE /*bNoNewProps*/ );
  922. } // if: new props are allowed
  923. else
  924. {
  925. bSuccess = FALSE;
  926. } // else: new props are not allowed
  927. } // if: invalid parameter error occurred
  928. else
  929. {
  930. bSuccess = FALSE;
  931. } // else: some other error occurred
  932. } // if: error setting/validating data
  933. //
  934. // If an error occurred, display an error message.
  935. //
  936. if ( ! bSuccess )
  937. {
  938. DisplaySetPropsError( sc, bValidateOnly ? IDS_ERROR_VALIDATING_PROPERTIES : IDS_ERROR_SETTING_PROPERTIES );
  939. if ( sc == ERROR_RESOURCE_PROPERTIES_STORED )
  940. {
  941. bSuccess = TRUE;
  942. } // if: properties only stored
  943. } // if: error occurred
  944. } // if: there is data to set
  945. } // if: no errors building the property list
  946. // Save data locally.
  947. if ( ! bValidateOnly && bSuccess )
  948. {
  949. // Save new values as previous values.
  950. try
  951. {
  952. DWORD cprop;
  953. const CObjectProperty * pprop;
  954. for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
  955. {
  956. switch ( pprop->m_propFormat )
  957. {
  958. case CLUSPROP_FORMAT_SZ:
  959. case CLUSPROP_FORMAT_EXPAND_SZ:
  960. ASSERT( pprop->m_value.pstr != NULL );
  961. ASSERT( pprop->m_valuePrev.pstr != NULL );
  962. *pprop->m_valuePrev.pstr = *pprop->m_value.pstr;
  963. break;
  964. case CLUSPROP_FORMAT_DWORD:
  965. case CLUSPROP_FORMAT_LONG:
  966. ASSERT( pprop->m_value.pdw != NULL );
  967. ASSERT( pprop->m_valuePrev.pdw != NULL );
  968. *pprop->m_valuePrev.pdw = *pprop->m_value.pdw;
  969. break;
  970. case CLUSPROP_FORMAT_BINARY:
  971. case CLUSPROP_FORMAT_MULTI_SZ:
  972. ASSERT( pprop->m_value.ppb != NULL );
  973. ASSERT( *pprop->m_value.ppb != NULL );
  974. ASSERT( pprop->m_value.pcb != NULL );
  975. ASSERT( pprop->m_valuePrev.ppb != NULL );
  976. ASSERT( *pprop->m_valuePrev.ppb != NULL );
  977. ASSERT( pprop->m_valuePrev.pcb != NULL );
  978. delete [] *pprop->m_valuePrev.ppb;
  979. *pprop->m_valuePrev.ppb = new BYTE[ *pprop->m_value.pcb ];
  980. if ( *pprop->m_valuePrev.ppb == NULL )
  981. {
  982. AfxThrowMemoryException();
  983. } // if: error allocating memory
  984. CopyMemory( *pprop->m_valuePrev.ppb, *pprop->m_value.ppb, *pprop->m_value.pcb );
  985. *pprop->m_valuePrev.pcb = *pprop->m_value.pcb;
  986. break;
  987. default:
  988. ASSERT( 0 ); // don't know how to deal with this type
  989. } // switch: property format
  990. } // for: each property
  991. } // try
  992. catch ( CException * pe )
  993. {
  994. pe->ReportError();
  995. pe->Delete();
  996. bSuccess = FALSE;
  997. } // catch: CException
  998. } // if: not just validating and successful so far
  999. //
  1000. // Indicate we successfully saved the properties.
  1001. //
  1002. if ( ! bValidateOnly && bSuccess )
  1003. {
  1004. m_bSaved = TRUE;
  1005. } // if: successfully saved data
  1006. return bSuccess;
  1007. } //*** CBasePropertyPage::BSetPrivateProps()
  1008. /////////////////////////////////////////////////////////////////////////////
  1009. //++
  1010. //
  1011. // CBasePropertyPage::DisplaySetPropsError
  1012. //
  1013. // Routine Description:
  1014. // Display an error caused by setting or validating properties.
  1015. //
  1016. // Arguments:
  1017. // sc [IN] Status to display error on.
  1018. // idsOper [IN] Operation message.
  1019. //
  1020. // Return Value:
  1021. // nStatus ERROR_SUCCESS = success, !0 = failure
  1022. //
  1023. //--
  1024. /////////////////////////////////////////////////////////////////////////////
  1025. void CBasePropertyPage::DisplaySetPropsError(
  1026. IN DWORD sc,
  1027. IN UINT idsOper
  1028. ) const
  1029. {
  1030. CString strErrorMsg;
  1031. CString strOperMsg;
  1032. CString strMsgIdFmt;
  1033. CString strMsgId;
  1034. CString strMsg;
  1035. strOperMsg.LoadString( IDS_ERROR_SETTING_PROPERTIES );
  1036. FormatError( strErrorMsg, sc );
  1037. strMsgIdFmt.LoadString( IDS_ERROR_MSG_ID );
  1038. strMsgId.Format( strMsgIdFmt, sc, sc );
  1039. strMsg.Format( _T("%s\n\n%s%s"), strOperMsg, strErrorMsg, strMsgId );
  1040. AfxMessageBox( strMsg );
  1041. } //*** CBasePropertyPage::DisplaySetPropsError()
  1042. /////////////////////////////////////////////////////////////////////////////
  1043. //++
  1044. //
  1045. // CBasePropertyPage::BRequiredDependenciesPresent
  1046. //
  1047. // Routine Description:
  1048. // Determine if the specified list contains each required resource
  1049. // for this type of resource.
  1050. //
  1051. // Arguments:
  1052. // None.
  1053. //
  1054. // Return Value:
  1055. // None.
  1056. //
  1057. // Exceptions Thrown:
  1058. // Any exceptions thrown by CString::LoadString() or CString::operator=().
  1059. //
  1060. //--
  1061. /////////////////////////////////////////////////////////////////////////////
  1062. BOOL CBasePropertyPage::BRequiredDependenciesPresent( void )
  1063. {
  1064. BOOL bFound = TRUE;
  1065. DWORD sc;
  1066. CClusPropValueList pvl;
  1067. HRESOURCE hres;
  1068. PCLUS_RESOURCE_CLASS_INFO prci = NULL;
  1069. CString strMissing;
  1070. do
  1071. {
  1072. // Collect the list of required dependencies.
  1073. sc = pvl.ScGetResourceValueList(
  1074. Peo()->PrdResData()->m_hresource,
  1075. CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES
  1076. );
  1077. if ( sc != ERROR_SUCCESS )
  1078. {
  1079. CNTException nte( sc, 0, NULL, NULL, FALSE );
  1080. nte.ReportError();
  1081. break;
  1082. } // if: error collecting required dependencies
  1083. // Move to the first value.
  1084. sc = pvl.ScMoveToFirstValue();
  1085. while ( sc == ERROR_SUCCESS )
  1086. {
  1087. switch ( pvl.CptCurrentValueType() )
  1088. {
  1089. case CLUSPROP_TYPE_RESCLASS:
  1090. prci = reinterpret_cast< PCLUS_RESOURCE_CLASS_INFO >( &pvl.CbhCurrentValue().pResourceClassInfoValue->li );
  1091. hres = ResUtilGetResourceDependencyByClass(
  1092. Hcluster(),
  1093. Peo()->PrdResData()->m_hresource,
  1094. prci,
  1095. FALSE // bRecurse
  1096. );
  1097. if ( hres != NULL )
  1098. {
  1099. CloseClusterResource( hres );
  1100. } // if: found the resource
  1101. else
  1102. {
  1103. if ( ! strMissing.LoadString( IDS_RESCLASS_UNKNOWN + prci->rc ) )
  1104. {
  1105. strMissing.LoadString( IDS_RESCLASS_UNKNOWN );
  1106. } // if: unknown resource class
  1107. bFound = FALSE;
  1108. } // else: resource not found
  1109. break;
  1110. case CLUSPROP_TYPE_NAME:
  1111. hres = ResUtilGetResourceDependencyByName(
  1112. Hcluster(),
  1113. Peo()->PrdResData()->m_hresource,
  1114. pvl.CbhCurrentValue().pName->sz,
  1115. FALSE // bRecurse
  1116. );
  1117. if ( hres != NULL )
  1118. {
  1119. CloseClusterResource( hres );
  1120. } // if: found the resource
  1121. else
  1122. {
  1123. GetResTypeDisplayOrTypeName( pvl.CbhCurrentValue().pName->sz, &strMissing );
  1124. bFound = FALSE;
  1125. } // else: resource not found
  1126. break;
  1127. } // switch: value type
  1128. // If a match was not found, changes cannot be applied.
  1129. if ( ! bFound )
  1130. {
  1131. CExceptionWithOper ewo( IDS_REQUIRED_DEPENDENCY_NOT_FOUND, NULL, NULL, FALSE );
  1132. ewo.SetOperation( IDS_REQUIRED_DEPENDENCY_NOT_FOUND, static_cast< LPCWSTR >( strMissing ) );
  1133. ewo.ReportError();
  1134. break;
  1135. } // if: not found
  1136. sc = pvl.ScMoveToNextValue();
  1137. } // while: more values in the value list
  1138. } while( 0 );
  1139. return bFound;
  1140. } //*** CBasePropertyPage::BRequiredDependenciesPresent()
  1141. /////////////////////////////////////////////////////////////////////////////
  1142. //++
  1143. //
  1144. // CBasePropertyPage::GetResTypeDisplayOrTypeName
  1145. //
  1146. // Routine Description:
  1147. // Get the display name for a resource type if possible. If any errors
  1148. // occur, just return the type name.
  1149. //
  1150. // Arguments:
  1151. // pszResTypeNameIn
  1152. // [IN] Name of resource type.
  1153. //
  1154. // pstrResTypeDisplayNameInOut
  1155. // [IN OUT] CString in which to return the display name.
  1156. //
  1157. // Return Value:
  1158. // None.
  1159. //
  1160. //--
  1161. /////////////////////////////////////////////////////////////////////////////
  1162. void CBasePropertyPage::GetResTypeDisplayOrTypeName(
  1163. IN LPCWSTR pszResTypeNameIn,
  1164. IN OUT CString * pstrResTypeDisplayNameInOut
  1165. )
  1166. {
  1167. DWORD sc;
  1168. CClusPropList cpl;
  1169. // Get resource type properties.
  1170. sc = cpl.ScGetResourceTypeProperties(
  1171. Hcluster(),
  1172. pszResTypeNameIn,
  1173. CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES
  1174. );
  1175. if ( sc != ERROR_SUCCESS )
  1176. goto Error;
  1177. // Find the Name property.
  1178. sc = cpl.ScMoveToPropertyByName( CLUSREG_NAME_RESTYPE_NAME );
  1179. if ( sc != ERROR_SUCCESS )
  1180. goto Error;
  1181. // Move to the first value for the property.
  1182. sc = cpl.ScMoveToFirstPropertyValue();
  1183. if ( sc != ERROR_SUCCESS )
  1184. goto Error;
  1185. // Make sure the name is a string.
  1186. if ( ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_SZ )
  1187. && ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_EXPAND_SZ )
  1188. && ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_EXPANDED_SZ )
  1189. )
  1190. goto Error;
  1191. // Copy the string into the output CString.
  1192. *pstrResTypeDisplayNameInOut = cpl.CbhCurrentValue().pStringValue->sz;
  1193. Cleanup:
  1194. return;
  1195. Error:
  1196. *pstrResTypeDisplayNameInOut = pszResTypeNameIn;
  1197. goto Cleanup;
  1198. } //*** CBasePropertyPage::GetResTypeDisplayOrTypeName()
  1199. /////////////////////////////////////////////////////////////////////////////
  1200. //++
  1201. //
  1202. // CBasePropertyPage::ScReadValue
  1203. //
  1204. // Routine Description:
  1205. // Read a REG_SZ value for this item.
  1206. //
  1207. // Arguments:
  1208. // pszValueName [IN] Name of the value to read.
  1209. // rstrValue [OUT] String in which to return the value.
  1210. // hkey [IN] Handle to the registry key to read from.
  1211. //
  1212. // Return Value:
  1213. // sc ERROR_SUCCESS = success, !0 = failure
  1214. //
  1215. //--
  1216. /////////////////////////////////////////////////////////////////////////////
  1217. DWORD CBasePropertyPage::ScReadValue(
  1218. IN LPCTSTR pszValueName,
  1219. OUT CString & rstrValue,
  1220. IN HKEY hkey
  1221. )
  1222. {
  1223. DWORD sc;
  1224. LPWSTR pwszValue = NULL;
  1225. DWORD dwValueLen;
  1226. DWORD dwValueType;
  1227. ASSERT( pszValueName != NULL );
  1228. ASSERT( hkey != NULL );
  1229. rstrValue.Empty();
  1230. try
  1231. {
  1232. // Get the size of the value.
  1233. dwValueLen = 0;
  1234. sc = ::ClusterRegQueryValue(
  1235. hkey,
  1236. pszValueName,
  1237. &dwValueType,
  1238. NULL,
  1239. &dwValueLen
  1240. );
  1241. if ( ( sc == ERROR_SUCCESS ) || ( sc == ERROR_MORE_DATA ) )
  1242. {
  1243. ASSERT( dwValueType == REG_SZ );
  1244. // Allocate enough space for the data.
  1245. pwszValue = rstrValue.GetBuffer( dwValueLen / sizeof( WCHAR ) );
  1246. if ( pwszValue == NULL )
  1247. {
  1248. AfxThrowMemoryException();
  1249. } // if: error getting the buffer
  1250. ASSERT( pwszValue != NULL );
  1251. dwValueLen += 1 * sizeof( WCHAR ); // Don't forget the final null-terminator.
  1252. // Read the value.
  1253. sc = ::ClusterRegQueryValue(
  1254. hkey,
  1255. pszValueName,
  1256. &dwValueType,
  1257. (LPBYTE) pwszValue,
  1258. &dwValueLen
  1259. );
  1260. if ( sc == ERROR_SUCCESS )
  1261. {
  1262. ASSERT( dwValueType == REG_SZ );
  1263. } // if: value read successfully
  1264. rstrValue.ReleaseBuffer();
  1265. } // if: got the size successfully
  1266. } // try
  1267. catch ( CMemoryException * pme )
  1268. {
  1269. pme->Delete();
  1270. sc = ERROR_NOT_ENOUGH_MEMORY;
  1271. } // catch: CMemoryException
  1272. return sc;
  1273. } //*** CBasePropertyPage::ScReadValue(LPCTSTR, CString&)
  1274. /////////////////////////////////////////////////////////////////////////////
  1275. //++
  1276. //
  1277. // CBasePropertyPage::ScReadValue
  1278. //
  1279. // Routine Description:
  1280. // Read a REG_DWORD value for this item.
  1281. //
  1282. // Arguments:
  1283. // pszValueName [IN] Name of the value to read.
  1284. // pdwValue [OUT] DWORD in which to return the value.
  1285. // hkey [IN] Handle to the registry key to read from.
  1286. //
  1287. // Return Value:
  1288. // _sc ERROR_SUCCESS = success, !0 = failure
  1289. //
  1290. //--
  1291. /////////////////////////////////////////////////////////////////////////////
  1292. DWORD CBasePropertyPage::ScReadValue(
  1293. IN LPCTSTR pszValueName,
  1294. OUT DWORD * pdwValue,
  1295. IN HKEY hkey
  1296. )
  1297. {
  1298. DWORD _sc;
  1299. DWORD _dwValue;
  1300. DWORD _dwValueLen;
  1301. DWORD _dwValueType;
  1302. ASSERT(pszValueName != NULL);
  1303. ASSERT(pdwValue != NULL);
  1304. ASSERT(hkey != NULL);
  1305. *pdwValue = 0;
  1306. // Read the value.
  1307. _dwValueLen = sizeof(_dwValue);
  1308. _sc = ::ClusterRegQueryValue(
  1309. hkey,
  1310. pszValueName,
  1311. &_dwValueType,
  1312. (LPBYTE) &_dwValue,
  1313. &_dwValueLen
  1314. );
  1315. if (_sc == ERROR_SUCCESS)
  1316. {
  1317. ASSERT(_dwValueType == REG_DWORD);
  1318. ASSERT(_dwValueLen == sizeof(_dwValue));
  1319. *pdwValue = _dwValue;
  1320. } // if: value read successfully
  1321. return _sc;
  1322. } //*** CBasePropertyPage::ScReadValue(LPCTSTR, DWORD*)
  1323. /////////////////////////////////////////////////////////////////////////////
  1324. //++
  1325. //
  1326. // CBasePropertyPage::ScReadValue
  1327. //
  1328. // Routine Description:
  1329. // Read a REG_BINARY value for this item.
  1330. //
  1331. // Arguments:
  1332. // pszValueName [IN] Name of the value to read.
  1333. // ppbValue [OUT] Pointer in which to return the data. Caller
  1334. // is responsible for deallocating the data.
  1335. // hkey [IN] Handle to the registry key to read from.
  1336. //
  1337. // Return Value:
  1338. // _sc ERROR_SUCCESS = success, !0 = failure
  1339. //
  1340. //--
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. DWORD CBasePropertyPage::ScReadValue(
  1343. IN LPCTSTR pszValueName,
  1344. OUT LPBYTE * ppbValue,
  1345. IN HKEY hkey
  1346. )
  1347. {
  1348. DWORD _sc;
  1349. DWORD _dwValueLen;
  1350. DWORD _dwValueType;
  1351. ASSERT(pszValueName != NULL);
  1352. ASSERT(ppbValue != NULL);
  1353. ASSERT(hkey != NULL);
  1354. *ppbValue = NULL;
  1355. // Get the length of the value.
  1356. _dwValueLen = 0;
  1357. _sc = ::ClusterRegQueryValue(
  1358. hkey,
  1359. pszValueName,
  1360. &_dwValueType,
  1361. NULL,
  1362. &_dwValueLen
  1363. );
  1364. if (_sc != ERROR_SUCCESS)
  1365. return _sc;
  1366. ASSERT(_dwValueType == REG_BINARY);
  1367. // Allocate a buffer,
  1368. try
  1369. {
  1370. *ppbValue = new BYTE[_dwValueLen];
  1371. } // try
  1372. catch (CMemoryException *)
  1373. {
  1374. _sc = ERROR_NOT_ENOUGH_MEMORY;
  1375. return _sc;
  1376. } // catch: CMemoryException
  1377. // Read the value.
  1378. _sc = ::ClusterRegQueryValue(
  1379. hkey,
  1380. pszValueName,
  1381. &_dwValueType,
  1382. *ppbValue,
  1383. &_dwValueLen
  1384. );
  1385. if (_sc != ERROR_SUCCESS)
  1386. {
  1387. delete [] *ppbValue;
  1388. *ppbValue = NULL;
  1389. } // if: value read successfully
  1390. return _sc;
  1391. } //*** CBasePropertyPage::ScReadValue(LPCTSTR, LPBYTE)
  1392. /////////////////////////////////////////////////////////////////////////////
  1393. //++
  1394. //
  1395. // CBasePropertyPage::ScWriteValue
  1396. //
  1397. // Routine Description:
  1398. // Write a REG_SZ value for this item if it hasn't changed.
  1399. //
  1400. // Arguments:
  1401. // pszValueName [IN] Name of the value to write.
  1402. // rstrValue [IN] Value data.
  1403. // rstrPrevValue [IN OUT] Previous value.
  1404. // hkey [IN] Handle to the registry key to write to.
  1405. //
  1406. // Return Value:
  1407. // _sc
  1408. //
  1409. //--
  1410. /////////////////////////////////////////////////////////////////////////////
  1411. DWORD CBasePropertyPage::ScWriteValue(
  1412. IN LPCTSTR pszValueName,
  1413. IN const CString & rstrValue,
  1414. IN OUT CString & rstrPrevValue,
  1415. IN HKEY hkey
  1416. )
  1417. {
  1418. DWORD _sc;
  1419. ASSERT(pszValueName != NULL);
  1420. ASSERT(hkey != NULL);
  1421. // Write the value if it hasn't changed.
  1422. if (rstrValue != rstrPrevValue)
  1423. {
  1424. _sc = ::ClusterRegSetValue(
  1425. hkey,
  1426. pszValueName,
  1427. REG_SZ,
  1428. (CONST BYTE *) (LPCTSTR) rstrValue,
  1429. (rstrValue.GetLength() + 1) * sizeof(TCHAR)
  1430. );
  1431. if (_sc == ERROR_SUCCESS)
  1432. rstrPrevValue = rstrValue;
  1433. } // if: value changed
  1434. else
  1435. _sc = ERROR_SUCCESS;
  1436. return _sc;
  1437. } //*** CBasePropertyPage::ScWriteValue(LPCTSTR, CString&)
  1438. /////////////////////////////////////////////////////////////////////////////
  1439. //++
  1440. //
  1441. // CBasePropertyPage::ScWriteValue
  1442. //
  1443. // Routine Description:
  1444. // Write a REG_DWORD value for this item if it hasn't changed.
  1445. //
  1446. // Arguments:
  1447. // pszValueName [IN] Name of the value to write.
  1448. // dwValue [IN] Value data.
  1449. // pdwPrevValue [IN OUT] Previous value.
  1450. // hkey [IN] Handle to the registry key to write to.
  1451. //
  1452. // Return Value:
  1453. // _sc
  1454. //
  1455. //--
  1456. /////////////////////////////////////////////////////////////////////////////
  1457. DWORD CBasePropertyPage::ScWriteValue(
  1458. IN LPCTSTR pszValueName,
  1459. IN DWORD dwValue,
  1460. IN OUT DWORD * pdwPrevValue,
  1461. IN HKEY hkey
  1462. )
  1463. {
  1464. DWORD _sc;
  1465. ASSERT(pszValueName != NULL);
  1466. ASSERT(pdwPrevValue != NULL);
  1467. ASSERT(hkey != NULL);
  1468. // Write the value if it hasn't changed.
  1469. if (dwValue != *pdwPrevValue)
  1470. {
  1471. _sc = ::ClusterRegSetValue(
  1472. hkey,
  1473. pszValueName,
  1474. REG_DWORD,
  1475. (CONST BYTE *) &dwValue,
  1476. sizeof(dwValue)
  1477. );
  1478. if (_sc == ERROR_SUCCESS)
  1479. *pdwPrevValue = dwValue;
  1480. } // if: value changed
  1481. else
  1482. _sc = ERROR_SUCCESS;
  1483. return _sc;
  1484. } //*** CBasePropertyPage::ScWriteValue(LPCTSTR, DWORD)
  1485. /////////////////////////////////////////////////////////////////////////////
  1486. //++
  1487. //
  1488. // CBasePropertyPage::ScWriteValue
  1489. //
  1490. // Routine Description:
  1491. // Write a REG_BINARY value for this item if it hasn't changed.
  1492. //
  1493. // Arguments:
  1494. // pszValueName [IN] Name of the value to write.
  1495. // pbValue [IN] Value data.
  1496. // cbValue [IN] Size of value data.
  1497. // ppbPrevValue [IN OUT] Previous value.
  1498. // cbPrevValue [IN] Size of the previous data.
  1499. // hkey [IN] Handle to the registry key to write to.
  1500. //
  1501. // Return Value:
  1502. // _sc
  1503. //
  1504. //--
  1505. /////////////////////////////////////////////////////////////////////////////
  1506. DWORD CBasePropertyPage::ScWriteValue(
  1507. IN LPCTSTR pszValueName,
  1508. IN const LPBYTE pbValue,
  1509. IN DWORD cbValue,
  1510. IN OUT LPBYTE * ppbPrevValue,
  1511. IN DWORD cbPrevValue,
  1512. IN HKEY hkey
  1513. )
  1514. {
  1515. DWORD _sc;
  1516. LPBYTE _pbPrevValue = NULL;
  1517. ASSERT(pszValueName != NULL);
  1518. ASSERT(pbValue != NULL);
  1519. ASSERT(ppbPrevValue != NULL);
  1520. ASSERT(cbValue > 0);
  1521. ASSERT(hkey != NULL);
  1522. // See if the data has changed.
  1523. if (cbValue == cbPrevValue)
  1524. {
  1525. if (memcmp(pbValue, *ppbPrevValue, cbValue) == 0)
  1526. return ERROR_SUCCESS;
  1527. } // if: lengths are the same
  1528. // Allocate a new buffer for the previous data pointer.
  1529. try
  1530. {
  1531. _pbPrevValue = new BYTE[cbValue];
  1532. }
  1533. catch (CMemoryException *)
  1534. {
  1535. return ERROR_NOT_ENOUGH_MEMORY;
  1536. } // catch: CMemoryException
  1537. ::CopyMemory(_pbPrevValue, pbValue, cbValue);
  1538. // Write the value if it hasn't changed.
  1539. _sc = ::ClusterRegSetValue(
  1540. hkey,
  1541. pszValueName,
  1542. REG_BINARY,
  1543. pbValue,
  1544. cbValue
  1545. );
  1546. if (_sc == ERROR_SUCCESS)
  1547. {
  1548. delete [] *ppbPrevValue;
  1549. *ppbPrevValue = _pbPrevValue;
  1550. } // if: set was successful
  1551. else
  1552. delete [] _pbPrevValue;
  1553. return _sc;
  1554. } //*** CBasePropertyPage::ScWriteValue(LPCTSTR, const LPBYTE)
  1555. /////////////////////////////////////////////////////////////////////////////
  1556. //++
  1557. //
  1558. // CBasePropertyPage::OnContextMenu
  1559. //
  1560. // Routine Description:
  1561. // Handler for the WM_CONTEXTMENU message.
  1562. //
  1563. // Arguments:
  1564. // pWnd Window in which user clicked the right mouse button.
  1565. // point Position of the cursor, in screen coordinates.
  1566. //
  1567. // Return Value:
  1568. // TRUE Help processed.
  1569. // FALSE Help not processed.
  1570. //
  1571. //--
  1572. /////////////////////////////////////////////////////////////////////////////
  1573. void CBasePropertyPage::OnContextMenu(CWnd * pWnd, CPoint point)
  1574. {
  1575. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1576. m_dlghelp.OnContextMenu(pWnd, point);
  1577. } //*** CBasePropertyPage::OnContextMenu()
  1578. /////////////////////////////////////////////////////////////////////////////
  1579. //++
  1580. //
  1581. // CBasePropertyPage::OnHelpInfo
  1582. //
  1583. // Routine Description:
  1584. // Handler for the WM_HELPINFO message.
  1585. //
  1586. // Arguments:
  1587. // pHelpInfo Structure containing info about displaying help.
  1588. //
  1589. // Return Value:
  1590. // TRUE Help processed.
  1591. // FALSE Help not processed.
  1592. //
  1593. //--
  1594. /////////////////////////////////////////////////////////////////////////////
  1595. BOOL CBasePropertyPage::OnHelpInfo(HELPINFO * pHelpInfo)
  1596. {
  1597. BOOL _bProcessed;
  1598. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1599. _bProcessed = m_dlghelp.OnHelpInfo(pHelpInfo);
  1600. if (!_bProcessed)
  1601. _bProcessed = CPropertyPage::OnHelpInfo(pHelpInfo);
  1602. return _bProcessed;
  1603. } //*** CBasePropertyPage::OnHelpInfo()
  1604. /////////////////////////////////////////////////////////////////////////////
  1605. //++
  1606. //
  1607. // CBasePropertyPage::OnCommandHelp
  1608. //
  1609. // Routine Description:
  1610. // Handler for the WM_COMMANDHELP message.
  1611. //
  1612. // Arguments:
  1613. // wParam [IN] WPARAM.
  1614. // lParam [IN] LPARAM.
  1615. //
  1616. // Return Value:
  1617. // TRUE Help processed.
  1618. // FALSE Help not processed.
  1619. //
  1620. //--
  1621. /////////////////////////////////////////////////////////////////////////////
  1622. LRESULT CBasePropertyPage::OnCommandHelp(WPARAM wParam, LPARAM lParam)
  1623. {
  1624. LRESULT _bProcessed;
  1625. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1626. _bProcessed = m_dlghelp.OnCommandHelp(wParam, lParam);
  1627. if (!_bProcessed)
  1628. _bProcessed = CPropertyPage::OnCommandHelp(wParam, lParam);
  1629. return _bProcessed;
  1630. } //*** CBasePropertyPage::OnCommandHelp()
  1631. /////////////////////////////////////////////////////////////////////////////
  1632. //++
  1633. //
  1634. // CBasePropertyPage::ConstructDefaultDirectory
  1635. //
  1636. // Routine Description:
  1637. // Get the name of the first partition from the first storage-class
  1638. // resource on which this resource is dependent.
  1639. //
  1640. // Arguments:
  1641. // rstrDir [OUT] Directory string.
  1642. // idsFormat [IN] Resource ID for the format string.
  1643. //
  1644. // Return Value:
  1645. // None.
  1646. //
  1647. //--
  1648. /////////////////////////////////////////////////////////////////////////////
  1649. void CBasePropertyPage::ConstructDefaultDirectory(
  1650. OUT CString & rstrDir,
  1651. IN IDS idsFormat
  1652. )
  1653. {
  1654. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1655. HRESOURCE _hres = NULL;
  1656. DWORD _sc = ERROR_SUCCESS;
  1657. DWORD _cbDiskInfo = sizeof(CLUSPROP_DWORD)
  1658. + sizeof(CLUSPROP_SCSI_ADDRESS)
  1659. + sizeof(CLUSPROP_DISK_NUMBER)
  1660. + sizeof(CLUSPROP_PARTITION_INFO)
  1661. + sizeof(CLUSPROP_SYNTAX);
  1662. PBYTE _pbDiskInfo = NULL;
  1663. CLUSPROP_BUFFER_HELPER _cbh;
  1664. // Get the first partition for the resource..
  1665. try
  1666. {
  1667. // Get the storage-class resource on which we are dependent.
  1668. _hres = GetDependentStorageResource();
  1669. if (_hres == NULL)
  1670. return;
  1671. // Get disk info.
  1672. _pbDiskInfo = new BYTE[_cbDiskInfo];
  1673. _sc = ClusterResourceControl(
  1674. _hres,
  1675. NULL,
  1676. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  1677. NULL,
  1678. 0,
  1679. _pbDiskInfo,
  1680. _cbDiskInfo,
  1681. &_cbDiskInfo
  1682. );
  1683. if (_sc == ERROR_MORE_DATA)
  1684. {
  1685. delete [] _pbDiskInfo;
  1686. _pbDiskInfo = new BYTE[_cbDiskInfo];
  1687. _sc = ClusterResourceControl(
  1688. _hres,
  1689. NULL,
  1690. CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  1691. NULL,
  1692. 0,
  1693. _pbDiskInfo,
  1694. _cbDiskInfo,
  1695. &_cbDiskInfo
  1696. );
  1697. } // if: buffer too small
  1698. if (_sc == ERROR_SUCCESS)
  1699. {
  1700. // Find the first partition.
  1701. _cbh.pb = _pbDiskInfo;
  1702. while (_cbh.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK)
  1703. {
  1704. if (_cbh.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO)
  1705. {
  1706. rstrDir.FormatMessage(
  1707. idsFormat,
  1708. _cbh.pPartitionInfoValue->szDeviceName
  1709. );
  1710. break;
  1711. } // if: found a partition
  1712. _cbh.pb += sizeof(*_cbh.pValue) + ALIGN_CLUSPROP(_cbh.pValue->cbLength);
  1713. } // while: not at end of list
  1714. } // if: no error getting disk info
  1715. else
  1716. {
  1717. CNTException nte( _sc, IDS_ERROR_CONSTRUCTING_DEF_DIR );
  1718. nte.ReportError();
  1719. } // else: error getting disk info
  1720. } // try
  1721. catch (CMemoryException * _pme)
  1722. {
  1723. _pme->Delete();
  1724. } // catch: CMemoryException
  1725. CloseClusterResource(_hres);
  1726. delete [] _pbDiskInfo;
  1727. } //*** CBasePropertyPage::ConstructDefaultDirectory()
  1728. /////////////////////////////////////////////////////////////////////////////
  1729. //++
  1730. //
  1731. // CBasePropertyPage::GetDependentStorageResource
  1732. //
  1733. // Routine Description:
  1734. // Construct a default spool directory based on the drive on which
  1735. // this resource is dependent and a default value for the directory.
  1736. //
  1737. // Arguments:
  1738. // phres [OUT] Handle to dependent resource.
  1739. //
  1740. // Return Value:
  1741. // HRESOURCE for the open dependent resource, or NULL if error.
  1742. //
  1743. //--
  1744. /////////////////////////////////////////////////////////////////////////////
  1745. HRESOURCE CBasePropertyPage::GetDependentStorageResource(void)
  1746. {
  1747. DWORD _sc = ERROR_SUCCESS;
  1748. HRESENUM _hresenum;
  1749. HRESOURCE _hres = NULL;
  1750. DWORD _ires;
  1751. DWORD _dwType;
  1752. DWORD _cchName;
  1753. DWORD _cchNameSize;
  1754. LPWSTR _pszName = NULL;
  1755. CLUS_RESOURCE_CLASS_INFO _classinfo;
  1756. DWORD _cbClassInfo;
  1757. // Open the dependency enumerator.
  1758. _hresenum = ClusterResourceOpenEnum(
  1759. Peo()->PrdResData()->m_hresource,
  1760. CLUSTER_RESOURCE_ENUM_DEPENDS
  1761. );
  1762. if (_hresenum == NULL)
  1763. return NULL;
  1764. // Allocate a default size name buffer.
  1765. _cchNameSize = 512;
  1766. _pszName = new WCHAR[_cchNameSize];
  1767. for (_ires = 0 ; ; _ires++)
  1768. {
  1769. // Get the name of the next resource.
  1770. _cchName = _cchNameSize;
  1771. _sc = ClusterResourceEnum(
  1772. _hresenum,
  1773. _ires,
  1774. &_dwType,
  1775. _pszName,
  1776. &_cchName
  1777. );
  1778. if (_sc == ERROR_MORE_DATA)
  1779. {
  1780. delete [] _pszName;
  1781. _cchNameSize = _cchName;
  1782. _pszName = new WCHAR[_cchNameSize];
  1783. _sc = ClusterResourceEnum(
  1784. _hresenum,
  1785. _ires,
  1786. &_dwType,
  1787. _pszName,
  1788. &_cchName
  1789. );
  1790. } // if: name buffer too small
  1791. if (_sc != ERROR_SUCCESS)
  1792. break;
  1793. // Open the resource.
  1794. _hres = OpenClusterResource(Hcluster(), _pszName);
  1795. if (_hres == NULL)
  1796. {
  1797. _sc = GetLastError();
  1798. break;
  1799. } // if: error opening the resource
  1800. // Get the class of the resource.
  1801. _sc = ClusterResourceControl(
  1802. _hres,
  1803. NULL,
  1804. CLUSCTL_RESOURCE_GET_CLASS_INFO,
  1805. NULL,
  1806. 0,
  1807. &_classinfo,
  1808. sizeof(_classinfo),
  1809. &_cbClassInfo
  1810. );
  1811. if (_sc != ERROR_SUCCESS)
  1812. {
  1813. CNTException nte( _sc, IDS_ERROR_GET_CLASS_INFO, _pszName, NULL, FALSE /*bAutoDelete*/ );
  1814. nte.ReportError();
  1815. continue;
  1816. }
  1817. // If this is a storage-class resource, we're done.
  1818. if (_classinfo.rc == CLUS_RESCLASS_STORAGE)
  1819. break;
  1820. // Not storage-class resource.
  1821. CloseClusterResource(_hres);
  1822. _hres = NULL;
  1823. } // for each resource on which we are dependent
  1824. // Handle errors.
  1825. if ((_sc != ERROR_SUCCESS) && (_hres != NULL))
  1826. {
  1827. CloseClusterResource(_hres);
  1828. _hres = NULL;
  1829. } // if: error getting resource
  1830. // Cleanup.
  1831. ClusterResourceCloseEnum(_hresenum);
  1832. delete [] _pszName;
  1833. return _hres;
  1834. } //*** CBasePropertyPage::GetDependentStorageResource()
  1835. /////////////////////////////////////////////////////////////////////////////
  1836. //++
  1837. //
  1838. // CBasePropertyPage::BGetClusterNetworkNameNode
  1839. //
  1840. // Routine Description:
  1841. // Get the node hosting the Network Name resource.
  1842. //
  1843. // Arguments:
  1844. // rstrNode [OUT] - receives the node name
  1845. //
  1846. // Return Value:
  1847. // BOOL -- TRUE for success, FALSE for error
  1848. //
  1849. //--
  1850. /////////////////////////////////////////////////////////////////////////////
  1851. BOOL CBasePropertyPage::BGetClusterNetworkNameNode( OUT CString & rstrNode )
  1852. {
  1853. BOOL _bSuccess = TRUE;
  1854. DWORD _sc;
  1855. DWORD _dwFlag;
  1856. DWORD _cbData;
  1857. DWORD _ires;
  1858. DWORD _dwType;
  1859. DWORD _cchName = 0;
  1860. DWORD _cchNameCurrent;
  1861. LPWSTR _pszName = NULL;
  1862. WCHAR _szResType[ RTL_NUMBER_OF( CLUS_RESTYPE_NAME_NETNAME ) ];
  1863. WCHAR _szNode[ MAX_COMPUTERNAME_LENGTH + 1 ];
  1864. HCLUSENUM _hclusenum = NULL;
  1865. HRESOURCE _hresource = NULL;
  1866. CLUSTER_RESOURCE_STATE _crs;
  1867. CWaitCursor _wc;
  1868. try
  1869. {
  1870. // Open a cluster enumerator.
  1871. _hclusenum = ClusterOpenEnum( Hcluster(), CLUSTER_ENUM_RESOURCE );
  1872. if (_hclusenum == NULL)
  1873. {
  1874. ThrowStaticException( GetLastError() );
  1875. }
  1876. // Allocate an initial buffer.
  1877. _cchName = 256;
  1878. _pszName = new WCHAR[_cchName];
  1879. // Loop through each resource.
  1880. for ( _ires = 0 ; ; _ires++ )
  1881. {
  1882. // Get the next resource.
  1883. _cchNameCurrent = _cchName;
  1884. _sc = ClusterEnum( _hclusenum, _ires, &_dwType, _pszName, &_cchNameCurrent );
  1885. if ( _sc == ERROR_MORE_DATA )
  1886. {
  1887. delete [] _pszName;
  1888. _cchName = ++_cchNameCurrent;
  1889. _pszName = new WCHAR[_cchName];
  1890. _sc = ClusterEnum(_hclusenum, _ires, &_dwType, _pszName, &_cchNameCurrent);
  1891. } // if: buffer too small
  1892. if (_sc == ERROR_NO_MORE_ITEMS)
  1893. break;
  1894. if (_sc != ERROR_SUCCESS)
  1895. ThrowStaticException(_sc);
  1896. // Open the resource.
  1897. _hresource = OpenClusterResource(Hcluster(), _pszName);
  1898. if (_hresource == NULL)
  1899. ThrowStaticException(GetLastError());
  1900. // Get its flags.
  1901. _sc = ClusterResourceControl(
  1902. _hresource,
  1903. NULL,
  1904. CLUSCTL_RESOURCE_GET_FLAGS,
  1905. NULL,
  1906. 0,
  1907. &_dwFlag,
  1908. sizeof(DWORD),
  1909. &_cbData
  1910. );
  1911. if (_sc != ERROR_SUCCESS)
  1912. {
  1913. CNTException nte( _sc, IDS_ERROR_GET_RESOURCE_FLAGS, _pszName, NULL, FALSE /*bAutoDelete*/ );
  1914. nte.ReportError();
  1915. continue;
  1916. }
  1917. // If this isn't a core resource, skip it.
  1918. if ((_dwFlag & CLUS_FLAG_CORE) == 0)
  1919. continue;
  1920. // Get its resource type name. If the buffer is too small,
  1921. // it isn't a Network Name resource so skip it.
  1922. _sc = ClusterResourceControl(
  1923. _hresource,
  1924. NULL,
  1925. CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
  1926. NULL,
  1927. 0,
  1928. _szResType,
  1929. sizeof(_szResType),
  1930. &_cbData
  1931. );
  1932. if (_sc == ERROR_MORE_DATA)
  1933. continue;
  1934. if (_sc != ERROR_SUCCESS)
  1935. ThrowStaticException(_sc);
  1936. // If this is a Network Name resource, get which node it is online on.
  1937. if ( ClRtlStrNICmp( _szResType, CLUS_RESTYPE_NAME_NETNAME, RTL_NUMBER_OF( CLUS_RESTYPE_NAME_NETNAME ) ) == 0 )
  1938. {
  1939. // Get the state of the resource.
  1940. _crs = GetClusterResourceState(
  1941. _hresource,
  1942. _szNode,
  1943. &_cchName,
  1944. NULL,
  1945. NULL
  1946. );
  1947. if (_crs == ClusterResourceStateUnknown)
  1948. ThrowStaticException(GetLastError());
  1949. // Save the node name in the return argument.
  1950. rstrNode = _szNode;
  1951. break;
  1952. } // if: Network Name resource
  1953. CloseClusterResource( _hresource );
  1954. _hresource = NULL;
  1955. } // for: each resource
  1956. if (rstrNode[0] == _T('\0'))
  1957. ThrowStaticException(ERROR_FILE_NOT_FOUND, (IDS) 0);
  1958. } // try
  1959. catch (CException * _pe)
  1960. {
  1961. _pe->ReportError();
  1962. _pe->Delete();
  1963. _bSuccess = FALSE;
  1964. } // catch: CException
  1965. delete [] _pszName;
  1966. if ( _hresource != NULL )
  1967. {
  1968. CloseClusterResource( _hresource );
  1969. } // if: resource is open
  1970. if ( _hclusenum != NULL )
  1971. {
  1972. ClusterCloseEnum( _hclusenum );
  1973. } // if: enumerator is open
  1974. return _bSuccess;
  1975. } //*** CBasePropertyPage::BGetClusterNetworkNameNode()