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.

673 lines
19 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // SelNodesPageCommon.cpp
  7. //
  8. // Maintained By:
  9. // David Potter (DavidP) 05-JUL-2001
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. #include "Pch.h"
  13. #include "SelNodesPageCommon.h"
  14. #include "WizardUtils.h"
  15. #include "DelimitedIterator.h"
  16. DEFINE_THISCLASS("CSelNodesPageCommon");
  17. //////////////////////////////////////////////////////////////////////////////
  18. //++
  19. //
  20. // CSelNodesPageCommon::CSelNodesPageCommon
  21. //
  22. // Description:
  23. // Constructor.
  24. //
  25. // Arguments:
  26. // idcBrowseButtonIn - ID of the Browse pushbutton control.
  27. //
  28. // Return Values:
  29. // None.
  30. //
  31. //--
  32. //////////////////////////////////////////////////////////////////////////////
  33. CSelNodesPageCommon::CSelNodesPageCommon( void )
  34. : m_hwnd( NULL )
  35. , m_cfDsObjectPicker( 0 )
  36. {
  37. TraceFunc( "" );
  38. TraceFuncExit();
  39. } //*** CSelNodesPageCommon::CSelNodesPageCommon
  40. //////////////////////////////////////////////////////////////////////////////
  41. //++
  42. //
  43. // CSelNodesPageCommon::~CSelNodesPageCommon
  44. //
  45. // Description:
  46. // Destructor.
  47. //
  48. // Arguments:
  49. // None.
  50. //
  51. // Return Values:
  52. // None.
  53. //
  54. //--
  55. //////////////////////////////////////////////////////////////////////////////
  56. CSelNodesPageCommon::~CSelNodesPageCommon( void )
  57. {
  58. TraceFunc( "" );
  59. TraceFuncExit();
  60. } //*** CSelNodesPageCommon::~CSelNodesPageCommon
  61. //////////////////////////////////////////////////////////////////////////////
  62. //++
  63. //
  64. // CSelNodesPageCommon::OnInitDialog
  65. //
  66. // Description:
  67. // Handle the WM_INITDIALOG window message.
  68. //
  69. // Arguments:
  70. // hDlgIn
  71. // pccwIn
  72. //
  73. // Return Values:
  74. // FALSE - Didn't set the focus.
  75. //
  76. //-
  77. //////////////////////////////////////////////////////////////////////////////
  78. LRESULT
  79. CSelNodesPageCommon::OnInitDialog(
  80. HWND hDlgIn
  81. , CClusCfgWizard* pccwIn
  82. )
  83. {
  84. TraceFunc( "" );
  85. Assert( m_hwnd == NULL );
  86. Assert( hDlgIn != NULL );
  87. LRESULT lr = FALSE; // Didn't set the focus.
  88. m_hwnd = hDlgIn;
  89. //
  90. // Get the Object Picker clipboard format.
  91. // Enable or disable the Browse button based on the success of that operation.
  92. //
  93. m_cfDsObjectPicker = RegisterClipboardFormat( CFSTR_DSOP_DS_SELECTION_LIST );
  94. if ( m_cfDsObjectPicker == 0 )
  95. {
  96. TW32( GetLastError() );
  97. //
  98. // If registering the clipboard format fails, then disable the Browse
  99. // button.
  100. //
  101. EnableWindow( GetDlgItem( hDlgIn, IDC_SELNODE_PB_BROWSE ), FALSE );
  102. } // if: failed to get the object picker clipboard format
  103. THR( HrInitNodeSelections( pccwIn ) );
  104. RETURN( lr );
  105. } //*** CSelNodesPageCommon::OnInitDialog
  106. //////////////////////////////////////////////////////////////////////////////
  107. //++
  108. //
  109. // CSelNodesPageCommon::HrBrowse
  110. //
  111. // Description:
  112. // Browse for a computer or multiple computers using the Object Picker.
  113. //
  114. // Arguments:
  115. // fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
  116. //
  117. // Return Values:
  118. // S_OK
  119. // Other HRESULT values.
  120. //
  121. //--
  122. //////////////////////////////////////////////////////////////////////////////
  123. HRESULT
  124. CSelNodesPageCommon::HrBrowse(
  125. bool fMultipleNodesIn
  126. )
  127. {
  128. TraceFunc( "" );
  129. Assert( m_hwnd != NULL );
  130. HRESULT hr = S_OK;
  131. IDsObjectPicker * piop = NULL;
  132. IDataObject * pido = NULL;
  133. HCURSOR hOldCursor = NULL;
  134. hOldCursor = SetCursor( LoadCursor( g_hInstance, IDC_WAIT ) );
  135. // Create an instance of the object picker.
  136. hr = THR( CoCreateInstance( CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (void **) &piop ) );
  137. if ( FAILED( hr ) )
  138. {
  139. goto Cleanup;
  140. } // if:
  141. // Initialize the object picker instance.
  142. hr = THR( HrInitObjectPicker( piop, fMultipleNodesIn ) );
  143. if ( FAILED( hr ) )
  144. {
  145. goto Cleanup;
  146. } // if:
  147. // Restore the old cursor.
  148. SetCursor( hOldCursor );
  149. hOldCursor = NULL;
  150. // Invoke the modal dialog.
  151. hr = THR( piop->InvokeDialog( m_hwnd, &pido ) );
  152. if ( FAILED( hr ) )
  153. {
  154. goto Cleanup;
  155. } // if:
  156. if ( hr == S_OK )
  157. {
  158. hr = THR( HrGetSelections( pido, fMultipleNodesIn ) );
  159. } // if:
  160. else if ( hr == S_FALSE )
  161. {
  162. hr = S_OK; // don't want to squawk in the caller...
  163. } // else if:
  164. Cleanup:
  165. if ( pido != NULL )
  166. {
  167. pido->Release();
  168. } // if:
  169. if ( piop != NULL )
  170. {
  171. piop->Release();
  172. } // if:
  173. if ( hOldCursor != NULL )
  174. {
  175. SetCursor( hOldCursor );
  176. }
  177. HRETURN( hr );
  178. } //*** CSelNodesPageCommon::HrBrowse
  179. //////////////////////////////////////////////////////////////////////////////
  180. //++
  181. //
  182. // CSelNodesPageCommon::HrInitObjectPicker
  183. //
  184. // Description:
  185. // Initialize the Object Picker dialog.
  186. //
  187. // Arguments:
  188. // piopIn - IDsObjectPicker
  189. // fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
  190. //
  191. // Return Values:
  192. // HRESULT values.
  193. //
  194. //--
  195. //////////////////////////////////////////////////////////////////////////////
  196. HRESULT
  197. CSelNodesPageCommon::HrInitObjectPicker(
  198. IDsObjectPicker * piopIn
  199. , bool fMultipleNodesIn
  200. )
  201. {
  202. TraceFunc( "" );
  203. Assert( piopIn != NULL );
  204. DSOP_SCOPE_INIT_INFO rgScopeInit[ 1 ];
  205. DSOP_INIT_INFO iiInfo;
  206. ZeroMemory( rgScopeInit, sizeof( rgScopeInit ) );
  207. rgScopeInit[ 0 ].cbSize = sizeof( DSOP_SCOPE_INIT_INFO );
  208. rgScopeInit[ 0 ].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
  209. | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
  210. rgScopeInit[ 0 ].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
  211. rgScopeInit[ 0 ].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
  212. rgScopeInit[ 0 ].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  213. ZeroMemory( &iiInfo, sizeof( iiInfo ) );
  214. iiInfo.cbSize = sizeof( iiInfo );
  215. iiInfo.pwzTargetComputer = NULL;
  216. iiInfo.cDsScopeInfos = 1;
  217. iiInfo.aDsScopeInfos = rgScopeInit;
  218. if ( fMultipleNodesIn )
  219. {
  220. iiInfo.flOptions = DSOP_FLAG_MULTISELECT;
  221. }
  222. else
  223. {
  224. iiInfo.flOptions = 0;
  225. }
  226. HRETURN( piopIn->Initialize( &iiInfo ) );
  227. } //*** CSelNodesPageCommon::HrInitObjectPicker
  228. //////////////////////////////////////////////////////////////////////////////
  229. //++
  230. //
  231. // CSelNodesPageCommon::HrGetSelections
  232. //
  233. // Description:
  234. // Get selections from the Object Picker dialog.
  235. //
  236. // Arguments:
  237. // pidoIn - IDataObject
  238. // fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
  239. //
  240. // Return Values:
  241. // S_OK
  242. // E_OUTOFMEMORY
  243. // Other HRESULT values.
  244. //
  245. //--
  246. //////////////////////////////////////////////////////////////////////////////
  247. HRESULT
  248. CSelNodesPageCommon::HrGetSelections(
  249. IDataObject * pidoIn
  250. , bool fMultipleNodesIn
  251. )
  252. {
  253. TraceFunc( "" );
  254. Assert( pidoIn != NULL );
  255. Assert( m_hwnd != NULL );
  256. HRESULT hr;
  257. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL, NULL };
  258. FORMATETC formatetc = { (CLIPFORMAT) m_cfDsObjectPicker, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  259. PDS_SELECTION_LIST pds = NULL;
  260. DWORD sc;
  261. HWND hwndEdit = GetDlgItem( m_hwnd, IDC_SELNODE_E_COMPUTERNAME );
  262. BSTR bstrSelectionList = NULL;
  263. BSTR bstrOldSelectionList = NULL;
  264. //
  265. // Get the data from the data object.
  266. //
  267. hr = THR( pidoIn->GetData( &formatetc, &stgmedium ) );
  268. if ( FAILED( hr ) )
  269. {
  270. goto Cleanup;
  271. }
  272. pds = (PDS_SELECTION_LIST) GlobalLock( stgmedium.hGlobal );
  273. if ( pds == NULL )
  274. {
  275. sc = TW32( GetLastError() );
  276. hr = HRESULT_FROM_WIN32( sc );
  277. goto Cleanup;
  278. } // if:
  279. //
  280. // Construct the string to write into the edit control.
  281. //
  282. Assert( pds->cItems > 0 );
  283. if ( ! fMultipleNodesIn )
  284. {
  285. Assert( pds->cItems == 1 );
  286. Edit_SetText( hwndEdit, pds->aDsSelection[ 0 ].pwzName );
  287. } // if: multiple items are NOT supported
  288. else
  289. {
  290. ULONG idx;
  291. for ( idx = 0 ; idx < pds->cItems; idx++ )
  292. {
  293. if ( bstrSelectionList == NULL ) // First name in list.
  294. {
  295. bstrSelectionList = TraceSysAllocString( pds->aDsSelection[ idx ].pwzName );
  296. if ( bstrSelectionList == NULL )
  297. {
  298. hr = THR( E_OUTOFMEMORY );
  299. goto Cleanup;
  300. }
  301. }
  302. else // Append another name to non-empty list.
  303. {
  304. TraceSysFreeString( bstrOldSelectionList );
  305. bstrOldSelectionList = bstrSelectionList;
  306. bstrSelectionList = NULL;
  307. hr = THR( HrFormatStringIntoBSTR(
  308. L"%1!ws!; %2!ws!"
  309. , &bstrSelectionList
  310. , bstrOldSelectionList
  311. , pds->aDsSelection[ idx ].pwzName
  312. ) );
  313. if ( FAILED( hr ) )
  314. {
  315. goto Cleanup;
  316. }
  317. } // else: append name to non-empty list.
  318. } // for each item in list
  319. Edit_SetText( hwndEdit, bstrSelectionList );
  320. } // else: multiple items are supported
  321. goto Cleanup;
  322. Cleanup:
  323. TraceSysFreeString( bstrSelectionList );
  324. TraceSysFreeString( bstrOldSelectionList );
  325. if ( pds != NULL )
  326. {
  327. GlobalUnlock( stgmedium.hGlobal );
  328. } // if:
  329. if ( stgmedium.hGlobal != NULL )
  330. {
  331. ReleaseStgMedium( &stgmedium );
  332. } // if:
  333. HRETURN( hr );
  334. } //*** CSelNodesPageCommon::HrGetSelections
  335. //////////////////////////////////////////////////////////////////////////////
  336. //++
  337. //
  338. // CSelNodesPageCommon::HrInitNodeSelections
  339. //
  340. // Description:
  341. // Validate node selections the wizard had on startup, and populate the
  342. // page's controls appropriately.
  343. //
  344. // Arguments:
  345. // pccwIn - The wizard containing this page.
  346. //
  347. // Return Values:
  348. // S_OK
  349. // E_OUTOFMEMORY
  350. // Other HRESULT values.
  351. //
  352. //--
  353. //////////////////////////////////////////////////////////////////////////////
  354. HRESULT
  355. CSelNodesPageCommon::HrInitNodeSelections( CClusCfgWizard* pccwIn )
  356. {
  357. TraceFunc( "" );
  358. HRESULT hr = S_OK;
  359. BSTR bstrNodeName = NULL;
  360. BSTR bstrComputerName = NULL;
  361. BSTR bstrBadNodeList = NULL;
  362. BSTR bstrLocalDomain = NULL;
  363. BSTR bstrShortName = NULL;
  364. bool fDefaultToLocalMachine = true;
  365. size_t cNodes = 0;
  366. //
  367. // Filter out any pre-loaded node FQDNs with bad domains.
  368. //
  369. hr = THR( pccwIn->HrFilterNodesWithBadDomains( &bstrBadNodeList ) );
  370. if ( FAILED( hr ) )
  371. {
  372. goto Cleanup;
  373. } // if
  374. if ( bstrBadNodeList != NULL )
  375. {
  376. fDefaultToLocalMachine = false;
  377. // Give subclasses a look at the whole list.
  378. OnFilteredNodesWithBadDomains( bstrBadNodeList );
  379. // Loop through the list, notifying the user of each invalid node.
  380. // This is destroys the list as it walks through it, so writing the
  381. // list to the edit box needs to happen first.
  382. {
  383. CDelimitedIterator it( L" ,;", bstrBadNodeList, SysStringLen( bstrBadNodeList ) );
  384. while ( it.Current() != NULL )
  385. {
  386. THR( HrMessageBoxWithStatusString(
  387. m_hwnd
  388. , IDS_ERR_VALIDATING_NAME_TITLE
  389. , IDS_ERR_VALIDATING_NAME_TEXT
  390. , IDS_ERR_HOST_DOMAIN_DOESNT_MATCH_CLUSTER
  391. , 0
  392. , MB_OK | MB_ICONSTOP
  393. , NULL
  394. , it.Current()
  395. ) );
  396. // Give subclasses a look at the bad node.
  397. OnProcessedNodeWithBadDomain( it.Current() );
  398. it.Next();
  399. }; // for each bad node
  400. } // Notify user of each bad node.
  401. } // if: some nodes have bad domains
  402. //
  403. // Process any remaining valid nodes.
  404. //
  405. hr = THR( pccwIn->HrGetNodeCount( &cNodes ) );
  406. if ( FAILED( hr ) )
  407. {
  408. goto Cleanup;
  409. } // if
  410. if ( cNodes > 0 )
  411. {
  412. for ( size_t idxNode = 0; idxNode < cNodes; ++idxNode )
  413. {
  414. hr = THR( pccwIn->HrGetNodeName( idxNode, &bstrNodeName ) );
  415. if ( FAILED( hr ) )
  416. {
  417. goto Cleanup;
  418. } // if
  419. hr = THR( HrGetFQNDisplayName( bstrNodeName, &bstrShortName ) );
  420. if ( FAILED( hr ) )
  421. {
  422. goto Cleanup;
  423. } // if
  424. // Give subclasses a look at the good node.
  425. OnProcessedValidNode( bstrShortName );
  426. TraceSysFreeString( bstrNodeName );
  427. bstrNodeName = NULL;
  428. TraceSysFreeString( bstrShortName );
  429. bstrShortName = NULL;
  430. } // for each valid node.
  431. fDefaultToLocalMachine = false;
  432. } // if any valid nodes remain.
  433. //
  434. // Decide whether defaulting to the local machine is appropriate at this time.
  435. //
  436. if ( fDefaultToLocalMachine )
  437. {
  438. DWORD dwStatus;
  439. DWORD dwClusterState;
  440. //
  441. // If the node is already in a cluster, don't have it default in the edit box.
  442. // If there is an error getting the "NodeClusterState", then default the node
  443. // name (it could be in the middle of cleaning up the node).
  444. //
  445. dwStatus = TW32( GetNodeClusterState( NULL, &dwClusterState ) );
  446. fDefaultToLocalMachine = ( ( dwStatus != ERROR_SUCCESS ) || ( dwClusterState == ClusterStateNotConfigured ) );
  447. if ( !fDefaultToLocalMachine )
  448. {
  449. goto Cleanup;
  450. } // if
  451. //
  452. // ...but don't default if the local machine is not in the cluster's domain.
  453. //
  454. hr = THR( HrGetComputerName(
  455. ComputerNamePhysicalDnsDomain
  456. , &bstrLocalDomain
  457. , TRUE // fBestEffortIn
  458. ) );
  459. if ( FAILED( hr ) )
  460. {
  461. goto Cleanup;
  462. } // if
  463. hr = STHR( pccwIn->HrIsCompatibleNodeDomain( bstrLocalDomain ) );
  464. if ( FAILED( hr ) )
  465. {
  466. goto Cleanup;
  467. } // if
  468. fDefaultToLocalMachine = ( hr == S_OK );
  469. if ( !fDefaultToLocalMachine )
  470. {
  471. goto Cleanup;
  472. } // if
  473. //
  474. // Now have cleared all the obstacles to defaulting to the local machine--hooray!
  475. //
  476. hr = THR( HrGetComputerName(
  477. ComputerNameDnsHostname
  478. , &bstrComputerName
  479. , TRUE // fBestEffortIn
  480. ) );
  481. if ( FAILED( hr ) )
  482. {
  483. goto Cleanup;
  484. } // if
  485. THR( HrSetDefaultNode( bstrComputerName ) );
  486. } // if defaulting to local machine is still an option.
  487. Cleanup:
  488. TraceSysFreeString( bstrNodeName );
  489. TraceSysFreeString( bstrComputerName );
  490. TraceSysFreeString( bstrBadNodeList );
  491. TraceSysFreeString( bstrLocalDomain );
  492. TraceSysFreeString( bstrShortName );
  493. HRETURN( hr );
  494. } //*** CSelNodesPageCommon::HrInitNodeSelections
  495. //////////////////////////////////////////////////////////////////////////////
  496. //++
  497. //
  498. // CSelNodesPageCommon::OnFilteredNodesWithBadDomains
  499. //
  500. // Description:
  501. // Tells the subclass that the wizard had nodes with bad domains, and
  502. // allows the subclass to inspect the list before the base class
  503. // iterates through them.
  504. //
  505. // Arguments:
  506. // pwcszNodeListIn
  507. // The nodes with clashing domains, delimited by spaces, commas, or
  508. // semicolons.
  509. //
  510. // Return Values:
  511. // None.
  512. //
  513. // Remarks:
  514. // This do-nothing default implementation allows subclasses
  515. // to avoid having to implement do-nothing responses themselves if they
  516. // don't want to do anything with the whole list at once.
  517. //
  518. //--
  519. //////////////////////////////////////////////////////////////////////////////
  520. void
  521. CSelNodesPageCommon::OnFilteredNodesWithBadDomains( PCWSTR pwcszNodeListIn )
  522. {
  523. UNREFERENCED_PARAMETER( pwcszNodeListIn );
  524. } //*** CSelNodesPageCommon::OnFilteredNodesWithBadDomains
  525. //////////////////////////////////////////////////////////////////////////////
  526. //++
  527. //
  528. // CSelNodesPageCommon::OnProcessedNodeWithBadDomain
  529. //
  530. // Description:
  531. // Allows the subclass to process each node in the list of nodes with
  532. // bad domains as the base class iterates through it.
  533. //
  534. // Arguments:
  535. // pwcszNodeNameIn
  536. // The node with a clashing domain.
  537. //
  538. // Return Values:
  539. // None.
  540. //
  541. // Remarks:
  542. // The base class notifies the user of each bad node name before calling
  543. // this method, so the base class provides also this default do-nothing
  544. // implementation for subclasses that don't need to do anything more.
  545. //--
  546. //////////////////////////////////////////////////////////////////////////////
  547. void
  548. CSelNodesPageCommon::OnProcessedNodeWithBadDomain( PCWSTR pwcszNodeNameIn )
  549. {
  550. UNREFERENCED_PARAMETER( pwcszNodeNameIn );
  551. } //*** CSelNodesPageCommon::OnProcessedNodeWithBadDomain
  552. //////////////////////////////////////////////////////////////////////////////
  553. //++
  554. //
  555. // CSelNodesPageCommon::OnProcessedValidNode
  556. //
  557. // Description:
  558. // Allows the subclass to process each node remaining in the wizard's
  559. // list after those with bad domains have been removed.
  560. //
  561. // Arguments:
  562. // pwcszNodeNameIn
  563. // The IP address or hostname (NOT the FQDN) of a valid node in
  564. // the wizard's list.
  565. //
  566. // Return Values:
  567. // None.
  568. //
  569. // Remarks:
  570. // This default do-nothing implementation allows subclasses to
  571. // ignore the node if they choose.
  572. //
  573. //--
  574. //////////////////////////////////////////////////////////////////////////////
  575. void
  576. CSelNodesPageCommon::OnProcessedValidNode( PCWSTR pwcszNodeNameIn )
  577. {
  578. UNREFERENCED_PARAMETER( pwcszNodeNameIn );
  579. } //*** CSelNodesPageCommon::OnProcessedValidNode