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.

6142 lines
218 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-1999 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // clusocm.cpp
  7. //
  8. // Abstract:
  9. // CLUSOCM.DLL is an Optional Components Manager DLL for installation of
  10. // Microsoft Cluster Server. This file is the class implementation file
  11. // for the CClusocmApp class which implements the component setup procedure.
  12. //
  13. // Author:
  14. // C. Brent Thomas (a-brentt)
  15. //
  16. // Revision History:
  17. // 1/29/98 original
  18. //
  19. // Notes:
  20. //
  21. // If this DLL is dynamically linked against the MFC
  22. // DLLs, any functions exported from this DLL which
  23. // call into MFC must have the AFX_MANAGE_STATE macro
  24. // added at the very beginning of the function.
  25. //
  26. // For example:
  27. //
  28. // extern "C" BOOL PASCAL EXPORT ExportedFunction()
  29. // {
  30. // AFX_MANAGE_STATE(AfxGetStaticModuleState());
  31. // // normal function body here
  32. // }
  33. //
  34. // It is very important that this macro appear in each
  35. // function, prior to any calls into MFC. This means that
  36. // it must appear as the first statement within the
  37. // function, even before any object variable declarations
  38. // as their constructors may generate calls into the MFC
  39. // DLL.
  40. //
  41. // Please see MFC Technical Notes 33 and 58 for additional
  42. // details.
  43. //
  44. //
  45. /////////////////////////////////////////////////////////////////////////////
  46. //
  47. #include "stdafx.h"
  48. #include "clusocm.h"
  49. #include <regcomobj.h>
  50. #include <StopService.h>
  51. #include <RemoveNetworkProvider.h>
  52. #include <IsClusterServiceRegistered.h>
  53. #ifdef _DEBUG
  54. #define new DEBUG_NEW
  55. #undef THIS_FILE
  56. static char THIS_FILE[] = __FILE__;
  57. #endif
  58. /////////////////////////////////////////////////////////////////////////////
  59. // Global Data
  60. /////////////////////////////////////////////////////////////////////////////
  61. // The one and only CClusocmApp object
  62. CClusocmApp theApp;
  63. /////////////////////////////////////////////////////////////////////////////
  64. // Global Functions
  65. // This is the function that OC Manager will call.
  66. /////////////////////////////////////////////////////////////////////////////
  67. //++
  68. //
  69. // ClusOcmSetupProc
  70. //
  71. // Routine Description:
  72. // This is the exported function that OC Manager calls. It merely passes
  73. // its' parameters to the CClusocmApp object and returns the results to
  74. // OC Manager.
  75. //
  76. // Arguments:
  77. // pvComponentId - points to a string that uniquely identifies the component
  78. // to be set up to OC Manager.
  79. // pvSubComponentId - points to a string that uniquely identifies a sub-
  80. // component in the component's hiearchy.
  81. // uxFunction - A numeric value indicating which function is to be perfomed.
  82. // See ocmanage.h for the macro definitions.
  83. // uxParam1 - supplies a function specific parameter.
  84. // pvParam2 - points to a function specific parameter (which may be an
  85. // output).
  86. //
  87. // Return Value:
  88. // A function specific value is returned to OC Manager.
  89. //
  90. //--
  91. /////////////////////////////////////////////////////////////////////////////
  92. extern "C" DWORD WINAPI ClusOcmSetupProc( IN LPCVOID pvComponentId,
  93. IN LPCVOID pvSubComponentId,
  94. IN UINT uxFunction,
  95. IN UINT uxParam1,
  96. IN OUT PVOID pvParam2 )
  97. {
  98. return theApp.ClusOcmSetupProc( pvComponentId,
  99. pvSubComponentId,
  100. uxFunction,
  101. uxParam1,
  102. pvParam2 );
  103. } //*** exported ClusOcmSetupProc()
  104. /////////////////////////////////////////////////////////////////////////////
  105. // CClusocmApp
  106. BEGIN_MESSAGE_MAP(CClusocmApp, CWinApp)
  107. //{{AFX_MSG_MAP(CClusocmApp)
  108. // NOTE - the ClassWizard will add and remove mapping macros here.
  109. // DO NOT EDIT what you see in these blocks of generated code!
  110. //}}AFX_MSG_MAP
  111. END_MESSAGE_MAP()
  112. /////////////////////////////////////////////////////////////////////////////
  113. // CClusocmApp construction
  114. // Default constructor
  115. CClusocmApp::CClusocmApp()
  116. {
  117. // TODO: add construction code here,
  118. // Place all significant initialization in InitInstance
  119. // Initialize the values of the HINF members in the SETUP_INIT_COMPONENT
  120. // structure data member.
  121. m_SetupInitComponent.OCInfHandle = (HINF) INVALID_HANDLE_VALUE;
  122. m_SetupInitComponent.ComponentInfHandle = (HINF) INVALID_HANDLE_VALUE;
  123. m_dwStepCount = 0L;
  124. }
  125. /////////////////////////////////////////////////////////////////////////////
  126. //++
  127. //
  128. // InitInstance
  129. //
  130. // Routine Description:
  131. //
  132. //
  133. // Arguments:
  134. //
  135. //
  136. //
  137. // Return Value:
  138. //
  139. //
  140. //--
  141. /////////////////////////////////////////////////////////////////////////////
  142. BOOL CClusocmApp::InitInstance( void )
  143. {
  144. BOOL fReturnValue = (BOOL) TRUE;
  145. m_hInstance = AfxGetInstanceHandle();
  146. // Initialize OLE libraries
  147. if (!AfxOleInit())
  148. {
  149. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) ==
  150. (DWORDLONG) 0L )
  151. {
  152. AfxMessageBox( IDS_OLE_INIT_FAILED );
  153. }
  154. ClRtlLogPrint( "OLE initialization failed. Make sure that the OLE libraries are the correct version.\n" );
  155. fReturnValue = (BOOL) FALSE;
  156. }
  157. return ( fReturnValue );
  158. }
  159. /////////////////////////////////////////////////////////////////////////////
  160. //++
  161. //
  162. // CClusocmApp::ClusOcmSetupProc
  163. //
  164. // Routine Description:
  165. // This function implements the Optional Components Manager component
  166. // setup procedure. This function is called by the exported function
  167. // of the same name, which in turn is called by OC Manager.
  168. //
  169. // Arguments:
  170. // pvComponentId - points to a string that uniquely identifies the component
  171. // to be set up to OC Manager.
  172. // pvSubComponentId - points to a string that uniquely identifies a sub-
  173. // component in the component's hiearchy.
  174. // uxFunction - A numeric value indicating which function is to be perfomed.
  175. // See ocmanage.h for the macro definitions.
  176. // uxParam1 - supplies a function specific parameter.
  177. // pvParam2 - points to a function specific parameter (which may be an
  178. // output).
  179. //
  180. //
  181. // Return Value:
  182. // A function specific value is returned to OC Manager.
  183. //
  184. //--
  185. /////////////////////////////////////////////////////////////////////////////
  186. #pragma warning ( disable : 4100 ) // disable "unreferenced formal parameter" warning
  187. // At this time (2/26/98) pvComponentId is unused.
  188. DWORD CClusocmApp::ClusOcmSetupProc( IN LPCVOID pvComponentId,
  189. IN LPCVOID pvSubComponentId,
  190. IN UINT uxFunction,
  191. IN UINT uxParam1,
  192. IN OUT PVOID pvParam2 )
  193. {
  194. AFX_MANAGE_STATE( AfxGetStaticModuleState() ); // As per the note in file header
  195. DWORD dwReturnValue;
  196. switch ( uxFunction )
  197. {
  198. case OC_PREINITIALIZE:
  199. // This is the first interface function that OC Manager calls.
  200. // OnOcPreinitialize enables the log file for clusocm.dll, verifies
  201. // that the OS version and Product Suite are correct, etc.
  202. dwReturnValue = OnOcPreinitialize();
  203. ClRtlLogPrint( "OnOcPreinitialize returned 0x%1!x!\n\n", dwReturnValue );
  204. break;
  205. case OC_INIT_COMPONENT:
  206. // This function is called soon after the component's setup dll is
  207. // loaded. This function provides initialization information to the
  208. // dll, instructs the dll to initialize itself, and provides a
  209. // mechanism for the dll to return information to OC Manager.
  210. // It may be desirable to verify that Microsoft Cluster Server is being
  211. // installed on NT Enterprise and to authenticate the user at this point.
  212. dwReturnValue = OnOcInitComponent((PSETUP_INIT_COMPONENT) pvParam2 );
  213. ClRtlLogPrint( "OnOcInitComponent returned 0x%1!x!\n\n", dwReturnValue );
  214. break;
  215. case OC_REQUEST_PAGES:
  216. // OC Manager is requesting a set of wizard pages from the dll.
  217. // As of 2/16/98 there are no wizard pages to supply.
  218. dwReturnValue = (DWORD) 0L;
  219. ClRtlLogPrint( "ClusOcmSetupProc is returning 0x%1!x! in response to OC_REQUEST_PAGES.\n\n",
  220. dwReturnValue );
  221. break;
  222. case OC_QUERY_STATE:
  223. // Oc Manager is requesting the selection state of the component.
  224. // It does that at least three times.
  225. dwReturnValue = OnOcQueryState( (LPCTSTR) pvSubComponentId, uxParam1 );
  226. ClRtlLogPrint( "OnQueryState returned 0x%1!x!\n\n", dwReturnValue );
  227. break;
  228. case OC_SET_LANGUAGE:
  229. // OC Manager documentation states:
  230. //
  231. // "If a component does not support multiple languages, or if it does
  232. // not support the requested language, then it may ignore OC_SET_LANGUAGE."
  233. // I have replicated the functionality in Pat Styles' generic sample, ocgen.cpp.
  234. dwReturnValue = OnOcSetLanguage();
  235. ClRtlLogPrint( "OnOcSetLanguage returned 0x%1!x!.\n\n", dwReturnValue );
  236. break;
  237. case OC_CALC_DISK_SPACE:
  238. dwReturnValue = OnOcCalcDiskSpace( (LPCTSTR) pvSubComponentId,
  239. uxParam1,
  240. (HDSKSPC) pvParam2 );
  241. ClRtlLogPrint( "OnOcCalcDiskSpace returned 0x%1!x!.\n\n", dwReturnValue );
  242. break;
  243. case OC_QUEUE_FILE_OPS:
  244. if ( (pvSubComponentId != (PVOID) NULL) &&
  245. (*((LPCTSTR) pvSubComponentId) != _T('\0')) )
  246. {
  247. dwReturnValue = OnOcQueueFileOps( (LPCTSTR) pvSubComponentId,
  248. (HSPFILEQ) pvParam2 );
  249. ClRtlLogPrint( "OnOcQueueFileOps returned 0x%1!x!.\n\n", dwReturnValue );
  250. }
  251. else
  252. {
  253. dwReturnValue = (DWORD) NO_ERROR;
  254. }
  255. break;
  256. case OC_QUERY_CHANGE_SEL_STATE:
  257. dwReturnValue = OnOcQueryChangeSelState( (LPCTSTR) pvSubComponentId,
  258. (UINT) uxParam1,
  259. (DWORD) ((DWORD_PTR)pvParam2) );
  260. ClRtlLogPrint( "OnOnQueryChangeSelState returned 0x%1!x!.\n\n", dwReturnValue );
  261. break;
  262. case OC_COMPLETE_INSTALLATION:
  263. if ( (pvSubComponentId != (PVOID) NULL) &&
  264. (*((LPCTSTR) pvSubComponentId) != _T('\0')) )
  265. {
  266. dwReturnValue = OnOcCompleteInstallation( (LPCTSTR) pvSubComponentId );
  267. ClRtlLogPrint( "OnOcCompleteInstallation returned 0x%1!x!.\n\n", dwReturnValue );
  268. }
  269. else
  270. {
  271. dwReturnValue = (DWORD) NO_ERROR;
  272. }
  273. break;
  274. case OC_WIZARD_CREATED:
  275. // This interface function code is not documented. I have replicated the
  276. // functionality of Pat Styles' generic sample, ocgen.cpp.
  277. dwReturnValue = (DWORD) NO_ERROR;
  278. ClRtlLogPrint( "returning 0x%1!x! for OC_WIZARD_CREATED.\n\n", dwReturnValue );
  279. break;
  280. case OC_NEED_MEDIA:
  281. // This interface function code is not documented. I have replicated the
  282. // functionality of Pat Styles' generic sample, ocgen.cpp.
  283. dwReturnValue = (DWORD) FALSE;
  284. ClRtlLogPrint( "returning 0x%1!x! for OC_NEED_MEDIA.\n\n" );
  285. break;
  286. case OC_QUERY_SKIP_PAGE:
  287. // This interface function code is not documented. I have replicated the
  288. // functionality of Pat Styles' generic sample, ocgen.cpp.
  289. dwReturnValue = (DWORD) FALSE;
  290. ClRtlLogPrint( "returning 0x%1!x! for OC_QUERY_SKIP_PAGE.\n\n", dwReturnValue );
  291. break;
  292. case OC_QUERY_STEP_COUNT:
  293. // OC Manager uses this interface function code to request the number
  294. // of "steps", other than file operations, that must be performed to
  295. // install the component.
  296. if ( (pvSubComponentId != (PVOID) NULL) &&
  297. (*((LPCTSTR) pvSubComponentId) != _T('\0')) )
  298. {
  299. dwReturnValue = CalculateStepCount( (LPCTSTR) pvSubComponentId );
  300. if ( dwReturnValue != 0L )
  301. {
  302. // Update the data member.
  303. SetStepCount( dwReturnValue );
  304. }
  305. }
  306. else
  307. {
  308. dwReturnValue = (DWORD) NO_ERROR;
  309. }
  310. ClRtlLogPrint( "returning 0x%1!x! for OC_QUERY_STEP_COUNT.\n\n", dwReturnValue );
  311. break;
  312. case OC_CLEANUP:
  313. // This interface function code is the last to be processed.
  314. // OC Manager documentation states that the return value from processing
  315. // this interface function code is ignored.
  316. dwReturnValue = OnOcCleanup();
  317. break;
  318. case OC_ABOUT_TO_COMMIT_QUEUE:
  319. if ( (pvSubComponentId != (PVOID) NULL) &&
  320. (*((LPCTSTR) pvSubComponentId) != _T('\0')) )
  321. {
  322. dwReturnValue = OnOcAboutToCommitQueue( (LPCTSTR) pvSubComponentId );
  323. ClRtlLogPrint( "OnOcAboutToCommitQueue returned 0x%1!x!.\n\n", dwReturnValue );
  324. }
  325. else
  326. {
  327. dwReturnValue = (DWORD) NO_ERROR;
  328. }
  329. break;
  330. case OC_EXTRA_ROUTINES:
  331. dwReturnValue = (DWORD) NO_ERROR;
  332. ClRtlLogPrint( "returning 0x%1!x! for OC_EXTRA_ROUTINES.\n\n", dwReturnValue );
  333. break;
  334. default:
  335. dwReturnValue = (DWORD) NO_ERROR;
  336. ClRtlLogPrint( "ClusOcmSetupProc received an unknown function code, 0x%1!x!.\n",
  337. uxFunction );
  338. ClRtlLogPrint( "returning 0x%1!x!.\n", dwReturnValue );
  339. break;
  340. } // end of switch( uxFunction )
  341. return ( (DWORD) dwReturnValue );
  342. }
  343. #pragma warning ( default : 4100 ) // default behavior "unreferenced formal parameter" warning
  344. /////////////////////////////////////////////////////////////////////////////
  345. //++
  346. //
  347. // OnOcPreinitialize
  348. //
  349. // Routine Description:
  350. // This funcion processes OC_PREINITIALIZE "messages" from Optional
  351. // Components Manager. This is the first function in the component
  352. // setup dll that OC Manager calls.
  353. //
  354. // This function prevents clusocm.dll from running on down level operating
  355. // systems and unuthorized platforms.
  356. //
  357. // Since Microsoft Cluster Server can only be installed on NT this function
  358. // selects the UNICODE character set.
  359. //
  360. // Arguments:
  361. // None
  362. //
  363. // Return Value:
  364. // (DWORD) OCFLAG_UNICODE - indicates success
  365. // (DWORD) 0 - indicates that the component cannot be initialized.
  366. //
  367. //--
  368. /////////////////////////////////////////////////////////////////////////////
  369. DWORD CClusocmApp::OnOcPreinitialize( void )
  370. {
  371. DWORD dwReturnValue;
  372. // The ClRtlInitialize function that opens a log file reads the ClusterLog
  373. // environment variable. This code segment reads that environment variable
  374. // and saves it so that it can be restored on exit.
  375. char * pszOriginalLogFileName;
  376. pszOriginalLogFileName = getenv( "ClusterLog" );
  377. if ( pszOriginalLogFileName != (char *) NULL )
  378. {
  379. strcpy( m_szOriginalLogFileName, pszOriginalLogFileName );
  380. }
  381. else
  382. {
  383. *m_szOriginalLogFileName = (char) '\0';
  384. }
  385. // Build the string used to set the ClusterLog environment variable to point
  386. // to the log for clusocm.dll.
  387. char szClusterLogEnvString[MAX_PATH];
  388. // Initialize the string to be empty.
  389. *szClusterLogEnvString = '\0';
  390. // The log file for clusocm.dll will be located in the windows directory.
  391. // Note that if the path to the Windows directory cannot be obtained the
  392. // ClusterLog environment variable will be set empty. Then function ClRtlInitialize
  393. // will use the default log file name and location.
  394. TCHAR tszWindowsDirectory[MAX_PATH];
  395. UINT uxReturnValue;
  396. uxReturnValue = GetWindowsDirectory( tszWindowsDirectory, (UINT) MAX_PATH );
  397. if ( uxReturnValue > 0 )
  398. {
  399. // The first part of the string to set the ClusterLog environment variable is
  400. // "ClusterLog=".
  401. strcpy( szClusterLogEnvString, "ClusterLog=" );
  402. // Convert the path to the Windows directory to MBCS.
  403. char szWindowsDirectory[MAX_PATH];
  404. wcstombs( szWindowsDirectory, tszWindowsDirectory, MAX_PATH );
  405. // Append the path to the Windows directory.
  406. strcat( szClusterLogEnvString, szWindowsDirectory );
  407. // Append the log file name.
  408. strcat( szClusterLogEnvString, "\\clusocm.log" );
  409. } // Was the path to the Windows directory obtained?
  410. // Set the ClusterLog environment variable. Note that _putenv returns 0
  411. // on success.
  412. if ( _putenv( szClusterLogEnvString ) != 0 )
  413. {
  414. dwReturnValue = GetLastError(); // just here for debugging
  415. }
  416. // Initialize the cluster runtime library. FALSE indicates that debug
  417. // output should not be redirected to a console window. If ClRtlInitialize
  418. // fails the calls to ClRtlLogPrint will be benign.
  419. ClRtlInitialize( FALSE );
  420. // Note: The date in the following statement is hardcoded on purpose. It is to
  421. // indicate when the last time the logging statements were revised.
  422. ClRtlLogPrint( "\n\nCLUSOCM.LOG version 04/09/99 13:20.\n" );
  423. // Microsoft Cluster Server can only be installed on Windows NT Server Enterprise 5.0+.
  424. // This code segment checks the operating system version.
  425. // Since Microsoft Cluster Server can only be installed on NT indicate
  426. // to OC Manager that the UNICODE character set should be used.
  427. dwReturnValue = (DWORD) OCFLAG_UNICODE;
  428. return ( dwReturnValue );
  429. }
  430. /////////////////////////////////////////////////////////////////////////////
  431. //++
  432. //
  433. // OnOcInitComponent
  434. //
  435. // Routine Description:
  436. // This funcion processes OC_INIT_COMPONENT "messages" from Optional
  437. // Components Manager.
  438. //
  439. // This function is called soon after the component's setup dll is
  440. // loaded. This function provides initialization information to the
  441. // dll, instructs the dll to initialize itself, and provides a
  442. // mechanism for the dll to return information to OC Manager.
  443. //
  444. // Arguments:
  445. // pSetupInitComponent - points to a SETUP_INIT_COMPONENT structure
  446. //
  447. // Return Value:
  448. // (DWORD) NO_ERROR - indicates success
  449. // Any other value is a standard Win32 error code.
  450. //
  451. // Note:
  452. // The SETUP_INIT_COMPONENT structure pointed to by pSetupInitComponent
  453. // DOES NOT PERSIST. It is ncessary to save a copy in the CClusocmApp object.
  454. // This function initializes the SETUP_INIT_COMPONENT data member,
  455. // m_SetupInitComponent.
  456. //
  457. //--
  458. /////////////////////////////////////////////////////////////////////////////
  459. DWORD CClusocmApp::OnOcInitComponent( IN OUT PSETUP_INIT_COMPONENT pSetupInitComponent )
  460. {
  461. DWORD dwReturnValue;
  462. if ( pSetupInitComponent != (PSETUP_INIT_COMPONENT) NULL )
  463. {
  464. // Save the pointer to the SETUP_INIT_COMPONENT structure.
  465. m_SetupInitComponent = *pSetupInitComponent;
  466. // This code segment determines whether the version of OC Manager is
  467. // correct.
  468. if ( OCMANAGER_VERSION <= m_SetupInitComponent.OCManagerVersion )
  469. {
  470. // Indicate to OC Manager which version of OC Manager this dll expects.
  471. pSetupInitComponent->ComponentVersion = OCMANAGER_VERSION;
  472. // Update CClusocmApp's copy of the SETUP_INIT_COMPONENT structure.
  473. m_SetupInitComponent.ComponentVersion = OCMANAGER_VERSION;
  474. // Is the handle to the component INF valid ?
  475. if ( (m_SetupInitComponent.ComponentInfHandle !=
  476. (HINF) INVALID_HANDLE_VALUE) &&
  477. (m_SetupInitComponent.ComponentInfHandle !=
  478. (HINF) NULL) )
  479. {
  480. // The following call to SetupOpenAppendInfFile ensures that layout.inf
  481. // gets appended to clusocm.inf. This is required for several reasons
  482. // dictated by the Setup API. In theory OC Manager should do this, but
  483. // as per Andrew Ritz, 8/24/98, OC manager neglects to do it and it is
  484. // harmless to do it here after OC Manager is revised.
  485. // Note that passing NULL as the first parameter causes SetupOpenAppendInfFile
  486. // to append the file(s) listed on the LayoutFile entry in clusocm.inf.
  487. UINT uxStatus;
  488. SetupOpenAppendInfFile( NULL, m_SetupInitComponent.ComponentInfHandle,
  489. &uxStatus );
  490. if ( ClRtlIsOSValid() == TRUE )
  491. {
  492. // Since Microsoft Cluster Server can only be installed on NT indicate
  493. // to OC Manager that the UNICODE character set should be used.
  494. dwReturnValue = (DWORD) NO_ERROR;
  495. }
  496. else
  497. {
  498. // The operating system version is not correct.
  499. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) ==
  500. (DWORDLONG) 0L )
  501. {
  502. CString csMessage;
  503. csMessage.LoadString( IDS_ERR_INCORRECT_OS_VERSION );
  504. AfxMessageBox( csMessage );
  505. }
  506. DWORD dwErrorCode;
  507. dwErrorCode = GetLastError();
  508. ClRtlLogPrint( "ClRtlIsOSValid failed with error code %1!x!.\n",
  509. dwErrorCode );
  510. dwReturnValue = (DWORD) ERROR_CALL_NOT_IMPLEMENTED;
  511. }
  512. }
  513. else
  514. {
  515. // Indicate failure.
  516. ClRtlLogPrint( "In OnOcInitComponent the ComponentInfHandle is bad.\n" );
  517. dwReturnValue = (DWORD) ERROR_CALL_NOT_IMPLEMENTED;
  518. }
  519. }
  520. else
  521. {
  522. // Indicate failure.
  523. ClRtlLogPrint( "An OC Manager version mismatch. Version %1!d! is required, version %2!d! was reported.\n",
  524. OCMANAGER_VERSION, m_SetupInitComponent.OCManagerVersion );
  525. dwReturnValue = (DWORD) ERROR_CALL_NOT_IMPLEMENTED;
  526. }
  527. }
  528. else
  529. {
  530. ClRtlLogPrint( "In OnOcInitComponent the pointer to the SETUP_INIT_COMPONENT structure is NULL.\n" );
  531. dwReturnValue = (DWORD) ERROR_CALL_NOT_IMPLEMENTED;
  532. }
  533. return ( dwReturnValue );
  534. }
  535. /////////////////////////////////////////////////////////////////////////////
  536. //++
  537. //
  538. // OnOcQueryState
  539. //
  540. // Routine Description:
  541. // This funcion sets the original, current, and final selection states of the
  542. // Cluster service optional component.
  543. //
  544. // Arguments:
  545. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  546. // component in the component's hiearchy.
  547. // uxSelStateQueryType - indicates whether OC Manager is requesting the
  548. // original, current, or final selection state of the
  549. // component
  550. //
  551. // Return Value:
  552. // SubcompOn - indicates that the checkbox should be set
  553. // SubcompOff - indicates that the checkbox should be clear
  554. // SubcompUseOCManagerDefault - OC Manager should set the state of the checkbox
  555. // according to state information that is maintained
  556. // internally by OC Manager itself.
  557. //
  558. // Note:
  559. // By the time this function gets called OnOcInitComponent has already determined
  560. // that Terminal Services is not installed. It is only necessary to determine
  561. // whether Terminal Services is selected for installation.
  562. //--
  563. /////////////////////////////////////////////////////////////////////////////
  564. DWORD CClusocmApp::OnOcQueryState( IN LPCTSTR ptszSubComponentId,
  565. IN UINT uxSelStateQueryType )
  566. {
  567. DWORD dwReturnValue;
  568. eClusterInstallState eState;
  569. // For unattended setup the selection state of the Cluster service optional
  570. // component is specified in the answer file. Pat Styles recommends returning
  571. // SubcompUseOcManagerDefault in every case.
  572. // The following "if" statement forces SubcompUseOcManagerDefault to be returned
  573. // if the subcomponent name is invalid.
  574. if ( ptszSubComponentId != (LPCTSTR) NULL )
  575. {
  576. // The subcomponent ID is valid. For what purpose was this function called?
  577. switch ( uxSelStateQueryType )
  578. {
  579. case OCSELSTATETYPE_ORIGINAL:
  580. // OC Manager is requesting the intitial (original) selection state
  581. // of the component.
  582. // Is this a fresh install running under GUI mode setup ?
  583. if ( ( (m_SetupInitComponent.SetupData.OperationFlags &
  584. (DWORDLONG) SETUPOP_STANDALONE) == (DWORDLONG) 0L ) &&
  585. ( (m_SetupInitComponent.SetupData.OperationFlags &
  586. (DWORDLONG) SETUPOP_NTUPGRADE) == (DWORDLONG) 0L ) )
  587. {
  588. // SETUPOP_STANDALONE flag clear means running under GUI mode setup.
  589. // SETUPOP_NTUPGRADE flag clear means not performing an upgrade.
  590. // Both flags clear means a fresh install in GUI MODE setup.
  591. // Return SubcompUseOcManagerDefault. As per AndrewR, for unattended
  592. // clean install return SubcompUseOcManagerDefault. For attended
  593. // clean install let OC Manager manage the selection state. Returning
  594. // SubcompUseOcManagerDefault will allow OC Manager to honor the
  595. // "modes" line in clusocm.inf if one is present.
  596. dwReturnValue = (DWORD) SubcompUseOcManagerDefault;
  597. ClRtlLogPrint( "OnOcQueryState is returning SubcompUseOcManagerDefault for ORIGINAL on a clean install.\n" );
  598. } // clean install?
  599. else
  600. {
  601. // This is standalone or upgrade. Is this an unattended clean install?
  602. if ( ( (m_SetupInitComponent.SetupData.OperationFlags &
  603. (DWORDLONG) SETUPOP_BATCH) != (DWORDLONG) 0L ) &&
  604. ( (m_SetupInitComponent.SetupData.OperationFlags &
  605. (DWORDLONG) SETUPOP_NTUPGRADE) == (DWORDLONG) 0L ) )
  606. {
  607. // This is UNATTENDED INSTALL with OCM running STANDALONE. Since
  608. // this is STANDALONE, the MUST be an answer file.
  609. // As per AndrewR for unattended clean install return SubcompUseOcManagerDefault.
  610. dwReturnValue = (DWORD) SubcompUseOcManagerDefault;
  611. ClRtlLogPrint( "ORIGINAL selection state: SubcompUseOcManagerDefault - UNATTENDED CLEAN install.\n" );
  612. }
  613. else
  614. {
  615. // Either an upgrade is in progress or OC Manager is running standalone.
  616. // The state of the checkbox depends on whether Cluster service has
  617. // previously been installed.
  618. // GetClusterInstallationState reports on the state of the registry value
  619. // that records the state of the Cluster service installation on NT 5 machines.
  620. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  621. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  622. // upgrading NT 4 machines, GetClusterInstallationState for NT 5 machines.
  623. ClRtlGetClusterInstallState( NULL, &eState );
  624. if ( ( eState != eClusterInstallStateUnknown ) ||
  625. ( IsClusterServiceRegistered() == (BOOL) TRUE ) )
  626. {
  627. // No error was detected.
  628. dwReturnValue = (DWORD) SubcompOn;
  629. ClRtlLogPrint( "ORIGINAL selection state: SubcompOn - UPGRADE or STANDALONE - Cluster service previously installed.\n" );
  630. }
  631. else
  632. {
  633. // Some error occured.
  634. dwReturnValue = (DWORD) SubcompOff;
  635. ClRtlLogPrint( "ORIGINAL selection state: SubcompOff - UPGRADE or STANDALONE - Cluster service NOT previously installed.\n" );
  636. } // Were the Cluster service files installed?
  637. } // unattended?
  638. } // Is this a fresh install?
  639. break;
  640. case OCSELSTATETYPE_CURRENT:
  641. // OC Manager is requesting the current selection state of the component.
  642. // For the cases of a "clean" install or when OC manager is running
  643. // standalone it is safe to let OC Manager use the default selection state
  644. // to determine the cuttent selection state. The UPGRADE case requires
  645. // specific handling. Is this an UPGRADE?
  646. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  647. (DWORDLONG) SETUPOP_NTUPGRADE) != (DWORDLONG) 0L )
  648. {
  649. // This is an upgrade. The state of the checkbox depends on whether
  650. // Cluster service has previously been installed.
  651. // GetClusterInstallationState reports on the state of the registry value
  652. // that records the state of the Cluster service installation on NT 5 machines.
  653. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  654. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  655. // upgrading NT 4 machines, GetClusterInstallationState for NT 5 machines.
  656. ClRtlGetClusterInstallState( NULL, &eState );
  657. if ( ( eState != eClusterInstallStateUnknown ) ||
  658. ( IsClusterServiceRegistered() == (BOOL) TRUE ) )
  659. {
  660. // No error was detected.
  661. dwReturnValue = (DWORD) SubcompOn;
  662. ClRtlLogPrint( "CURRENT selection state: SubcompOn - UPGRADE - Cluster service previously installed.\n" );
  663. }
  664. else
  665. {
  666. // Some error occured.
  667. dwReturnValue = (DWORD) SubcompOff;
  668. ClRtlLogPrint( "CURRENT selection state: SubcompOff - UPGRADE - Cluster service NOT previously installed.\n" );
  669. } // Were the Cluster service files installed?
  670. }
  671. else
  672. {
  673. // This is either a "fresh" install or OC Manager is running standalone.
  674. dwReturnValue = (DWORD) SubcompUseOcManagerDefault;
  675. ClRtlLogPrint( "CURRENT selection state: SubcompUseOcManagerDefault - CLEAN install or STANDALONE.\n" );
  676. } // Is this an UPGRADE?
  677. break;
  678. case OCSELSTATETYPE_FINAL:
  679. // OC Manager is requesting the final selection state of the component.
  680. // As per Pat Styles, this call to OnOcQueryState will occur AFTER
  681. // OnOcCompleteInstallation has been called. The registry operation that
  682. // creates the registry key that GetClusterInstallationState checks as
  683. // its' indicator of success is queued by OnOcCompleteInstallation.
  684. // Does this OC Manager Setup DLL believe it has completed without error?
  685. ClRtlGetClusterInstallState( NULL, &eState );
  686. if ( eState != eClusterInstallStateUnknown )
  687. {
  688. // No error was detected.
  689. dwReturnValue = (DWORD) SubcompOn;
  690. ClRtlLogPrint( "FINAL selection state: SubcompOn.\n" );
  691. }
  692. else
  693. {
  694. // Some error occured.
  695. dwReturnValue = (DWORD) SubcompOff;
  696. ClRtlLogPrint( "FINAL selection state: SubcompOff.\n" );
  697. } // Were the Cluster service files installed?
  698. break;
  699. default:
  700. // This is an error condition.
  701. dwReturnValue = (DWORD) SubcompUseOcManagerDefault;
  702. ClRtlLogPrint( "Bad Param1 passed to OnOcQueryState.\n" );
  703. break;
  704. } // end of switch ( uxSelStateQueryType )
  705. }
  706. else
  707. {
  708. // The subcomponent ID is invalid.
  709. dwReturnValue = (DWORD) SubcompUseOcManagerDefault;
  710. ClRtlLogPrint( "In OnOcQueryState the subcomponent ID is NULL.\n" );
  711. } // Is the subcomponent ID legal?
  712. return ( dwReturnValue );
  713. }
  714. /////////////////////////////////////////////////////////////////////////////
  715. //++
  716. //
  717. // OnOcSetLanguage
  718. //
  719. // Routine Description:
  720. // This funcion indicates to OC Manager that clusocm.dll cannot handle
  721. // alternate langiages.
  722. //
  723. // Arguments:
  724. // None
  725. //
  726. // Return Value:
  727. // (DWORD) FALSE
  728. //
  729. //--
  730. /////////////////////////////////////////////////////////////////////////////
  731. DWORD CClusocmApp::OnOcSetLanguage( void )
  732. {
  733. // Returning (DWORD) FALSE will indicate to OC Manager that the component
  734. // setup dll does not support the requested language.
  735. return (DWORD) FALSE;
  736. }
  737. /////////////////////////////////////////////////////////////////////////////
  738. //++
  739. //
  740. // OnOcCalcDiskSpace
  741. //
  742. // Routine Description:
  743. // This function processes the OC_CALC_DISK_SPACE "messages" from the
  744. // Optional Components Manager. It either adds or removes disk space
  745. // requirements from the Disk Space List maintained by OC Manager.
  746. //
  747. // Arguments:
  748. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  749. // component in the component's hiearchy.
  750. // uxAddOrRemoveFlag - Non-zero means that the component setup dll is being
  751. // asked to add space requirements for a subcomponent to
  752. // the disk space list. ZERO means that the component
  753. // setup dll is being asked to remove space requirements
  754. // for the subcomponent from the disk space list.
  755. // hDiskSpaceList - a HDSPSPC (typedefed in setupapi.h to PVOID)
  756. //
  757. // Return Value:
  758. // (DWORD) NO_ERROR - indicates success
  759. // Any other value is a standard Win32 error code.
  760. //
  761. //--
  762. /////////////////////////////////////////////////////////////////////////////
  763. DWORD CClusocmApp::OnOcCalcDiskSpace( IN LPCTSTR ptszSubComponentId,
  764. IN UINT uxAddOrRemoveFlag,
  765. IN OUT HDSKSPC hDiskSpaceList )
  766. {
  767. DWORD dwReturnValue = NO_ERROR;
  768. // Is the subcomponent ID meaningfull?
  769. if ( ptszSubComponentId != (LPCTSTR) NULL )
  770. {
  771. // Is the handle to the component INF file meaningfull?
  772. if ( (m_SetupInitComponent.ComponentInfHandle !=
  773. (HINF) INVALID_HANDLE_VALUE) &&
  774. (m_SetupInitComponent.ComponentInfHandle !=
  775. (HINF) NULL) )
  776. {
  777. BOOL fReturnValue;
  778. // The INF file is open. Now we can use it.
  779. // Associate the user defined Directory IDs in the [DestinationDirs] section
  780. // of clusocm.inf with actual directories.
  781. BOOL fClusterServiceRegistered;
  782. fClusterServiceRegistered = IsClusterServiceRegistered();
  783. if ( SetDirectoryIds( fClusterServiceRegistered ) == (BOOL) TRUE )
  784. {
  785. if ( uxAddOrRemoveFlag != (UINT) 0 )
  786. {
  787. // Add disk space requirements to the file disk space list.
  788. fReturnValue =
  789. SetupAddInstallSectionToDiskSpaceList( hDiskSpaceList,
  790. m_SetupInitComponent.ComponentInfHandle,
  791. NULL,
  792. ptszSubComponentId,
  793. 0,
  794. 0 );
  795. if ( fReturnValue == (BOOL) FALSE )
  796. {
  797. dwReturnValue = GetLastError();
  798. }
  799. ClRtlLogPrint( "SetupAddInstallSectionToDiskSpaceList returned 0x%1!x! to OnOcCalcDiskSpace.\n",
  800. fReturnValue );
  801. }
  802. else
  803. {
  804. // Remove disk space requirements from the disk space list.
  805. fReturnValue =
  806. SetupRemoveInstallSectionFromDiskSpaceList( hDiskSpaceList,
  807. m_SetupInitComponent.ComponentInfHandle,
  808. NULL,
  809. ptszSubComponentId,
  810. 0,
  811. 0 );
  812. if ( fReturnValue == (BOOL) FALSE )
  813. {
  814. dwReturnValue = GetLastError();
  815. }
  816. ClRtlLogPrint( "SetupRemoveInstallSectionFromDiskSpaceList returned 0x%1!x! to OnOcCalcDiskSpace.\n",
  817. fReturnValue );
  818. }
  819. }
  820. else
  821. {
  822. dwReturnValue = GetLastError();
  823. ClRtlLogPrint( "In OnCalcDiskSpace the call to SetDirectoryIds failed.\n" );
  824. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwReturnValue );
  825. } // Were the directory Id associations made successfully?
  826. }
  827. else
  828. {
  829. ClRtlLogPrint( "In OnOcCalcDiskSpace ComponentInfHandle is bad.\n" );
  830. dwReturnValue = ERROR_FILE_NOT_FOUND;
  831. }
  832. }
  833. return ( dwReturnValue );
  834. }
  835. /////////////////////////////////////////////////////////////////////////////
  836. //++
  837. //
  838. // OnOcCompleteInstallation
  839. //
  840. // Routine Description:
  841. // This function processes the OC_COMPLETE_INSTALLATION "messages" from the
  842. // Optional Components Manager. It queues registry operations.
  843. //
  844. // Arguments:
  845. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  846. // component in the component's hiearchy.
  847. //
  848. // Return Value:
  849. // (DWORD) NO_ERROR - indicates success
  850. // Any other value is a standard Win32 error code.
  851. //
  852. //--
  853. /////////////////////////////////////////////////////////////////////////////
  854. DWORD CClusocmApp::OnOcCompleteInstallation( IN LPCTSTR ptszSubComponentId )
  855. {
  856. DWORD dwReturnValue = NO_ERROR;
  857. if ( (m_SetupInitComponent.ComponentInfHandle != (HINF) INVALID_HANDLE_VALUE) &&
  858. (m_SetupInitComponent.ComponentInfHandle != (HINF) NULL) )
  859. {
  860. // The INF file handle is valid.
  861. BOOL fOriginalSelectionState;
  862. BOOL fCurrentSelectionState;
  863. // Is the subcomponent currently selected ?
  864. fCurrentSelectionState =
  865. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  866. (LPCTSTR) ptszSubComponentId,
  867. (UINT) OCSELSTATETYPE_CURRENT );
  868. if ( fCurrentSelectionState == (BOOL) TRUE )
  869. {
  870. ClRtlLogPrint( "In OnOcCompleteInstallation the current selection state is TRUE.\n" );
  871. // The subcomponent is currently selected. Is this a fresh install ?
  872. if ( ( (m_SetupInitComponent.SetupData.OperationFlags &
  873. (DWORDLONG) SETUPOP_STANDALONE) == (DWORDLONG) 0L ) &&
  874. ( (m_SetupInitComponent.SetupData.OperationFlags &
  875. (DWORDLONG) SETUPOP_NTUPGRADE) == (DWORDLONG) 0L ) )
  876. {
  877. ClRtlLogPrint( "In OnOcCompleteInstallation this is a GUI mode clean install.\n" );
  878. // SETUPOP_STANDALONE flag clear means running under GUI mode setup.
  879. // SETUPOP_NTUPGRADE flag clear means not performing an upgrade.
  880. // Both flags clear means a fresh install. Do not check for a selection
  881. // state transition.
  882. dwReturnValue = CompleteInstallingClusteringService( (LPCTSTR) ptszSubComponentId );
  883. ClRtlLogPrint( "CompleteInstallingClusteringService returned 0x%1!x! to OnOcCompleteInstallation.\n",
  884. dwReturnValue );
  885. }
  886. else
  887. {
  888. // This is not a GUI mode fresh install. Is it an UPGRADE ?
  889. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  890. (DWORDLONG) SETUPOP_NTUPGRADE) != (DWORDLONG) 0L )
  891. {
  892. ClRtlLogPrint( "In OnOcCompleteInstallation - This is an UPGRADE.\n" );
  893. // Complete the process of upgrading Cluster service.
  894. dwReturnValue = CompleteUpgradingClusteringService( (LPCTSTR) ptszSubComponentId );
  895. ClRtlLogPrint( "CompleteUpgradingClusteringService returned 0x%1!x! to OnOnCompleteInstallation.\n",
  896. dwReturnValue );
  897. }
  898. else
  899. {
  900. ClRtlLogPrint( "In OnOcCompleteinstallation - this is STANDALONE.\n" );
  901. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  902. (DWORDLONG) SETUPOP_BATCH) != (DWORDLONG) 0L )
  903. {
  904. ClRtlLogPrint( "In OnOcCompleteInstallation this is UNATTENDED STANDALONE and Cluster service is selected.\n" );
  905. }
  906. // This is not an upgrade. That means Add/Remove Programs must be
  907. // running.
  908. // Check for a selection state transition.
  909. fOriginalSelectionState =
  910. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  911. ptszSubComponentId,
  912. (UINT) OCSELSTATETYPE_ORIGINAL );
  913. if ( fCurrentSelectionState != fOriginalSelectionState )
  914. {
  915. ClRtlLogPrint( "In OnOcCompleteInstallation a selection state transition has been detected.\n" );
  916. dwReturnValue = CompleteStandAloneInstallationOfClusteringService( (LPCTSTR) ptszSubComponentId );
  917. ClRtlLogPrint( "CompleteStandAloneInstallationOfClusteringService returned 0x%1!x! to OnOcCompleteInstallation.\n",
  918. dwReturnValue );
  919. }
  920. else
  921. {
  922. ClRtlLogPrint( "In OnOcCompleteInstallation since no selection state transition was detected there is nothing to do.\n" );
  923. // The selection state has not been changed. Perform no action.
  924. dwReturnValue = (DWORD) NO_ERROR;
  925. } // was there a selection state transition?
  926. } // is this an UPGRADE?
  927. } // is this a fresh install ?
  928. }
  929. else
  930. {
  931. ClRtlLogPrint( "In OnOcCompleteInstallation the current selection state is FALSE.\n" );
  932. // The subcomponent is not selected. Is OC Manager running stand-alone ?
  933. // If not, i.e. if GUI mode setup is running, there is nothing to do.
  934. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  935. (DWORDLONG) SETUPOP_STANDALONE) != (DWORDLONG) 0L )
  936. {
  937. ClRtlLogPrint( "In OnOcCompleteInstallation this is STANDALONE.\n" );
  938. // SETUPOP_STANDALONE set implies GUI mode setup is not running. If
  939. // there was a selection state change (to unselected) then delete
  940. // registry entries.
  941. fOriginalSelectionState =
  942. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  943. ptszSubComponentId,
  944. (UINT) OCSELSTATETYPE_ORIGINAL );
  945. // Has there been a selection state transition ?
  946. if ( fCurrentSelectionState != fOriginalSelectionState )
  947. {
  948. ClRtlLogPrint( "In OnOcCompleteInstallation a selection state transition has been detected.\n" );
  949. // Complete the process of uninstalling Cluster service.
  950. dwReturnValue = CompleteUninstallingClusteringService( (LPCTSTR) ptszSubComponentId );
  951. ClRtlLogPrint( "CompleteUninstallingClusteringService returned 0x%1!x! to OnOcCompleteInstallation.\n",
  952. dwReturnValue );
  953. }
  954. else
  955. {
  956. // The selection state has not been changed. Perform no action.
  957. dwReturnValue = (DWORD) NO_ERROR;
  958. ClRtlLogPrint( "In OnOcCompleteInstallation a selection state transition was not detected\n" );
  959. ClRtlLogPrint( "so there is nothing to do.\n" );
  960. } // Was there a selection state transition ?
  961. }
  962. else
  963. {
  964. // GUI mode setup is running. Perform no action.
  965. dwReturnValue = (DWORD) NO_ERROR;
  966. ClRtlLogPrint( "In OnOcCompleteInstallation GUI mode setup is running and the\n" );
  967. ClRtlLogPrint( "component is not selected so there is nothing to do.\n" );
  968. } // Is GUI mode setup running ?
  969. } // Is the subcomponent currently selected ?
  970. }
  971. else
  972. {
  973. dwReturnValue = ERROR_FILE_NOT_FOUND;
  974. ClRtlLogPrint( "In OnOcCompleteInstallation the handle to the component INF file is bad.\n" );
  975. } // Is the handle to the component INF file valid ?
  976. ClRtlLogPrint( "OnOcCompleteInstallation is preparing to return 0x%1!x!.\n", dwReturnValue );
  977. return ( dwReturnValue );
  978. }
  979. /////////////////////////////////////////////////////////////////////////////
  980. //++
  981. //
  982. // OnOcQueryChangeSelState
  983. //
  984. // Routine Description:
  985. // This function processes the OC_QUERY_CHANGE_SEL_STATE "messages" from the
  986. // Optional Components Manager.
  987. //
  988. // Arguments:
  989. // pvComponentId - points to a string that uniquely identifies the component
  990. // to be set up to OC Manager.
  991. // pvSubComponentId - points to a string that uniquely identifies a sub-
  992. // component in the component's hiearchy.
  993. // uxFunction - OC_QUERY_CHANGE_SEL_STATE - See ocmanage.h for the macro definitions.
  994. // uxParam1 - proposed state of the subcomponent
  995. // zero means unselected
  996. // non-zero means selected
  997. // pvParam2 - Flags
  998. //
  999. // Return Value:
  1000. // (DWORD) TRUE - the proposed selection state should be accepted
  1001. // (DWORD) FALSE - the proposed selection state should be rejected
  1002. //
  1003. // Note:
  1004. // As currently implemented on 2/25/1998, this function will disallow all
  1005. // changes to the selection state of Cluster service during an upgrade to a
  1006. // machine on which Cluster service has previously been installed.
  1007. //
  1008. // I have assumed that if the SETUPOP_NTUPGRADE flag is set that GUI mode
  1009. // setup is running because there is no way to perform and upgrade other
  1010. // than running NT setup.
  1011. //
  1012. // Cluster service and Terminal Services are mutually exclusive. By the
  1013. // time that this function gets called, OnOcInitComponent has already determined
  1014. // that Terminal Services is not installed. Therefore it is only necessary to
  1015. // determine whether Terminal Services is selected for installation.
  1016. //
  1017. //--
  1018. /////////////////////////////////////////////////////////////////////////////
  1019. DWORD CClusocmApp::OnOcQueryChangeSelState( IN LPCTSTR ptszSubComponentId,
  1020. IN UINT uxProposedSelectionState,
  1021. IN DWORD dwFlags )
  1022. {
  1023. DWORD dwReturnValue = (DWORD) TRUE;
  1024. eClusterInstallState eState;
  1025. // Is an upgrade in progress ?
  1026. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_NTUPGRADE) !=
  1027. (DWORDLONG) 0L )
  1028. {
  1029. ClRtlLogPrint( "In OnOnQueryChangeSelState this is an UPGRADE. Selection state transitions are not allowed.\n" );
  1030. // Since this is an UPGRADE the selection state cannot be changed.
  1031. // Return FALSE to disallow selection state changes.
  1032. dwReturnValue = (DWORD) FALSE;
  1033. }
  1034. else
  1035. {
  1036. if ( dwReturnValue == (DWORD) TRUE )
  1037. {
  1038. // Either Cluster service is being deselected, which implies that the
  1039. // selection state of Terminal Services is inconsequential, or Terminal
  1040. // Services is not selected for installation.
  1041. // Is GUI mode setup running?
  1042. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  1043. (DWORDLONG) SETUPOP_STANDALONE) == (DWORDLONG) 0L )
  1044. {
  1045. ClRtlLogPrint( "In OnOcQueryChangeSelState this is NOT STANDALONE.\n" );
  1046. // SETUPOP_STANDALONE clear means GUI mode setup is running.
  1047. // In conjunction with SETUPOP_NTUPGRADE clear it means that
  1048. // a fresh NT installation is in progress.
  1049. // It is possible for the user to request that a fresh install target
  1050. // the directory for an existing NT installation. In that event, as per
  1051. // David P., if Cluster Server has been installed, the user should
  1052. // not be allowed to deselect the Cluster Server component.
  1053. // GetClusterInstallationState reports on the state of the registry value
  1054. // that records the state of the Cluster service installation on NT 5 machines.
  1055. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  1056. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  1057. // upgrading NT 4 machines, GetClusterInstallationState for NT 5 machines.
  1058. ClRtlGetClusterInstallState( NULL, &eState );
  1059. if ( ( eState != eClusterInstallStateUnknown ) ||
  1060. ( IsClusterServiceRegistered() == (BOOL) TRUE ) )
  1061. {
  1062. // Disallow deselection of the cluster component(s).
  1063. dwReturnValue = (DWORD) FALSE;
  1064. ClRtlLogPrint( "In OnOcQueryChangeSelState since Clustering Server has previously\n" );
  1065. ClRtlLogPrint( "been installed selection state transitions are not allowed.\n" );
  1066. }
  1067. else
  1068. {
  1069. // Allow the selection state to be changed.
  1070. dwReturnValue = (DWORD) TRUE;
  1071. ClRtlLogPrint( "In OnOcQueryChangeSelState since Clustering Server has never\n" );
  1072. ClRtlLogPrint( "been installed selection state transitions are allowed.\n" );
  1073. }
  1074. } // GUI mode setup running?
  1075. else
  1076. {
  1077. // This is a standalone operation. Allow the selection state to be changed.
  1078. dwReturnValue = (DWORD) TRUE;
  1079. ClRtlLogPrint( "In OnOcQueryChangeSelState this is STANDALONE so selection state transitions are allowed.\n" );
  1080. } // GUI mode setup running?
  1081. }
  1082. }
  1083. return ( dwReturnValue );
  1084. }
  1085. /////////////////////////////////////////////////////////////////////////////
  1086. //++
  1087. //
  1088. // PerformRegistryOperations
  1089. //
  1090. // Routine Description:
  1091. // This function performs the registry operations, both the AddReg and DelReg
  1092. // in the section indicated by ptszSectionName are processed.
  1093. // registry entries.
  1094. //
  1095. // Arguments:
  1096. // hInfHandle - a handle to the component INF file.
  1097. // ptszSectionName - points to a string containing the name of a section in
  1098. // the INF file.
  1099. //
  1100. // Return Value:
  1101. // (DWORD) NO_ERROR - indicated success
  1102. // Any other retuen value is a Win32 error code.
  1103. //
  1104. //--
  1105. /////////////////////////////////////////////////////////////////////////////
  1106. DWORD CClusocmApp::PerformRegistryOperations( HINF hInfHandle,
  1107. LPCTSTR ptszSectionName )
  1108. {
  1109. DWORD dwReturnValue;
  1110. // Install ... perform the registry operations.
  1111. dwReturnValue = SetupInstallFromInfSection( NULL, // hwndOwner
  1112. m_SetupInitComponent.ComponentInfHandle, // inf handle
  1113. ptszSectionName, // name of section
  1114. SPINST_REGISTRY, // operation flags
  1115. NULL, // relative key root
  1116. NULL, // source root path -
  1117. // irrelevant for registry operations
  1118. 0, // copy flags
  1119. NULL, // callback routine
  1120. NULL, // callback routine context
  1121. NULL, // device info set
  1122. NULL ); // device info struct
  1123. // Were the registry operations performed successfully?
  1124. if ( dwReturnValue == (DWORD) TRUE )
  1125. {
  1126. dwReturnValue = (DWORD) NO_ERROR;
  1127. }
  1128. else
  1129. {
  1130. dwReturnValue = GetLastError();
  1131. } // Were the registry operations performed successfully?
  1132. return ( dwReturnValue );
  1133. }
  1134. /////////////////////////////////////////////////////////////////////////////
  1135. //++
  1136. //
  1137. // UninstallRegistryOperations
  1138. //
  1139. // Routine Description:
  1140. // This function queues the registry operations that delete cluster related
  1141. // registry entries on UNINSTALL.
  1142. //
  1143. // Arguments:
  1144. // hInfHandle - a handle to the component INF file.
  1145. // ptszSubComponentId - points to a string containing the name of the subcomponent.
  1146. //
  1147. //
  1148. // Return Value:
  1149. // (DWORD) NO_ERROR - indicated success
  1150. // Any other retuen value is a Win32 error code.
  1151. //
  1152. //--
  1153. /////////////////////////////////////////////////////////////////////////////
  1154. DWORD CClusocmApp::UninstallRegistryOperations( IN HINF hInfHandle,
  1155. IN LPCTSTR ptszSubComponentId )
  1156. {
  1157. DWORD dwReturnValue;
  1158. BOOL fReturnValue;
  1159. INFCONTEXT InfContext;
  1160. // There is an entry called "Uninstall" in the [Cluster] section of
  1161. // cluster.inf. That entry provides the name of an "install" section
  1162. // that should be substituted for the [Cluster] section when uninstalling.
  1163. // The following function locates that line so it can be read.
  1164. CString csSectionName;
  1165. csSectionName = UNINSTALL_INF_KEY;
  1166. fReturnValue = SetupFindFirstLine( m_SetupInitComponent.ComponentInfHandle,
  1167. ptszSubComponentId,
  1168. csSectionName,
  1169. &InfContext );
  1170. if ( fReturnValue == (BOOL) TRUE )
  1171. {
  1172. // Read the name of the replacement section.
  1173. TCHAR tszReplacementSection[256]; // Receives the section name
  1174. fReturnValue = SetupGetStringField( &InfContext,
  1175. 1, // there should be a single field
  1176. tszReplacementSection,
  1177. sizeof( tszReplacementSection ) / sizeof( TCHAR ),
  1178. NULL );
  1179. if ( fReturnValue == (BOOL) TRUE )
  1180. {
  1181. // Remove the registry keys.
  1182. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  1183. tszReplacementSection );
  1184. ClRtlLogPrint( "PerformRegistryOperations returned 0x%1!x! to UninstallRegistryOperations.\n",
  1185. dwReturnValue );
  1186. }
  1187. else
  1188. {
  1189. ClRtlLogPrint( "UninstallDelRegistryOperations could not read the INF file.\n" );
  1190. dwReturnValue = (DWORD) ERROR_FILE_NOT_FOUND;
  1191. }
  1192. }
  1193. else
  1194. {
  1195. ClRtlLogPrint( "UninstallDelRegistryOperations could not read the INF file.\n" );
  1196. dwReturnValue = (DWORD) ERROR_FILE_NOT_FOUND;
  1197. }
  1198. return ( dwReturnValue );
  1199. }
  1200. /////////////////////////////////////////////////////////////////////////////
  1201. //++
  1202. //
  1203. // QueueInstallFileOperations
  1204. //
  1205. // Routine Description:
  1206. // This function queues the file operations that install cluster related files.
  1207. //
  1208. // Arguments:
  1209. // hInfHandle - a handle to the component INF file.
  1210. // ptszSubComponentId - points to a string containing the name of the subcomponent.
  1211. //
  1212. //
  1213. // Return Value:
  1214. // (DWORD) NO_ERROR - indicated success
  1215. // Any other retuen value is a Win32 error code.
  1216. //
  1217. //--
  1218. /////////////////////////////////////////////////////////////////////////////
  1219. DWORD CClusocmApp::QueueInstallFileOperations( IN HINF hInfHandle,
  1220. IN LPCTSTR ptszSubComponentId,
  1221. IN OUT HSPFILEQ hSetupFileQueue )
  1222. {
  1223. DWORD dwReturnValue;
  1224. CString csSectionName;
  1225. // Dummy do-while loop to avoid gotos.
  1226. do
  1227. {
  1228. // As per Pat Styles on 7/16/98 pass NULL in the SourcePath parameter.
  1229. dwReturnValue = SetupInstallFilesFromInfSection(
  1230. hInfHandle, // handle to the INF file
  1231. NULL, // optional, layout INF handle
  1232. hSetupFileQueue, // handle to the file queue
  1233. ptszSubComponentId, // name of the Install section
  1234. NULL, // optional, root path to source files
  1235. SP_COPY_NEWER // optional, specifies copy behavior
  1236. );
  1237. ClRtlLogPrint( "The first call to SetupInstallFilesFromInfSection returned 0x%1!x! to QueueInstallFileOperations.\n",
  1238. dwReturnValue );
  1239. // Was the operation successful ?
  1240. if ( dwReturnValue == (DWORD) FALSE )
  1241. {
  1242. dwReturnValue = GetLastError();
  1243. break;
  1244. }
  1245. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  1246. (DWORDLONG) SETUPOP_NTUPGRADE) == (DWORDLONG) 0L )
  1247. {
  1248. dwReturnValue = (DWORD) NO_ERROR;
  1249. // This is not an UPGRADE.
  1250. break;
  1251. }
  1252. // If this is an UPGRADE (from NT 4.0) then queue the file operations
  1253. // specified in the [Upgrade] section.
  1254. ClRtlLogPrint( "In QueueInstallFileOperations this is an UPGRADE.\n" );
  1255. // Copy the replace-only files. Some files like IISCLUS3.DLL need to be copied
  1256. // on an upgrade only if they already existed before the upgrade.
  1257. // This is what I learnt from Brent (a-brentt) on 7/15/1999.
  1258. csSectionName = UPGRADE_REPLACEONLY_INF_KEY;
  1259. // As per Pat Styles on 7/16/98 pass NULL in the SourcePath parameter.
  1260. dwReturnValue = SetupInstallFilesFromInfSection(
  1261. hInfHandle, // handle to the INF file
  1262. NULL, // optional, layout INF handle
  1263. hSetupFileQueue, // handle to the file queue
  1264. csSectionName, // name of the Install section
  1265. NULL, // optional, root path to source files
  1266. SP_COPY_REPLACEONLY // optional, specifies copy behavior
  1267. );
  1268. ClRtlLogPrint(
  1269. "The first call to SetupInstallFilesFromInfSection returned 0x%1!x! to QueueInstallFileOperations.\n",
  1270. dwReturnValue
  1271. );
  1272. if ( dwReturnValue == (DWORD) FALSE )
  1273. {
  1274. dwReturnValue = GetLastError();
  1275. break;
  1276. }
  1277. // The replace only copy was successful. Now do the normal CopyFiles and DelFiles
  1278. // subsections.
  1279. csSectionName = UPGRADE_INF_KEY;
  1280. // This function processes the CopyFiles subsection under the UPGRADE_INF_KEY section.
  1281. dwReturnValue = SetupInstallFilesFromInfSection(
  1282. hInfHandle, // handle to the INF file
  1283. NULL, // optional, layout INF handle
  1284. hSetupFileQueue, // handle to the file queue
  1285. csSectionName, // name of the Install section
  1286. NULL, // optional, root path to source files
  1287. SP_COPY_NEWER // optional, specifies copy behavior
  1288. );
  1289. ClRtlLogPrint(
  1290. "The second call to SetupInstallFilesFromInfSection returned 0x%1!x! to QueueInstallFileOperations.\n",
  1291. dwReturnValue
  1292. );
  1293. if ( dwReturnValue == (DWORD) FALSE )
  1294. {
  1295. dwReturnValue = GetLastError();
  1296. break;
  1297. }
  1298. // This function processes the DelFiles subsection under the UPGRADE_INF_KEY section.
  1299. dwReturnValue = SetupQueueDeleteSection(
  1300. hSetupFileQueue, // handle to the file queue
  1301. hInfHandle, // handle to the INF file containing the [DestinationDirs] section
  1302. hInfHandle, // handle to the INF file
  1303. csSectionName // INF section that lists the files to delete
  1304. );
  1305. ClRtlLogPrint(
  1306. "The call to SetupQueueDeleteSection returned 0x%1!x! to QueueInstallFileOperations.\n", dwReturnValue
  1307. );
  1308. if ( dwReturnValue == (DWORD) FALSE )
  1309. {
  1310. dwReturnValue = GetLastError();
  1311. break;
  1312. }
  1313. dwReturnValue = (DWORD) NO_ERROR;
  1314. }
  1315. while ( FALSE ); // dummy do-while loop to avoid gotos.
  1316. if ( dwReturnValue == (DWORD) NO_ERROR )
  1317. {
  1318. ClRtlLogPrint( "QueueInstallFileOperations compeleted successfully.\n" );
  1319. }
  1320. else
  1321. {
  1322. ClRtlLogPrint( "Error in QueueInstallFileOperations.\n" );
  1323. }
  1324. return ( dwReturnValue );
  1325. }
  1326. /////////////////////////////////////////////////////////////////////////////
  1327. //++
  1328. //
  1329. // QueueRemoveFileOperations
  1330. //
  1331. // Routine Description:
  1332. // This function queues the file operations that delete cluster related files.
  1333. //
  1334. // Arguments:
  1335. // hInfHandle - a handle to the component INF file.
  1336. // ptszSubComponentId - points to a string containing the name of the subcomponent.
  1337. //
  1338. //
  1339. // Return Value:
  1340. // (DWORD) NO_ERROR - indicated success
  1341. // Any other return value is a Win32 error code.
  1342. //
  1343. //--
  1344. /////////////////////////////////////////////////////////////////////////////
  1345. DWORD CClusocmApp::QueueRemoveFileOperations( IN HINF hInfHandle,
  1346. IN LPCTSTR ptszSubComponentId,
  1347. IN OUT HSPFILEQ hSetupFileQueue )
  1348. {
  1349. DWORD dwReturnValue;
  1350. BOOL fReturnValue;
  1351. INFCONTEXT InfContext;
  1352. // There is an entry called "Uninstall" in the [Cluster] section of
  1353. // cluster.inf. That entry provides the name of an "install" section
  1354. // that should be substituted for the [Cluster] section when uninstalling.
  1355. // The following function locates that line so it can be read.
  1356. CString csSectionName;
  1357. csSectionName = UNINSTALL_INF_KEY;
  1358. fReturnValue = SetupFindFirstLine( hInfHandle,
  1359. ptszSubComponentId,
  1360. csSectionName,
  1361. &InfContext );
  1362. if ( fReturnValue == (BOOL) TRUE )
  1363. {
  1364. // Read the name of the replacement section.
  1365. TCHAR tszReplacementSection[256]; // Receives the section name
  1366. fReturnValue = SetupGetStringField( &InfContext,
  1367. 1, // there should be a single field
  1368. tszReplacementSection,
  1369. sizeof( tszReplacementSection ) / sizeof( TCHAR ),
  1370. NULL );
  1371. if ( fReturnValue == (BOOL) TRUE )
  1372. {
  1373. // Remove the files.
  1374. dwReturnValue = SetupInstallFilesFromInfSection( hInfHandle,
  1375. (HINF) NULL, // No layout file
  1376. hSetupFileQueue,
  1377. (LPCTSTR) tszReplacementSection,
  1378. (LPCTSTR) NULL, // SourceRootPath is irrelevant
  1379. (UINT) 0 );
  1380. ClRtlLogPrint( "SetupInstallFilesFromInfSection returned 0x%1!x! to QueueRemoveFilesOperations.\n",
  1381. dwReturnValue );
  1382. // Was the operation successfull ?
  1383. if ( dwReturnValue == (DWORD) TRUE )
  1384. {
  1385. dwReturnValue = (DWORD) NO_ERROR;
  1386. }
  1387. else
  1388. {
  1389. dwReturnValue = GetLastError();
  1390. }
  1391. }
  1392. else
  1393. {
  1394. dwReturnValue = (DWORD) ERROR_FILE_NOT_FOUND;
  1395. ClRtlLogPrint( "QueueRemoveFileOperations was unable to read the [Uninstall] section in the INF file.\n" );
  1396. }
  1397. }
  1398. else
  1399. {
  1400. dwReturnValue = (DWORD) ERROR_FILE_NOT_FOUND;
  1401. ClRtlLogPrint( "QueueRemoveFileOperations was unable to locate the [Uninstall] section in the INF file.\n" );
  1402. }
  1403. return ( dwReturnValue );
  1404. }
  1405. /////////////////////////////////////////////////////////////////////////////
  1406. //++
  1407. //
  1408. // OnOcAboutToCommitQueue
  1409. //
  1410. // Routine Description:
  1411. // If clusocm.dll is performing an uninstall, this function unregisters the
  1412. // cluster services.
  1413. //
  1414. // if clusocm.dll is performing an install or an upgrade this function does
  1415. // nothing.
  1416. //
  1417. // Arguments:
  1418. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  1419. // component in the component's hiearchy.
  1420. //
  1421. // Return Value:
  1422. // (DWORD) NO_ERROR - indicates success
  1423. // Any other value is a Win32 error code.
  1424. //
  1425. //--
  1426. /////////////////////////////////////////////////////////////////////////////
  1427. DWORD CClusocmApp::OnOcAboutToCommitQueue( IN LPCTSTR ptszSubComponentId )
  1428. {
  1429. DWORD dwReturnValue;
  1430. if ( (m_SetupInitComponent.ComponentInfHandle != (HINF) INVALID_HANDLE_VALUE) &&
  1431. (m_SetupInitComponent.ComponentInfHandle != (HINF) NULL) )
  1432. {
  1433. // The INF file handle is valid.
  1434. BOOL fOriginalSelectionState;
  1435. BOOL fCurrentSelectionState;
  1436. // Is the subcomponent currently selected ?
  1437. fCurrentSelectionState =
  1438. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  1439. (LPCTSTR) ptszSubComponentId,
  1440. (UINT) OCSELSTATETYPE_CURRENT );
  1441. if ( fCurrentSelectionState != (BOOL) TRUE )
  1442. {
  1443. // The subcomponent is not selected. Is OC Manager running stand-alone ?
  1444. // If not, i.e. if GUI mode setup is running, there is nothing to do.
  1445. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  1446. (DWORDLONG) SETUPOP_STANDALONE) != (DWORDLONG) 0L )
  1447. {
  1448. ClRtlLogPrint( "In OnOcAboutToCommitQueue this is STANDALONE and the component is not selected.\n" );
  1449. ClRtlLogPrint( "So, this is an uninstall operation.\n" );
  1450. // SETUPOP_STANDALONE set implies GUI mode setup is not running. If
  1451. // there was a selection state change (to unselected) then delete
  1452. // registry entries.
  1453. fOriginalSelectionState =
  1454. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  1455. ptszSubComponentId,
  1456. (UINT) OCSELSTATETYPE_ORIGINAL );
  1457. // Has there been a selection state transition ?
  1458. if ( fCurrentSelectionState != fOriginalSelectionState )
  1459. {
  1460. CString csTemp;
  1461. ClRtlLogPrint( "In OnOcAboutToCommitQueue a selection state transition has been detected.\n" );
  1462. // At this point in cluscfg.exe file utils.cpp function DoUninstall
  1463. // called function IsOtherSoftwareInstalled. That function apparently
  1464. // checked for the presence of custom cluster resources and warned the
  1465. // user to handle them before proceeding. (at least that is what David
  1466. // told me). So, that logic needs to be replicated here.
  1467. // NOTE: According to Andrew Ritz (AndrewR), there is no way to abort the
  1468. // installation at this point. So the user is just shown the list of
  1469. // custom resource types and is prompted to remove them after the cluster
  1470. // service has been uninstalled. The user is not given an option to abort
  1471. // the installation.
  1472. // (Vvasu 14-DEC-1999)
  1473. if ( ( m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH ) ==
  1474. (DWORDLONG) 0L )
  1475. {
  1476. // If this is not an unattended operation.
  1477. BOOL fReturnValue = CheckForCustomResourceTypes();
  1478. ClRtlLogPrint( "CheckForCustomResourceTypes returned 0x%1!x! to OnOcAboutToCommitQueue.\n",
  1479. fReturnValue );
  1480. }
  1481. else
  1482. {
  1483. ClRtlLogPrint( "CheckForCustomResourceTypes not called in OnOcAboutToCommitQueue as this is an unattended operation.\n" );
  1484. }
  1485. // Stop ClusSvc. Note that if ClusDisk is someday revised so that
  1486. // it will unload, it will be appropriate to stop ClusDisk here
  1487. // as well.
  1488. csTemp = CLUSTER_SERVICE_NAME;
  1489. // I'm going to assume that, since UNICODE is defined, the casts
  1490. // in the calls to function StopService are OK, even though there
  1491. // is probably a better approach.
  1492. StopService( (LPCWSTR) (LPCTSTR) csTemp );
  1493. csTemp = TIME_SERVICE_NAME;
  1494. StopService( (LPCWSTR) (LPCTSTR) csTemp );
  1495. ClRtlLogPrint( "OnOcAboutToCommitQueue has attempted to stop ClusSvc and TimeServ.\n" );
  1496. //
  1497. // Unregister the COM objects that may previously have been registered.
  1498. //
  1499. // Note that since msclus.dll is registered as part of NT setup
  1500. // it is not unregistered here.
  1501. //
  1502. csTemp = CLUSTER_DIRECTORY;
  1503. TCHAR tszPathToClusterDir[_MAX_PATH];
  1504. if ( ExpandEnvironmentStrings( (LPCTSTR) csTemp,
  1505. tszPathToClusterDir, _MAX_PATH ) > 0L )
  1506. {
  1507. BOOL bUnregisterResult = UnRegisterClusterCOMObjects( m_hInstance, tszPathToClusterDir );
  1508. ClRtlLogPrint( "OnOcAboutToCommitQueue has unregistered the COM objects. The return value is %1!d!\n", bUnregisterResult );
  1509. }
  1510. else
  1511. {
  1512. // Couldn't expand the environment string.
  1513. ClRtlLogPrint( "OnOcAboutToCommitQueue could not unregister the COM objects\n" );
  1514. ClRtlLogPrint( "because it could not locate the cluster directory.\n" );
  1515. }
  1516. // Unload the Cluster hive so that the Cluster hive file can be removed.
  1517. UnloadClusDB();
  1518. ClRtlLogPrint( "OnOcAbouToCommitQueue has unloaded the Cluster hive.\n" );
  1519. dwReturnValue = (DWORD) NO_ERROR;
  1520. }
  1521. else
  1522. {
  1523. // The selection state has not been changed. Perform no action.
  1524. dwReturnValue = (DWORD) NO_ERROR;
  1525. ClRtlLogPrint("In OnOcAboutToCommitQueue no selection state transition was detected.\n" );
  1526. } // Was there a selection state transition ?
  1527. }
  1528. else
  1529. {
  1530. // OC Manager is NOT running stand-alone. This CANNOT be an uninstall
  1531. // operation. There is nothing for this function to do.
  1532. dwReturnValue = (DWORD) NO_ERROR;
  1533. } // Is GUI mode setup running ?
  1534. } // Is the subcomponent cuttently selected ?
  1535. else
  1536. {
  1537. // Since the component is selected this CANNOT be an uninstall operation.
  1538. // There is nothing for this function to do.
  1539. dwReturnValue = (DWORD) NO_ERROR;
  1540. ClRtlLogPrint( "In OnOcAboutToCommitQueue the component is selected so there is nothing to do.\n" );
  1541. }
  1542. }
  1543. else
  1544. {
  1545. dwReturnValue = ERROR_FILE_NOT_FOUND;
  1546. ClRtlLogPrint( "In OnOcAboutToCommitQueue the handle to the INF file is bad.\n" );
  1547. } // Is the handle to the component INF file valid ?
  1548. return ( dwReturnValue );
  1549. }
  1550. /////////////////////////////////////////////////////////////////////////////
  1551. //++
  1552. //
  1553. // LocateClusterHiveFile
  1554. //
  1555. // Routine Description:
  1556. // This function attempts to locate the Cluster hive file and supply the
  1557. // path to the calling function.
  1558. //
  1559. // Arguments:
  1560. // rcsClusterHiveFilePath - a reference to a the CString to receive the
  1561. // path to the Cluster hive file.
  1562. //
  1563. // Return Value:
  1564. // TRUE - incicates that the Cluster hive file was located and that
  1565. // rcsClusterHiveFilePath is meaningfull.
  1566. // FALSE - indicates that the Cluster hive file was not located and
  1567. // rcsClusterHiveFilePath is empty.
  1568. //
  1569. //--
  1570. /////////////////////////////////////////////////////////////////////////////
  1571. BOOL CClusocmApp::LocateClusterHiveFile( CString & rcsClusterHiveFilePath )
  1572. {
  1573. BOOL fReturnValue;
  1574. // The path to the Cluster hive file may be deduced by reading the
  1575. // [DestinationDirs] section of the INF file. The ClusterFiles entry
  1576. // will specify the file's location.
  1577. if ( (m_SetupInitComponent.ComponentInfHandle != (HINF) INVALID_HANDLE_VALUE) &&
  1578. (m_SetupInitComponent.ComponentInfHandle != (HINF) NULL) )
  1579. {
  1580. // The handle to the INF file is valid.
  1581. TCHAR tszPathToClusterDirectory[MAX_PATH];
  1582. // First, get the path to the cluster directory.
  1583. DWORD dwRequiredSize;
  1584. CString csSectionName;
  1585. csSectionName = CLUSTER_FILES_INF_KEY;
  1586. fReturnValue = SetupGetTargetPath( m_SetupInitComponent.ComponentInfHandle,
  1587. (PINFCONTEXT) NULL,
  1588. (PCTSTR) csSectionName,
  1589. tszPathToClusterDirectory,
  1590. (DWORD) MAX_PATH,
  1591. (PDWORD) &dwRequiredSize );
  1592. if ( fReturnValue == (BOOL) TRUE )
  1593. {
  1594. rcsClusterHiveFilePath = (CString) tszPathToClusterDirectory;
  1595. // Append the name of the Cluster hive file to the path.
  1596. CString csClusterDatabaseName;
  1597. csClusterDatabaseName = CLUSTER_DATABASE_NAME;
  1598. rcsClusterHiveFilePath += (CString) _T("\\") + csClusterDatabaseName;
  1599. ClRtlLogPrint( "LocateClusterHiveFile has deduced that the cluster hive is in %1!s!.\n",
  1600. rcsClusterHiveFilePath );
  1601. // The path to the Cluster hive file has been built. Now, make
  1602. // sure that the file is present.
  1603. HANDLE hSearchHandle;
  1604. WIN32_FIND_DATA FindData;
  1605. hSearchHandle = FindFirstFile( rcsClusterHiveFilePath,
  1606. &FindData);
  1607. if( hSearchHandle != (HANDLE) INVALID_HANDLE_VALUE )
  1608. {
  1609. FindClose( hSearchHandle );
  1610. // A file with the correct name was located. Is it the cluster hive
  1611. // file? If it is a directory it is not.
  1612. if( (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=
  1613. (DWORD) 0L )
  1614. {
  1615. // The file is a directory. That means that the Cluster
  1616. // hive file could not be located.
  1617. ClRtlLogPrint( "LocateClusterHiveFile could not find file %1!s!.\n",
  1618. rcsClusterHiveFilePath );
  1619. rcsClusterHiveFilePath.Empty();
  1620. fReturnValue = (BOOL) FALSE;
  1621. }
  1622. else
  1623. {
  1624. // The Cluster hive file was found.
  1625. ClRtlLogPrint( "LocateClusterHiveFile found the Cluster hive at %1!s!.\n",
  1626. rcsClusterHiveFilePath );
  1627. fReturnValue = (BOOL) TRUE;
  1628. }
  1629. }
  1630. else
  1631. {
  1632. // The cluster hive file was not located.
  1633. ClRtlLogPrint( "LocateClusterHiveFile could not find file %1!s!.\n",
  1634. rcsClusterHiveFilePath );
  1635. rcsClusterHiveFilePath.Empty();
  1636. fReturnValue = (BOOL) FALSE;
  1637. }
  1638. }
  1639. else
  1640. {
  1641. rcsClusterHiveFilePath.Empty();
  1642. ClRtlLogPrint( "SetupGetTargetPath failed in LocateClusterHiveFile.\n" );
  1643. }
  1644. }
  1645. else
  1646. {
  1647. // The handle to the INF file is not valid. That means that the Cluster
  1648. // hive file could not be located.
  1649. ClRtlLogPrint( "LocateClusterHiveFile could not locate the cluster hive because the\n" );
  1650. ClRtlLogPrint( "handle to the INF file is bad.\n" );
  1651. rcsClusterHiveFilePath.Empty();
  1652. fReturnValue = (BOOL) FALSE;
  1653. }
  1654. return ( fReturnValue );
  1655. }
  1656. /////////////////////////////////////////////////////////////////////////////
  1657. //++
  1658. //
  1659. // CheckForCustomResourceTypes
  1660. //
  1661. // Routine Description:
  1662. // This function examines the ResourceTypes subkey of the Cluster key to
  1663. // determine whether custom resource types have been installed.
  1664. //
  1665. // Arguments:
  1666. // None
  1667. //
  1668. //
  1669. // Return Value:
  1670. // TRUE - indicates that either no custom resource types have been detected
  1671. // or the user chooses to continue uninstalling Cluster Server without
  1672. // first uninstalling the software packages associated with the custom
  1673. // resource types.
  1674. // FALSE - indicates that custom resource types were detected and the user
  1675. // wishes to terminate uninstallation of Cluster Server.
  1676. //
  1677. // Note:
  1678. // This function was originally called IsOtherSoftwareInstalled in the old
  1679. // cluster\newsetup project in the file called utils.cpp.
  1680. //
  1681. //--
  1682. /////////////////////////////////////////////////////////////////////////////
  1683. BOOL CClusocmApp::CheckForCustomResourceTypes( void )
  1684. {
  1685. BOOL fReturnValue = (BOOL) TRUE;
  1686. BOOL fEnumerateResourceTypesKeys = (BOOL) TRUE;
  1687. BOOL fClusterHiveLoadedByThisFunction = (BOOL) FALSE;
  1688. HKEY hClusterKey;
  1689. LONG lReturnValue;
  1690. // Attempt to open the Cluster Registry key.
  1691. CString csClusterRegKey;
  1692. csClusterRegKey = CLUSREG_KEYNAME_CLUSTER;
  1693. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE, csClusterRegKey,
  1694. 0, KEY_READ, &hClusterKey);
  1695. if ( lReturnValue != ERROR_SUCCESS )
  1696. {
  1697. ClRtlLogPrint( "In CheckForCustomResourceTypes the first attempt to open the Cluster key failed.\n" );
  1698. // The Cluster hive is not currently loaded. This condition means that
  1699. // the cluster service has not been started. Attempt to load the Cluster
  1700. // hive so that it can be read.
  1701. // First, locate the Cluster hive file. It should be in the location
  1702. // specified for the ClusterFiles entry in the [DestinationDirs] section
  1703. // of clusocm.inf.
  1704. CString csClusterHiveFilePath;
  1705. fReturnValue = LocateClusterHiveFile( (CString &) csClusterHiveFilePath );
  1706. ClRtlLogPrint( "LocateClusterHiveFile returned 0x%1!x! to CheckForCustomResourceTypes.\n",
  1707. fReturnValue );
  1708. // Was the Cluster hive file located?
  1709. if ( fReturnValue == (BOOL) TRUE )
  1710. {
  1711. // The Cluster hive file was located. Custom resource types may exist.
  1712. // Attempt to load the cluster hive.
  1713. BOOLEAN OriginalState;
  1714. // I'm not sure what the following function does, but the prototype is
  1715. // in sdk\inc\ntrtl.h. Look in stdafx.h for the inclusion of ntrtl.h. I
  1716. // replicated the logic that was used in newsetup.h to make it work.
  1717. // RtlAdjustPrivilege returns NTSTATUS.
  1718. NTSTATUS Status;
  1719. Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  1720. TRUE,
  1721. FALSE,
  1722. &OriginalState );
  1723. if ( NT_SUCCESS( Status ) )
  1724. {
  1725. // Attempt to Load the Cluster Hive.
  1726. lReturnValue = RegLoadKey( HKEY_LOCAL_MACHINE,
  1727. csClusterRegKey,
  1728. csClusterHiveFilePath );
  1729. if ( lReturnValue == ERROR_SUCCESS )
  1730. {
  1731. fClusterHiveLoadedByThisFunction = (BOOL) TRUE;
  1732. // Now that the Cluster hive has been loaded, attempt to open the
  1733. // Cluster registry key.
  1734. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1735. csClusterRegKey,
  1736. 0, KEY_READ,
  1737. &hClusterKey );
  1738. // lReturnValue will be tested by the next BLOCK of code.
  1739. } // cluster hive loaded?
  1740. else
  1741. {
  1742. // The Cluster hive could not be loaded. Treat that as if there
  1743. // are no custom resource types.
  1744. // A return value of TRUE will allow the uninstall operation to
  1745. // continue. Since lReturnValue is NOT ERROR_SUCCESS no additional
  1746. // processing will be performed by this function.
  1747. fReturnValue = (BOOL) TRUE;
  1748. } // Was the cluster hive loaded successfully?
  1749. // Undo whatever the preceding call to RtlAdjustPrivilege() did.
  1750. RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  1751. OriginalState,
  1752. FALSE,
  1753. &OriginalState );
  1754. } // Initial call to RtlAdjustPrivilege succeeded?
  1755. else
  1756. {
  1757. // The initial call to RtlAdjustPrivilege FAILED.
  1758. ClRtlLogPrint( "In CheckForCustomResources the initial call to RtlAdjustPrivileges failed with status %1!d!.\n",
  1759. Status );
  1760. // A return value of TRUE will allow the uninstall operation to
  1761. // continue. Since lReturnValue is NOT ERROR_SUCCESS no additional
  1762. // processing will be performed by this function.
  1763. fReturnValue = (BOOL) TRUE;
  1764. } // Did RtlAdjustPrivilege succeed?
  1765. } // cluster hive file located?
  1766. else
  1767. {
  1768. // The Cluster hive file was not located. That implies that there can be
  1769. // no custom resources. Since lReturnValue is NOT ERROR_SUCCESS no
  1770. // additional processing will be done by this function. A return value
  1771. // of TRUE will allow the uninstall operation to continue.
  1772. ClRtlLogPrint( "Since the Cluster hive file could not be located CheckForCustomResources will\n" );
  1773. ClRtlLogPrint( "report that the uninstall operation may continue.\n" );
  1774. fReturnValue = (BOOL) TRUE;
  1775. } // Was the cluster hive file located?
  1776. } // Was the Cluster registry key opened successfully?
  1777. // The preceeding code segment may have loaded the cluster hive and
  1778. // attempted to open the cluster key. Was it sucessful?
  1779. if ( lReturnValue == ERROR_SUCCESS )
  1780. {
  1781. // At this point, the Cluster registry key was opened successfully. Now, attempt
  1782. // to open the Resource Type subkey.
  1783. HKEY hResourceTypesKey;
  1784. CString csResourceTypesRegKey;
  1785. csResourceTypesRegKey = CLUSREG_KEYNAME_RESOURCE_TYPES;
  1786. lReturnValue = RegOpenKeyEx( hClusterKey,
  1787. csResourceTypesRegKey,
  1788. 0, KEY_READ, &hResourceTypesKey );
  1789. if ( lReturnValue == ERROR_SUCCESS )
  1790. {
  1791. // The ResourceTypes sub key is open.
  1792. // Enumerate the subkeys of the REG_RESTYPES.
  1793. FILETIME t_LastWriteTime;
  1794. WCHAR wszSubKeyName[256];
  1795. DWORD dwCharCount;
  1796. DWORD dwIndex = 0; // index of the first sub-key to enumerate
  1797. dwCharCount = sizeof( wszSubKeyName ) / sizeof( wszSubKeyName[0] );
  1798. lReturnValue = RegEnumKeyEx( hResourceTypesKey,
  1799. dwIndex,
  1800. wszSubKeyName,
  1801. &dwCharCount,
  1802. NULL,
  1803. NULL,// Class of the Key. Not Reqd.
  1804. NULL,// Size of the above param.
  1805. &t_LastWriteTime );
  1806. // RegEnumKeyEx returns ERROR_NO_MORE_ITEMS when there are
  1807. // no additional sub-keys to enumerate.
  1808. if ( lReturnValue == ERROR_SUCCESS )
  1809. {
  1810. // The initial call to RegEnumKeyEx succeeded. Determine whether
  1811. // the sub-key is associated with a non-standard resource type.
  1812. // Function TryToRecognizeResourceType builds a list of non-standard resource types
  1813. // in the CString variable csNonStandardResourceTypeList.
  1814. CString csNonStandardResourceTypeList;
  1815. TryToRecognizeResourceType( csNonStandardResourceTypeList, wszSubKeyName );
  1816. // The following loop checks the remaining sub-keys in the
  1817. // Resource Types registry key.
  1818. while ( lReturnValue == ERROR_SUCCESS )
  1819. {
  1820. dwIndex++;
  1821. dwCharCount = sizeof( wszSubKeyName ) / sizeof( wszSubKeyName[0] );
  1822. lReturnValue = RegEnumKeyEx( hResourceTypesKey,
  1823. dwIndex,
  1824. wszSubKeyName,
  1825. &dwCharCount,
  1826. NULL,
  1827. NULL,// Class of the Key. Not Reqd.
  1828. NULL,// Size of the above param.
  1829. &t_LastWriteTime );
  1830. TryToRecognizeResourceType( csNonStandardResourceTypeList, wszSubKeyName );
  1831. }
  1832. // Were all subkeys of the ResourceTypes registry key "verified"?
  1833. if( lReturnValue == ERROR_NO_MORE_ITEMS )
  1834. {
  1835. CString csMessage;
  1836. fReturnValue = (BOOL) TRUE;
  1837. RegCloseKey( hResourceTypesKey );
  1838. RegCloseKey( hClusterKey );
  1839. // Were there any non-standard subkeys in the Resource Types registry key?
  1840. if ( csNonStandardResourceTypeList.IsEmpty() == (BOOL) FALSE )
  1841. {
  1842. // Non-standard subkeys were found. Ask the user about removal.
  1843. // Build and present a message of the form:
  1844. //
  1845. // The following software packages should be removed before removing
  1846. // the Microsoft Cluster Server software.
  1847. //
  1848. // <list of packages>
  1849. //
  1850. // Do you want to continue with uninstall?
  1851. CString csLastPartOfMessage;
  1852. CString csMessageBoxTitle;
  1853. csLastPartOfMessage.LoadString(IDS_ERR_UNINSTALL_OTHER_SW_EXT);
  1854. csNonStandardResourceTypeList += csLastPartOfMessage;
  1855. // BUGBUG - The next two statements are commented out temporarily because the localization
  1856. // changes needed for this have not been approved. Uncomment after NT 5.0.
  1857. // Also restore clusocm.rc@v2 and resource.h@v2
  1858. // (Vvasu 05-Jan-2000
  1859. // csMessageBoxTitle.LoadString(IDS_TITLE_CUSTOM_RESTYPES);
  1860. //::MessageBox( NULL,
  1861. // csNonStandardResourceTypeList,
  1862. // csMessageBoxTitle,
  1863. // MB_OK | MB_ICONINFORMATION
  1864. // );
  1865. ClRtlLogPrint( "CheckForClusterResourceTypes detected custom resources.\n" );
  1866. } // Were non-standard resource typed detected?
  1867. else
  1868. {
  1869. ClRtlLogPrint( "CheckForCustomResourceTypes did not detect any custom resource types,\n" );
  1870. }
  1871. } // Was there an error enumerating the ResourceTypes key?
  1872. else
  1873. {
  1874. ClRtlLogPrint( "CheckForCustomResourceTypes was unable to enumerate the resource types,\n" );
  1875. ClRtlLogPrint( "implying that no custom resource types exist, so the uninstall will continue.\n" );
  1876. ClRtlLogPrint( "The error code is %1!d!.\n", lReturnValue );
  1877. // An error occured while enumerating the ResourceTypes sub-keys.
  1878. RegCloseKey( hResourceTypesKey );
  1879. RegCloseKey( hClusterKey );
  1880. // The uninstall operation should continue because the installation
  1881. // is apparently defective.
  1882. fReturnValue = (BOOL) TRUE;
  1883. } // Was there an error enumerating the ResourceTypes key?
  1884. }
  1885. else
  1886. {
  1887. // The initial call to RegEnumKeyEx failed.
  1888. // Issue an error message and exit.
  1889. RegCloseKey( hClusterKey );
  1890. ClRtlLogPrint( "CheckForCustomResourceTypes was unable to enumerate the resource types,\n" );
  1891. ClRtlLogPrint( "implying that no custom resource types exist, so the uninstall will continue.\n" );
  1892. ClRtlLogPrint( "The error code is %1!d!.\n", lReturnValue );
  1893. // A return value of TRUE will allow the uninstall operation to
  1894. // continue.
  1895. fReturnValue = (BOOL) TRUE;
  1896. } // Did RegEnumKeyEx open the ResourceTypes key?
  1897. } // Was the ResourceTypes sub key opened?
  1898. else
  1899. {
  1900. // The ResourceTypes sub key could not be opened.
  1901. // Issue an error message and exit.
  1902. RegCloseKey( hClusterKey );
  1903. ClRtlLogPrint( "CheckForCustomResourceTypes was unable to open the Cluster\\ResourceTypes key,\n" );
  1904. ClRtlLogPrint( "implying that no custom resource types exist, so the uninstall will continue.\n" );
  1905. // A return value of TRUE will allow the uninstall operation to
  1906. // continue.
  1907. fReturnValue = (BOOL) TRUE;
  1908. } // Was the ResourceTypes sub key opened?
  1909. } // cluster hive opened?
  1910. else
  1911. {
  1912. // The Cluster registry key could not be opened, even after possibly
  1913. // attempting to load the cluster hive.
  1914. ClRtlLogPrint( "CheckForCustomResourceTypes was unable to open the Cluster key,\n" );
  1915. ClRtlLogPrint( "implying that no custom resource types exist, so the uninstall will continue.\n" );
  1916. ClRtlLogPrint( "The error code is %1!d!.\n", lReturnValue );
  1917. // A return value of TRUE will allow the uninstall operation to
  1918. // continue.
  1919. fReturnValue = (BOOL) TRUE;
  1920. } // Second test whether the Cluster registry key was opened successfully.
  1921. if ( fClusterHiveLoadedByThisFunction == (BOOL) TRUE )
  1922. {
  1923. UnloadClusDB();
  1924. }
  1925. return ( fReturnValue );
  1926. }
  1927. /////////////////////////////////////////////////////////////////////////////
  1928. //++
  1929. //
  1930. // UnloadClusDB
  1931. //
  1932. // Routine Description:
  1933. // This function unloads the Cluster hive.
  1934. //
  1935. // Arguments:
  1936. // None
  1937. //
  1938. // Return Value:
  1939. // None
  1940. //
  1941. // Note:
  1942. // This function was originally in newsetup\utils.cpp.
  1943. //
  1944. //--
  1945. /////////////////////////////////////////////////////////////////////////////
  1946. VOID CClusocmApp::UnloadClusDB( VOID )
  1947. {
  1948. DWORD Status;
  1949. BOOLEAN WasEnabled;
  1950. Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
  1951. TRUE,
  1952. FALSE,
  1953. &WasEnabled);
  1954. if ( Status == ERROR_SUCCESS )
  1955. {
  1956. LONG lReturnValue;
  1957. CString csClusterRegKey;
  1958. csClusterRegKey = CLUSREG_KEYNAME_CLUSTER;
  1959. lReturnValue = RegUnLoadKeyW(HKEY_LOCAL_MACHINE, csClusterRegKey );
  1960. RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
  1961. WasEnabled,
  1962. FALSE,
  1963. &WasEnabled);
  1964. }
  1965. }
  1966. PWCHAR WellKnownResourceTypes[] = {
  1967. CLUS_RESTYPE_NAME_GENAPP,
  1968. CLUS_RESTYPE_NAME_GENSVC,
  1969. CLUS_RESTYPE_NAME_FTSET,
  1970. CLUS_RESTYPE_NAME_PHYS_DISK,
  1971. CLUS_RESTYPE_NAME_IPADDR,
  1972. CLUS_RESTYPE_NAME_NETNAME,
  1973. CLUS_RESTYPE_NAME_FILESHR,
  1974. CLUS_RESTYPE_NAME_PRTSPLR,
  1975. CLUS_RESTYPE_NAME_TIMESVC,
  1976. CLUS_RESTYPE_NAME_LKQUORUM,
  1977. CLUS_RESTYPE_NAME_DHCP,
  1978. CLUS_RESTYPE_NAME_MSMQ,
  1979. CLUS_RESTYPE_NAME_NEW_MSMQ,
  1980. CLUS_RESTYPE_NAME_MSDTC,
  1981. CLUS_RESTYPE_NAME_WINS,
  1982. CLUS_RESTYPE_NAME_IIS4,
  1983. CLUS_RESTYPE_NAME_SMTP,
  1984. CLUS_RESTYPE_NAME_NNTP,
  1985. (PWCHAR) UNICODE_NULL
  1986. };
  1987. /////////////////////////////////////////////////////////////////////////////
  1988. //++
  1989. //
  1990. // TryToRecognizeResourceType
  1991. //
  1992. // Routine Description:
  1993. // This function determines whether the resource type whose name is in
  1994. // parameter "keyname" is recognized as a standard resource type as defined
  1995. // in clusudef.h.
  1996. //
  1997. // This function builds a list of unrecognized reaource types in the CString
  1998. // referenced by parameter "str".
  1999. //
  2000. // Arguments:
  2001. // str - a reference to a CString in which to build a list of unrecognized
  2002. // resource types.
  2003. // keyname - points to a string that contains the resource type name.
  2004. //
  2005. // Return Value:
  2006. // None
  2007. //
  2008. // Note:
  2009. // This function was excerpted verbatim from newsetup\utils.cpp.
  2010. //
  2011. //--
  2012. /////////////////////////////////////////////////////////////////////////////
  2013. VOID CClusocmApp::TryToRecognizeResourceType( CString& str, LPTSTR keyname )
  2014. {
  2015. PWCHAR * ppName = WellKnownResourceTypes;
  2016. while ( *ppName != (PWCHAR)UNICODE_NULL )
  2017. {
  2018. if ( lstrcmp( keyname, *ppName) == 0 )
  2019. return;
  2020. ++ppName;
  2021. }
  2022. if ( !str.IsEmpty() )
  2023. str += L", ";
  2024. else
  2025. {
  2026. str.LoadString(IDS_ERR_UNINSTALL_OTHER_SW);
  2027. str += _T('\n');
  2028. }
  2029. str += keyname;
  2030. }
  2031. /////////////////////////////////////////////////////////////////////////////
  2032. //++
  2033. //
  2034. // GetServiceBinaryPath
  2035. //
  2036. // Routine Description:
  2037. // This function retrieves the fully qualified path to a Service
  2038. // from the Service Control Manager.
  2039. //
  2040. // Arguments:
  2041. // lpwszServiceName - points to a wide character string containing the service name
  2042. // lptszBinaryPathName - points to a string to receive the fully qualified
  2043. // path to the Cluster Service.
  2044. //
  2045. // Return Value:
  2046. // TRUE - The path to the Cluster Service was obtained successfully.
  2047. // FALSE - The path to the Cluster Service was not obtained.
  2048. //
  2049. // Note:
  2050. // Calling this function makes sense IFF the Cluster Service is registered
  2051. // with the Service Control Manager. Call IsClusterServiceRegistered() to
  2052. // ascertain that BEFORE calling GetServiceBinaryPath.
  2053. //
  2054. //--
  2055. /////////////////////////////////////////////////////////////////////////////
  2056. BOOL CClusocmApp::GetServiceBinaryPath( IN LPWSTR lpwszServiceName,
  2057. OUT LPTSTR lptszBinaryPathName )
  2058. {
  2059. BOOL fReturnValue;
  2060. DWORD dwErrorCode = (DWORD) ERROR_SUCCESS;
  2061. if ( lpwszServiceName != (LPWSTR) NULL )
  2062. {
  2063. SC_HANDLE hscServiceMgr;
  2064. SC_HANDLE hscService;
  2065. // Connect to the Service Control Manager and open the specified service
  2066. // control manager database.
  2067. hscServiceMgr = OpenSCManager( NULL, NULL, GENERIC_READ | GENERIC_WRITE );
  2068. // Was the service control manager database opened successfully?
  2069. if ( hscServiceMgr != NULL )
  2070. {
  2071. // The service control manager database is open.
  2072. // Open a handle to the Service.
  2073. hscService = OpenService( hscServiceMgr,
  2074. lpwszServiceName,
  2075. GENERIC_READ );
  2076. // Was the handle to the service opened?
  2077. if ( hscService != NULL )
  2078. {
  2079. // A valid handle to the Service was obtained.
  2080. DWORD dwBufferSize;
  2081. // Note that the size of the buffer required to get the service configuration
  2082. // information was determined empherically to be 240 bytes.
  2083. LPQUERY_SERVICE_CONFIG lpServiceConfig;
  2084. dwBufferSize = (DWORD) sizeof( QUERY_SERVICE_CONFIG ) + 256; // The delta from the
  2085. // size of the structure
  2086. // was chosen arbitrarily.
  2087. // Attempt to allocate the buffer.
  2088. lpServiceConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LMEM_ZEROINIT, dwBufferSize );
  2089. // Was the bufer allocated successfully?
  2090. if ( lpServiceConfig != (LPQUERY_SERVICE_CONFIG) NULL )
  2091. {
  2092. // The following call to QueryServiceConfig should return something
  2093. // usefull. If it fails it is probably because the guess at the size
  2094. // of the buffer is too small.
  2095. fReturnValue = QueryServiceConfig( hscService,
  2096. lpServiceConfig,
  2097. dwBufferSize,
  2098. (LPDWORD) &dwBufferSize );
  2099. // Was the Service configuration info obtained?
  2100. if ( fReturnValue == (BOOL) TRUE )
  2101. {
  2102. // Update the output parameter.
  2103. _tcscpy( lptszBinaryPathName, lpServiceConfig->lpBinaryPathName );
  2104. // lptszBinaryPathName includes the service name. Strip that off.
  2105. LPTSTR ptszTemp;
  2106. ptszTemp = _tcsrchr( (const wchar_t *) lptszBinaryPathName,
  2107. (int) _T('\\') );
  2108. *ptszTemp = _T('\0');
  2109. ClRtlLogPrint( "In GetServiceBinaryPath the first call to QueryServiceConfig succeeded.\n" );
  2110. }
  2111. else
  2112. {
  2113. // Was the buffer too small?
  2114. dwErrorCode = GetLastError();
  2115. if ( dwErrorCode == (DWORD) ERROR_INSUFFICIENT_BUFFER )
  2116. {
  2117. ClRtlLogPrint( "GetServiceBinaryPath is enlarging the buffer for the QUERY_SERVICE_CONFIG structure.\n" );
  2118. // Increase the size of the buffer.
  2119. HLOCAL hLocalBlock;
  2120. // As per RodGa LocalReAlloc is not always reliable. Here that functionality
  2121. // is implemented by freeing the buffer for the QUERY_SERVICE_CONFIG struct
  2122. // and allocating a nre block using LocalFree and LocalAlloc.
  2123. hLocalBlock = LocalFree( lpServiceConfig );
  2124. if ( hLocalBlock == (HLOCAL) NULL )
  2125. {
  2126. // The previously allocated block has been released. Now,
  2127. // allocate a block of the proper size.
  2128. lpServiceConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc( LMEM_ZEROINIT,
  2129. (UINT) dwBufferSize );
  2130. // Was the larger buffer allocated successfully?
  2131. if ( lpServiceConfig != (LPQUERY_SERVICE_CONFIG) NULL )
  2132. {
  2133. // The following call to QueryServiceConfig should return something
  2134. // usefull. If it fails it is not because the buffer is too small.
  2135. fReturnValue = QueryServiceConfig( hscService,
  2136. lpServiceConfig,
  2137. dwBufferSize,
  2138. (LPDWORD) &dwBufferSize );
  2139. // Was the Service configuration info obtained this time.
  2140. if ( fReturnValue == (BOOL) TRUE )
  2141. {
  2142. // Update the output parameter.
  2143. _tcscpy( lptszBinaryPathName, lpServiceConfig->lpBinaryPathName );
  2144. // lptszBinaryPathName includes the service name. Strip that off.
  2145. LPTSTR ptszTemp;
  2146. ptszTemp = _tcsrchr( (const wchar_t *) lptszBinaryPathName,
  2147. (int) _T('\\') );
  2148. *ptszTemp = _T('\0');
  2149. ClRtlLogPrint( "In GetServiceBinaryPath the second call to QueryServiceConfig succeeded.\n" );
  2150. }
  2151. else
  2152. {
  2153. // The Service configuration info was not obtained.
  2154. dwErrorCode = GetLastError();
  2155. ClRtlLogPrint( "In GetServiceBinaryPath the second call to QueryServiceConfig failed\n" );
  2156. ClRtlLogPrint( "with error code 0x%1!x!,\n", dwErrorCode );
  2157. fReturnValue = (BOOL) FALSE;
  2158. } // second call to QueryServiceConfig succeeded?
  2159. }
  2160. else
  2161. {
  2162. // The attempt to enlarge the buffer failed.
  2163. dwErrorCode = GetLastError();
  2164. ClRtlLogPrint( "GetServiceBinaryPath was unable to enlarge the buffer for the QUERY_SERVICE_CONFIG structure.\n" );
  2165. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwErrorCode );
  2166. fReturnValue = (BOOL) FALSE;
  2167. }
  2168. }
  2169. else
  2170. {
  2171. dwErrorCode = GetLastError();
  2172. ClRtlLogPrint( "In GetServiceBinaryPath the call to LocalFree failed with error code 0x%1!x!.\n",
  2173. dwErrorCode );
  2174. fReturnValue = (BOOL) FALSE;
  2175. }
  2176. }
  2177. else
  2178. {
  2179. // Some other error occured.
  2180. ClRtlLogPrint( "In GetServiceBinaryPath the first call to QueryServiceConfig failed\n" );
  2181. ClRtlLogPrint( "with error code 0x%1!x!.\n", dwErrorCode );
  2182. fReturnValue = (BOOL) FALSE;
  2183. } // Was the buffer to small?
  2184. } // Service config info obtained from first call to QueryServiceConfig?
  2185. // Free the buffer if it was ever allocated successfully.
  2186. if ( lpServiceConfig != (LPQUERY_SERVICE_CONFIG) NULL )
  2187. {
  2188. LocalFree( lpServiceConfig );
  2189. }
  2190. }
  2191. else
  2192. {
  2193. // Could not allocate the buffer.
  2194. dwErrorCode = GetLastError();
  2195. ClRtlLogPrint( "GetServiceBinaryPath could not allocate a buffer for the QUERY_SERVICE_CONFIG structure.\n" );
  2196. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwErrorCode );
  2197. fReturnValue = (BOOL) FALSE;
  2198. } // Was the buffer allocated successfully?
  2199. // Close the handle to the Cluster Service.
  2200. CloseServiceHandle( hscService );
  2201. }
  2202. else
  2203. {
  2204. // The Service could not be opened.
  2205. dwErrorCode = GetLastError();
  2206. ClRtlLogPrint( "GetServiceBinaryPath could not open an handle to %1!ws!.\n",
  2207. lpwszServiceName );
  2208. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwErrorCode );
  2209. fReturnValue = (BOOL) FALSE;
  2210. } // Was the Cluster Service opened?
  2211. // Close the handle to the Service Control Manager.
  2212. CloseServiceHandle( hscServiceMgr );
  2213. }
  2214. else
  2215. {
  2216. // The Service Control Manager could not be opened.
  2217. dwErrorCode = GetLastError();
  2218. ClRtlLogPrint( "GetServiceBinaryPath could not open the Service Control Manager.\n" );
  2219. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwErrorCode );
  2220. fReturnValue = (BOOL) FALSE;
  2221. } // Was the Service Control Manager opened?
  2222. }
  2223. else
  2224. {
  2225. // The service name pointer was bogus.
  2226. ClRtlLogPrint( "The service name passed to GetServiceBinaryPath is invalid.\n" );
  2227. fReturnValue = FALSE;
  2228. } // Is the service name legal?
  2229. if ( fReturnValue == (BOOL) FALSE )
  2230. {
  2231. // Set the binary path invalid.
  2232. *lptszBinaryPathName = _T('\0');
  2233. }
  2234. else
  2235. {
  2236. ClRtlLogPrint( "GetServiceBinaryPath located %1!ws! at %2!s!.\n",
  2237. lpwszServiceName, lptszBinaryPathName );
  2238. }
  2239. SetLastError( dwErrorCode ); // Set the "last" error code (which may be ERROR_SUCCESS)
  2240. // because this function's caller is likely to call GetLastError().
  2241. return ( fReturnValue );
  2242. }
  2243. /////////////////////////////////////////////////////////////////////////////
  2244. //++
  2245. //
  2246. // SetDirectoryIds
  2247. //
  2248. // Routine Description:
  2249. // This function associates the user defined Directory Identifiers in the
  2250. // [DestinationDirs] section of the component INF file with particular
  2251. // directories, either the default location for NT 5 installations,
  2252. // %windir%\cluster, or the location of a previous installation.
  2253. //
  2254. // Arguments:
  2255. // fClusterServiceRegistered - TRUE indicates that Cluster service has
  2256. // previously been installed and the files should
  2257. // be updated in place.
  2258. //
  2259. // FALSE - indicates that the Cluster service
  2260. // files should be installed into the default
  2261. // location.
  2262. //
  2263. // Return Value:
  2264. // TRUE - indicates success
  2265. // FALSE - indicates error
  2266. //
  2267. // Note:
  2268. // The [DestinationDirs] section in clusocm.inf contains the following keys:
  2269. //
  2270. // ClusterFiles = 33001
  2271. // ClusterUpgradeFiles = 33002
  2272. // ClusterAdminFiles = 33003
  2273. // ClusterUninstallFiles = 33004
  2274. //
  2275. // Those directory IDs were chosen to be larger than DIRID_USER.
  2276. //--
  2277. /////////////////////////////////////////////////////////////////////////////
  2278. BOOL CClusocmApp::SetDirectoryIds( BOOL fClusterServiceRegistered )
  2279. {
  2280. BOOL fReturnValue;
  2281. TCHAR tszClusterServiceBinaryPath[MAX_PATH];
  2282. // Are Cluster service files already present?
  2283. if ( fClusterServiceRegistered == (BOOL) TRUE )
  2284. {
  2285. // Cluster service files should be upgraded in place.
  2286. // Query the path to the Cluster Service executable from the Service Control Manager.
  2287. CString csClusterService;
  2288. csClusterService = CLUSTER_SERVICE_NAME;
  2289. fReturnValue = GetServiceBinaryPath( (LPWSTR) (LPCTSTR) csClusterService,
  2290. tszClusterServiceBinaryPath );
  2291. if ( fReturnValue == (BOOL) FALSE )
  2292. {
  2293. DWORD dwErrorCode;
  2294. dwErrorCode = GetLastError();
  2295. ClRtlLogPrint( "In SetDirectoryIds the call to GetServiceBinaryPath failed with error code 0x%1!x!.\n",
  2296. dwErrorCode );
  2297. }
  2298. }
  2299. else
  2300. {
  2301. // Cluster service files should be installed in the default location.
  2302. CString csClusterDirectory;
  2303. csClusterDirectory = CLUSTER_DIRECTORY;
  2304. if ( ExpandEnvironmentStrings( (LPCTSTR) csClusterDirectory,
  2305. tszClusterServiceBinaryPath, MAX_PATH ) > 0L )
  2306. {
  2307. fReturnValue = (BOOL) TRUE;
  2308. }
  2309. else
  2310. {
  2311. // Could not expand the enviornment string. The default location for the
  2312. // Cluster service could not be determined.
  2313. fReturnValue = (BOOL) FALSE;
  2314. DWORD dwErrorCode;
  2315. dwErrorCode = GetLastError();
  2316. ClRtlLogPrint( "ExpandEnvironmentString returned 0x%1!x! to SetDirectoryIds.\n",
  2317. dwErrorCode );
  2318. } // Was the default location for the Cluster service determined?
  2319. } // Where should Cluster service files be installed?
  2320. // Was the location into which Cluster service files should be copied obtained?
  2321. if ( fReturnValue == (BOOL) TRUE )
  2322. {
  2323. // Associate selected Directory Ids with the path in tszClusterServiceBinaryPath.
  2324. // Set the Directory Id for the ClusterFiles key in [DestinationDirs].
  2325. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2326. 33001,
  2327. (PCTSTR) tszClusterServiceBinaryPath );
  2328. // Was the Directory Id for the ClusterFiles key set successfully?
  2329. if ( fReturnValue = (BOOL) TRUE )
  2330. {
  2331. ClRtlLogPrint( "Directory Id 33001 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2332. // Set the Directory Id for the ClusterUpgradeFiles key in [DestinationDirs].
  2333. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2334. 33002,
  2335. (PCTSTR) tszClusterServiceBinaryPath );
  2336. } // Was the Directory Id for the ClusterFiles key set successfully?
  2337. // Was the Directory Id for the ClusterUpgradeFiles key set successfully?
  2338. if ( fReturnValue = (BOOL) TRUE )
  2339. {
  2340. ClRtlLogPrint( "Directory Id 33002 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2341. // Set the Directory Id for the ClusterAdminFiles key in [DestinationDirs].
  2342. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2343. 33003,
  2344. (PCTSTR) tszClusterServiceBinaryPath );
  2345. } // Was the Directory Id for the ClusterUpgradeFiles key set successfully?
  2346. // Was the Directory Id for the ClusterAdminFiles key set successfully?
  2347. if ( fReturnValue = (BOOL) TRUE )
  2348. {
  2349. ClRtlLogPrint( "Directory Id 33003 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2350. // Set the Directory Id for the ClusterUninstallFiles key in [DestinationDirs].
  2351. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2352. 33004,
  2353. (PCTSTR) tszClusterServiceBinaryPath );
  2354. } // Was the Directory Id for the ClusterAdminFiles key set successfully?
  2355. // Was the Directory Id for the ClusterUninstallFiles key set successfully?
  2356. if ( fReturnValue = (BOOL) TRUE )
  2357. {
  2358. ClRtlLogPrint( "Directory Id 33004 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2359. // Set the Directory Id for the NT4.files.root key in [DestinationDirs].
  2360. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2361. 33005,
  2362. (PCTSTR) tszClusterServiceBinaryPath );
  2363. } // Was the Directory Id for the ClusterUninstallFiles key set successfully?
  2364. // Was the Directory Id for NT4.files.root key set successfully?
  2365. if ( fReturnValue = (BOOL) TRUE )
  2366. {
  2367. ClRtlLogPrint( "Directory Id 33005 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2368. // Append the "private" directory to the path.
  2369. // Note, I didn't put this string in the stringtable because it is
  2370. // not localizable, and will never change.
  2371. _tcscat( tszClusterServiceBinaryPath, _T("\\private") );
  2372. // Set the Directory Id for the NT4.files.private key in [DestinationDirs].
  2373. fReturnValue = SetupSetDirectoryId( m_SetupInitComponent.ComponentInfHandle,
  2374. 33006,
  2375. (PCTSTR) tszClusterServiceBinaryPath );
  2376. } // Was the Directory Id for the NT4.files.root key set successfully?
  2377. // Was the Directory Id for NT4.files.private key set successfully?
  2378. if ( fReturnValue = (BOOL) TRUE )
  2379. {
  2380. ClRtlLogPrint( "Directory Id 33006 was set to %1!s!.\n", tszClusterServiceBinaryPath );
  2381. } // Was the Directory Id for NT4.files.private key set successfully?
  2382. } // Was the path to the Cluster files determined?
  2383. else
  2384. {
  2385. ClRtlLogPrint( "SetDirectoryIds could not locate the cluster directory, so it failed.\n" );
  2386. }
  2387. return ( fReturnValue );
  2388. }
  2389. /////////////////////////////////////////////////////////////////////////////
  2390. //++
  2391. //
  2392. // UpgradeClusterServiceImagePath
  2393. //
  2394. // Routine Description:
  2395. // This function "upgrades" the ImagePath value in the Cluster Service registry
  2396. // key to the location queried from the Service Control Manager.
  2397. //
  2398. // Arguments:
  2399. // None
  2400. //
  2401. // Return Value:
  2402. // NO_ERROR - indicates success
  2403. // Any other value is a Win32 error code.
  2404. //
  2405. //--
  2406. /////////////////////////////////////////////////////////////////////////////
  2407. DWORD CClusocmApp::UpgradeClusterServiceImagePath( void )
  2408. {
  2409. BOOL fReturnValue;
  2410. DWORD dwReturnValue;
  2411. // Query the path to the Cluster Service from the Service Control Manager.
  2412. TCHAR tszClusterServiceBinaryPath[MAX_PATH];
  2413. CString csClusterService;
  2414. csClusterService = CLUSTER_SERVICE_NAME;
  2415. fReturnValue = GetServiceBinaryPath( (LPWSTR) (LPCTSTR) csClusterService,
  2416. tszClusterServiceBinaryPath );
  2417. // Was the path to the Cluster Service obtained?
  2418. if ( fReturnValue == (BOOL) TRUE )
  2419. {
  2420. // Set the ImagePath value in the Cluster Service reg key to the location
  2421. // obtained from the Service Control Manager.
  2422. LONG lReturnValue;
  2423. HKEY hClusterServiceKey;
  2424. DWORD dwType;
  2425. DWORD dwSize;
  2426. // Attempt to open the Cluster Service reg key.
  2427. CString csClusterServiceRegKey;
  2428. csClusterServiceRegKey = CLUSREG_KEYNAME_CLUSSVC;
  2429. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2430. csClusterServiceRegKey,
  2431. (DWORD) 0L, // reserved
  2432. (REGSAM) KEY_SET_VALUE,
  2433. &hClusterServiceKey );
  2434. // Was the Cluster Service reg key opened?
  2435. if ( lReturnValue == (LONG) ERROR_SUCCESS )
  2436. {
  2437. TCHAR tszClusterServicePath[MAX_PATH];
  2438. _tcscpy( tszClusterServicePath, tszClusterServiceBinaryPath );
  2439. _tcscat( tszClusterServicePath, _T("\\") );
  2440. // Append the name of the Cluster Service.
  2441. CString csClusterService;
  2442. csClusterService = CLUSTER_SERVICE_NAME;
  2443. csClusterService += (CString) _T(".exe");
  2444. _tcscat( tszClusterServicePath, csClusterService );
  2445. DWORD dwImagePathValueLength;
  2446. dwImagePathValueLength = (DWORD) ((_tcslen( tszClusterServicePath ) + 1) * sizeof( TCHAR ));
  2447. CString csImagePath;
  2448. csImagePath = CLUSREG_KEYNAME_IMAGE_PATH;
  2449. lReturnValue = RegSetValueEx( hClusterServiceKey,
  2450. csImagePath,
  2451. (DWORD) 0L, // reserved
  2452. (DWORD) REG_EXPAND_SZ,
  2453. (CONST BYTE *) tszClusterServicePath,
  2454. dwImagePathValueLength );
  2455. // Was the ImagePath written successfully?
  2456. if ( lReturnValue == (LONG) ERROR_SUCCESS )
  2457. {
  2458. dwReturnValue = (DWORD) NO_ERROR;
  2459. ClRtlLogPrint( "UpgradeClusterServiceImagePath succeeded.\n" );
  2460. }
  2461. else
  2462. {
  2463. dwReturnValue = GetLastError();
  2464. ClRtlLogPrint( "UpgradeClusterServiceImagePath failed with error code 0x%1!x!.\n",
  2465. dwReturnValue );
  2466. } // Was the ImagePath written successfully?
  2467. // Close the Cluster Service registry key.
  2468. RegCloseKey( hClusterServiceKey ); // do we care about the return value?
  2469. }
  2470. else
  2471. {
  2472. dwReturnValue = GetLastError();
  2473. ClRtlLogPrint( "UpgradeClusterServiceImagePath failed with error code 0x%1!x!.\n",
  2474. dwReturnValue );
  2475. } // Was the Cluster Service reg key opened?
  2476. } // Was the path to the Cluster Service obtained?
  2477. else
  2478. {
  2479. // Indicate error.
  2480. dwReturnValue = GetLastError();
  2481. ClRtlLogPrint( "UpgradeClusterServiceImagePath failed with error code 0x%1!x!.\n",
  2482. dwReturnValue );
  2483. }
  2484. return ( dwReturnValue );
  2485. }
  2486. /////////////////////////////////////////////////////////////////////////////
  2487. //++
  2488. //
  2489. // OnOcQueueFileOps
  2490. //
  2491. // Routine Description:
  2492. // This function processes the OC_QUEUE_FILE_OPS "messages" from the
  2493. // Optional Components Manager.
  2494. //
  2495. // Arguments:
  2496. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  2497. // component in the component's hiearchy.
  2498. // hSetupFileQueue - a HSPFILEQ (typedefed in setupapi.h to PVOID)
  2499. //
  2500. // Return Value:
  2501. // (DWORD) NO_ERROR - indicates success
  2502. // Any other value is a standard Win32 error code.
  2503. //
  2504. //--
  2505. /////////////////////////////////////////////////////////////////////////////
  2506. DWORD CClusocmApp::OnOcQueueFileOps( IN LPCTSTR ptszSubComponentId,
  2507. IN OUT HSPFILEQ hSetupFileQueue )
  2508. {
  2509. DWORD dwReturnValue = NO_ERROR;
  2510. // Is the handle to the component INF file valid?
  2511. if ( (m_SetupInitComponent.ComponentInfHandle != (HINF) INVALID_HANDLE_VALUE) &&
  2512. (m_SetupInitComponent.ComponentInfHandle != (HINF) NULL) )
  2513. {
  2514. // Is this UNATTENDED or ATTENDED?
  2515. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) !=
  2516. (DWORDLONG) 0L )
  2517. {
  2518. // This is UNATTENDED.
  2519. ClRtlLogPrint( "In OnOcQueueFileOps this is an UNATTENDED operation.\n" );
  2520. dwReturnValue = OnOcQueueFileOpsUnattended( (LPCTSTR) ptszSubComponentId,
  2521. hSetupFileQueue );
  2522. }
  2523. else
  2524. {
  2525. // This is ATTENDED.
  2526. ClRtlLogPrint( "In OnOcQueueFileOps this is an ATTENDED operation.\n" );
  2527. dwReturnValue = OnOcQueueFileOpsAttended( (LPCTSTR) ptszSubComponentId,
  2528. hSetupFileQueue );
  2529. } // Is this UNATTENDED or ATTENDED?
  2530. }
  2531. else
  2532. {
  2533. dwReturnValue = ERROR_FILE_NOT_FOUND;
  2534. ClRtlLogPrint( "In OnOcQueueFileOps the handle to the component INF file is bad.\n" );
  2535. } // Is the handle to the component INF file valid?
  2536. return ( dwReturnValue );
  2537. }
  2538. /////////////////////////////////////////////////////////////////////////////
  2539. //++
  2540. //
  2541. // OnOcQueueFileOpsUnattended
  2542. //
  2543. // Routine Description:
  2544. // This function processes the OC_QUEUE_FILE_OPS "messages" from the
  2545. // Optional Components Manager during UNATTENDED operations.
  2546. //
  2547. // Arguments:
  2548. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  2549. // component in the component's hiearchy.
  2550. // hSetupFileQueue - a HSPFILEQ (typedefed in setupapi.h to PVOID)
  2551. //
  2552. // Return Value:
  2553. // (DWORD) NO_ERROR - indicates success
  2554. // Any other value is a standard Win32 error code.
  2555. //
  2556. // Note:
  2557. // OC Manager sends OC_QUEUE_FILE_OPS to the component DLL when the Components
  2558. // List wizard page is dismissed.
  2559. //
  2560. //--
  2561. /////////////////////////////////////////////////////////////////////////////
  2562. DWORD CClusocmApp::OnOcQueueFileOpsUnattended( IN LPCTSTR ptszSubComponentId,
  2563. IN OUT HSPFILEQ hSetupFileQueue )
  2564. {
  2565. DWORD dwReturnValue;
  2566. // Is this an UPGRADE?
  2567. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  2568. (DWORDLONG) SETUPOP_NTUPGRADE) != (DWORDLONG) 0L )
  2569. {
  2570. // This is an unattended UPGRADE.
  2571. dwReturnValue = QueueFileOpsUnattendedUpgrade( (LPCTSTR) ptszSubComponentId,
  2572. hSetupFileQueue );
  2573. ClRtlLogPrint( "QueueFileOpsUnattendedUpgrade returned 0x%1!x!.\n", dwReturnValue );
  2574. }
  2575. else
  2576. {
  2577. HINF hAnswerFile; // WARNING: NEVER close this handle because clusocm.dll
  2578. // did not open it.
  2579. // Get a handle to the answer file. WARNING: NEVER close this handle because clusocm.dll
  2580. // did not open it.
  2581. hAnswerFile = m_SetupInitComponent.HelperRoutines.GetInfHandle( INFINDEX_UNATTENDED,
  2582. m_SetupInitComponent.HelperRoutines.OcManagerContext );
  2583. if ( (hAnswerFile != (HINF) NULL) && (hAnswerFile != (HINF) INVALID_HANDLE_VALUE) )
  2584. {
  2585. ClRtlLogPrint( "In OnOcQueueFileOpsUnattended this is a CLEAN install.\n" );
  2586. // Is Cluster service selected? It is probably overkill to check, but
  2587. // it is safer to check than to be sorry later.
  2588. BOOL fCurrentSelectionState;
  2589. BOOL fOriginalSelectionState;
  2590. fCurrentSelectionState =
  2591. m_SetupInitComponent.HelperRoutines.QuerySelectionState(
  2592. m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2593. (LPCTSTR) ptszSubComponentId,
  2594. (UINT) OCSELSTATETYPE_CURRENT
  2595. );
  2596. fOriginalSelectionState =
  2597. m_SetupInitComponent.HelperRoutines.QuerySelectionState(
  2598. m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2599. ptszSubComponentId,
  2600. (UINT) OCSELSTATETYPE_ORIGINAL
  2601. );
  2602. if ( fCurrentSelectionState == (BOOL) TRUE )
  2603. {
  2604. // Was there a selection state transition?
  2605. if ( fCurrentSelectionState != fOriginalSelectionState )
  2606. {
  2607. ClRtlLogPrint( "A selection state transition was detected.\n" );
  2608. // A selection state transition has occured. Install files.
  2609. dwReturnValue = QueueInstallFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2610. ptszSubComponentId,
  2611. hSetupFileQueue );
  2612. ClRtlLogPrint( "QueueInstallFileOperations returned 0x%1!x! to OnOcQueueFileOpsAttended,\n",
  2613. dwReturnValue );
  2614. }
  2615. else
  2616. {
  2617. ClRtlLogPrint( "NO selection state transition was detected.\n" );
  2618. // The selection state has not been changed. Perform no action.
  2619. dwReturnValue = (DWORD) NO_ERROR;
  2620. } // Was there a selection state transition?
  2621. }
  2622. else
  2623. {
  2624. // Has there been a selection state transition ?
  2625. ClRtlLogPrint( "In OnOcQueueFileOpsUnattended Cluster service is not selected for installation.\n" );
  2626. if ( fCurrentSelectionState != fOriginalSelectionState )
  2627. {
  2628. // Remove files.
  2629. dwReturnValue = QueueRemoveFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2630. ptszSubComponentId,
  2631. hSetupFileQueue );
  2632. ClRtlLogPrint( "QueueRemoveFileOperations returned 0x%1!x! to OnOcQueueFileOpsUnattended.\n",
  2633. dwReturnValue );
  2634. }
  2635. else
  2636. {
  2637. ClRtlLogPrint( "In OnOcQueueFileOpsUnattended NO selection state transition was detected.\n" );
  2638. // The selection state has not been changed. Perform no action.
  2639. dwReturnValue = (DWORD) NO_ERROR;
  2640. } // Was there a selection state transition ?
  2641. }
  2642. }
  2643. else
  2644. {
  2645. // A handle to the answer file could not be obtained. Treat it as a UPGRADE.
  2646. ClRtlLogPrint( "InOnOcQueueFileOpsUnattended the handle to the answer file could not be obtained.\n" );
  2647. dwReturnValue = QueueFileOpsUnattendedUpgrade( (LPCTSTR) ptszSubComponentId,
  2648. hSetupFileQueue );
  2649. ClRtlLogPrint( "QueueFileOpsUnattendedUpgrade returned 0x%1!x!.\n", dwReturnValue );
  2650. }
  2651. }
  2652. return ( dwReturnValue );
  2653. }
  2654. /////////////////////////////////////////////////////////////////////////////
  2655. //++
  2656. //
  2657. // QueueFileOpsUnattendedUpgrade
  2658. //
  2659. // Routine Description:
  2660. // This function queues the file operations appropriate for an unattended
  2661. // upgrade operation.
  2662. //
  2663. // Arguments:
  2664. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  2665. // component in the component's hiearchy.
  2666. // hSetupFileQueue - a HSPFILEQ (typedefed in setupapi.h to PVOID)
  2667. //
  2668. // Return Value:
  2669. // (DWORD) NO_ERROR - indicates success
  2670. // Any other value is a standard Win32 error code.
  2671. //
  2672. //--
  2673. /////////////////////////////////////////////////////////////////////////////
  2674. DWORD CClusocmApp::QueueFileOpsUnattendedUpgrade( IN LPCTSTR ptszSubComponentId,
  2675. IN OUT HSPFILEQ hSetupFileQueue )
  2676. {
  2677. DWORD dwReturnValue;
  2678. eClusterInstallState eState;
  2679. // Has Cluster service previously been installed?
  2680. // GetClusterInstallationState reports on the state of the registry value
  2681. // that records the state of the Cluster service installation on NT 5 machines.
  2682. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  2683. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  2684. // upgrading NT 4 machines, GetClusterInstallationState for NT 5 machines.
  2685. BOOL fClusteringServicePreviouslyInstalled;
  2686. ClRtlGetClusterInstallState( NULL, &eState );
  2687. if ( ( eState != eClusterInstallStateUnknown ) ||
  2688. ( IsClusterServiceRegistered() == (BOOL) TRUE ) )
  2689. {
  2690. fClusteringServicePreviouslyInstalled = (BOOL) TRUE;
  2691. }
  2692. else
  2693. {
  2694. fClusteringServicePreviouslyInstalled = (BOOL) FALSE;
  2695. }
  2696. if ( fClusteringServicePreviouslyInstalled == (BOOL) TRUE )
  2697. {
  2698. // Upgrade the ClusteringService files.
  2699. dwReturnValue = QueueInstallFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2700. ptszSubComponentId,
  2701. hSetupFileQueue );
  2702. ClRtlLogPrint( "QueueInstallFileOperations returned 0x%1!x! to QueueFileOpsUnattendedUpgrade.\n",
  2703. dwReturnValue );
  2704. } // Has Cluster service previously been installed?
  2705. else
  2706. {
  2707. // Since Cluster service has not been previously installed there is
  2708. // nothing to do.
  2709. ClRtlLogPrint( "In QueueFileOpsUnattendedUpgrade Cluster service has never been installed.\n" );
  2710. dwReturnValue = (DWORD) NO_ERROR;
  2711. } // Has Cluster service previously been installed?
  2712. return ( dwReturnValue );
  2713. }
  2714. /////////////////////////////////////////////////////////////////////////////
  2715. //++
  2716. //
  2717. // OnOcQueueFileOpsAttended
  2718. //
  2719. // Routine Description:
  2720. // This function processes the OC_QUEUE_FILE_OPS "messages" from the
  2721. // Optional Components Manager during ATTENDED operations.
  2722. //
  2723. // Arguments:
  2724. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  2725. // component in the component's hiearchy.
  2726. // hSetupFileQueue - a HSPFILEQ (typedefed in setupapi.h to PVOID)
  2727. //
  2728. // Return Value:
  2729. // (DWORD) NO_ERROR - indicates success
  2730. // Any other value is a standard Win32 error code.
  2731. //
  2732. //--
  2733. /////////////////////////////////////////////////////////////////////////////
  2734. DWORD CClusocmApp::OnOcQueueFileOpsAttended( IN LPCTSTR ptszSubComponentId,
  2735. IN OUT HSPFILEQ hSetupFileQueue )
  2736. {
  2737. DWORD dwReturnValue;
  2738. eClusterInstallState eState;
  2739. // Is Cluster service selected?
  2740. BOOL fCurrentSelectionState;
  2741. BOOL fOriginalSelectionState;
  2742. fCurrentSelectionState =
  2743. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2744. (LPCTSTR) ptszSubComponentId,
  2745. (UINT) OCSELSTATETYPE_CURRENT );
  2746. if ( fCurrentSelectionState == (BOOL) TRUE )
  2747. {
  2748. // The subcomponent is selected. Is this a fresh install ?
  2749. ClRtlLogPrint( "In OnOcQueueFileOpsAttended the current selection state is TRUE.\n" );
  2750. if ( ( (m_SetupInitComponent.SetupData.OperationFlags &
  2751. (DWORDLONG) SETUPOP_STANDALONE) == (DWORDLONG) 0L ) &&
  2752. ( (m_SetupInitComponent.SetupData.OperationFlags &
  2753. (DWORDLONG) SETUPOP_NTUPGRADE) == (DWORDLONG) 0L ) )
  2754. {
  2755. // SETUPOP_STANDALONE flag clear means running under GUI mode setup.
  2756. // SETUPOP_NTUPGRADE flag clear means not performing an upgrade.
  2757. // Both flags clear means a fresh install. Do not check for a selection
  2758. // state transition.
  2759. ClRtlLogPrint( "In OnOcQueueFileOpsAttended this is a CLEAN install.\n" );
  2760. dwReturnValue = QueueInstallFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2761. ptszSubComponentId,
  2762. hSetupFileQueue );
  2763. ClRtlLogPrint( "QueueInstallFileOperations returned 0x%1!x! to OnOcQueueFileOpsAttended.\n",
  2764. dwReturnValue );
  2765. }
  2766. else
  2767. {
  2768. // This is either an upgrade or OC Manager is running stand-alone.
  2769. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  2770. (DWORDLONG) SETUPOP_NTUPGRADE) != (DWORDLONG) 0L )
  2771. {
  2772. ClRtlLogPrint( "In OnOcQueueFileOpsAttended this is an UPGRADE.\n" );
  2773. // This is an upgrade, if Cluster Server has previously been
  2774. // been installed then queue the file copies.
  2775. // Has Cluster service perviously been installed? Ask the Service Control
  2776. // Manager whether the Cluster Service is registered.
  2777. // GetClusterInstallationState reports on the state of the registry value
  2778. // that records the state of the Cluster service installation on NT 5 machines.
  2779. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  2780. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  2781. // upgrading NT 4 machines, GetClusterInstallationState for NT 5 machines.
  2782. BOOL fClusterServiceRegistered;
  2783. fClusterServiceRegistered = IsClusterServiceRegistered();
  2784. BOOL fClusterServicePreviouslyInstalled;
  2785. ClRtlGetClusterInstallState( NULL, &eState );
  2786. if ( ( eState != eClusterInstallStateUnknown ) ||
  2787. ( fClusterServiceRegistered == (BOOL) TRUE ) )
  2788. {
  2789. fClusterServicePreviouslyInstalled = (BOOL) TRUE;
  2790. }
  2791. else
  2792. {
  2793. fClusterServicePreviouslyInstalled = (BOOL) FALSE;
  2794. }
  2795. if ( fClusterServicePreviouslyInstalled == (BOOL) TRUE )
  2796. {
  2797. // Since this is an UPGRADE and Cluster service has been
  2798. // installed there is no need to test for a selection state transition.
  2799. dwReturnValue = QueueInstallFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2800. ptszSubComponentId,
  2801. hSetupFileQueue );
  2802. ClRtlLogPrint( "QueueInstallFileOperations returned 0x%1!x! to OnOcQueueFileOpsAttended.\n",
  2803. dwReturnValue );
  2804. }
  2805. else
  2806. {
  2807. ClRtlLogPrint( "In OnOcQueueFileOps attempted an UPGRADE but Cluster service has never been installed.\n" );
  2808. dwReturnValue = (DWORD) NO_ERROR;
  2809. } // Was Cluster service perviously installed?
  2810. }
  2811. else
  2812. {
  2813. ClRtlLogPrint( "In OnOcQueueFileOpsAttended this is STANDALONE.\n" );
  2814. // This is not an upgrade. That means Add/Remove Programs must be
  2815. // running. It is necessary to test for a selection state transition.
  2816. fOriginalSelectionState =
  2817. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2818. ptszSubComponentId,
  2819. (UINT) OCSELSTATETYPE_ORIGINAL );
  2820. // Was there a selection state transition?
  2821. if ( fCurrentSelectionState != fOriginalSelectionState )
  2822. {
  2823. ClRtlLogPrint( "A selection state transition was detected.\n" );
  2824. // A selection state transition has occured. Install files.
  2825. dwReturnValue = QueueInstallFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2826. ptszSubComponentId,
  2827. hSetupFileQueue );
  2828. ClRtlLogPrint( "QueueInstallFileOperations returned 0x%1!x! to OnOcQueueFileOpsAttended,\n",
  2829. dwReturnValue );
  2830. }
  2831. else
  2832. {
  2833. ClRtlLogPrint( "NO selection state transition was detected.\n" );
  2834. // The selection state has not been changed. Perform no action.
  2835. dwReturnValue = (DWORD) NO_ERROR;
  2836. } // Was there a selection state transition?
  2837. } // Is this an UPGRADE?
  2838. } // Is this a clean install?
  2839. } // Is Cluster service currently selected ?
  2840. else
  2841. {
  2842. ClRtlLogPrint( "In OnOcQueueFileOpsAttended the current selection state is FALSE.\n" );
  2843. // Cluster service is not selected. Is OC Manager running stand-alone ?
  2844. // If not, i.e. if GUI mode setup is running, there is nothing to do.
  2845. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  2846. (DWORDLONG) SETUPOP_STANDALONE) != (DWORDLONG) 0L )
  2847. {
  2848. ClRtlLogPrint( "In OnOcQueueFileOpsAttended this is STANDALONE.\n" );
  2849. // SETUPOP_STANDALONE set implies GUI mode setup is not running. If
  2850. // there was a selection state change (to unselected) then remove files.
  2851. fOriginalSelectionState =
  2852. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2853. ptszSubComponentId,
  2854. (UINT) OCSELSTATETYPE_ORIGINAL );
  2855. // Has there been a selection state transition ?
  2856. if ( fCurrentSelectionState != fOriginalSelectionState )
  2857. {
  2858. // Remove files.
  2859. dwReturnValue = QueueRemoveFileOperations( m_SetupInitComponent.ComponentInfHandle,
  2860. ptszSubComponentId,
  2861. hSetupFileQueue );
  2862. ClRtlLogPrint( "QueueRemoveFileOperations returned 0x%1!x! to OnOcQueueFileOpsAttended.\n",
  2863. dwReturnValue );
  2864. }
  2865. else
  2866. {
  2867. ClRtlLogPrint( "NO selection state transition was detected.\n" );
  2868. // The selection state has not been changed. Perform no action.
  2869. dwReturnValue = (DWORD) NO_ERROR;
  2870. } // Was there a selection state transition ?
  2871. }
  2872. else
  2873. {
  2874. // GUI mode setup is running and Cluster service is not selected.
  2875. // There is nothing to do.
  2876. dwReturnValue = (DWORD) NO_ERROR;
  2877. } // Is GUI mode setup running ?
  2878. } // Is Cluster service currently selected ?
  2879. return ( dwReturnValue );
  2880. }
  2881. /////////////////////////////////////////////////////////////////////////////
  2882. //++
  2883. //
  2884. // CompleteUninstallingClusteringService
  2885. //
  2886. // Routine Description:
  2887. // This function completes uninstalling ClusteringService by queuing the
  2888. // registry operations to delete the Cluster service registry keys,
  2889. // cleaning up the Start Menu, removing the Network Provider, and requesting
  2890. // a reboot.
  2891. //
  2892. // Arguments:
  2893. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  2894. // component in the component's hiearchy.
  2895. //
  2896. // Return Value:
  2897. // (DWORD) NO_ERROR - indicates success
  2898. // Any other value is a standard Win32 error code.
  2899. //
  2900. //--
  2901. /////////////////////////////////////////////////////////////////////////////
  2902. DWORD CClusocmApp::CompleteUninstallingClusteringService( IN LPCTSTR ptszSubComponentId )
  2903. {
  2904. DWORD dwReturnValue;
  2905. eClusterInstallState ecisInstallState;
  2906. BOOL bRebootRequired = FALSE;
  2907. // Update the "progress text"
  2908. CString csProgressText;
  2909. csProgressText.LoadString( IDS_REMOVING_CLUS_SERVICE );
  2910. m_SetupInitComponent.HelperRoutines.SetProgressText( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2911. (LPCTSTR) csProgressText );
  2912. // Request that the system reboot only if clusdisk has been started.
  2913. // We can deduce this by looking at the cluster installation state.
  2914. // If the state is not eClusterInstallStateFilesCopied then it means that
  2915. // ClusCfg may have run successfully and therefore, clusdisk may have been started.
  2916. // We must call ClRtlGetClusterInstallState before calling UninstallRegistryOperations.
  2917. // Otherwise it will always return eClusterInstallStateUnknown!
  2918. // If ClRtlGetClusterInstallState fails, reboot anyway.
  2919. // If it succeeds, reboot only if ClusCfg has completed successfully.
  2920. if ( ( ClRtlGetClusterInstallState( NULL, &ecisInstallState ) != ERROR_SUCCESS )
  2921. || ( ecisInstallState != eClusterInstallStateFilesCopied )
  2922. )
  2923. {
  2924. bRebootRequired = TRUE;
  2925. }
  2926. // Delete registry entries. Queue the base registry operations.
  2927. dwReturnValue = UninstallRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  2928. ptszSubComponentId );
  2929. ClRtlLogPrint( "UninstallRegistryOperations returned 0x%1!x! to CompleteUninstallingClusteringService.\n",
  2930. dwReturnValue );
  2931. //
  2932. // Remove the cluster item from the start menu
  2933. //
  2934. CString csGroupName;
  2935. CString csItemName;
  2936. csGroupName.LoadString( IDS_START_GROUP_NAME );
  2937. csItemName.LoadString( IDS_START_ITEM_NAME );
  2938. DeleteLinkFile( CSIDL_COMMON_PROGRAMS,
  2939. (LPCWSTR) csGroupName,
  2940. (LPCWSTR) csItemName,
  2941. (BOOL) FALSE );
  2942. // Delete the cluster directory. BUGBUG
  2943. //
  2944. // Remove the cluster network provider
  2945. //
  2946. dwReturnValue = RemoveNetworkProvider();
  2947. if ( bRebootRequired )
  2948. {
  2949. BOOL fRebootRequestStatus;
  2950. // In the following call the value passed in the second parameter
  2951. // was chosen arbitrarily. Ocmanage.h implies that the parameter is not used.
  2952. fRebootRequestStatus =
  2953. m_SetupInitComponent.HelperRoutines.SetReboot( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  2954. (BOOL) TRUE );
  2955. }
  2956. return ( dwReturnValue );
  2957. }
  2958. /////////////////////////////////////////////////////////////////////////////
  2959. //++
  2960. //
  2961. // OpenClusterRegistryRoot
  2962. //
  2963. // Routine Description:
  2964. // This function retuns a handle to the root key of the Cluster hive.
  2965. // It will load the hive if necessary.
  2966. //
  2967. // Arguments:
  2968. // none
  2969. //
  2970. //
  2971. // Return Value:
  2972. // If success, handle to the cluster root key. Otherwise, NULL
  2973. //
  2974. //--
  2975. /////////////////////////////////////////////////////////////////////////////
  2976. HKEY CClusocmApp::OpenClusterRegistryRoot( void )
  2977. {
  2978. BOOL fReturnValue;
  2979. HKEY hClusterKey = NULL;
  2980. LONG lReturnValue;
  2981. // Attempt to open the Cluster Registry key.
  2982. CString csClusterRegKey;
  2983. csClusterRegKey = CLUSREG_KEYNAME_CLUSTER;
  2984. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE, csClusterRegKey,
  2985. 0, KEY_READ, &hClusterKey);
  2986. if ( lReturnValue != ERROR_SUCCESS )
  2987. {
  2988. ClRtlLogPrint( "In OpenClusterRegistryRoot, the first attempt to open the Cluster key failed.\n" );
  2989. // The Cluster hive is not currently loaded. This condition means that
  2990. // the cluster service has not been started. Attempt to load the Cluster
  2991. // hive so that it can be read.
  2992. // First, locate the Cluster hive file. It should be in the location
  2993. // specified for the ClusterFiles entry in the [DestinationDirs] section
  2994. // of clusocm.inf.
  2995. CString csClusterHiveFilePath;
  2996. fReturnValue = LocateClusterHiveFile( (CString &) csClusterHiveFilePath );
  2997. ClRtlLogPrint( "LocateClusterHiveFile returned 0x%1!x! to OpenClusterRegistryRoot.\n",
  2998. fReturnValue );
  2999. // Was the Cluster hive file located?
  3000. if ( fReturnValue == (BOOL) TRUE )
  3001. {
  3002. // The Cluster hive file was located.
  3003. // Attempt to load the cluster hive.
  3004. BOOLEAN OriginalState;
  3005. // I'm not sure what the following function does, but the prototype is
  3006. // in sdk\inc\ntrtl.h. Look in stdafx.h for the inclusion of ntrtl.h. I
  3007. // replicated the logic that was used in newsetup.h to make it work.
  3008. lReturnValue = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  3009. TRUE,
  3010. FALSE,
  3011. &OriginalState );
  3012. if ( lReturnValue == ERROR_SUCCESS )
  3013. {
  3014. // Attempt to Load the Cluster Hive.
  3015. lReturnValue = RegLoadKey( HKEY_LOCAL_MACHINE,
  3016. csClusterRegKey,
  3017. csClusterHiveFilePath );
  3018. if ( lReturnValue == ERROR_SUCCESS )
  3019. {
  3020. // Now that the Cluster hive has been loaded, attempt to open the
  3021. // Cluster registry key.
  3022. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  3023. csClusterRegKey,
  3024. 0, KEY_READ,
  3025. &hClusterKey );
  3026. // lReturnValue will be tested by the next BLOCK of code.
  3027. }
  3028. // Undo whatever the preceding call to RtlAdjustPrivilege() did.
  3029. RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  3030. OriginalState,
  3031. FALSE,
  3032. &OriginalState );
  3033. if ( lReturnValue != ERROR_SUCCESS )
  3034. {
  3035. // Set the error code.
  3036. SetLastError( lReturnValue );
  3037. }
  3038. }
  3039. else
  3040. {
  3041. // The initial call to RtlAdjustPrivilege FAILED.
  3042. SetLastError( lReturnValue );
  3043. // A return value of TRUE will allow the uninstall operation to
  3044. // continue. Since lReturnValue is NOT ERROR_SUCCESS no additional
  3045. // processing will be performed by this function.
  3046. } // Did RtlAdjustPrivilege succeed?
  3047. }
  3048. else
  3049. {
  3050. // The Cluster hive file was not located. Set last error and return
  3051. // a null handle
  3052. ClRtlLogPrint( "OpenClusterRegistryRoot couldn't locate the hive files\n" );
  3053. SetLastError( ERROR_FILE_NOT_FOUND );
  3054. } // Was the cluster hive file located?
  3055. } // Was the Cluster registry key opened successfully?
  3056. return ( hClusterKey );
  3057. } // OpenClusterRegistryRoot
  3058. /////////////////////////////////////////////////////////////////////////////
  3059. //++
  3060. //
  3061. // FindNodeNumber
  3062. //
  3063. // Routine Description:
  3064. // This function looks through the cluster's Node key and returns a pointer to
  3065. // the node number string of the current node.
  3066. //
  3067. // Arguments:
  3068. // ClusterKey - handle to cluster root key
  3069. //
  3070. // NodeNumberString - pointer to location that receives the node number
  3071. //
  3072. // Return Value:
  3073. // (DWORD) NO_ERROR - indicates success
  3074. // Any other value is a standard Win32 error code.
  3075. //
  3076. //--
  3077. /////////////////////////////////////////////////////////////////////////////
  3078. PWSTR CClusocmApp::FindNodeNumber( HKEY ClusterKey )
  3079. {
  3080. WCHAR nodeName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  3081. DWORD nodeNameLength = sizeof( nodeName );
  3082. WCHAR registryNodeName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  3083. DWORD registryNodeNameLength;
  3084. HKEY nodesKey = NULL;
  3085. HKEY nodesEnumKey = NULL;
  3086. DWORD status;
  3087. PWSTR nodeNumberString;
  3088. DWORD nodeNumberStringLength;
  3089. DWORD index = 0;
  3090. DWORD dataType;
  3091. //
  3092. // allocate space for the node number string
  3093. //
  3094. nodeNumberString = (PWSTR)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  3095. ( CS_MAX_NODE_ID_LENGTH + 1 ) * sizeof( WCHAR ));
  3096. if ( nodeNumberString == NULL ) {
  3097. status = GetLastError();
  3098. ClRtlLogPrint( "FindNodeNumber couldn't allocate node number buffer: %1!u!\n",
  3099. status );
  3100. return NULL;
  3101. }
  3102. //
  3103. // get our node name and a handle to the root key in the cluster hive
  3104. //
  3105. if ( !GetComputerName( nodeName, &nodeNameLength )) {
  3106. status = GetLastError();
  3107. ClRtlLogPrint( "FindNodeNumber failed to get computer name: %1!u!\n",
  3108. status );
  3109. goto error_exit;
  3110. }
  3111. status = RegOpenKeyEx( ClusterKey,
  3112. CLUSREG_KEYNAME_NODES,
  3113. 0,
  3114. KEY_READ,
  3115. &nodesKey );
  3116. if ( status != ERROR_SUCCESS ) {
  3117. ClRtlLogPrint( "FindNodeName failed to open Nodes key: %1!u!\n",
  3118. status );
  3119. goto error_exit;
  3120. }
  3121. //
  3122. // enum the entries under the Nodes key
  3123. //
  3124. do {
  3125. nodeNumberStringLength = sizeof( nodeNumberString );
  3126. status = RegEnumKeyEx( nodesKey,
  3127. index,
  3128. nodeNumberString,
  3129. &nodeNumberStringLength,
  3130. NULL,
  3131. NULL,
  3132. NULL,
  3133. NULL );
  3134. if ( status == ERROR_NO_MORE_ITEMS ) {
  3135. ClRtlLogPrint( "FindNodeNumber finished enum'ing the Nodes key\n" );
  3136. break;
  3137. } else if ( status != ERROR_SUCCESS ) {
  3138. ClRtlLogPrint( "FindNodeNumber failed to enum Nodes key: %1!u!\n",
  3139. status );
  3140. goto error_exit;
  3141. }
  3142. //
  3143. // open this key and get the Name value
  3144. //
  3145. status = RegOpenKeyEx( nodesKey,
  3146. nodeNumberString,
  3147. 0,
  3148. KEY_READ,
  3149. &nodesEnumKey );
  3150. if ( status != ERROR_SUCCESS ) {
  3151. ClRtlLogPrint( "FindNodeNumber failed to open Nodes key %1!ws!: %2!u!\n",
  3152. nodeNumberString,
  3153. status );
  3154. goto error_exit;
  3155. }
  3156. registryNodeNameLength = sizeof( registryNodeName );
  3157. status = RegQueryValueEx( nodesEnumKey,
  3158. CLUSREG_NAME_NODE_NAME,
  3159. NULL,
  3160. &dataType,
  3161. (LPBYTE)registryNodeName,
  3162. &registryNodeNameLength );
  3163. RegCloseKey( nodesEnumKey );
  3164. nodesEnumKey = NULL;
  3165. if ( status != ERROR_SUCCESS || dataType != REG_SZ ) {
  3166. ClRtlLogPrint( "FindNodeNumber failed to get NodeName value: "
  3167. "status %1!u!, data type %2!u!\n",
  3168. status, dataType );
  3169. goto error_exit;
  3170. }
  3171. //
  3172. // finally, we get to see if this is our node
  3173. //
  3174. if ( lstrcmpiW( nodeName, registryNodeName ) == 0 ) {
  3175. break;
  3176. }
  3177. ++index;
  3178. } while ( TRUE );
  3179. error_exit:
  3180. if ( nodesKey != NULL ) {
  3181. RegCloseKey( nodesKey );
  3182. }
  3183. if ( nodesEnumKey != NULL ) {
  3184. RegCloseKey( nodesEnumKey );
  3185. }
  3186. if ( status != ERROR_SUCCESS || lstrlenW( nodeNumberString ) == 0 ) {
  3187. LocalFree( nodeNumberString );
  3188. nodeNumberString = NULL;
  3189. }
  3190. return nodeNumberString;
  3191. } // FindNodeNumber
  3192. /////////////////////////////////////////////////////////////////////////////
  3193. //++
  3194. //
  3195. // GetConnectionName
  3196. //
  3197. // Routine Description:
  3198. // This function finds the matching connection object based on the IP address
  3199. // of the network interface. NOTE that the return value is also pointed to in
  3200. // the Adapter Info of the Adapter enum struct. This return value must not be
  3201. // freed with LocalFree.
  3202. //
  3203. // Arguments:
  3204. // NetInterfacesKey - handle to key of network interface
  3205. //
  3206. // AdapterEnum - pointer to struct with adapter/IP interface info
  3207. //
  3208. // Return Value:
  3209. // If successful, pointer to connectoid name. Otherwise, NULL with Win32
  3210. // error available from GetLastError().
  3211. //
  3212. //--
  3213. /////////////////////////////////////////////////////////////////////////////
  3214. PWSTR CClusocmApp::GetConnectionName( HKEY NetInterfacesGuidKey,
  3215. PCLRTL_NET_ADAPTER_ENUM AdapterEnum )
  3216. {
  3217. WCHAR ipAddress[ 16 ];
  3218. DWORD ipAddressLength = sizeof( ipAddress );
  3219. DWORD status;
  3220. PCLRTL_NET_ADAPTER_INFO adapterInfo;
  3221. PCLRTL_NET_INTERFACE_INFO interfaceInfo;
  3222. PWSTR connectoidName = NULL;
  3223. DWORD dataType;
  3224. //
  3225. // query for the netIf's IP address
  3226. //
  3227. status = RegQueryValueEx( NetInterfacesGuidKey,
  3228. CLUSREG_NAME_NETIFACE_ADDRESS,
  3229. NULL,
  3230. &dataType,
  3231. (LPBYTE)ipAddress,
  3232. &ipAddressLength );
  3233. if ( status != ERROR_SUCCESS || dataType != REG_SZ ) {
  3234. ClRtlLogPrint( "GetConnectionName failed to get Address value: "
  3235. "status %1!u!, data type %2!u!\n",
  3236. status, dataType );
  3237. SetLastError( ERROR_INVALID_DATA );
  3238. goto error_exit;
  3239. }
  3240. adapterInfo = ClRtlFindNetAdapterByInterfaceAddress( AdapterEnum,
  3241. ipAddress,
  3242. &interfaceInfo );
  3243. if ( adapterInfo != NULL ) {
  3244. connectoidName = adapterInfo->ConnectoidName;
  3245. }
  3246. error_exit:
  3247. return connectoidName;
  3248. } // GetConnectionName
  3249. /////////////////////////////////////////////////////////////////////////////
  3250. //++
  3251. //
  3252. // GetTCPAdapterInfo
  3253. //
  3254. // Routine Description:
  3255. // This function opens a handle to the service controller and tries to
  3256. // start the DHCP service. If successful, then TCP is queried for its
  3257. // NIC and IP interface info.
  3258. //
  3259. // Arguments:
  3260. // none
  3261. //
  3262. // Return Value:
  3263. // (DWORD) NO_ERROR - indicates success
  3264. // Any other value is a standard Win32 error code.
  3265. //
  3266. //--
  3267. /////////////////////////////////////////////////////////////////////////////
  3268. PCLRTL_NET_ADAPTER_ENUM CClusocmApp::GetTCPAdapterInfo( void )
  3269. {
  3270. SC_HANDLE schSCManager;
  3271. SC_HANDLE serviceHandle;
  3272. PCLRTL_NET_ADAPTER_ENUM adapterEnum = NULL;
  3273. BOOL success;
  3274. DWORD retryCount;
  3275. DWORD status;
  3276. schSCManager = OpenSCManager(NULL, // machine (NULL == local)
  3277. NULL, // database (NULL == default)
  3278. SC_MANAGER_CONNECT); // access required
  3279. if ( schSCManager ) {
  3280. //
  3281. // start DHCP for nodes that are using it. it will cause TCP to start
  3282. // as well. For statically configured nodes, starting DHCP causes no
  3283. // harm.
  3284. //
  3285. serviceHandle = OpenService(schSCManager,
  3286. L"DHCP",
  3287. SERVICE_START );
  3288. if ( serviceHandle ) {
  3289. success = StartService( serviceHandle, 0, NULL );
  3290. if ( !success ) {
  3291. status = GetLastError();
  3292. if ( status == ERROR_SERVICE_ALREADY_RUNNING ) {
  3293. success = TRUE;
  3294. }
  3295. }
  3296. if ( success ) {
  3297. //
  3298. // wait while TCP gets bound to all its adapters and discovers
  3299. // its IP interfaces.
  3300. //
  3301. retryCount = 3;
  3302. do {
  3303. Sleep( 2000 );
  3304. adapterEnum = ClRtlEnumNetAdapters();
  3305. if (adapterEnum != NULL) {
  3306. break;
  3307. }
  3308. } while ( --retryCount != 0 );
  3309. if (adapterEnum == NULL) {
  3310. status = GetLastError();
  3311. ClRtlLogPrint( "Failed to obtain local system network config. "
  3312. "status %1!u! retryCount %2!u!\n",
  3313. status, retryCount);
  3314. }
  3315. } else {
  3316. ClRtlLogPrint( "StartService returned %1!u! to StartTCP\n", status);
  3317. }
  3318. CloseServiceHandle( serviceHandle );
  3319. } else {
  3320. status = GetLastError();
  3321. ClRtlLogPrint( "OpenService returned %1!u! to StartTCP\n", status);
  3322. }
  3323. CloseServiceHandle( schSCManager );
  3324. } else {
  3325. status = GetLastError();
  3326. ClRtlLogPrint("OpenSCManager returned %1!u! to StartTCP\n", status);
  3327. }
  3328. return adapterEnum;
  3329. }
  3330. /////////////////////////////////////////////////////////////////////////////
  3331. //++
  3332. //
  3333. // RenameConnectionObjects
  3334. //
  3335. // Routine Description:
  3336. // This function walks through the node's network interfaces and changes,
  3337. // if necessary, their associated connection objects.
  3338. //
  3339. // Arguments:
  3340. // none
  3341. //
  3342. // Return Value:
  3343. // (DWORD) NO_ERROR - indicates success
  3344. // Any other value is a standard Win32 error code.
  3345. //
  3346. //--
  3347. /////////////////////////////////////////////////////////////////////////////
  3348. DWORD CClusocmApp::RenameConnectionObjects( void )
  3349. {
  3350. HKEY clusterKey;
  3351. HKEY netInterfacesKey = NULL;
  3352. HKEY netInterfacesGuidKey = NULL;
  3353. HKEY networkGuidKey = NULL;
  3354. HKEY networksKey = NULL;
  3355. DWORD status;
  3356. PCLRTL_NET_ADAPTER_ENUM adapterEnum = NULL;
  3357. PCLRTL_NET_ADAPTER_INFO adapterInfo = NULL;
  3358. PCLRTL_NET_INTERFACE_INFO adapterIfInfo = NULL;
  3359. DWORD hiddenAdapterCount = 0;
  3360. PWSTR ourNodeNumber = NULL;
  3361. DWORD index = 0;
  3362. WCHAR netIfGuidString[ CS_NETINTERFACE_ID_LENGTH + 1 ];
  3363. DWORD netIfGuidStringLength;
  3364. WCHAR networkGuidString[ CS_NETWORK_ID_LENGTH + 1 ];
  3365. DWORD networkGuidStringLength;
  3366. WCHAR netIfNodeNumber[ CS_MAX_NODE_ID_LENGTH + 1 ];
  3367. DWORD netIfNodeNumberLength;
  3368. DWORD dataType;
  3369. PWSTR connectoidName;
  3370. PWSTR networkName = NULL;
  3371. DWORD networkNameLength;
  3372. //
  3373. // initialize COM
  3374. //
  3375. status = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
  3376. if ( !SUCCEEDED( status )) {
  3377. ClRtlLogPrint( "RenameConnectionObjects Couldn't init COM %1!08X!\n", status );
  3378. return status;
  3379. }
  3380. //
  3381. // get a handle to the root key in the cluster hive
  3382. //
  3383. clusterKey = OpenClusterRegistryRoot();
  3384. if ( clusterKey == NULL ) {
  3385. status = GetLastError();
  3386. ClRtlLogPrint( "OpenClusterRegistryRoot returned %1!u! to RenameConnectionObjects\n",
  3387. status );
  3388. goto error_exit;
  3389. }
  3390. //
  3391. // start TCP if necessary
  3392. //
  3393. adapterEnum = GetTCPAdapterInfo();
  3394. if ( adapterEnum == NULL ) {
  3395. status = GetLastError();
  3396. if ( status == ERROR_SUCCESS ) {
  3397. ClRtlLogPrint( "No usable network adapters are installed in this system.\n" );
  3398. } else {
  3399. ClRtlLogPrint( "GetTCPAdapterInfo returned %1!u! to RenameConnectionObjects\n",
  3400. status );
  3401. }
  3402. goto error_exit;
  3403. }
  3404. //
  3405. // Ignore all adapters which are hidden or have an address of 0.0.0.0.
  3406. //
  3407. for (adapterInfo = adapterEnum->AdapterList;
  3408. adapterInfo != NULL;
  3409. adapterInfo = adapterInfo->Next
  3410. )
  3411. {
  3412. if (adapterInfo->Flags & CLRTL_NET_ADAPTER_HIDDEN) {
  3413. ClRtlLogPrint( "Ignoring hidden adapter '%1!ws!'.\n",
  3414. adapterInfo->DeviceName );
  3415. adapterInfo->Ignore = TRUE;
  3416. hiddenAdapterCount++;
  3417. }
  3418. else {
  3419. adapterIfInfo = ClRtlGetPrimaryNetInterface(adapterInfo);
  3420. if (adapterIfInfo->InterfaceAddress == 0) {
  3421. ClRtlLogPrint( "Ignoring adapter '%1!ws!' because primary address is 0.0.0.0.\n",
  3422. adapterInfo->DeviceName );
  3423. adapterInfo->Ignore = TRUE;
  3424. hiddenAdapterCount++;
  3425. }
  3426. }
  3427. }
  3428. if ((adapterEnum->AdapterCount - hiddenAdapterCount) == 0) {
  3429. ClRtlLogPrint( "No usable network adapters are installed in this system.\n" );
  3430. status = ERROR_SUCCESS;
  3431. goto error_exit;
  3432. }
  3433. ClRtlLogPrint( "RenameConnectionObject found %1!u! adapters to process.\n",
  3434. adapterEnum->AdapterCount - hiddenAdapterCount );
  3435. //
  3436. // now find our node number by looking through the node key in the cluster
  3437. // registry and comparing our netbios name with the names in the registry
  3438. //
  3439. ourNodeNumber = FindNodeNumber( clusterKey );
  3440. if ( ourNodeNumber == NULL ) {
  3441. status = GetLastError();
  3442. ClRtlLogPrint( "FindNodeNumber failed: status %1!u!\n",
  3443. status );
  3444. goto error_exit;
  3445. }
  3446. //
  3447. // open the network and network interface keys
  3448. //
  3449. status = RegOpenKeyEx( clusterKey,
  3450. CLUSREG_KEYNAME_NETWORKS,
  3451. 0,
  3452. KEY_READ,
  3453. &networksKey );
  3454. if ( status != ERROR_SUCCESS ) {
  3455. ClRtlLogPrint( "RenameConnectionObjects failed to open Networks key: %1!u!\n",
  3456. status );
  3457. goto error_exit;
  3458. }
  3459. status = RegOpenKeyEx( clusterKey,
  3460. CLUSREG_KEYNAME_NETINTERFACES,
  3461. 0,
  3462. KEY_READ,
  3463. &netInterfacesKey );
  3464. if ( status != ERROR_SUCCESS ) {
  3465. ClRtlLogPrint( "RenameConnectionObjects failed to open NetworkInterfaces key: %1!u!\n",
  3466. status );
  3467. goto error_exit;
  3468. }
  3469. //
  3470. // enum the NetworkInterfaces key, looking for interfaces on this node. If
  3471. // we find one, get their IP address and find the corresponding network and
  3472. // connection object.
  3473. //
  3474. do {
  3475. netIfGuidStringLength = sizeof( netIfGuidString );
  3476. status = RegEnumKeyEx( netInterfacesKey,
  3477. index,
  3478. netIfGuidString,
  3479. &netIfGuidStringLength,
  3480. NULL,
  3481. NULL,
  3482. NULL,
  3483. NULL );
  3484. if ( status == ERROR_NO_MORE_ITEMS ) {
  3485. ClRtlLogPrint( "RenameConnectionObjects finished enum'ing the "
  3486. "NetworkInterfaces key\n" );
  3487. status = ERROR_SUCCESS;
  3488. break;
  3489. } else if ( status != ERROR_SUCCESS ) {
  3490. ClRtlLogPrint( "RenameConnectionObjects failed to enum NetworkInterfaces "
  3491. "key: %1!u!\n",
  3492. status );
  3493. goto error_exit;
  3494. }
  3495. //
  3496. // open this key and get the Node value
  3497. //
  3498. status = RegOpenKeyEx( netInterfacesKey,
  3499. netIfGuidString,
  3500. 0,
  3501. KEY_READ,
  3502. &netInterfacesGuidKey );
  3503. if ( status != ERROR_SUCCESS ) {
  3504. ClRtlLogPrint( "RenameConnectionObjects failed to open NetworkIntefaces "
  3505. "subkey %1!ws!: %2!u!\n",
  3506. netIfGuidString,
  3507. status );
  3508. goto error_exit;
  3509. }
  3510. netIfNodeNumberLength = sizeof( netIfNodeNumber );
  3511. status = RegQueryValueEx( netInterfacesGuidKey,
  3512. CLUSREG_NAME_NETIFACE_NODE,
  3513. NULL,
  3514. &dataType,
  3515. (LPBYTE)netIfNodeNumber,
  3516. &netIfNodeNumberLength );
  3517. if ( status != ERROR_SUCCESS || dataType != REG_SZ ) {
  3518. ClRtlLogPrint( "RenameConnectionObjects failed to get Node value: "
  3519. "status %1!u!, data type %2!u!\n",
  3520. status, dataType );
  3521. status = ERROR_INVALID_DATA;
  3522. goto error_exit;
  3523. }
  3524. //
  3525. // if this is one our interfaces, then adjust the name of the
  3526. // associated connection object
  3527. //
  3528. if ( lstrcmpiW( ourNodeNumber, netIfNodeNumber ) == 0 ) {
  3529. ClRtlLogPrint( "Net Interface %1!ws! is on this node.\n",
  3530. netIfGuidString );
  3531. connectoidName = GetConnectionName( netInterfacesGuidKey,
  3532. adapterEnum );
  3533. if ( connectoidName != NULL ) {
  3534. ClRtlLogPrint( "Associated connectoid name is '%1!ws!'.\n",
  3535. connectoidName);
  3536. //
  3537. // look up network GUID and open its Key to get the network name
  3538. //
  3539. networkGuidStringLength = sizeof( networkGuidString );
  3540. status = RegQueryValueEx( netInterfacesGuidKey,
  3541. CLUSREG_NAME_NETIFACE_NETWORK,
  3542. NULL,
  3543. &dataType,
  3544. (LPBYTE)networkGuidString,
  3545. &networkGuidStringLength );
  3546. if ( status != ERROR_SUCCESS || dataType != REG_SZ ) {
  3547. ClRtlLogPrint( "RenameConnectionObjects failed to get Network value: "
  3548. "status %1!u!, data type %2!u!\n",
  3549. status, dataType );
  3550. status = ERROR_INVALID_DATA;
  3551. goto error_exit;
  3552. }
  3553. status = RegOpenKeyEx( networksKey,
  3554. networkGuidString,
  3555. 0,
  3556. KEY_READ,
  3557. &networkGuidKey );
  3558. if ( status != ERROR_SUCCESS ) {
  3559. ClRtlLogPrint( "RenameConnectionObjects failed to open networks "
  3560. "subkey %1!ws!: %2!u!\n",
  3561. networkGuidString,
  3562. status );
  3563. goto error_exit;
  3564. }
  3565. //
  3566. // query the Name value to get its size, allocate a buffer large
  3567. // enough to hold it and request the data contained in the value.
  3568. //
  3569. networkNameLength = 0;
  3570. status = RegQueryValueEx( networkGuidKey,
  3571. CLUSREG_NAME_NET_NAME,
  3572. NULL,
  3573. &dataType,
  3574. (LPBYTE)NULL,
  3575. &networkNameLength );
  3576. if ( status != ERROR_SUCCESS || dataType != REG_SZ ) {
  3577. ClRtlLogPrint( "RenameConnectionObjects failed to get Network Name "
  3578. "size: status %1!u!, data type %2!u!\n",
  3579. status, dataType );
  3580. status = ERROR_INVALID_DATA;
  3581. goto error_exit;
  3582. }
  3583. networkName = (PWCHAR)LocalAlloc( LMEM_FIXED, networkNameLength );
  3584. if ( networkName == NULL ) {
  3585. status = GetLastError();
  3586. ClRtlLogPrint( "RenameConnectionObjects failed to alloc space "
  3587. "for network name: %1!u!\n",
  3588. status );
  3589. goto error_exit;
  3590. }
  3591. status = RegQueryValueEx( networkGuidKey,
  3592. CLUSREG_NAME_NET_NAME,
  3593. NULL,
  3594. NULL,
  3595. (LPBYTE)networkName,
  3596. &networkNameLength );
  3597. RegCloseKey( networkGuidKey );
  3598. networkGuidKey = NULL;
  3599. if ( status != ERROR_SUCCESS ) {
  3600. ClRtlLogPrint( "RenameConnectionObjects failed to get Network "
  3601. "Name: status %1!u!\n",
  3602. status );
  3603. goto error_exit;
  3604. }
  3605. ClRtlLogPrint( "Network name is '%1!ws!'.\n", networkName );
  3606. if ( lstrcmpiW( connectoidName, networkName ) != 0 ) {
  3607. ClRtlLogPrint( "Changing connectoid name to '%1!ws!'.\n", networkName );
  3608. ClRtlFindConnectoidByNameAndSetName(
  3609. connectoidName,
  3610. networkName
  3611. );
  3612. }
  3613. } else {
  3614. ClRtlLogPrint( "RenameConnectionObjects failed to get connection name.\n" );
  3615. }
  3616. }
  3617. RegCloseKey( netInterfacesGuidKey );
  3618. netInterfacesGuidKey = NULL;
  3619. ++index;
  3620. } while ( TRUE );
  3621. error_exit:
  3622. if ( clusterKey != NULL ) {
  3623. RegCloseKey( clusterKey );
  3624. }
  3625. if ( netInterfacesKey != NULL ) {
  3626. RegCloseKey( netInterfacesKey );
  3627. }
  3628. if ( netInterfacesGuidKey != NULL ) {
  3629. RegCloseKey( netInterfacesGuidKey );
  3630. }
  3631. if ( networksKey != NULL ) {
  3632. RegCloseKey( networksKey );
  3633. }
  3634. if ( networkGuidKey != NULL ) {
  3635. RegCloseKey( networkGuidKey );
  3636. }
  3637. if ( ourNodeNumber != NULL ) {
  3638. LocalFree( ourNodeNumber );
  3639. }
  3640. if ( networkName != NULL ) {
  3641. LocalFree( networkName );
  3642. }
  3643. if ( adapterEnum != NULL ) {
  3644. ClRtlFreeNetAdapterEnum( adapterEnum );
  3645. }
  3646. CoUninitialize();
  3647. return status;
  3648. } // RenameConnectionObjects
  3649. /////////////////////////////////////////////////////////////////////////////
  3650. //++
  3651. //
  3652. // CompleteUpgradingClusteringService
  3653. //
  3654. // Routine Description:
  3655. // This function completes the process of upgrading a Cluster service installation.
  3656. //
  3657. // Arguments:
  3658. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  3659. // component in the component's hiearchy.
  3660. //
  3661. // Return Value:
  3662. // (DWORD) NO_ERROR - indicates success
  3663. // Any other value is a standard Win32 error code.
  3664. //
  3665. //--
  3666. /////////////////////////////////////////////////////////////////////////////
  3667. DWORD CClusocmApp::CompleteUpgradingClusteringService( IN LPCTSTR ptszSubComponentId )
  3668. {
  3669. DWORD dwReturnValue;
  3670. eClusterInstallState eState;
  3671. // This is an upgrade, if Cluster Server has previously been
  3672. // been installed then queue the registry additions.
  3673. // GetClusterInstallationState reports on the state of the registry value
  3674. // that records the state of the Cluster service installation on NT 5 machines.
  3675. // IsClusterServiceRegistered indicates whether the Cluster service is registered on
  3676. // BOTH NT 4 and NT 5 machines. Both tests are required: IsClusterServiceRegistered for
  3677. // upgrading NT 4 machines, ClRtlGetClusterInstallState for NT 5 machines.
  3678. BOOL fClusterServiceRegistered;
  3679. fClusterServiceRegistered = IsClusterServiceRegistered();
  3680. ClRtlGetClusterInstallState( NULL, &eState );
  3681. if ( ( eState != eClusterInstallStateUnknown ) ||
  3682. ( fClusterServiceRegistered == (BOOL) TRUE ) )
  3683. {
  3684. // Update the progress bar.
  3685. m_SetupInitComponent.HelperRoutines.TickGauge( m_SetupInitComponent.HelperRoutines.OcManagerContext );
  3686. // Update the "progress text"
  3687. CString csProgressText;
  3688. csProgressText.LoadString( IDS_UPGRADING_CLUS_SERVICE );
  3689. m_SetupInitComponent.HelperRoutines.SetProgressText( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  3690. (LPCTSTR) csProgressText );
  3691. ClRtlLogPrint( "In CompleteUpgradingClusteringService Cluster service has previously been installed.\n" );
  3692. // Perform the base registry operations.
  3693. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  3694. ptszSubComponentId );
  3695. ClRtlLogPrint( "The base call to PerformRegistryOperations returned 0x%1!x! to "
  3696. "CompleteUpgradingClusteringService.\n",
  3697. dwReturnValue );
  3698. // Were the base registry operations performed successfully?
  3699. CString csUpgrade;
  3700. if ( dwReturnValue == (DWORD) NO_ERROR )
  3701. {
  3702. // Perform the registry operations that pertain to UPGRADE.
  3703. csUpgrade = UPGRADE_INF_KEY;
  3704. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  3705. csUpgrade );
  3706. ClRtlLogPrint( "The UPGRADE call to PerformRegistryOperations returned 0x%1!x! "
  3707. "to CompleteUpgradingClusteringService.\n",
  3708. dwReturnValue );
  3709. } // Were the base registry operations performed successfully?
  3710. // Were the UPGRADE registry operations performed successfully?
  3711. if ( dwReturnValue == (DWORD) NO_ERROR )
  3712. {
  3713. // If the Cluster Service is registered with the Service Control Manager then
  3714. // the registry keys that add "Configure Cluster service" to the Welcome UI
  3715. // should be eliminated because the service has already been configured.
  3716. if ( fClusterServiceRegistered == (BOOL) TRUE )
  3717. {
  3718. CString csClusterService;
  3719. csClusterService = CLUSTER_SERVICE_NAME;
  3720. CString csRegistered;
  3721. csRegistered = REGISTERED_INF_KEY_FRAGMENT;
  3722. CString csSectionName;
  3723. csSectionName = csUpgrade + (CString) _T(".") +
  3724. csClusterService + (CString) _T(".") +
  3725. csRegistered;
  3726. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  3727. csSectionName );
  3728. ClRtlLogPrint( "The REGISTERED call to PerformRegistryOperations returned 0x%1!x! "
  3729. "to CompleteUpgradingClusteringService.\n",
  3730. dwReturnValue );
  3731. }
  3732. // Were the Welcome UI registry operations performed successfully?
  3733. if ( dwReturnValue == (DWORD) NO_ERROR )
  3734. {
  3735. ClRtlLogPrint( "In CompleteUpgradingClusteringService the registry operations "
  3736. "were performed successfully.\n" );
  3737. // In NT 4 the ImagePath value in HKLM\System\CurrentControlSet\Services\ClusSvc
  3738. // is set to reference clusprxy.exe. In NT 5 it must reference clussvc.exe.
  3739. // The ImagePath value in the Cluster Service registry key must
  3740. // be set programmatically because the path to the service
  3741. // executable image is not known to the component INF file. That
  3742. // is because in NT 4 "Cluster Server" as it was known, could be
  3743. // installed in an arbitrary location.
  3744. // There is no straightforward way to determine whether this upgrade
  3745. // is from NT 4 or NT 5. The assumption made here is that if the
  3746. // Cluster Service is registered with the Service Control Manager
  3747. // then it was upgraded in place, regardless of the OS level. In that
  3748. // case it will be safe to set the ImagePath value to reference clussvc.exe
  3749. // in that location. If the Cluster Service is not registered with the
  3750. // SC Manager then it is safe to leave that reg value alone because when
  3751. // cluscfg.exe configures the Cluster service the ImagePath value will
  3752. // get written correctly.
  3753. if ( fClusterServiceRegistered == (BOOL) TRUE )
  3754. {
  3755. dwReturnValue = UpgradeClusterServiceImagePath();
  3756. ClRtlLogPrint( "UpgradeClusterServiceImagePath returned 0x%1!x! to "
  3757. "CompleteUpgradingClusteringService.\n",
  3758. dwReturnValue );
  3759. }
  3760. // Was the ImagePath set successfully?
  3761. if ( dwReturnValue == (DWORD) NO_ERROR )
  3762. {
  3763. // did the connection objects get renamed?
  3764. dwReturnValue = RenameConnectionObjects();
  3765. ClRtlLogPrint( "RenameConnectionObjects returned 0x%1!x! to "
  3766. "CompleteUpgradingClusteringService.\n",
  3767. dwReturnValue );
  3768. if ( dwReturnValue == (DWORD) NO_ERROR )
  3769. {
  3770. //
  3771. // set the service controller default failure actions
  3772. //
  3773. dwReturnValue = ClRtlSetSCMFailureActions( NULL );
  3774. ClRtlLogPrint( "ClRtlSetDefaultFailureActions returned 0x%1!x! to "
  3775. "CompleteUpgradingClusteringService.\n",
  3776. dwReturnValue );
  3777. if ( dwReturnValue == (DWORD) NO_ERROR )
  3778. {
  3779. // In NT4 the "Display Name" for the Cluster service was
  3780. // "Cluster Server". It must be programatically changed to
  3781. // "Cluster service".
  3782. if ( fClusterServiceRegistered == (BOOL) TRUE )
  3783. {
  3784. CString csClusterService;
  3785. csClusterService = CLUSTER_SERVICE_NAME;
  3786. SC_HANDLE hscServiceMgr;
  3787. SC_HANDLE hscService;
  3788. // Connect to the Service Control Manager and open the specified service
  3789. // control manager database.
  3790. hscServiceMgr = OpenSCManager( NULL, NULL, GENERIC_READ | GENERIC_WRITE );
  3791. // Was the service control manager database opened successfully?
  3792. if ( hscServiceMgr != NULL )
  3793. {
  3794. // The service control manager database is open.
  3795. // Get the current display name of the service.
  3796. TCHAR tszDisplayName[50]; // arbitrary size
  3797. DWORD dwBufferSize = 50;
  3798. BOOL fStatus;
  3799. fStatus = GetServiceDisplayName( hscServiceMgr,
  3800. (LPCTSTR) csClusterService,
  3801. tszDisplayName,
  3802. &dwBufferSize );
  3803. if ( fStatus == (BOOL) TRUE )
  3804. {
  3805. // Is the service name "Cluster service"?
  3806. if ( _tcscmp( tszDisplayName, _T("Cluster service") ) != 0 )
  3807. {
  3808. // The display name is not correct. Change it.
  3809. // Open a handle to the Service. Allow configuration changes.
  3810. hscService = OpenService( hscServiceMgr,
  3811. (LPWSTR) (LPCTSTR) csClusterService,
  3812. SERVICE_CHANGE_CONFIG );
  3813. // Was the handle to the service opened?
  3814. if ( hscService != NULL )
  3815. {
  3816. // A valid handle to the Service was obtained.
  3817. fStatus = ChangeServiceConfig( hscService,
  3818. SERVICE_NO_CHANGE,
  3819. SERVICE_NO_CHANGE,
  3820. SERVICE_NO_CHANGE,
  3821. NULL,
  3822. NULL,
  3823. NULL,
  3824. NULL,
  3825. NULL,
  3826. NULL,
  3827. _T("Cluster service") );
  3828. // Was the change succesful?
  3829. if ( fStatus != (BOOL) TRUE )
  3830. {
  3831. dwReturnValue = GetLastError();
  3832. ClRtlLogPrint( "Could not change the cluster service display name"
  3833. " in CompleteUpgradingClusteringService."
  3834. " Error: 0x%1!x!.\n",
  3835. dwReturnValue );
  3836. }
  3837. // Close the handle to the Cluster Service.
  3838. CloseServiceHandle( hscService );
  3839. } // service opened?
  3840. } // display name correct?
  3841. }
  3842. else
  3843. {
  3844. // Couldn't get the display name.
  3845. dwReturnValue = GetLastError();
  3846. ClRtlLogPrint( "Could not query the cluster service display name"
  3847. " in CompleteUpgradingClusteringService."
  3848. " Error: 0x%1!x!.\n",
  3849. dwReturnValue );
  3850. }// got display name?
  3851. // Close the handle to the Service Control Manager.
  3852. CloseServiceHandle( hscServiceMgr );
  3853. }
  3854. } // cluster service registered?
  3855. if ( dwReturnValue == (DWORD) NO_ERROR )
  3856. {
  3857. // Register ClAdmWiz.
  3858. // First, get the path to the cluster directory.
  3859. CString csTemp;
  3860. csTemp = CLUSTER_DIRECTORY;
  3861. TCHAR tszPathToClusterDir[_MAX_PATH];
  3862. if ( ExpandEnvironmentStrings( (LPCTSTR) csTemp,
  3863. tszPathToClusterDir, _MAX_PATH ) > 0L )
  3864. {
  3865. HRESULT hResult;
  3866. // Attempt to initialize the COM library.
  3867. hResult = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  3868. if ( (hResult == S_OK) || // success
  3869. (hResult == S_FALSE) || // already initialized
  3870. (hResult == RPC_E_CHANGED_MODE) ) // previous initialization specified
  3871. // a different concurrency model
  3872. {
  3873. DWORD dwRCOrv;
  3874. // RegisterCOMObject returns ERROR_SUCCESS on success.
  3875. dwRCOrv = RegisterCOMObject( TEXT("ClAdmWiz.dll"), tszPathToClusterDir );
  3876. if ( dwRCOrv != (DWORD) ERROR_SUCCESS )
  3877. {
  3878. ClRtlLogPrint( "CompleteUpgradingClusteringService failed to register ClAdmWiz.dll with error %1!d!.\n", dwRCOrv );
  3879. } // ClAdmWiz registered?
  3880. else
  3881. {
  3882. // ERROR_SUCCESS and NO_ERROR are coincidentally the same.
  3883. ClRtlLogPrint( "CompleteUpgradingClusteringService has registered ClAdmWiz.dll.\n" );
  3884. } // ClAdmWiz registered?
  3885. // RegisterCOMObject returns ERROR_SUCCESS on success.
  3886. dwRCOrv = RegisterCOMObject( TEXT("ClNetREx.dll"), tszPathToClusterDir );
  3887. if ( dwRCOrv != (DWORD) ERROR_SUCCESS )
  3888. {
  3889. ClRtlLogPrint( "CompleteUpgradingClusteringService failed to register ClNetREx.dll with error %1!d!.\n", dwRCOrv );
  3890. } // ClNetREx registered?
  3891. else
  3892. {
  3893. // ERROR_SUCCESS and NO_ERROR are coincidentally the same.
  3894. ClRtlLogPrint( "CompleteUpgradingClusteringService has registered ClNetREx.dll.\n" );
  3895. } // ClNetREx registered?
  3896. // RegisterCOMObject returns ERROR_SUCCESS on success.
  3897. dwRCOrv = RegisterCOMObject( TEXT("CluAdMMC.dll"), tszPathToClusterDir );
  3898. if ( dwRCOrv != (DWORD) ERROR_SUCCESS )
  3899. {
  3900. ClRtlLogPrint( "CompleteUpgradingClusteringService failed to register CluAdMMC.dll with error %1!d!.\n", dwRCOrv );
  3901. } // CluAdMMC registered?
  3902. else
  3903. {
  3904. // ERROR_SUCCESS and NO_ERROR are coincidentally the same.
  3905. ClRtlLogPrint( "CompleteUpgradingClusteringService has registered CluAdMMC.dll.\n" );
  3906. } // CluAdMMC registered?
  3907. // Close the COM library. As per MSDN, each successfull call
  3908. // to CoInitializeEx() must be balanced ba a call to CoUnitialize().
  3909. CoUninitialize();
  3910. } // COM library initialized?
  3911. else
  3912. {
  3913. // Could not inititlize the COM library.
  3914. ClRtlLogPrint( "CompleteUpgradingClusteringService could not initialize the COM library. Error %1!d!.\n", hResult );
  3915. } // COM library initialized?
  3916. } // path to cluster directory obtained?
  3917. else
  3918. {
  3919. // Couldn't expand the environment string.
  3920. dwReturnValue = GetLastError();
  3921. ClRtlLogPrint( "CompleteUpgradingClusteringService could not register ClAdmWiz.dll\n" );
  3922. ClRtlLogPrint( "because it could not locate the cluster directory. Error %1!d!.\n", dwReturnValue );
  3923. } // path to cluster directory obtained?
  3924. }
  3925. if ( dwReturnValue == (DWORD) NO_ERROR )
  3926. {
  3927. // Set the ClusterInstallationState reg value to "UPGRADED"
  3928. ClRtlSetClusterInstallState( eClusterInstallStateUpgraded );
  3929. }
  3930. } // did the default failure actions get set?
  3931. } // did the connection objects get renamed?
  3932. } // Was the ImagePath set successfully?
  3933. } // Were the Welcome UI registry operations performed successfully?
  3934. } // Were the UPGRADE registry operations performed successfully?
  3935. }
  3936. else
  3937. {
  3938. ClRtlLogPrint( "In CompleteUpgradingClusteringService since Cluster service "
  3939. "has never been installed there is nothing to do.\n" );
  3940. dwReturnValue = (DWORD) NO_ERROR;
  3941. } // Has Cluster service previously been installed?
  3942. return ( dwReturnValue );
  3943. }
  3944. /////////////////////////////////////////////////////////////////////////////
  3945. //++
  3946. //
  3947. // CompleteStandAloneInstallationOfClusteringService
  3948. //
  3949. // Routine Description:
  3950. // This function completes the process of installing Cluster service when
  3951. // either Add/Remove Programs is running or sysocmgr.exe was launched from
  3952. // a command prompt.
  3953. //
  3954. // Arguments:
  3955. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  3956. // component in the component's hiearchy.
  3957. //
  3958. // Return Value:
  3959. // (DWORD) NO_ERROR - indicates success
  3960. // Any other value is a standard Win32 error code.
  3961. //
  3962. //--
  3963. /////////////////////////////////////////////////////////////////////////////
  3964. DWORD CClusocmApp::CompleteStandAloneInstallationOfClusteringService( IN LPCTSTR ptszSubComponentId )
  3965. {
  3966. DWORD dwReturnValue;
  3967. DWORD_PTR dwResult;
  3968. // Update the progress bar.
  3969. m_SetupInitComponent.HelperRoutines.TickGauge( m_SetupInitComponent.HelperRoutines.OcManagerContext );
  3970. // Update the "progress text"
  3971. CString csProgressText;
  3972. csProgressText.LoadString( IDS_INSTALLING_CLUS_SERVICE );
  3973. m_SetupInitComponent.HelperRoutines.SetProgressText( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  3974. (LPCTSTR) csProgressText );
  3975. // A selection state transition has occured. Perform the base
  3976. // registry operations.
  3977. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  3978. ptszSubComponentId );
  3979. // On a standalone installation, we need to send a WM_SETTINGCHANGE message to all top level windows
  3980. // so that any changes we have made to the system environment variables take effect.
  3981. // During fresh installation, this happens automatically since there is a reboot.
  3982. // See Knowledge Base article Q104011.
  3983. SendMessageTimeout(
  3984. HWND_BROADCAST, // handle to window
  3985. WM_SETTINGCHANGE, // message
  3986. 0, // wparam
  3987. (LPARAM) _T("Environment"), // lparam
  3988. SMTO_ABORTIFHUNG | SMTO_NORMAL, // send options
  3989. 100, // time-out duration (ms). Note, each top level window can wait upto this time
  3990. &dwResult // return value for synchronous call - we ignore this
  3991. );
  3992. ClRtlLogPrint( "The base call to PerformRegistryOperations returned 0x%1!x! to CompleteStandAloneInstallationOfClusteringService.\n",
  3993. dwReturnValue );
  3994. // Were the base registry operations performed successfully?
  3995. if ( dwReturnValue == (DWORD) NO_ERROR )
  3996. {
  3997. // Queue the registry operations to add "Configure Cluster service"
  3998. // to the Welcome UI task list. As per Sharon Montgomery on 12/18/98 the
  3999. // Server Solutions will use those same keys.
  4000. CString csSectionName;
  4001. csSectionName = CLUSREG_KEYNAME_WELCOME_UI;
  4002. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  4003. csSectionName );
  4004. ClRtlLogPrint( "The WelcomeUI call to PerformRegistryOperations returned 0x%1!x! to CompleteStandAloneInstallationOfClusteringService.\n",
  4005. dwReturnValue );
  4006. if ( dwReturnValue == (DWORD) NO_ERROR )
  4007. {
  4008. ClRtlLogPrint( "In CompleteStandAloneInstallationOfClusteringService the registry operations were queued successfully.\n" );
  4009. // Since this was a standalone installation launch the Cluster Configuration
  4010. // program, cluscfg.exe.
  4011. // First, build the command line used to launch cluscfg. The specific
  4012. // command depends on whether this is an unattended operation. Regardless
  4013. // of whether this is unattended, the first part of the command line is
  4014. // the fully qualified path to cluscfg.
  4015. BOOL fReturnValue;
  4016. TCHAR tszClusCfgCommandLine[MAX_PATH];
  4017. fReturnValue = GetPathToClusCfg( tszClusCfgCommandLine );
  4018. // Was the path to cluscfg.exe deduced?
  4019. if ( fReturnValue == (BOOL) TRUE )
  4020. {
  4021. // Update the progress bar.
  4022. m_SetupInitComponent.HelperRoutines.TickGauge( m_SetupInitComponent.HelperRoutines.OcManagerContext );
  4023. // Update the "progress text"
  4024. CString csProgressText;
  4025. csProgressText.LoadString( IDS_CONFIGURING_CLUS_SERVICE );
  4026. m_SetupInitComponent.HelperRoutines.SetProgressText( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  4027. (LPCTSTR) csProgressText );
  4028. // Is this an unattended operation?
  4029. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) !=
  4030. (DWORDLONG) 0L )
  4031. {
  4032. // This is unattended.
  4033. HINF hAnswerFile; // WARNING: NEVER close this handle because clusocm.dll
  4034. // did not open it.
  4035. // Get a handle to the answer file. WARNING: NEVER close this handle because clusocm.dll
  4036. // did not open it.
  4037. hAnswerFile = m_SetupInitComponent.HelperRoutines.GetInfHandle( INFINDEX_UNATTENDED,
  4038. m_SetupInitComponent.HelperRoutines.OcManagerContext );
  4039. // Is the handle to the answer file OK?
  4040. if ( (hAnswerFile != (HINF) NULL) && (hAnswerFile != (HINF) INVALID_HANDLE_VALUE) )
  4041. {
  4042. // The handle to the answer file is legal.
  4043. // tszClusCfgCommandLine is the path to cluscfg.exe. Append the "-UNATTEND"
  4044. // command line option.
  4045. CString csUnattendCommandLineOption;
  4046. csUnattendCommandLineOption = UNATTEND_COMMAND_LINE_OPTION;
  4047. _tcscat( tszClusCfgCommandLine, _T(" ") );
  4048. _tcscat( tszClusCfgCommandLine, csUnattendCommandLineOption );
  4049. // Append the path to the answer file.
  4050. _tcscat( tszClusCfgCommandLine, _T(" ") );
  4051. _tcscat( tszClusCfgCommandLine, m_SetupInitComponent.SetupData.UnattendFile );
  4052. } // handle to answer file OK?
  4053. } // unattended?
  4054. // Launch cluscfg - tszClusCfgCommandLine contains the command, either
  4055. // attended or unattended.
  4056. STARTUPINFO StartupInfo;
  4057. ZeroMemory( &StartupInfo, sizeof( StartupInfo ) );
  4058. StartupInfo.cb = sizeof( StartupInfo );
  4059. PROCESS_INFORMATION ProcessInformation;
  4060. fReturnValue = CreateProcess( (LPCTSTR) NULL,
  4061. (LPTSTR) tszClusCfgCommandLine,
  4062. (LPSECURITY_ATTRIBUTES) NULL,
  4063. (LPSECURITY_ATTRIBUTES) NULL,
  4064. (BOOL) FALSE,
  4065. (DWORD) (CREATE_DEFAULT_ERROR_MODE | CREATE_UNICODE_ENVIRONMENT),
  4066. (LPVOID) GetEnvironmentStrings(),
  4067. (LPCTSTR) NULL,
  4068. (LPSTARTUPINFO) &StartupInfo,
  4069. (LPPROCESS_INFORMATION) &ProcessInformation );
  4070. // Was the process created?
  4071. if ( fReturnValue == (BOOL) TRUE )
  4072. {
  4073. // Wait for cluscfg.exe to complete. As per Pat Styles on 7/6/98,
  4074. // an OCM Setup DLL MUST wait for any process it spawns to complete.
  4075. DWORD dwWFSOrv;
  4076. dwWFSOrv = WaitForSingleObject( ProcessInformation.hProcess,
  4077. INFINITE );
  4078. }
  4079. else
  4080. {
  4081. DWORD dwErrorCode;
  4082. dwErrorCode = GetLastError();
  4083. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) ==
  4084. (DWORDLONG) 0L )
  4085. {
  4086. CString csMessage;
  4087. csMessage.Format( IDS_ERROR_SPAWNING_CLUSCFG, dwErrorCode );
  4088. AfxMessageBox( csMessage );
  4089. }
  4090. ClRtlLogPrint( "Error %1!d! occured attempting to spawn cluscfg.exe.\n", dwErrorCode );
  4091. } // Was the process created?
  4092. } // Path to cluscfg obtained?
  4093. } // WelcomeUI registry operations succeeded?
  4094. } // Were the base registry operations performed successfully?
  4095. return ( dwReturnValue );
  4096. }
  4097. /////////////////////////////////////////////////////////////////////////////
  4098. //++
  4099. //
  4100. // CompleteInstallingClusteringService
  4101. //
  4102. // Routine Description:
  4103. // This function performs much of the processing when OC_COMPLETE_INSTALLATION
  4104. // has been received and a clean installation is being performed.
  4105. //
  4106. // Arguments:
  4107. // ptszSubComponentId - points to a string that uniquely identifies a sub-
  4108. // component in the component's hiearchy.
  4109. //
  4110. // Return Value:
  4111. // (DWORD) NO_ERROR - indicates success
  4112. // Any other value is a standard Win32 error code.
  4113. //
  4114. //--
  4115. /////////////////////////////////////////////////////////////////////////////
  4116. DWORD CClusocmApp::CompleteInstallingClusteringService( IN LPCTSTR ptszSubComponentId )
  4117. {
  4118. DWORD dwReturnValue;
  4119. // Update the progress bar.
  4120. if ( GetStepCount() != 0L )
  4121. {
  4122. // Update the progress meter.
  4123. m_SetupInitComponent.HelperRoutines.TickGauge( m_SetupInitComponent.HelperRoutines.OcManagerContext );
  4124. }
  4125. // Update the "progress text"
  4126. CString csProgressText;
  4127. csProgressText.LoadString( IDS_INSTALLING_CLUS_SERVICE );
  4128. m_SetupInitComponent.HelperRoutines.SetProgressText( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  4129. (LPCTSTR) csProgressText );
  4130. // Perform the base registry operations.
  4131. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  4132. ptszSubComponentId );
  4133. ClRtlLogPrint( "The base call to PerformRegistryOperations returned 0x%1!x! to CompleteInstallingClusteringService.\n",
  4134. dwReturnValue );
  4135. // Were the base registry operations performed successfully?
  4136. if ( dwReturnValue == (DWORD) NO_ERROR )
  4137. {
  4138. // Queue the registry operations to add "Configure Cluster service"
  4139. // to the Welcome UI task list. As per Sharon Montgomery on 12/18/98, Server
  4140. // Solutions will use those same keys.
  4141. CString csSectionName;
  4142. csSectionName = CLUSREG_KEYNAME_WELCOME_UI;
  4143. dwReturnValue = PerformRegistryOperations( m_SetupInitComponent.ComponentInfHandle,
  4144. csSectionName );
  4145. ClRtlLogPrint( "The WelcomeUI call to PerformRegistryOperations returned 0x%1!x! to CompleteInstallingClusteringService.\n",
  4146. dwReturnValue );
  4147. } // Were the base registry operations performed successfully?
  4148. // Were the Welcome UI registry operations performed successfully?
  4149. if ( dwReturnValue == (DWORD) NO_ERROR )
  4150. {
  4151. ClRtlLogPrint( "In CompleteInstallingClusteringService for a clean install all registery operations were performed successfully.\n" );
  4152. }
  4153. else
  4154. {
  4155. ClRtlLogPrint( "In CompleteInstallingClusteringService for a clean install the registry operations were not performed successfully.\n" );
  4156. }
  4157. // For unattended setup this needs to write the WelcomeUI reg keys in a way that
  4158. // will cause Configure Your Server to launch cluscfg.exe in unattended mode.
  4159. // revisions to CompleteInstallingClusteringService may be appropriate prior to this code segment.
  4160. // Were all registry operations performed correctly?
  4161. if ( dwReturnValue == (DWORD) NO_ERROR )
  4162. {
  4163. LONG lReturnValue; // used below for registry operations
  4164. HKEY hKey; // used below for registry operations
  4165. // Is this an unattended installation?
  4166. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) !=
  4167. (DWORDLONG) 0L )
  4168. {
  4169. HINF hAnswerFile; // WARNING: NEVER close this handle because clusocm.dll
  4170. // did not open it.
  4171. // Get a handle to the answer file. WARNING: NEVER close this handle because clusocm.dll
  4172. // did not open it.
  4173. hAnswerFile = m_SetupInitComponent.HelperRoutines.GetInfHandle( INFINDEX_UNATTENDED,
  4174. m_SetupInitComponent.HelperRoutines.OcManagerContext );
  4175. if ( (hAnswerFile != (HINF) NULL) && (hAnswerFile != (HINF) INVALID_HANDLE_VALUE) )
  4176. {
  4177. // Write the WelcomeUI registry entry to launch cluscfg in unattended mode.
  4178. // Note that the registry operations performed when CLUSREG_KEYNAME_WELCOME_UI
  4179. // was passed to PerformRegistryOperations() above included creation of
  4180. // HKLM\Software\Microsoft\Windows NT\CurrentVersion\Setup\OCManager\ToDoList\Cluster\ConfigCommand.
  4181. // All that is necessary is to create the ConfigArgs value with the
  4182. // appropriate command line arguments to execute cluscfg.exe in unattended mode.
  4183. HKEY hKey;
  4184. DWORD dwType;
  4185. // Attempt to open an existing key in the registry.
  4186. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4187. _T( "Software\\Microsoft\\Windows NT\\CurrentVersion\\Setup\\OCManager\\ToDoList\\Cluster" ),
  4188. (DWORD) 0, // reserved
  4189. KEY_SET_VALUE,
  4190. &hKey );
  4191. // Was the Cluster "to do list" registry key opened?
  4192. if ( lReturnValue == (LONG) ERROR_SUCCESS )
  4193. {
  4194. // The key is open.
  4195. TCHAR tszValue[MAX_PATH];
  4196. _tcscpy( tszValue, UNATTEND_COMMAND_LINE_OPTION );
  4197. // Append the path to the answer file.
  4198. _tcscat( tszValue, _T(" ") );
  4199. _tcscat( tszValue, m_SetupInitComponent.SetupData.UnattendFile );
  4200. // Set the key.
  4201. DWORD dwValueLength;
  4202. dwValueLength = (DWORD) ((_tcslen( tszValue ) + 1) * sizeof( TCHAR ));
  4203. lReturnValue = RegSetValueEx( hKey,
  4204. _T( "ConfigArgs" ),
  4205. (DWORD) 0L, // reserved
  4206. (DWORD) REG_EXPAND_SZ,
  4207. (CONST BYTE *) tszValue,
  4208. dwValueLength );
  4209. // Was the key written successfully?
  4210. if ( lReturnValue == (LONG) ERROR_SUCCESS )
  4211. {
  4212. dwReturnValue = (DWORD) NO_ERROR;
  4213. ClRtlLogPrint( "CompleteInstallingClusteringService created the ConfigArgs reg key for unattended operation of cluscfg.\n" );
  4214. }
  4215. else
  4216. {
  4217. dwReturnValue = GetLastError();
  4218. ClRtlLogPrint( "CompleteInstallingClusteringService failed to create the ConfigArgs reg key with error code %1!d!.\n",
  4219. dwReturnValue );
  4220. } // Was the reg key written successfully?
  4221. // Close the registry key.
  4222. RegCloseKey( hKey ); // do we care about the return value?
  4223. }
  4224. else
  4225. {
  4226. // The key could not be opened.
  4227. DWORD dwErrorCode;
  4228. dwErrorCode = GetLastError();
  4229. ClRtlLogPrint( "In CompleteInstallingClusteringService RegOpenKeyEx failed with error code 0x%1!x!.\n",
  4230. dwErrorCode );
  4231. } // Was the key opened?
  4232. } // handle to answer file OK?
  4233. } // Is this unattended?
  4234. else
  4235. {
  4236. // This is NOT unattended, so make sure the ConfigArgs value is removed.
  4237. // That will prevent any value left from a previous unattended install
  4238. // which was never successfully configured from corrupting the behavior
  4239. // of Configure Your Server or Add/Remove Programs.
  4240. // Attempt to open an existing key in the registry.
  4241. lReturnValue = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  4242. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Setup\\OCManager\\ToDoList\\Cluster"),
  4243. (DWORD) 0, // reserved
  4244. KEY_READ,
  4245. &hKey );
  4246. // Was the Cluster "to do list" registry key opened?
  4247. if ( lReturnValue == (long) ERROR_SUCCESS )
  4248. {
  4249. // Delete the values (which may not exist).
  4250. RegDeleteValue( hKey, (LPCTSTR) TEXT("ConfigArgs") );
  4251. } // if ToDoList opened
  4252. } // if unattended?
  4253. } // registry operations successfull?
  4254. return ( dwReturnValue );
  4255. }
  4256. /////////////////////////////////////////////////////////////////////////////
  4257. //++
  4258. //
  4259. // OnOcCleanup
  4260. //
  4261. // Routine Description:
  4262. // This function processes the OC_CLEANUP messages by removing the "private"
  4263. // subdirectory in the cluster directory if it is empty and the cluster directory
  4264. // itself it it is empty.
  4265. //
  4266. // Arguments:
  4267. // none
  4268. //
  4269. // Return Value:
  4270. // (DWORD) NO_ERROR - indicates success
  4271. // Any other value is a standard Win32 error code.
  4272. //
  4273. // Note:
  4274. // The "private" subrirectory may exist in the cluster directory if the system
  4275. // was upgraded from NT4.
  4276. //
  4277. //--
  4278. /////////////////////////////////////////////////////////////////////////////
  4279. DWORD CClusocmApp::OnOcCleanup( void )
  4280. {
  4281. ClRtlLogPrint( "Processing OC_CLEANUP.\n" );
  4282. DWORD dwReturnValue;
  4283. dwReturnValue = CleanupDirectories();
  4284. ClRtlLogPrint( "\n\n\n\n" );
  4285. // Close the log file.
  4286. ClRtlCleanup();
  4287. // Set the ClusterLog environment variable back to its' original state.
  4288. char szLogFileName[MAX_PATH];
  4289. strcpy( szLogFileName, "ClusterLog=" );
  4290. if ( *m_szOriginalLogFileName != (char) '\0' )
  4291. {
  4292. strcat( szLogFileName, m_szOriginalLogFileName );
  4293. }
  4294. _putenv( szLogFileName );
  4295. return ( dwReturnValue );
  4296. }
  4297. /////////////////////////////////////////////////////////////////////////////
  4298. //++
  4299. //
  4300. // CleanupDirectories
  4301. //
  4302. // Routine Description:
  4303. // This function removes the "private" subdirectory that may remain in the
  4304. // cluster directory if the system has ever been upgraded from NT 4 if that
  4305. // directory is empty. It will also remove the cluster directory itself if
  4306. // it is empty.
  4307. //
  4308. // Arguments:
  4309. // none
  4310. //
  4311. // Return Value:
  4312. // (DWORD) NO_ERROR - indicates success
  4313. // (DWORD) -1L - means that the cluster directory was not empty
  4314. // Any other value is a standard Win32 error code.
  4315. //
  4316. // Note:
  4317. // This function assumes that the path to the cluster directory is less than
  4318. // MAX_PATH TCHARs long and that function SetupGetTargetPath expects the fifth
  4319. // parameter to specify the number of TCHARS (not bytes) in the buffer.
  4320. //
  4321. // No recovery is attempted if the call to SetupGetTargetPath fails.
  4322. //
  4323. //--
  4324. /////////////////////////////////////////////////////////////////////////////
  4325. DWORD CClusocmApp::CleanupDirectories( void )
  4326. {
  4327. DWORD dwReturnValue = (DWORD) NO_ERROR;
  4328. BOOL fReturnValue;
  4329. DWORD dwRequiredSize;
  4330. TCHAR tszPathToClusterDirectory[MAX_PATH];
  4331. // First, get the path to the cluster directory.
  4332. CString csSectionName;
  4333. csSectionName = CLUSTER_FILES_INF_KEY;
  4334. fReturnValue = SetupGetTargetPath( m_SetupInitComponent.ComponentInfHandle,
  4335. (PINFCONTEXT) NULL,
  4336. (PCTSTR) csSectionName,
  4337. tszPathToClusterDirectory,
  4338. (DWORD) MAX_PATH,
  4339. (PDWORD) &dwRequiredSize );
  4340. // Was the path to the cluster directory obtained?
  4341. if ( fReturnValue == (BOOL) TRUE )
  4342. {
  4343. // Test for the presence of a subdirectory named "private".
  4344. TCHAR tszPathToPrivateDirectory[MAX_PATH];
  4345. // Append "\private" to the path to the cluster directory that was obtained above.
  4346. // Note, I didn't put this string in the stringtable because it is
  4347. // not localizable, and will never change.
  4348. _tcscpy( tszPathToPrivateDirectory, tszPathToClusterDirectory );
  4349. _tcscat( tszPathToPrivateDirectory, _T("\\private") );
  4350. HANDLE hFindHandle;
  4351. WIN32_FIND_DATA FindData;
  4352. // Does a file or directory named "private" exist?
  4353. hFindHandle = FindFirstFile( (LPCTSTR) tszPathToPrivateDirectory, &FindData );
  4354. if ( hFindHandle != (HANDLE) INVALID_HANDLE_VALUE )
  4355. {
  4356. // A file named "private" exists in the cluster directory. Is it a directory?
  4357. if ( (FindData.dwFileAttributes & (DWORD) FILE_ATTRIBUTE_DIRECTORY) != (DWORD) 0L )
  4358. {
  4359. // The "private" directory has been located. Determine whether it is empty.
  4360. if ( IsDirectoryEmpty( tszPathToPrivateDirectory ) == (BOOL) TRUE )
  4361. {
  4362. // No file was found in the "private" directory. Remove the "private" directory.
  4363. if ( RemoveDirectory( (LPCTSTR) tszPathToPrivateDirectory ) == (BOOL) TRUE )
  4364. {
  4365. dwReturnValue = (DWORD) NO_ERROR;
  4366. }
  4367. else
  4368. {
  4369. // Could not delete the "private" directory even though it was empty.
  4370. dwReturnValue = GetLastError();
  4371. ClRtlLogPrint( "CleanupDirectories was unable to remove %1!s!. The error code is %2!x!.\n",
  4372. tszPathToPrivateDirectory, dwReturnValue );
  4373. } // Was the "private" directory removed successfully?
  4374. }
  4375. else
  4376. {
  4377. ClRtlLogPrint( "CleanupDirectories did not attempt to remove %1!s! because it is not empty.\n",
  4378. tszPathToPrivateDirectory );
  4379. // An error code of -1 means the "private" directory, and thus the
  4380. // cluster directory was not empty.
  4381. dwReturnValue = (DWORD) -1L;
  4382. } // Was any file found in the "private" directory?
  4383. }
  4384. else
  4385. {
  4386. ClRtlLogPrint( "In CleanupDirectories the file named private is not a directory.\n");
  4387. dwReturnValue = (DWORD) ERROR_FILE_NOT_FOUND;
  4388. } // Is it a directory?
  4389. // Close the search that located the "private" directory.
  4390. FindClose( hFindHandle );
  4391. }
  4392. else
  4393. {
  4394. dwReturnValue = GetLastError();
  4395. ClRtlLogPrint( "CleanupDirectories was unable to find any file named private in the cluster directory.\n");
  4396. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwReturnValue );
  4397. } // Does a file or directory named "private" exist?
  4398. // Was the "private" directory absent or removed successfully?
  4399. if ( (dwReturnValue == (DWORD) ERROR_FILE_NOT_FOUND) ||
  4400. (dwReturnValue == (DWORD) NO_ERROR) )
  4401. {
  4402. // The "private" directory either did not exist or has been removed.
  4403. // Now determine whether the cluster directory is empty and therefore should be removed.
  4404. // This code segment assumes that the cluster directory, as specified
  4405. // in tszPathToClusterDirectory exists.
  4406. if ( IsDirectoryEmpty( tszPathToClusterDirectory ) == (BOOL) TRUE )
  4407. {
  4408. // The cluster directory is empty.
  4409. if ( RemoveDirectory( tszPathToClusterDirectory ) == (BOOL) TRUE )
  4410. {
  4411. dwReturnValue = (DWORD) NO_ERROR;
  4412. }
  4413. else
  4414. {
  4415. // Could not delete the "cluster" directory even though it was empty.
  4416. dwReturnValue = GetLastError();
  4417. ClRtlLogPrint( "CleanupDirectories was unable to remove %1!s!. The error code is %2!x!.\n",
  4418. tszPathToClusterDirectory, dwReturnValue );
  4419. } // Was the cluster directory removed?
  4420. }
  4421. else
  4422. {
  4423. // The cluster directory is not empty.
  4424. ClRtlLogPrint( "CleanupDirectories did not attempt to remove %1!s! because it is not empty.\n",
  4425. tszPathToClusterDirectory );
  4426. // An error code of -1 means the cluster directory was not empty.
  4427. dwReturnValue = (DWORD) -1L;
  4428. } // Is the cluster directory empty?
  4429. } // Was the "private" directory absent or removed?
  4430. }
  4431. else
  4432. {
  4433. dwReturnValue = GetLastError();
  4434. ClRtlLogPrint( "CleanupDirectories was unable to obtain the path to the cluster directory.\n");
  4435. ClRtlLogPrint( "The error code is 0x%1!x!.\n", dwReturnValue );
  4436. } // Was the path to the cluster directory obtained?
  4437. return ( dwReturnValue );
  4438. }
  4439. /////////////////////////////////////////////////////////////////////////////
  4440. //++
  4441. //
  4442. // IsDirectoryEmpty
  4443. //
  4444. // Routine Description:
  4445. // This function determines whether a directory is empty.
  4446. //
  4447. // Arguments:
  4448. // ptzDirectoryName - points to a string specifying the directory name.
  4449. //
  4450. // Return Value:
  4451. // TRUE - indicates that the directory is empty
  4452. // FALSE - indicates that the directory is not empty
  4453. //
  4454. //--
  4455. /////////////////////////////////////////////////////////////////////////////
  4456. BOOL CClusocmApp::IsDirectoryEmpty( LPCTSTR ptszDirectoryName )
  4457. {
  4458. BOOL fDirectoryEmpty;
  4459. HANDLE hFindHandle;
  4460. WIN32_FIND_DATA FindData;
  4461. TCHAR tszFindPath[MAX_PATH];
  4462. // Append the file specification to the path supplied.
  4463. _tcscpy( tszFindPath, ptszDirectoryName );
  4464. _tcscat( tszFindPath, _T("\\*") );
  4465. hFindHandle = FindFirstFile( tszFindPath, &FindData );
  4466. // Was any file found in the directory?
  4467. if ( hFindHandle != (HANDLE) INVALID_HANDLE_VALUE )
  4468. {
  4469. // A file was found. It could be "." or "..".
  4470. if ( (_tcscmp( FindData.cFileName, _T(".") ) == 0) ||
  4471. (_tcscmp( FindData.cFileName, _T("..") ) == 0) )
  4472. {
  4473. // The file was either "." or "..". Keep trying.
  4474. DWORD dwErrorCode;
  4475. if ( FindNextFile( hFindHandle, &FindData ) == (BOOL) TRUE )
  4476. {
  4477. // A file was found. It could be "." or "..".
  4478. if ( (_tcscmp( FindData.cFileName, _T(".") ) == 0) ||
  4479. (_tcscmp( FindData.cFileName, _T("..") ) == 0) )
  4480. {
  4481. // The file was either "." or "..". Keep trying.
  4482. if ( FindNextFile( hFindHandle, &FindData ) == (BOOL) TRUE )
  4483. {
  4484. // The file cannot possibly be either "." or "..".
  4485. fDirectoryEmpty = (BOOL) FALSE;
  4486. }
  4487. else
  4488. {
  4489. dwErrorCode = GetLastError();
  4490. if ( dwErrorCode == (DWORD) ERROR_NO_MORE_FILES )
  4491. {
  4492. fDirectoryEmpty = (BOOL) TRUE;
  4493. }
  4494. else
  4495. {
  4496. fDirectoryEmpty = (BOOL) FALSE;
  4497. }
  4498. }
  4499. }
  4500. else
  4501. {
  4502. // The private directory is not empty.
  4503. fDirectoryEmpty = (BOOL) FALSE;
  4504. }
  4505. }
  4506. else
  4507. {
  4508. dwErrorCode = GetLastError();
  4509. if ( dwErrorCode == ERROR_NO_MORE_FILES )
  4510. {
  4511. fDirectoryEmpty = (BOOL) TRUE;
  4512. }
  4513. else
  4514. {
  4515. fDirectoryEmpty = (BOOL) FALSE;
  4516. }
  4517. }
  4518. }
  4519. else
  4520. {
  4521. // The directory is not empty.
  4522. fDirectoryEmpty = (BOOL) FALSE;
  4523. }
  4524. // Close the search.
  4525. FindClose( hFindHandle );
  4526. }
  4527. else
  4528. {
  4529. fDirectoryEmpty = (BOOL) TRUE;
  4530. }
  4531. return ( fDirectoryEmpty );
  4532. }
  4533. /////////////////////////////////////////////////////////////////////////////
  4534. //++
  4535. //
  4536. // GetPathToClusCfg
  4537. //
  4538. // Routine Description:
  4539. // This function deduces the path to the Cluster service configuration
  4540. // program, cluscfg.exe.
  4541. //
  4542. // It assumes that if the Cluster service is registered with the Service
  4543. // COntrol Manager then cluscfg.exe is located in the directory with clussvc.exe.
  4544. // Otherwise it expands %windir%\cluster and declares that to be the path.
  4545. //
  4546. // The name of the Cluster service configuration pogram is then appended to
  4547. // the path.
  4548. //
  4549. // Arguments:
  4550. // lptszPathToClusCfg - points to a string in which the fully qualified path to
  4551. // the Cluster service configuration program is to be placed.
  4552. //
  4553. // Return Value:
  4554. // TRUE - indicates that lptszPathToClusCfg is valid
  4555. // FALSE - indicates that an error occured
  4556. //
  4557. //--
  4558. /////////////////////////////////////////////////////////////////////////////
  4559. BOOL CClusocmApp::GetPathToClusCfg( LPTSTR lptszPathToClusCfg )
  4560. {
  4561. BOOL fReturnValue;
  4562. // If the Cluster service is registered assume that cluscfg is in
  4563. // the same directory as clussvc.exe and get the path to cluscfg.exe
  4564. // from the Service Control Mamager. If the Cluster service is not
  4565. // registered, assume cluscfg.exe is in %windir%\cluster.
  4566. if ( IsClusterServiceRegistered() == (BOOL) TRUE )
  4567. {
  4568. // Query the path to the Cluster Service executable from the Service Control Manager.
  4569. CString csClusterService;
  4570. csClusterService = CLUSTER_SERVICE_NAME;
  4571. fReturnValue = GetServiceBinaryPath( (LPWSTR) (LPCTSTR) csClusterService,
  4572. lptszPathToClusCfg );
  4573. }
  4574. else
  4575. {
  4576. // Use the default location.
  4577. CString csClusterDirectory;
  4578. csClusterDirectory = CLUSTER_DIRECTORY;
  4579. if ( ExpandEnvironmentStrings( (LPCTSTR) csClusterDirectory,
  4580. lptszPathToClusCfg, MAX_PATH ) > 0L )
  4581. {
  4582. fReturnValue = (BOOL) TRUE;
  4583. }
  4584. else
  4585. {
  4586. // Could not expand the enviornment string. The default location for the
  4587. // Cluster service could not be determined.
  4588. fReturnValue = (BOOL) FALSE;
  4589. } // Was the default location for cluscfg.exe determined?
  4590. } // Where is cluscfg.exe?
  4591. // Was the path to cluscfg.exe deduced?
  4592. if ( fReturnValue == (BOOL) TRUE )
  4593. {
  4594. // tszPathToClusCfg is the path to cluscfg.exe. Append the program name.
  4595. CString csClusterConfigurationProgram;
  4596. csClusterConfigurationProgram = CLUSTER_CONFIGURATION_PGM;
  4597. _tcscat( lptszPathToClusCfg, _T("\\") );
  4598. _tcscat( lptszPathToClusCfg, csClusterConfigurationProgram );
  4599. }
  4600. else
  4601. {
  4602. // Set the target string empty.
  4603. *lptszPathToClusCfg = _T( '\0' );
  4604. }
  4605. return ( fReturnValue );
  4606. }
  4607. /////////////////////////////////////////////////////////////////////////////
  4608. //++
  4609. //
  4610. // CalculateStepCount
  4611. //
  4612. // Routine Description:
  4613. // This function calculates the "step count", i.e the number of non-file operations
  4614. // to be performed when processing OC_COMPLETE_INSTALLATION.
  4615. //
  4616. // Arguments:
  4617. // ptszSubComponentId
  4618. //
  4619. // Return Value:
  4620. // The number of non-file operation (steps) to perform when processing
  4621. // OC_COMPLETE_INSTALLATION
  4622. //
  4623. //--
  4624. /////////////////////////////////////////////////////////////////////////////
  4625. DWORD CClusocmApp::CalculateStepCount( LPCTSTR ptszSubComponentId )
  4626. {
  4627. DWORD dwStepCount;
  4628. // Is this UNATTENDED or ATTENDED?
  4629. if ( (m_SetupInitComponent.SetupData.OperationFlags & (DWORDLONG) SETUPOP_BATCH) !=
  4630. (DWORDLONG) 0L )
  4631. {
  4632. // This is UNATTENDED.
  4633. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  4634. (DWORDLONG) SETUPOP_NTUPGRADE) != (DWORDLONG) 0L )
  4635. {
  4636. // This is UPGRADE. Cluscfg.exe will not be launched, so there is
  4637. // one non-file operation to be performed, registry revisions.
  4638. dwStepCount = 1L;
  4639. }
  4640. else
  4641. {
  4642. // This is a clean INSTALL. Cluscfg.exe may be launched.
  4643. // Is there a [cluster] section in the answer file? BUGBUG
  4644. // so there
  4645. // are two non-file operations to be performed, registry revisions
  4646. // and execution of cluscfg.
  4647. dwStepCount = 2L;
  4648. } // unattended: upgrade or install?
  4649. }
  4650. else
  4651. {
  4652. // This is ATTENDED.
  4653. if ( (m_SetupInitComponent.SetupData.OperationFlags &
  4654. (DWORDLONG) SETUPOP_STANDALONE) != (DWORDLONG) 0L )
  4655. {
  4656. // This is STANDALONE. Is Cluster service selected?
  4657. BOOL fCurrentSelectionState;
  4658. BOOL fOriginalSelectionState;
  4659. fCurrentSelectionState =
  4660. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  4661. (LPCTSTR) ptszSubComponentId,
  4662. (UINT) OCSELSTATETYPE_CURRENT );
  4663. fOriginalSelectionState =
  4664. m_SetupInitComponent.HelperRoutines.QuerySelectionState( m_SetupInitComponent.HelperRoutines.OcManagerContext,
  4665. ptszSubComponentId,
  4666. (UINT) OCSELSTATETYPE_ORIGINAL );
  4667. // Was there a selection state transition?
  4668. if ( fCurrentSelectionState != fOriginalSelectionState )
  4669. {
  4670. if ( fCurrentSelectionState == (BOOL) TRUE )
  4671. {
  4672. // Currently selected - This is a clean install. There are two
  4673. // non-file operations to be performed, registry revisions and
  4674. // execution of cluscfg.exe.
  4675. dwStepCount = 2L;
  4676. }
  4677. else
  4678. {
  4679. // Currently not selected - This is an uninstall. There is one
  4680. // non-file operation to be performed, registry revisions.
  4681. dwStepCount = 1L;
  4682. } // currently selected?
  4683. dwStepCount = 1L;
  4684. }
  4685. else
  4686. {
  4687. // There was no selection state transition, therefore there
  4688. // are zero non-file operations to be performed.
  4689. dwStepCount = 0L;
  4690. } // selection state transition?
  4691. }
  4692. else
  4693. {
  4694. // This is GUI mode setup. The two operations that may be performed
  4695. // during GUI mode setup are clean install and upgrade. In neither
  4696. // case does cluscfg.exe get launched. Thus, there is one non-file
  4697. // operation to be performed, registry revisions.
  4698. dwStepCount = 1L;
  4699. } // interactive: standalone or atttended?
  4700. } // Is this UNATTENDED or ATTENDED?
  4701. return ( dwStepCount );
  4702. }
  4703. /////////////////////////////////////////////////////////////////////////////
  4704. //++
  4705. //
  4706. // SetStepCount
  4707. //
  4708. // Routine Description:
  4709. // This function sets the value of the m_dwStepCount member of the CClusocmApp object.
  4710. //
  4711. // Arguments:
  4712. // dwStepCount - the value to which the m_dwStepCount member should be set.
  4713. //
  4714. // Return Value:
  4715. // None
  4716. //
  4717. //--
  4718. /////////////////////////////////////////////////////////////////////////////
  4719. void CClusocmApp::SetStepCount( DWORD dwStepCount )
  4720. {
  4721. m_dwStepCount = dwStepCount;
  4722. }
  4723. /////////////////////////////////////////////////////////////////////////////
  4724. //++
  4725. //
  4726. // GetStepCount
  4727. //
  4728. // Routine Description:
  4729. // This function returns the content of the m_dwStepCount member of the
  4730. // CClusocmApp object.
  4731. //
  4732. // Arguments:
  4733. // None
  4734. //
  4735. // Return Value:
  4736. // The content of the m_dwStepCount member.
  4737. //
  4738. //--
  4739. /////////////////////////////////////////////////////////////////////////////
  4740. DWORD CClusocmApp::GetStepCount( void )
  4741. {
  4742. return ( m_dwStepCount );
  4743. }