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.

2172 lines
64 KiB

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