Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2605 lines
72 KiB

  1. //-----------------------------------------------------------------------------------------
  2. #define _WIN32_MSI 200
  3. #ifndef OLEDBVER
  4. #define OLEDBVER 0x0200
  5. #endif
  6. #ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
  7. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
  8. #endif
  9. #ifndef SECURITY_WIN32
  10. #define SECURITY_WIN32
  11. #endif
  12. // Windows Header Files:
  13. #include <windows.h>
  14. #include <windef.h>
  15. #include <tchar.h>
  16. #include <lmcons.h>
  17. #include <setupapi.h>
  18. #include <Security.h>
  19. #include <msi.h>
  20. #include <assert.h>
  21. #include <time.h>
  22. #include <atldbcli.h>
  23. #include <oledberr.h>
  24. #include "uddiinst.h"
  25. #include "..\shared\common.h"
  26. #include "ocmcallback.h"
  27. #include "net_config_get.h"
  28. #include "ADM_addServiceAccount.h"
  29. #include "resource.h"
  30. using namespace ATL;
  31. //
  32. // The following block defines types and identifiers used by the clustering "discovery" unit
  33. //
  34. #define RESTYPE_DISK TEXT( "Physical Disk" )
  35. #define RESTYPE_SQL TEXT( "SQL Server" )
  36. #define PROPNAME_VIRTUALSERVER L"VirtualServerName"
  37. #define PROPNAME_INSTANCENAME L"InstanceName"
  38. #define PROPNAME_DBSCHEMAVER TEXT("Database.Version")
  39. //
  40. // Callback data blocks
  41. //
  42. typedef struct
  43. {
  44. HCLUSTER hCluster;
  45. cStrList *pSqlDependencies;
  46. cDrvMap *pPhysSrvMap;
  47. }
  48. DISK_CALLBACK_DATA, *LPDISK_CALLBACK_DATA;
  49. typedef struct
  50. {
  51. HCLUSTER hCluster;
  52. tstring sSqlInstanceName;
  53. cStrList *pSqlDependencies;
  54. }
  55. SQL_CALLBACK_DATA, *LPSQL_CALLBACK_DATA;
  56. typedef struct
  57. {
  58. tstring sSqlInstanceName;
  59. tstring sNodeName;
  60. CLUSTER_RESOURCE_STATE resState;
  61. }
  62. SQL_NODE_CALLBACK_DATA, *LPSQL_NODE_CALLBACK_DATA;
  63. //
  64. // Callback functions
  65. //
  66. static DWORD PhysDiskCallback( HRESOURCE hOriginal, HRESOURCE hResource, PVOID lpParams );
  67. static DWORD SqlDepCallback( HRESOURCE hOriginal, HRESOURCE hResource, PVOID lpParams );
  68. static DWORD SqlCallback( HRESOURCE hOriginal, HRESOURCE hResource, PVOID lpParams );
  69. //
  70. // Helper functions
  71. //
  72. static LPBYTE ParseDiskInfo( LPBYTE DiskInfo, DWORD DiskInfoSize, DWORD SyntaxValue );
  73. static BOOL IsInList( LPCTSTR szStrToFind, cStrList *pList, BOOL bIgnoreCase = TRUE );
  74. static DWORD GetClusterResourceControl( HRESOURCE hResource, DWORD dwControlCode, LPBYTE *pOutBuffer, DWORD *dwBytesReturned );
  75. void HandleOLEDBError( HRESULT hrErr );
  76. //-----------------------------------------------------------------------------------------
  77. // General installation definitions
  78. //
  79. PTCHAR szInstallStateText[] = { TEXT( "Uninstall" ), TEXT( "No Action" ), TEXT( "Install" ) };
  80. LPCTSTR szWamPwdKey = TEXT( "C9E18" );
  81. //-----------------------------------------------------------------------------------------
  82. // Global objects and data items
  83. //
  84. extern CDBInstance g_dbLocalInstances;
  85. //-----------------------------------------------------------------------------------------
  86. CUDDIInstall::CUDDIInstall()
  87. {
  88. ZeroMemory( m_package, sizeof( SINGLE_UDDI_PACKAGE_DEF ) * UDDI_PACKAGE_COUNT );
  89. m_package[ UDDI_MSDE ].cMSIName = TEXT( "sqlrun.dat" ); // this is the "cloaked" name of sqlrun08.msi
  90. m_package[ UDDI_WEB ].cMSIName = TEXT( "uddiweb.msi" );
  91. m_package[ UDDI_DB ].cMSIName = TEXT( "uddidb.msi" );
  92. m_package[ UDDI_ADMIN ].cMSIName = TEXT( "uddiadm.msi" );
  93. m_package[ UDDI_MSDE ].bOCMComponent = false;
  94. m_package[ UDDI_WEB ].bOCMComponent = true;
  95. m_package[ UDDI_DB ].bOCMComponent = true;
  96. m_package[ UDDI_ADMIN ].bOCMComponent = true;
  97. m_package[ UDDI_COMBO ].bOCMComponent = false;
  98. //
  99. // sql is the only package that has a cab file
  100. //
  101. m_package[ UDDI_MSDE ].cCABName = TEXT( "sqlrun.cab" );
  102. //
  103. // the following names must match the names given in UDDI.INF
  104. //
  105. m_package[ UDDI_MSDE ].cOCMName = TEXT( "(n/a)" );
  106. m_package[ UDDI_WEB ].cOCMName = TEXT( "uddiweb" );
  107. m_package[ UDDI_DB ].cOCMName = TEXT( "uddidatabase" );
  108. m_package[ UDDI_ADMIN ].cOCMName = TEXT( "uddiadmin" );
  109. m_package[ UDDI_COMBO ].cOCMName = TEXT( "uddicombo" );
  110. //
  111. // 775306
  112. // A-DSEBES: Swapped the product code for MSDE instance #8 with WMSDE instance #8.
  113. //
  114. _tcscpy( m_package[ UDDI_MSDE ].szProductCode, TEXT( "{B42339CD-9F22-4A6A-A023-D12990E0B918}" ) );
  115. _tcscpy( m_package[ UDDI_WEB ].szProductCode, TEXT( "{D9F718B1-61D5-41B3-81E6-C6B6B4FC712C}" ) );
  116. _tcscpy( m_package[ UDDI_DB ].szProductCode, TEXT( "{22FD5ACF-9151-483E-8E8F-41B1DC28E671}" ) );
  117. _tcscpy( m_package[ UDDI_ADMIN ].szProductCode, TEXT( "{98F055D3-99CF-4BBB-BC35-3672F9A297C1}" ) );
  118. //
  119. // 775306
  120. // A-DSEBES: Upgrade code has not changed.
  121. //
  122. _tcscpy( m_package[ UDDI_MSDE ].szUpgradeCode, TEXT( "{421A321C-2214-4713-B3EB-253F2FBCCE49}" ) );
  123. _tcscpy( m_package[ UDDI_WEB ].szUpgradeCode, TEXT( "{E2B9B8F4-D0F2-4810-92AB-81F8E60732A4}" ) );
  124. _tcscpy( m_package[ UDDI_DB ].szUpgradeCode, TEXT( "{B7EB7DEC-9CCA-4EBD-96CB-801EABE06A17}" ) );
  125. _tcscpy( m_package[ UDDI_ADMIN ].szUpgradeCode, TEXT( "{50CA09F3-3FAE-4FE1-BEF2-C29980E95B9A}" ) );
  126. //
  127. // this property will turn off networking
  128. //
  129. AddProperty( UDDI_MSDE, TEXT( "DISABLENETWORKPROTOCOLS" ), TEXT( "1" ) );
  130. //
  131. // this property will prevent the agent from starting
  132. //
  133. AddProperty( UDDI_MSDE, TEXT( "DISABLEAGENTSTARTUP" ), TEXT( "1" ) );
  134. //
  135. // this property will allow MSDE to use a blank sa password.
  136. //
  137. AddProperty( UDDI_MSDE, TEXT( "BLANKSAPWD" ), TEXT( "1" ) );
  138. //
  139. // this property will keep these components off ARP
  140. //
  141. AddProperty( UDDI_WEB, TEXT( "ARPSYSTEMCOMPONENT" ), TEXT( "1" ) );
  142. AddProperty( UDDI_DB, TEXT( "ARPSYSTEMCOMPONENT" ), TEXT( "1" ) );
  143. AddProperty( UDDI_ADMIN, TEXT( "ARPSYSTEMCOMPONENT" ), TEXT( "1" ) );
  144. //
  145. // this property will install for all users and not current user
  146. //
  147. AddProperty( UDDI_MSDE, TEXT( "ALLUSERS" ), TEXT( "2" ) );
  148. AddProperty( UDDI_WEB, TEXT( "ALLUSERS" ), TEXT( "2" ) );
  149. AddProperty( UDDI_DB, TEXT( "ALLUSERS" ), TEXT( "2" ) );
  150. AddProperty( UDDI_ADMIN, TEXT( "ALLUSERS" ), TEXT( "2" ) );
  151. //
  152. // this property will prevent MSI from rebooting, but will return the reboot code back to us
  153. //
  154. AddProperty( UDDI_MSDE, TEXT( "REBOOT" ), TEXT( "ReallySuppress" ) );
  155. AddProperty( UDDI_WEB, TEXT( "REBOOT" ), TEXT( "ReallySuppress" ) );
  156. AddProperty( UDDI_DB, TEXT( "REBOOT" ), TEXT( "ReallySuppress" ) );
  157. AddProperty( UDDI_ADMIN, TEXT( "REBOOT" ), TEXT( "ReallySuppress" ) );
  158. //
  159. // this property will prevent user from running the installation outside OCM
  160. //
  161. AddProperty( UDDI_WEB, TEXT( "RUNFROMOCM" ), TEXT( "1" ) );
  162. AddProperty( UDDI_DB, TEXT( "RUNFROMOCM" ), TEXT( "1" ) );
  163. AddProperty( UDDI_ADMIN, TEXT( "RUNFROMOCM" ), TEXT( "1" ) );
  164. //
  165. // now figure out the Windows volume and the target path
  166. //
  167. TCHAR szTargetPath[ MAX_PATH + 1 ];
  168. DWORD dwRet = ExpandEnvironmentStrings( TEXT( "%SystemDrive%\\Inetpub" ), szTargetPath, MAX_PATH );
  169. if ( !dwRet ) // fallback on C:\Inetpub
  170. _tcscpy( szTargetPath, TEXT( "C:\\Inetpub" ) );
  171. m_cDefaultDataDir = szTargetPath;
  172. m_cDefaultDataDir += TEXT( "\\uddi\\data" );
  173. AddProperty( UDDI_WEB, TEXT( "TARGETDIR" ), szTargetPath );
  174. AddProperty( UDDI_DB, TEXT( "TARGETDIR" ), szTargetPath );
  175. AddProperty( UDDI_ADMIN, TEXT( "TARGETDIR" ), szTargetPath );
  176. //
  177. // Now set up the install date property so that it goes to the registry in
  178. // a locale-independent fashion
  179. //
  180. TCHAR szMDYDate[ 256 ];
  181. time_t now = time( NULL );
  182. struct tm *today = localtime( &now );
  183. _tcsftime( szMDYDate, sizeof szMDYDate / sizeof szMDYDate[0], TEXT( "%m/%d/%Y" ), today );
  184. AddProperty( UDDI_WEB, TEXT( "MDY" ), szMDYDate );
  185. AddProperty( UDDI_DB, TEXT( "MDY" ), szMDYDate );
  186. AddProperty( UDDI_ADMIN, TEXT( "MDY" ), szMDYDate );
  187. m_hInstance = NULL;
  188. m_uSuiteMask = 0;
  189. }
  190. //-----------------------------------------------------------------------------------------
  191. //
  192. // set the install level of a component given the component index
  193. //
  194. void CUDDIInstall::SetInstallLevel( UDDI_PACKAGE_ID id, INSTALL_LEVEL iInstallLevel, BOOL bForceInstall )
  195. {
  196. if( UDDI_INSTALL == iInstallLevel )
  197. {
  198. if ( bForceInstall )
  199. {
  200. m_package[ id ].iInstallLevel = UDDI_INSTALL;
  201. if ( UDDI_COMBO == id )
  202. {
  203. m_package[ UDDI_WEB ].iInstallLevel = UDDI_INSTALL;
  204. m_package[ UDDI_DB ].iInstallLevel = UDDI_INSTALL;
  205. }
  206. }
  207. else
  208. {
  209. m_package[ id ].iInstallLevel = IsInstalled( id ) ? UDDI_NOACTION : UDDI_INSTALL;
  210. if ( UDDI_COMBO == id )
  211. {
  212. m_package[ UDDI_WEB ].iInstallLevel = m_package[ id ].iInstallLevel;
  213. m_package[ UDDI_DB ].iInstallLevel = m_package[ id ].iInstallLevel;
  214. }
  215. }
  216. }
  217. else if( UDDI_UNINSTALL == iInstallLevel )
  218. {
  219. m_package[ id ].iInstallLevel = IsInstalled( id ) ? UDDI_UNINSTALL : UDDI_NOACTION;
  220. if ( UDDI_COMBO == id )
  221. {
  222. m_package[ UDDI_WEB ].iInstallLevel = m_package[ id ].iInstallLevel;
  223. m_package[ UDDI_DB ].iInstallLevel = m_package[ id ].iInstallLevel;
  224. }
  225. }
  226. else if( UDDI_NOACTION == iInstallLevel )
  227. {
  228. m_package[ id ].iInstallLevel = UDDI_NOACTION;
  229. if ( UDDI_COMBO == id )
  230. {
  231. m_package[ UDDI_WEB ].iInstallLevel = m_package[ id ].iInstallLevel;
  232. m_package[ UDDI_DB ].iInstallLevel = m_package[ id ].iInstallLevel;
  233. }
  234. }
  235. else
  236. {
  237. assert( false );
  238. }
  239. }
  240. //-----------------------------------------------------------------------------------------
  241. //
  242. // set the install level of a component give the component name
  243. //
  244. void CUDDIInstall::SetInstallLevel( LPCTSTR szOCMName, INSTALL_LEVEL iInstallLevel, BOOL bForceInstall )
  245. {
  246. SetInstallLevel( GetPackageID( szOCMName ), iInstallLevel, bForceInstall );
  247. }
  248. //-----------------------------------------------------------------------------------------
  249. //
  250. // Get the install level of a component give the component name
  251. //
  252. LPCTSTR CUDDIInstall::GetInstallStateText( LPCTSTR szOCMName )
  253. {
  254. return GetInstallStateText( GetPackageID( szOCMName ) );
  255. }
  256. //-----------------------------------------------------------------------------------------
  257. //
  258. // Get the install level of a component give the component index
  259. //
  260. LPCTSTR CUDDIInstall::GetInstallStateText( UDDI_PACKAGE_ID id )
  261. {
  262. return szInstallStateText[ m_package[ id ].iInstallLevel ];
  263. }
  264. //-----------------------------------------------------------------------------------------
  265. //
  266. // look up the id ( index ) of the component based on the name.
  267. // The name set in the constructor must match the name given in uddi.inf.
  268. //
  269. UDDI_PACKAGE_ID CUDDIInstall::GetPackageID( LPCTSTR szOCMName )
  270. {
  271. for( UINT uid=UDDI_MSDE; uid <= UDDI_COMBO; uid++ )
  272. {
  273. UDDI_PACKAGE_ID id = ( UDDI_PACKAGE_ID ) uid;
  274. if( 0 == m_package[ id ].cOCMName.compare( szOCMName ) )
  275. {
  276. return id;
  277. }
  278. }
  279. assert( false );
  280. return ( UDDI_PACKAGE_ID ) 0;
  281. }
  282. //--------------------------------------------------------------------------------------
  283. // Returns the default Data Files location (typically %SystemDrive%\Inetpub\uddi\data)
  284. //
  285. LPCTSTR CUDDIInstall::GetDefaultDataPath ()
  286. {
  287. return m_cDefaultDataDir.c_str();
  288. }
  289. //-----------------------------------------------------------------------------------------
  290. void CUDDIInstall::AddProperty( UDDI_PACKAGE_ID id, LPCTSTR szProperty, LPCTSTR szValue )
  291. {
  292. m_package[ id ].installProperties.Add( szProperty, szValue );
  293. }
  294. //-----------------------------------------------------------------------------------------
  295. void CUDDIInstall::AddProperty( UDDI_PACKAGE_ID id, LPCTSTR szProperty, DWORD dwValue )
  296. {
  297. m_package[ id ].installProperties.Add( szProperty, dwValue );
  298. }
  299. //-----------------------------------------------------------------------------------------
  300. LPCTSTR CUDDIInstall::GetProperty ( UDDI_PACKAGE_ID id, LPCTSTR szProperty, LPTSTR szOutBuf )
  301. {
  302. return m_package[ id ].installProperties.GetString( szProperty, szOutBuf );
  303. }
  304. //-----------------------------------------------------------------------------------------
  305. void CUDDIInstall::DeleteProperty( UDDI_PACKAGE_ID id, LPCTSTR szProperty )
  306. {
  307. m_package[ id ].installProperties.Delete( szProperty );
  308. }
  309. //-----------------------------------------------------------------------------------------
  310. //
  311. // clear out all the properties for a component
  312. //
  313. void CUDDIInstall::DeleteProperties( UDDI_PACKAGE_ID id )
  314. {
  315. m_package[ id ].installProperties.Clear();
  316. }
  317. //-----------------------------------------------------------------------------------------
  318. bool CUDDIInstall::SetDBInstanceName( LPCTSTR szComputerName, LPCTSTR szNewInstanceName,
  319. bool bIsInstallingMSDE, bool bIsCluster )
  320. {
  321. const cBUFFSIZE = 50;
  322. bool bFullyQualifiedInstance = false;
  323. bool bIsLocalComputer = false;
  324. TCHAR szTempInstanceName[ cBUFFSIZE ] = {0};
  325. TCHAR szCompNameBuf[ 256 ] = {0};
  326. TCHAR szInstNameBuf[ 256 ] = {0};
  327. assert( NULL != szNewInstanceName );
  328. //
  329. // First, should we parse the instance name out and separate the server name from the
  330. // instance name ?
  331. //
  332. TCHAR *pChar = _tcschr( szNewInstanceName, TEXT( '\\') );
  333. if ( pChar )
  334. {
  335. //
  336. // We were given a fully-qualified instance name
  337. // Use the computer name from the instance, as it may differ from the physical
  338. // computer name when run on a cluster node
  339. //
  340. bFullyQualifiedInstance = true;
  341. bIsLocalComputer = false;
  342. _tcsncpy( szCompNameBuf, szNewInstanceName, (pChar - szNewInstanceName) );
  343. _tcsncpy( szInstNameBuf, pChar+1, cBUFFSIZE - 1 );
  344. }
  345. else
  346. {
  347. bFullyQualifiedInstance = false;
  348. _tcscpy( szInstNameBuf, szNewInstanceName );
  349. if( szComputerName )
  350. {
  351. bIsLocalComputer = false;
  352. _tcscpy( szCompNameBuf, szComputerName );
  353. }
  354. else
  355. {
  356. bIsLocalComputer = true;
  357. TCHAR szLocalComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ] = {0};
  358. DWORD dwLen = MAX_COMPUTERNAME_LENGTH + 1;
  359. GetComputerName( szLocalComputerName, &dwLen );
  360. _tcscpy( szCompNameBuf, szLocalComputerName );
  361. }
  362. }
  363. //
  364. // now set up the dbInstance structure
  365. //
  366. m_dbinstance.bIsCluster = bIsCluster;
  367. m_dbinstance.cComputerName = szCompNameBuf;
  368. m_dbinstance.bIsLocalComputer = bIsLocalComputer;
  369. _tcsncpy( szTempInstanceName, szInstNameBuf, cBUFFSIZE - 1 );
  370. //
  371. // if we are creating a new db, make sure the name select is not already in use
  372. //
  373. if( bIsInstallingMSDE )
  374. {
  375. //
  376. // container class of all the local db instance names
  377. //
  378. CDBInstance localDBInstance;
  379. bool bUnusedNameFound = false;
  380. for( int i=1; i<100 && !bUnusedNameFound; i++ )
  381. {
  382. if( localDBInstance.IsInstanceInstalled( szTempInstanceName ) == -1 )
  383. {
  384. bUnusedNameFound = true;
  385. }
  386. else
  387. {
  388. Log( TEXT( "MSDE instance name %s is already in use." ), szTempInstanceName );
  389. _stprintf( szTempInstanceName, TEXT( "%s%d" ), szNewInstanceName, i );
  390. }
  391. }
  392. if( !bUnusedNameFound )
  393. {
  394. Log( TEXT( "FAIL: Unable to find an unused instance name" ) );
  395. return false;
  396. }
  397. }
  398. m_dbinstance.cSQLInstanceName = szTempInstanceName;
  399. m_dbinstance.cFullName = m_dbinstance.cComputerName;
  400. if( m_dbinstance.cSQLInstanceName.compare( DEFAULT_SQL_INSTANCE_NAME ) )
  401. {
  402. m_dbinstance.cFullName += TEXT( "\\" );
  403. m_dbinstance.cFullName += m_dbinstance.cSQLInstanceName;
  404. }
  405. //
  406. // add a property to the db and web install command line to note the instance name
  407. //
  408. AddProperty( UDDI_DB, TEXT( "INSTANCENAMEONLY" ), m_dbinstance.cSQLInstanceName.c_str() );
  409. AddProperty( UDDI_DB, TEXT( "INSTANCENAME" ), m_dbinstance.cFullName.c_str() );
  410. AddProperty( UDDI_WEB, TEXT( "INSTANCENAME" ), m_dbinstance.cFullName.c_str() );
  411. //
  412. // MSDE needs only the instance name, not the machine name
  413. //
  414. AddProperty( UDDI_MSDE, TEXT( "INSTANCENAME" ), m_dbinstance.cSQLInstanceName.c_str() );
  415. return true;
  416. }
  417. //-----------------------------------------------------------------------------------------
  418. // Counterpart routines for the Set above
  419. //
  420. LPCTSTR CUDDIInstall::GetDBInstanceName()
  421. {
  422. return m_dbinstance.cSQLInstanceName.c_str();
  423. }
  424. LPCTSTR CUDDIInstall::GetFullDBInstanceName()
  425. {
  426. return m_dbinstance.cFullName.c_str();
  427. }
  428. LPCTSTR CUDDIInstall::GetDBComputerName()
  429. {
  430. return m_dbinstance.cComputerName.c_str();
  431. }
  432. //-----------------------------------------------------------------------------------------
  433. //
  434. // determine if a component is installed given the component name
  435. //
  436. bool CUDDIInstall::IsInstalled( LPCTSTR szOCMName )
  437. {
  438. return IsInstalled( GetPackageID( szOCMName ) );
  439. }
  440. //-----------------------------------------------------------------------------------------
  441. //
  442. // determine if a component is installed given the component id
  443. //
  444. bool CUDDIInstall::IsInstalled( UDDI_PACKAGE_ID id )
  445. {
  446. TCHAR szProductGuid[ MSI_GUID_LEN ];
  447. //
  448. // Here we handle the "virtual" component UDDI_COMBO that actually is a mix of DB and Web
  449. //
  450. if ( UDDI_COMBO == id )
  451. {
  452. bool bRes = IsInstalled( UDDI_WEB ) && IsInstalled( UDDI_DB );
  453. return bRes;
  454. }
  455. assert( MSI_GUID_LEN - 1 == _tcslen( m_package[ id ].szUpgradeCode ) );
  456. UINT iRet = MsiEnumRelatedProducts( m_package[ id ].szUpgradeCode, 0, 0, szProductGuid );
  457. if( ERROR_NO_MORE_ITEMS == iRet )
  458. {
  459. Log( TEXT( "%s is not already installed." ), m_package[ id ].cMSIName.c_str() );
  460. return false ;
  461. }
  462. else if( ERROR_SUCCESS == iRet )
  463. {
  464. Log( TEXT( "A version of %s is already installed." ), m_package[ id ].cMSIName.c_str() );
  465. return true;
  466. }
  467. else if( ERROR_INVALID_PARAMETER == iRet )
  468. {
  469. Log( TEXT( "FAIL: Invalid upgrade code %s passed to MsiEnumRelatedProducts() for %s." ),
  470. m_package[ id ].szUpgradeCode,
  471. m_package[ id ].cMSIName.c_str() );
  472. assert( false );
  473. return false;
  474. }
  475. else
  476. {
  477. Log( TEXT( "FAIL: Error calling MsiEnumRelatedProducts()." ) );
  478. assert( false );
  479. return false;
  480. }
  481. }
  482. //-----------------------------------------------------------------------------------------
  483. //
  484. // determine if any of the components are set to install
  485. //
  486. bool CUDDIInstall::IsAnyInstalling()
  487. {
  488. for( UINT uid=UDDI_MSDE; uid <= UDDI_ADMIN; uid++ )
  489. {
  490. UDDI_PACKAGE_ID id = ( UDDI_PACKAGE_ID ) uid;
  491. if( IsInstalling( id ) )
  492. {
  493. return true;
  494. }
  495. }
  496. return false;
  497. }
  498. //-----------------------------------------------------------------------------------------
  499. //
  500. // determine if any of the components are set to install
  501. //
  502. bool CUDDIInstall::IsUninstalling( UDDI_PACKAGE_ID id )
  503. {
  504. return ( UDDI_UNINSTALL == m_package[ id ].iInstallLevel );
  505. }
  506. //-----------------------------------------------------------------------------------------
  507. //
  508. // determine if any of the components are set to install
  509. //
  510. bool CUDDIInstall::IsInstalling( UDDI_PACKAGE_ID id )
  511. {
  512. return ( UDDI_INSTALL == m_package[ id ].iInstallLevel );
  513. }
  514. //-----------------------------------------------------------------------------------------
  515. //
  516. // determine if any of the components are set to install
  517. //
  518. bool CUDDIInstall::IsInstalling( LPCTSTR szOCMName )
  519. {
  520. return IsInstalling( GetPackageID( szOCMName ) );
  521. }
  522. //-----------------------------------------------------------------------------------------
  523. //
  524. // get the selection state from the OCM and updat the install level
  525. //
  526. void CUDDIInstall::UpdateAllInstallLevel()
  527. {
  528. for( UINT uid=UDDI_MSDE; uid <= UDDI_ADMIN; uid++ )
  529. {
  530. UDDI_PACKAGE_ID id = ( UDDI_PACKAGE_ID ) uid;
  531. if( m_package[ id ].bOCMComponent )
  532. {
  533. //
  534. // if this is an OCM component (i.e. NOT MSDE), check its selection state
  535. //
  536. bool bIsInstalling = false;
  537. if( ERROR_SUCCESS == COCMCallback::QuerySelectionState( m_package[ id ].cOCMName.c_str(), bIsInstalling ) )
  538. {
  539. SetInstallLevel( id, bIsInstalling ? UDDI_INSTALL : UDDI_UNINSTALL );
  540. }
  541. }
  542. }
  543. //
  544. // now as we updated the DB and Web components, we can take care of the "combo" one
  545. //
  546. bool bIsInstallingCombo = false;
  547. if( ERROR_SUCCESS == COCMCallback::QuerySelectionState( m_package[ UDDI_COMBO ].cOCMName.c_str(), bIsInstallingCombo ) )
  548. {
  549. SetInstallLevel( UDDI_COMBO, bIsInstallingCombo ? UDDI_INSTALL : UDDI_UNINSTALL );
  550. }
  551. }
  552. //-----------------------------------------------------------------------------------------
  553. //
  554. // install and uninstall any or all of the components
  555. //
  556. UINT CUDDIInstall::Install()
  557. {
  558. ENTER();
  559. BOOL InstallingPackage[ UDDI_PACKAGE_COUNT ] = {0};
  560. //
  561. // if any errors, don't bail
  562. // keep going and report errors at the very end
  563. //
  564. UINT uFinalRetCode = ERROR_SUCCESS;
  565. //
  566. // uninstall ALL the packages that are set to uninstall
  567. //
  568. for( int id = UDDI_ADMIN; id >= UDDI_MSDE; id-- )
  569. {
  570. UDDI_PACKAGE_ID pkgid = (UDDI_PACKAGE_ID) id;
  571. if( IsUninstalling( pkgid ) )
  572. {
  573. COCMCallback::AdvanceTickGauge();
  574. UINT uRetCode = UninstallPackage( pkgid );
  575. if( ERROR_SUCCESS != uRetCode )
  576. uFinalRetCode = uRetCode;
  577. }
  578. }
  579. //
  580. // install ALL the packages that are set to install
  581. //
  582. for( UINT uid=UDDI_MSDE; uid <= UDDI_ADMIN; uid++ )
  583. {
  584. UDDI_PACKAGE_ID id = ( UDDI_PACKAGE_ID ) uid;
  585. InstallingPackage[ uid ] = IsInstalling( id );
  586. if( IsInstalling( id ) )
  587. {
  588. COCMCallback::AdvanceTickGauge();
  589. UINT uRetCode = InstallPackage( id );
  590. if( ERROR_SUCCESS != uRetCode )
  591. {
  592. uFinalRetCode = uRetCode;
  593. //
  594. // on the Standard Server, the first failed component fails the whole thing
  595. //
  596. if ( IsStdServer() && ERROR_SUCCESS_REBOOT_REQUIRED != uRetCode )
  597. {
  598. for( int tmpid = id; tmpid > UDDI_MSDE; tmpid-- )
  599. {
  600. if( InstallingPackage[ tmpid ] )
  601. {
  602. COCMCallback::AdvanceTickGauge();
  603. UninstallPackage( (UDDI_PACKAGE_ID)tmpid );
  604. }
  605. }
  606. if ( InstallingPackage[ UDDI_MSDE ] )
  607. UninstallPackage( UDDI_MSDE );
  608. break;
  609. }
  610. }
  611. else
  612. {
  613. uRetCode = PostInstallPackage( id );
  614. if( ERROR_SUCCESS != uRetCode && ERROR_SUCCESS_REBOOT_REQUIRED != uRetCode )
  615. {
  616. uFinalRetCode = uRetCode;
  617. //
  618. // Remove the package that failed on post-installation phase
  619. //
  620. UninstallPackage( id );
  621. }
  622. }
  623. }
  624. }
  625. return uFinalRetCode;
  626. }
  627. //-----------------------------------------------------------------------------------------
  628. UINT CUDDIInstall::InstallPackage( UDDI_PACKAGE_ID id )
  629. {
  630. ENTER();
  631. DWORD dwRetCode = 0;
  632. //
  633. // Before we do anything else, try to enable the Remote Registry
  634. //
  635. if ( id == UDDI_DB || id == UDDI_WEB )
  636. {
  637. EnableRemoteRegistry();
  638. }
  639. //
  640. // 739722 - Change installing message to better suite localization.
  641. //
  642. //
  643. // create and display the text on the OCM progress dialog
  644. //
  645. TCHAR szBuffer[ 1024 ];
  646. TCHAR szComponent[ 256 ];
  647. TCHAR szMsgFormat[ 256 ];
  648. //
  649. // Get the Installing %S ... message.
  650. //
  651. if( !LoadString( m_hInstance, IDS_INSTALL, szMsgFormat, sizeof( szMsgFormat ) / sizeof( TCHAR ) ) )
  652. return GetLastError();
  653. //
  654. // Get the component that we are installing.
  655. //
  656. if( !LoadString( m_hInstance, IDS_MSDE_NAME + id, szComponent, sizeof( szComponent ) / sizeof( TCHAR ) ) )
  657. return GetLastError();
  658. //
  659. // Write out a formatted string that combines these 2.
  660. //
  661. _sntprintf( szBuffer, 1023, szMsgFormat, szComponent );
  662. COCMCallback::SetProgressText( szBuffer );
  663. Log( szBuffer );
  664. //
  665. // create the path to the msi file
  666. //
  667. TCHAR szWindowsDir[ MAX_PATH + 1 ];
  668. if( 0 == GetWindowsDirectory( szWindowsDir, MAX_PATH ) )
  669. {
  670. return GetLastError();
  671. }
  672. tstring cMSIPath = szWindowsDir;
  673. cMSIPath.append( TEXT( "\\" ) );
  674. cMSIPath.append( m_package[ id ].cMSIName.c_str() );
  675. //
  676. // start the msiexec command line
  677. //
  678. tstring cMSIArgs = TEXT( "/i " );
  679. cMSIArgs.append( TEXT ("\"") );
  680. cMSIArgs.append( cMSIPath );
  681. cMSIArgs.append( TEXT ("\"") );
  682. //
  683. // add the "quiet" switch
  684. //
  685. cMSIArgs.append( TEXT( " /q" ) );
  686. //
  687. // turn logging on, put log into a file in the windows folder,
  688. // same name as the MSI file, with a .log extension
  689. //
  690. cMSIArgs.append( TEXT( " /l* " ) );
  691. cMSIArgs.append( TEXT ("\"") );
  692. cMSIArgs.append( cMSIPath );
  693. cMSIArgs.append( TEXT( ".log" ) );
  694. cMSIArgs.append( TEXT ("\"") );
  695. //
  696. // append all the MSI properties to the command line
  697. //
  698. Log ( TEXT ("Composing the command-line") );
  699. //
  700. // 777143
  701. //
  702. if( UDDI_MSDE == id )
  703. {
  704. const WORD hongKongLangID = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG );
  705. LCID systemLocale = ::GetSystemDefaultLCID();
  706. WORD systemLangID = LANGIDFROMLCID( systemLocale );
  707. if( hongKongLangID == systemLangID )
  708. {
  709. Log( TEXT( "**********Hong Kong system locale detected**********" ) );
  710. cMSIArgs.append( TEXT( " COLLATION=" ) );
  711. cMSIArgs.append( TEXT( "\"Chinese_PRC_CI_AS\" " ) );
  712. }
  713. else
  714. {
  715. Log( TEXT( "**********System locale is not Hong Kong************" ) );
  716. }
  717. }
  718. ATOM at = 0;
  719. TCHAR szWamPwd[ 1024 ];
  720. ZeroMemory( szWamPwd, sizeof szWamPwd );
  721. if ( m_package[ id ].installProperties.GetString( TEXT("WAM_PWD"), szWamPwd ) )
  722. {
  723. //
  724. // we found the property, now let's change it so it does not get passed across
  725. // in a clear text format
  726. //
  727. at = GlobalAddAtom( szWamPwd );
  728. m_package[ id ].installProperties.Delete( TEXT("WAM_PWD") );
  729. m_package[ id ].installProperties.Add ( szWamPwdKey, at );
  730. }
  731. TCHAR tmpBuf [4096];
  732. m_package[ id ].installProperties.ConcatValuePairs (_T(" "), tmpBuf);
  733. cMSIArgs.append ( _T(" ") );
  734. cMSIArgs.append ( tmpBuf );
  735. dwRetCode = RunMSIEXECCommandLine( cMSIArgs );
  736. if( ERROR_SUCCESS != dwRetCode )
  737. {
  738. LogError( TEXT( "Error Installing UDDI" ), dwRetCode );
  739. }
  740. //
  741. // delete the msi file and the cab file
  742. //
  743. DeleteFile( cMSIPath.c_str() );
  744. GlobalDeleteAtom( at );
  745. if( m_package[ id ].cCABName.length() )
  746. {
  747. tstring cCABPath = szWindowsDir;
  748. cCABPath.append( TEXT( "\\" ) );
  749. cCABPath.append( m_package[ id ].cCABName.c_str() );
  750. DeleteFile( cCABPath.c_str() );
  751. }
  752. return dwRetCode;
  753. }
  754. //-----------------------------------------------------------------------------------------
  755. // Executes the post-installation tasks
  756. // BEWARE: if the function returns an error code, then the whole package will be uninstalled
  757. //
  758. UINT CUDDIInstall::PostInstallPackage( UDDI_PACKAGE_ID id )
  759. {
  760. Log( TEXT( "Executing the post-installation tasks for the package '%s'" ), m_package[ id ].cOCMName.c_str() );
  761. return ERROR_SUCCESS;
  762. }
  763. //-----------------------------------------------------------------------------------------
  764. UINT CUDDIInstall::UninstallPackage( UDDI_PACKAGE_ID id )
  765. {
  766. tstring cMSIArgs, cOptionalParams;
  767. DWORD dwRetCode = 0;
  768. //
  769. // create and display the text on the OCM progress dialog
  770. //
  771. TCHAR szMask[ 256 ] = {0},
  772. szComponent[ 256 ] = {0},
  773. szStage[ 256 ] = {0},
  774. szBuf[ 512 ] = {0};
  775. if( !LoadString( m_hInstance, IDS_UNINSTALL, szMask, DIM( szMask ) ) )
  776. return GetLastError();
  777. //
  778. // concat the name of this component
  779. //
  780. if( !LoadString( m_hInstance, IDS_MSDE_NAME + id, szComponent, DIM( szComponent ) ) )
  781. return GetLastError();
  782. //
  783. // First, format the message (in case we are on a cluster node, we need to say something)
  784. //
  785. if ( id == UDDI_DB )
  786. {
  787. if( !LoadString( m_hInstance, IDS_DB_ANALYSING_MSG, szStage, DIM( szStage ) ) )
  788. return GetLastError();
  789. }
  790. _stprintf( szBuf, szMask, szComponent, szStage );
  791. COCMCallback::SetProgressText( szBuf );
  792. Log( szBuf );
  793. //
  794. // Now, proceed with the cluster environment analysis
  795. //
  796. if ( id == UDDI_DB || id == UDDI_WEB )
  797. {
  798. TCHAR szInstance[ 1024 ] = {0};
  799. DWORD cbBuf = DIM( szInstance );
  800. bool bCluster = false;
  801. //
  802. // We create a temp instance as we don't want to interfere with the other components
  803. //
  804. CDBInstance dbInstances;
  805. bool bRes = dbInstances.GetUDDIDBInstanceName( NULL, szInstance, &cbBuf, &bCluster );
  806. if ( !bRes )
  807. {
  808. //
  809. // apparently there is no instance to uninstall. Assume we are in the "normal" mode
  810. //
  811. bCluster = false;
  812. }
  813. //
  814. // Now we need to detect the cluster node (if any) and its state
  815. //
  816. if ( bCluster )
  817. {
  818. TCHAR szComputer[ 256 ];
  819. WCHAR szNode[ 256 ];
  820. DWORD cbNode = DIM( szNode );
  821. DWORD cbComputer = DIM( szComputer );
  822. bool bIsActiveNode = true;
  823. DWORD dwErr = GetSqlNode( szInstance, szNode, cbNode - 1 );
  824. if ( dwErr == ERROR_SUCCESS && wcslen( szNode ) )
  825. {
  826. //
  827. // this is a node. Now let's see whether it's an owning one
  828. //
  829. GetComputerName( szComputer, &cbComputer );
  830. if ( _tcsicmp( szNode, szComputer ) )
  831. bIsActiveNode = false;
  832. }
  833. //
  834. // Now we will set the additional command-line parameters for the custome action,
  835. // indicating the type of the node
  836. //
  837. cOptionalParams += TEXT( " " );
  838. cOptionalParams += PROPKEY_CLUSTERNODETYPE;
  839. cOptionalParams += TEXT( "=\"" );
  840. cOptionalParams += bIsActiveNode ? PROPKEY_ACTIVENODE : PROPKEY_PASSIVENODE;
  841. cOptionalParams += TEXT( "\" " );
  842. }
  843. }
  844. //
  845. // create the path to the msi file
  846. //
  847. TCHAR szWindowsDir[ MAX_PATH + 1 ];
  848. if( 0 == GetWindowsDirectory( szWindowsDir, MAX_PATH ) )
  849. {
  850. return GetLastError();
  851. }
  852. tstring cMSIPath = szWindowsDir;
  853. cMSIPath.append( TEXT( "\\" ) );
  854. cMSIPath.append( m_package[ id ].cMSIName.c_str() );
  855. //
  856. // create the command line for the msiexec uninstall
  857. //
  858. cMSIArgs = TEXT( "/q /x " );
  859. cMSIArgs.append( m_package[ id ].szProductCode );
  860. //
  861. // turn logging on
  862. //
  863. cMSIArgs.append( TEXT( " /l* " ) );
  864. cMSIArgs.append( TEXT ("\"") );
  865. cMSIArgs.append( cMSIPath );
  866. cMSIArgs.append( TEXT( ".uninst.log" ) );
  867. cMSIArgs.append( TEXT ("\"") );
  868. //
  869. // 777143
  870. //
  871. if( UDDI_MSDE == id )
  872. {
  873. const WORD hongKongLangID = MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG );
  874. LCID systemLocale = ::GetSystemDefaultLCID();
  875. WORD systemLangID = LANGIDFROMLCID( systemLocale );
  876. if( hongKongLangID == systemLangID )
  877. {
  878. Log( TEXT( "**********Hong Kong system locale detected**********" ) );
  879. cMSIArgs.append( TEXT( " COLLATION=" ) );
  880. cMSIArgs.append( TEXT( "\"Chinese_PRC_CI_AS\" " ) );
  881. }
  882. else
  883. {
  884. Log( TEXT( "**********System locale is not Hong Kong************" ) );
  885. }
  886. }
  887. //
  888. // suppress MSI reboots!
  889. // The return code from msiexec will tell us if MSI needs a reboot,
  890. // we will then instruct the OCM to request a reboot
  891. //
  892. cMSIArgs.append( TEXT( " REBOOT=ReallySuppress RUNFROMOCM=1 " ) );
  893. cMSIArgs.append( cOptionalParams );
  894. dwRetCode = RunMSIEXECCommandLine( cMSIArgs );
  895. if( ERROR_SUCCESS != dwRetCode )
  896. {
  897. LogError( TEXT( "FAIL: Error Installing package" ), dwRetCode );
  898. }
  899. return dwRetCode;
  900. }
  901. //-----------------------------------------------------------------------------------------
  902. HRESULT CUDDIInstall::DetectOSFlavor()
  903. {
  904. return GetOSProductSuiteMask( NULL, &m_uSuiteMask );
  905. }
  906. //-----------------------------------------------------------------------------------------
  907. //-----------------------------------------------------------------------------------------
  908. //-----------------------------------------------------------------------------------------
  909. CDBInstance::CDBInstance( LPCTSTR szRemoteMachine )
  910. {
  911. m_instanceCount = 0;
  912. GetInstalledDBInstanceNames( szRemoteMachine );
  913. }
  914. //-----------------------------------------------------------------------------------------
  915. LONG CDBInstance::GetInstalledDBInstanceNames( LPCTSTR szRemoteMachine )
  916. {
  917. HKEY hParentKey = NULL;
  918. TCHAR szInstanceVersion[ 256 ];
  919. TCHAR szCSDVersion[ 256 ];
  920. TCHAR szVirtualMachineName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  921. TCHAR szComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  922. DWORD dwLen = MAX_COMPUTERNAME_LENGTH + 1;
  923. DWORD dwCSDVersion = 0;
  924. bool bIsLocalComputer;
  925. LONG iRet1 = 0;
  926. Log( TEXT( "Looking for installed instances on machine: %s" ), szRemoteMachine );
  927. //
  928. // connect to the remote machine (NULL indicates local machine)
  929. //
  930. if( NULL != szRemoteMachine )
  931. {
  932. bIsLocalComputer = false;
  933. _tcsncpy( szComputerName, szRemoteMachine, MAX_COMPUTERNAME_LENGTH );
  934. iRet1 = RegConnectRegistry( szRemoteMachine, HKEY_LOCAL_MACHINE, &hParentKey );
  935. if( ERROR_SUCCESS != iRet1 )
  936. {
  937. LogError( TEXT( "Unable to connect to remote machine" ), iRet1 );
  938. return iRet1;
  939. }
  940. }
  941. //
  942. // or else connect to the local machine registry
  943. //
  944. else
  945. {
  946. bIsLocalComputer = true;
  947. if( !GetComputerName( szComputerName, &dwLen ) )
  948. {
  949. Log( TEXT( "GetComputerName() failed, error = %d" ), GetLastError() );
  950. }
  951. Log( TEXT( "Local computer name is: %s" ), szComputerName );
  952. iRet1 = RegOpenKeyEx( HKEY_LOCAL_MACHINE, NULL, NULL, KEY_READ, &hParentKey );
  953. if( ERROR_SUCCESS != iRet1 )
  954. {
  955. LogError( TEXT( "Unable to open local registry" ), iRet1 );
  956. return iRet1;
  957. }
  958. }
  959. CRegKey key;
  960. assert( hParentKey );
  961. iRet1 = key.Open( hParentKey, TEXT( "SOFTWARE\\Microsoft\\Microsoft SQL Server" ), KEY_READ );
  962. if( ERROR_SUCCESS != iRet1 )
  963. {
  964. Log( TEXT( "Unable to open the SQL Server regkey - SQLServer must not be installed" ) );
  965. RegCloseKey( hParentKey );
  966. return iRet1;
  967. }
  968. TCHAR szInstanceNames[ 500 ];
  969. ULONG uLen = sizeof( szInstanceNames ) / sizeof( TCHAR );
  970. //
  971. // get the list of installed instances of SQL on this machine
  972. //
  973. Log( TEXT( "Looking for installed instances on machine: %s" ), szComputerName );
  974. DWORD dwType = REG_MULTI_SZ;
  975. iRet1 = RegQueryValueEx( key.m_hKey, TEXT( "InstalledInstances" ), NULL, &dwType, (LPBYTE) szInstanceNames, &uLen );
  976. if( ERROR_SUCCESS != iRet1 )
  977. {
  978. Log( TEXT( "There is no InstalledInstances value on this machine - SQLServer must not be installed" ) );
  979. RegCloseKey( hParentKey );
  980. return iRet1;
  981. }
  982. m_instanceCount = 0;
  983. //
  984. // process all the instance names that were found
  985. //
  986. for( PTCHAR pInstance = szInstanceNames;
  987. _tcslen( pInstance ) && m_instanceCount < MAX_INSTANCE_COUNT;
  988. pInstance += _tcslen( pInstance ) + 1 )
  989. {
  990. //
  991. // get the version number of this instance
  992. //
  993. if( !GetSqlInstanceVersion( hParentKey, pInstance, szInstanceVersion, sizeof( szInstanceVersion ) / sizeof( TCHAR ), szCSDVersion, sizeof( szCSDVersion ) / sizeof( TCHAR ) ) )
  994. {
  995. Log( TEXT( "Error getting version for SQL instance %s" ), pInstance );
  996. continue;
  997. }
  998. //
  999. // if this is not sql 2000 (8.0.0) or later, do not add this one to the list
  1000. //
  1001. if( CompareVersions( szInstanceVersion , TEXT( "8.0.0" ) ) < 0 )
  1002. {
  1003. Log( TEXT( "SQL instance %s, version %s is not supported" ), pInstance, szInstanceVersion );
  1004. continue;
  1005. }
  1006. //
  1007. // if this is not sql sp3 or later, do not add this one to the list
  1008. //
  1009. if( CompareVersions( szCSDVersion , MIN_SQLSP_VERSION ) < 0 )
  1010. {
  1011. Log( TEXT( "Warning: SQL instance %s, SP Level [%s] is not supported" ), pInstance, szCSDVersion );
  1012. }
  1013. //
  1014. // see if this is a cluster (virtual) instance
  1015. //
  1016. bool bIsClusterDB = IsClusteredDB( hParentKey, pInstance, szVirtualMachineName, sizeof( szVirtualMachineName ) );
  1017. m_dbinstance[ m_instanceCount ].cComputerName = bIsClusterDB ? szVirtualMachineName : szComputerName;
  1018. m_dbinstance[ m_instanceCount ].bIsLocalComputer = bIsLocalComputer;
  1019. m_dbinstance[ m_instanceCount ].bIsCluster = bIsClusterDB;
  1020. m_dbinstance[ m_instanceCount ].cSQLVersion = szInstanceVersion;
  1021. m_dbinstance[ m_instanceCount ].cSPVersion = szCSDVersion;
  1022. //
  1023. // look for the default instance
  1024. //
  1025. if( _tcsicmp( pInstance, DEFAULT_SQL_INSTANCE_NATIVE ) == 0 )
  1026. {
  1027. //
  1028. // if this is the default instance, use only the machine name
  1029. //
  1030. m_dbinstance[ m_instanceCount ].cSQLInstanceName = DEFAULT_SQL_INSTANCE_NAME;
  1031. m_dbinstance[ m_instanceCount ].cFullName = m_dbinstance[ m_instanceCount ].cComputerName;
  1032. }
  1033. else
  1034. {
  1035. //
  1036. // if this this a named instance, use "machine\instance"
  1037. //
  1038. m_dbinstance[ m_instanceCount ].cSQLInstanceName = pInstance;
  1039. m_dbinstance[ m_instanceCount ].cFullName = m_dbinstance[ m_instanceCount ].cComputerName;
  1040. m_dbinstance[ m_instanceCount ].cFullName.append( TEXT( "\\" ) );
  1041. m_dbinstance[ m_instanceCount ].cFullName.append( m_dbinstance[ m_instanceCount ].cSQLInstanceName );
  1042. }
  1043. Log( TEXT( "SQL instance %s added to list" ), m_dbinstance[ m_instanceCount ].cFullName.c_str() );
  1044. m_instanceCount++;
  1045. }
  1046. if( 0 == m_instanceCount )
  1047. {
  1048. Log( TEXT( "No acceptable SQL instances found" ) );
  1049. return ERROR_SUCCESS;
  1050. }
  1051. return ERROR_SUCCESS;
  1052. }
  1053. //-----------------------------------------------------------------------------------------
  1054. bool CDBInstance::IsClusteredDB( HKEY hParentKey, LPCTSTR szInstanceName, LPTSTR szVirtualMachineName, DWORD dwLen )
  1055. {
  1056. tstring cVersionKey;
  1057. if( _tcsicmp( szInstanceName, DEFAULT_SQL_INSTANCE_NAME ) == 0 || _tcsicmp( szInstanceName, TEXT( "MSSQLSERVER" ) ) == 0 )
  1058. {
  1059. cVersionKey = TEXT( "SOFTWARE\\Microsoft\\MSSQLServer\\Cluster" );
  1060. }
  1061. else
  1062. {
  1063. cVersionKey = TEXT( "SOFTWARE\\Microsoft\\Microsoft SQL Server\\" );
  1064. cVersionKey.append( szInstanceName );
  1065. cVersionKey.append( TEXT( "\\Cluster" ) );
  1066. }
  1067. CRegKey key;
  1068. assert( hParentKey );
  1069. LONG iRet1 = key.Open( hParentKey, cVersionKey.c_str(), KEY_READ );
  1070. if( ERROR_SUCCESS == iRet1 )
  1071. {
  1072. DWORD dwType = REG_SZ;
  1073. iRet1 = RegQueryValueEx( key.m_hKey, TEXT( "ClusterName" ), NULL, &dwType, (LPBYTE) szVirtualMachineName, &dwLen );
  1074. if( ERROR_SUCCESS == iRet1 )
  1075. {
  1076. Log( TEXT( "DB Instance %s is a cluster, VM name = %s" ), szInstanceName, szVirtualMachineName );
  1077. return true;
  1078. }
  1079. else
  1080. {
  1081. Log( TEXT( "Unable to read ClusterName value in regkey %s, error=%d" ), cVersionKey.c_str(), iRet1 );
  1082. }
  1083. }
  1084. else
  1085. {
  1086. Log( TEXT( "Unable to open regkey %s, error=%d" ), cVersionKey.c_str(), iRet1 );
  1087. }
  1088. Log( TEXT( "DB Instance %s is NOT a cluster" ), szInstanceName );
  1089. return false;
  1090. }
  1091. //-----------------------------------------------------------------------------------------
  1092. bool CDBInstance::GetSqlInstanceVersion( HKEY hParentKey, LPCTSTR szInstanceName,
  1093. LPTSTR szInstanceVersion, DWORD dwVersionLen,
  1094. LPTSTR szCSDVersion, DWORD dwCSDVersionLen )
  1095. {
  1096. tstring cVersionKey;
  1097. if( _tcsicmp( szInstanceName, DEFAULT_SQL_INSTANCE_NAME ) == 0 || _tcsicmp( szInstanceName, TEXT( "MSSQLSERVER" ) ) == 0 )
  1098. {
  1099. cVersionKey = TEXT( "SOFTWARE\\Microsoft\\MSSQLServer\\MSSQLServer\\CurrentVersion" );
  1100. }
  1101. else
  1102. {
  1103. cVersionKey = TEXT( "SOFTWARE\\Microsoft\\Microsoft SQL Server\\" );
  1104. cVersionKey.append( szInstanceName );
  1105. cVersionKey.append( TEXT( "\\MSSQLServer\\CurrentVersion" ) );
  1106. }
  1107. CRegKey key;
  1108. assert( hParentKey );
  1109. LONG iRet = key.Open( hParentKey, cVersionKey.c_str() );
  1110. if( ERROR_SUCCESS != iRet )
  1111. {
  1112. return false;
  1113. }
  1114. DWORD dwType = REG_SZ;
  1115. iRet = RegQueryValueEx( key.m_hKey, TEXT( "CurrentVersion" ), NULL, &dwType, (LPBYTE) szInstanceVersion, &dwVersionLen );
  1116. if( ERROR_SUCCESS != iRet )
  1117. {
  1118. return false;
  1119. }
  1120. //
  1121. // Now see if there a SP installed, and if yes - what version
  1122. //
  1123. dwType = REG_SZ;
  1124. iRet = RegQueryValueEx( key.m_hKey, TEXT( "CSDVersion" ), NULL, &dwType, (LPBYTE) szCSDVersion, &dwCSDVersionLen );
  1125. if ( ERROR_SUCCESS != iRet )
  1126. {
  1127. _tcscpy( szCSDVersion, TEXT( "" ) );
  1128. }
  1129. return true;
  1130. }
  1131. //-----------------------------------------------------------------------------------------
  1132. // retrieves the UDDI instance name on a local or remote computer
  1133. // looks for a string registry values that is created by the UDDI DB installer
  1134. bool CDBInstance::GetUDDIDBInstanceName( LPCTSTR szRemoteMachine, LPTSTR szInstanceName, PULONG puLen, bool *pbIsClustered )
  1135. {
  1136. LONG iRet;
  1137. HKEY hParentKey;
  1138. ULONG uBufSize = puLen ? *puLen : 0;
  1139. TCHAR szVirtualMachineName[ 2 * MAX_COMPUTERNAME_LENGTH + 1 ] = {0};
  1140. Log( TEXT( "Looking for UDDI databases on machine %s" ), szRemoteMachine ? szRemoteMachine : TEXT( "( local )" ) );
  1141. if( NULL != szRemoteMachine )
  1142. {
  1143. iRet = RegConnectRegistry( szRemoteMachine, HKEY_LOCAL_MACHINE, &hParentKey );
  1144. if( ERROR_SUCCESS != iRet )
  1145. {
  1146. LogError( TEXT( "Unable to connect to remote machine" ), iRet );
  1147. return false;
  1148. }
  1149. }
  1150. else
  1151. {
  1152. iRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, NULL, NULL, KEY_READ, &hParentKey );
  1153. if( ERROR_SUCCESS != iRet )
  1154. {
  1155. LogError( TEXT( "Unable to open local registry" ), iRet );
  1156. return false;
  1157. }
  1158. }
  1159. CRegKey key;
  1160. assert( hParentKey );
  1161. iRet = key.Open( hParentKey, TEXT( "SOFTWARE\\Microsoft\\UDDI\\Setup\\DBServer" ) );
  1162. if( ERROR_SUCCESS != iRet )
  1163. {
  1164. LogError( TEXT( "Unable to open the UDDI\\Setup\\DBServer regkey" ), iRet );
  1165. RegCloseKey( hParentKey );
  1166. return false;
  1167. }
  1168. DWORD dwType = REG_SZ;
  1169. iRet = RegQueryValueEx( key.m_hKey, TEXT( "InstanceNameOnly" ), NULL, &dwType, (LPBYTE) szInstanceName, &uBufSize );
  1170. if( ERROR_SUCCESS != iRet )
  1171. {
  1172. LogError( TEXT( "There are no UDDI databases on this machine" ), iRet );
  1173. RegCloseKey( hParentKey );
  1174. return false;
  1175. }
  1176. //
  1177. // Now check whether the instance belongs to a cluster
  1178. //
  1179. if ( pbIsClustered )
  1180. *pbIsClustered = false;
  1181. if ( IsClusteredDB( hParentKey, szInstanceName, szVirtualMachineName, DIM( szVirtualMachineName ) - 1 ) )
  1182. {
  1183. _tcscat( szVirtualMachineName, TEXT( "\\" ) );
  1184. _tcscat( szVirtualMachineName, szInstanceName );
  1185. if ( puLen )
  1186. *puLen = (ULONG)_tcslen( szVirtualMachineName );
  1187. _tcsncpy( szInstanceName, szVirtualMachineName, uBufSize );
  1188. if ( pbIsClustered )
  1189. *pbIsClustered = true;
  1190. }
  1191. RegCloseKey( hParentKey );
  1192. return true;
  1193. }
  1194. //-----------------------------------------------------------------------------------------
  1195. bool CDBInstance::GetInstanceName( int i, PTCHAR szBuffer, UINT uBufLen )
  1196. {
  1197. if( NULL == szBuffer )
  1198. return false;
  1199. if( i >= 0 && i < m_instanceCount )
  1200. {
  1201. _tcsncpy( szBuffer, m_dbinstance[ i ].cSQLInstanceName.c_str(), uBufLen );
  1202. return true;
  1203. }
  1204. else
  1205. {
  1206. *szBuffer = '\0';
  1207. return false;
  1208. }
  1209. }
  1210. //-----------------------------------------------------------------------------------------
  1211. int CDBInstance::IsInstanceInstalled( LPCTSTR szInstanceName )
  1212. {
  1213. for( int i=0; i<m_instanceCount; i++ )
  1214. {
  1215. if( _tcsicmp( m_dbinstance[ i ].cSQLInstanceName.c_str(), szInstanceName ) == 0 )
  1216. {
  1217. return i;
  1218. }
  1219. }
  1220. return -1;
  1221. }
  1222. //-----------------------------------------------------------------------------------------
  1223. //-----------------------------------------------------------------------------------------
  1224. //-----------------------------------------------------------------------------------------
  1225. DWORD RunMSIEXECCommandLine( tstring &cMSIArgs )
  1226. {
  1227. STARTUPINFO si = {0};
  1228. si.cb = sizeof( si );
  1229. PROCESS_INFORMATION pi = {0};
  1230. TCHAR szSystemFolder[ MAX_PATH ];
  1231. if( 0 == GetSystemDirectory( szSystemFolder, MAX_PATH ) )
  1232. {
  1233. return GetLastError();
  1234. }
  1235. tstring cApplicationName( szSystemFolder );
  1236. cApplicationName.append( TEXT( "\\msiexec.exe" ) );
  1237. tstring cCommandLine( cApplicationName );
  1238. cCommandLine.append( TEXT( " " ) );
  1239. cCommandLine.append( cMSIArgs );
  1240. TCHAR szName[ 500 ];
  1241. ULONG uLen = 500;
  1242. GetUserNameEx( NameSamCompatible, szName, &uLen );
  1243. Log( TEXT( "Creating Process as: %s" ), szName );
  1244. MyOutputDebug( TEXT( "CreateProcess( \"%s\", \"%s\" )" ), cApplicationName.c_str(), cCommandLine.c_str() );
  1245. Log( TEXT( "Using command line: [%s]" ), cCommandLine.c_str() );
  1246. BOOL bOK = CreateProcess(
  1247. cApplicationName.c_str(), // LPCTSTR lpApplicationName, // name of executable module
  1248. ( LPTSTR ) cCommandLine.c_str(), // LPTSTR lpCommandLine, // command line string
  1249. NULL, // LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  1250. NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
  1251. NULL, // BOOL bInheritHandles, // handle inheritance option
  1252. CREATE_NO_WINDOW, // DWORD dwCreationFlags, // creation flags
  1253. NULL, // LPVOID lpEnvironment, // new environment block
  1254. NULL, // LPCTSTR lpCurrentDirectory, // current directory name
  1255. &si, // LPSTARTUPINFO lpStartupInfo, // startup information
  1256. &pi ); // LPPROCESS_INFORMATION lpProcessInformation // process information
  1257. if( !bOK )
  1258. {
  1259. Log( TEXT( "FAIL: CreateProcess() failed, error code=%d" ), GetLastError() );
  1260. return GetLastError();
  1261. }
  1262. DWORD dwRet = WaitForSingleObject( pi.hProcess, INFINITE );
  1263. if( dwRet == WAIT_TIMEOUT )
  1264. {
  1265. Log( TEXT( "FAIL: CreateProcess() timed out" ) );
  1266. return ERROR_SEM_TIMEOUT;
  1267. }
  1268. else if( dwRet == WAIT_ABANDONED )
  1269. {
  1270. Log( TEXT( "FAIL: WaitForSingleObject() failed on WAIT_ABANDONED" ) );
  1271. return ERROR_SEM_TIMEOUT;
  1272. }
  1273. else if( dwRet == WAIT_FAILED )
  1274. {
  1275. LogError( TEXT( "FAIL: WaitForSingleObject() failed" ), GetLastError() );
  1276. return GetLastError();
  1277. }
  1278. DWORD dwExitCode = 0;
  1279. if( GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
  1280. {
  1281. if( dwExitCode )
  1282. {
  1283. Log( TEXT( "FAIL: MSIExec() threw an error=%d" ), dwExitCode );
  1284. return dwExitCode;
  1285. }
  1286. else
  1287. {
  1288. Log( TEXT( "CreateProcess() succeeded" ) );
  1289. }
  1290. }
  1291. else
  1292. {
  1293. LogError( TEXT( "GetExitCodeProcess()" ), GetLastError() );
  1294. return GetLastError();
  1295. }
  1296. return ERROR_SUCCESS;
  1297. }
  1298. //-----------------------------------------------------------------------------------------
  1299. bool IsSQLRun08AlreadyUsed( bool *pbIsUsed )
  1300. {
  1301. //
  1302. // 775306
  1303. // A-DSEBES: swapped the Product Code for MSDE Instance #8 with WMSDE Instance #8's
  1304. // Product Code.
  1305. //
  1306. INSTALLSTATE istate = MsiQueryProductState( TEXT( "{B42339CD-9F22-4A6A-A023-D12990E0B918}" ) );
  1307. if( INSTALLSTATE_ABSENT == istate )
  1308. {
  1309. Log( TEXT( "The product is installed for a different user." ) );
  1310. *pbIsUsed = true;
  1311. }
  1312. else if( INSTALLSTATE_ADVERTISED == istate )
  1313. {
  1314. Log( TEXT( "The product is advertised but not installed." ) );
  1315. *pbIsUsed = false;
  1316. }
  1317. else if( INSTALLSTATE_DEFAULT == istate )
  1318. {
  1319. Log( TEXT( "The product is installed for the current user." ) );
  1320. *pbIsUsed = true;
  1321. }
  1322. else if( INSTALLSTATE_UNKNOWN == istate )
  1323. {
  1324. Log( TEXT( "The product is neither advertised nor installed." ) );
  1325. *pbIsUsed = false;
  1326. }
  1327. else if( INSTALLSTATE_INVALIDARG == istate )
  1328. {
  1329. Log( TEXT( "FAIL: An invalid parameter was passed to MsiQueryProductState()." ) );
  1330. return false;
  1331. }
  1332. else
  1333. {
  1334. Log( TEXT( "FAIL: MsiQueryProductState() returned an unrecognized code." ) );
  1335. return false;
  1336. }
  1337. return true;
  1338. }
  1339. //-----------------------------------------------------------------------------------------
  1340. //-----------------------------------------------------------------------------------------
  1341. extern "C"
  1342. {
  1343. typedef HRESULT (__stdcall* GetCORVersion)( LPWSTR, DWORD, PDWORD );
  1344. }
  1345. bool IsExistMinDotNetVersion( LPCTSTR szMinDotNetVersion )
  1346. {
  1347. DWORD dwVersionLen = 100;
  1348. TCHAR szVersion[ 100 ];
  1349. bool bVersionOK = false;
  1350. //
  1351. // load the DLL
  1352. //
  1353. HMODULE hinstLib = LoadLibrary( TEXT( "mscoree.dll" ) );
  1354. if( NULL == hinstLib )
  1355. {
  1356. Log( TEXT( "Unable to load the .NET framework DLL so I'm assuming it is not installed" ) );
  1357. return false;
  1358. }
  1359. //
  1360. // get a pointer to the function
  1361. //
  1362. GetCORVersion pfn = ( GetCORVersion ) GetProcAddress( hinstLib, "GetCORVersion" );
  1363. //
  1364. // If the function address is valid, call the function.
  1365. //
  1366. if( pfn )
  1367. {
  1368. ( pfn )( szVersion, MAX_PATH, &dwVersionLen );
  1369. // did we find a .NET version >= to our minimum version?
  1370. if( CompareVersions( szVersion, szMinDotNetVersion ) >= 0 )
  1371. {
  1372. bVersionOK = true;
  1373. }
  1374. }
  1375. FreeLibrary(hinstLib);
  1376. return bVersionOK;
  1377. }
  1378. //-----------------------------------------------------------------------------------------
  1379. // if version1 > version2 returns 1
  1380. // if version1 = version2 returns 0
  1381. // if version1 < version2 returns -1
  1382. int CompareVersions( LPCTSTR szVersion1, LPCTSTR szVersion2 )
  1383. {
  1384. if( NULL == szVersion1 || NULL == szVersion2 )
  1385. {
  1386. return 0;
  1387. }
  1388. const cBUFFSIZE = 100;
  1389. TCHAR szV1[ cBUFFSIZE ];
  1390. TCHAR szV2[ cBUFFSIZE ];
  1391. _tcsncpy( szV1, szVersion1, cBUFFSIZE - 1 );
  1392. _tcsncpy( szV2, szVersion2, cBUFFSIZE - 1 );
  1393. szV1[ cBUFFSIZE - 1 ] = NULL;
  1394. szV2[ cBUFFSIZE - 1 ] = NULL;
  1395. StrTrim( szV1, TEXT( " vV" ) );
  1396. StrTrim( szV2, TEXT( " vV" ) );
  1397. PTCHAR p1 = szV1;
  1398. PTCHAR p2 = szV2;
  1399. // look at up to four sections of the version string ( e.g. 1.0.3233.14 )
  1400. for( int i=0; i<4; i++ )
  1401. {
  1402. UINT v1 = StrToInt( p1 );
  1403. UINT v2 = StrToInt( p2 );
  1404. if( v1 > v2 )
  1405. return 1;
  1406. if( v1 < v2 )
  1407. return -1;
  1408. // otherwise keep on going
  1409. p1 = StrChr( p1, '.' );
  1410. if( NULL == p1 )
  1411. return 0;
  1412. p1++;
  1413. p2 = StrChr( p2, '.' );
  1414. if( NULL == p2 )
  1415. return 0;
  1416. p2++;
  1417. }
  1418. return 0; // assume we are equal
  1419. }
  1420. //-----------------------------------------------------------------------------------------
  1421. void RaiseErrorDialog( LPCTSTR szAction, DWORD dwErrorCode )
  1422. {
  1423. LPVOID lpMsgBuf = NULL;
  1424. FormatMessage(
  1425. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1426. FORMAT_MESSAGE_FROM_SYSTEM |
  1427. FORMAT_MESSAGE_IGNORE_INSERTS,
  1428. NULL,
  1429. dwErrorCode,
  1430. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  1431. ( LPTSTR ) &lpMsgBuf,
  1432. 0,
  1433. NULL
  1434. );
  1435. TCHAR szMsg[ 1000 ];
  1436. _sntprintf( szMsg, 1000, TEXT( "%s\n%s" ), szAction, ( LPCTSTR ) lpMsgBuf );
  1437. szMsg[ 999 ] = NULL;
  1438. // Display the string.
  1439. if( 0 == MessageBox( NULL, szMsg, TEXT( "UDDI Services Setup Error" ), MB_OK | MB_ICONWARNING ) )
  1440. {
  1441. UINT uErr = GetLastError();
  1442. }
  1443. // Free the buffer.
  1444. LocalFree( lpMsgBuf );
  1445. }
  1446. //-----------------------------------------------------------------------------------------
  1447. bool IsOsWinXP()
  1448. {
  1449. OSVERSIONINFOEX osvi = { 0 };
  1450. DWORDLONG dwlConditionMask = 0;
  1451. // Initialize the OSVERSIONINFOEX structure.
  1452. osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  1453. osvi.dwMajorVersion = 5;
  1454. osvi.dwMinorVersion = 1;
  1455. osvi.wProductType = VER_NT_SERVER;
  1456. // Initialize the condition mask.
  1457. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
  1458. VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
  1459. VER_SET_CONDITION( dwlConditionMask, VER_PRODUCT_TYPE, VER_GREATER_EQUAL );
  1460. // Perform the test.
  1461. BOOL bIsServer = VerifyVersionInfo(
  1462. &osvi,
  1463. VER_MAJORVERSION | VER_MINORVERSION | VER_PRODUCT_TYPE,
  1464. dwlConditionMask );
  1465. return( TRUE == bIsServer );
  1466. }
  1467. //-----------------------------------------------------------------------------------------
  1468. bool IsTSAppCompat()
  1469. {
  1470. OSVERSIONINFOEX osvi = { 0 };
  1471. DWORDLONG dwlConditionMask = 0;
  1472. // Initialize the OSVERSIONINFOEX structure.
  1473. osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );
  1474. osvi.wSuiteMask = VER_SUITE_TERMINAL;
  1475. // Initialize the condition mask.
  1476. VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  1477. // Perform the test.
  1478. BOOL bIsServer = VerifyVersionInfo(
  1479. &osvi,
  1480. VER_SUITENAME,
  1481. dwlConditionMask );
  1482. if( FALSE == bIsServer )
  1483. return false;
  1484. //
  1485. // check to see if we are in application server mode
  1486. //
  1487. CRegKey key;
  1488. DWORD dwValue = 0;
  1489. LONG iRet = key.Open( HKEY_LOCAL_MACHINE, TEXT( "System\\CurrentControlSet\\Control\\Terminal Server" ), KEY_READ );
  1490. if( ERROR_SUCCESS != iRet )
  1491. return false;
  1492. iRet = key.QueryValue( dwValue, TEXT( "TSAppCompat" ));
  1493. if( ERROR_SUCCESS != iRet )
  1494. return false;
  1495. return ( 1 == dwValue );
  1496. }
  1497. //-----------------------------------------------------------------------------------------
  1498. bool CheckForAdminPrivs()
  1499. {
  1500. BYTE psidLocalAdmins[ SECURITY_MAX_SID_SIZE + 2 ];
  1501. BOOL isLocalAdmin = FALSE;
  1502. DWORD cbSid = DIM( psidLocalAdmins );
  1503. DWORD dwErr = 0;
  1504. BOOL bRet;
  1505. cbSid = SECURITY_MAX_SID_SIZE;
  1506. bRet = CreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, psidLocalAdmins, &cbSid );
  1507. dwErr = GetLastError();
  1508. if ( !bRet )
  1509. {
  1510. Log( TEXT( "CheckForAdminPrivs: Error creating LocalAdmins SID. Error %d [%x]" ), dwErr, dwErr );
  1511. return false;
  1512. }
  1513. CheckTokenMembership( NULL, psidLocalAdmins, &isLocalAdmin );
  1514. return isLocalAdmin ? true : false;
  1515. }
  1516. //--------------------------------------------------------------------------------
  1517. // Enables the RemoteRegistry service and puts it into "AutoStart" mode
  1518. //
  1519. DWORD EnableRemoteRegistry()
  1520. {
  1521. DWORD dwRet = 0;
  1522. SC_HANDLE hSCM = NULL;
  1523. SC_HANDLE hService = NULL;
  1524. SC_LOCK hLock = NULL;
  1525. try
  1526. {
  1527. hSCM = OpenSCManager( NULL, NULL, GENERIC_ALL );
  1528. if ( !hSCM )
  1529. throw ( dwRet = GetLastError() );
  1530. hLock = LockServiceDatabase( hSCM );
  1531. if ( !hLock )
  1532. throw ( dwRet = GetLastError() );
  1533. hService = OpenService( hSCM, _T( "RemoteRegistry" ), GENERIC_ALL );
  1534. if ( !hService )
  1535. {
  1536. throw ( dwRet = GetLastError() );
  1537. }
  1538. BOOL bRes = ChangeServiceConfig( hService, SERVICE_NO_CHANGE,
  1539. SERVICE_AUTO_START,
  1540. SERVICE_NO_CHANGE,
  1541. NULL, NULL, NULL, NULL, NULL, NULL, NULL );
  1542. if ( !bRes )
  1543. throw ( dwRet = GetLastError() );
  1544. }
  1545. catch ( DWORD err )
  1546. {
  1547. LogError( TEXT( "EnableRemoteRegistry()" ), err );
  1548. dwRet = err;
  1549. }
  1550. catch (...)
  1551. {
  1552. LogError( TEXT( "EnableRemoteRegistry()" ), E_UNEXPECTED );
  1553. dwRet = E_UNEXPECTED;
  1554. }
  1555. if ( hService )
  1556. CloseServiceHandle( hService );
  1557. if ( hLock )
  1558. UnlockServiceDatabase( hLock );
  1559. if ( hSCM )
  1560. CloseServiceHandle( hSCM );
  1561. return dwRet;
  1562. }
  1563. //**************************************************************************************
  1564. // Clustering functions
  1565. //
  1566. // Enumerates the physical drives and filters out online ones, then collects the
  1567. // drive data etc.
  1568. //
  1569. DWORD EnumPhysicalDrives( HCLUSTER hCls, cStrList *pSqlDependencies, cDrvMap *pMap )
  1570. {
  1571. if ( IsBadReadPtr( pMap, sizeof cDrvMap ) ||
  1572. IsBadReadPtr( pSqlDependencies, sizeof cStrList ) )
  1573. return E_INVALIDARG;
  1574. DISK_CALLBACK_DATA callbackData;
  1575. callbackData.hCluster = hCls;
  1576. callbackData.pPhysSrvMap = pMap;
  1577. callbackData.pSqlDependencies = pSqlDependencies;
  1578. pMap->clear();
  1579. DWORD dwErr = ResUtilEnumResources( NULL, RESTYPE_DISK, PhysDiskCallback, &callbackData );
  1580. return dwErr;
  1581. }
  1582. //---------------------------------------------------------------------------------------
  1583. // Enumerates all SQL Server resources and their "Physical Drive" dependencies
  1584. //
  1585. DWORD EnumSQLDependencies( HCLUSTER hCls, cStrList *pList, LPCTSTR szInstanceName )
  1586. {
  1587. if ( IsBadReadPtr( pList, sizeof cStrList ) )
  1588. return E_INVALIDARG;
  1589. pList->clear();
  1590. SQL_CALLBACK_DATA callbackData;
  1591. callbackData.hCluster = hCls;
  1592. callbackData.pSqlDependencies = pList;
  1593. callbackData.sSqlInstanceName = szInstanceName ? szInstanceName : TEXT( "" );
  1594. DWORD dwErr = ResUtilEnumResources( NULL, RESTYPE_SQL, SqlDepCallback, &callbackData );
  1595. return dwErr;
  1596. }
  1597. //----------------------------------------------------------------------------------------
  1598. // Retrieves the Sql instance owning node
  1599. //
  1600. DWORD GetSqlNode( LPCWSTR szInstanceName, LPWSTR szNodeNameBuf, DWORD cbBufSize )
  1601. {
  1602. if ( IsBadWritePtr( szNodeNameBuf, cbBufSize * sizeof WCHAR ) ||
  1603. IsBadStringPtr( szInstanceName, 256 ) )
  1604. return E_INVALIDARG;
  1605. SQL_NODE_CALLBACK_DATA callbackData;
  1606. callbackData.sSqlInstanceName = szInstanceName;
  1607. callbackData.sNodeName = TEXT( "" );
  1608. wcscpy( szNodeNameBuf, L"" );
  1609. DWORD dwErr = ResUtilEnumResources( NULL, RESTYPE_SQL, SqlCallback, &callbackData );
  1610. if ( dwErr == ERROR_SUCCESS )
  1611. {
  1612. wcsncpy( szNodeNameBuf, callbackData.sNodeName.c_str(), cbBufSize );
  1613. }
  1614. return dwErr;
  1615. }
  1616. //---------------------------------------------------------------------------------------
  1617. // Physical drive enumeration callback
  1618. // all the data filtering and property collecting happens here
  1619. //
  1620. DWORD PhysDiskCallback( HRESOURCE hOriginal,
  1621. HRESOURCE hResource,
  1622. PVOID lpParams )
  1623. {
  1624. DWORD dwErr = 0;
  1625. HCLUSTER hCls = NULL;
  1626. cStrList *pSqlDeps = NULL;
  1627. cDrvMap *pMap = NULL;
  1628. if ( IsBadReadPtr( lpParams, sizeof DISK_CALLBACK_DATA ) )
  1629. return E_INVALIDARG;
  1630. try
  1631. {
  1632. BOOL bFilterDependencies = FALSE;
  1633. BOOL bSkipResource = FALSE;
  1634. //
  1635. // Grab the parameter block
  1636. //
  1637. hCls = ((LPDISK_CALLBACK_DATA) lpParams)->hCluster;
  1638. pSqlDeps = ((LPDISK_CALLBACK_DATA) lpParams)->pSqlDependencies;
  1639. pMap = ((LPDISK_CALLBACK_DATA) lpParams)->pPhysSrvMap;
  1640. //
  1641. // Do we need to filter out the SQL dependencies only ?
  1642. //
  1643. bFilterDependencies = ( pSqlDeps->size() > 0 );
  1644. if ( ResUtilResourceTypesEqual( RESTYPE_DISK, hResource ) )
  1645. {
  1646. //
  1647. // This is a physical disk. Let's collect more data on it
  1648. //
  1649. CLUSPROP_PARTITION_INFO *pInfo = NULL;
  1650. WCHAR szNameBuf[ 512 ],
  1651. szNodeBuf[ 512 ],
  1652. szGroupBuf[ 512 ],
  1653. szLetter[ MAX_PATH + 1 ];
  1654. DWORD cbNameBuf = DIM( szNameBuf ),
  1655. cbNodeBuf = DIM( szNodeBuf ),
  1656. cbGroupBuf = DIM( szGroupBuf ),
  1657. cbLetter = DIM( szLetter );
  1658. ZeroMemory( szNameBuf, sizeof szNameBuf );
  1659. ZeroMemory( szNodeBuf, sizeof szNodeBuf );
  1660. ZeroMemory( szGroupBuf, sizeof szGroupBuf );
  1661. ZeroMemory( szLetter, sizeof szLetter );
  1662. dwErr = ResUtilGetResourceName( hResource, szNameBuf, &cbNameBuf );
  1663. if ( dwErr != ERROR_SUCCESS )
  1664. return dwErr;
  1665. //
  1666. // See if wee need to consider this resource at all
  1667. //
  1668. if ( bFilterDependencies )
  1669. bSkipResource = ! IsInList( szNameBuf, pSqlDeps );
  1670. if ( !bSkipResource )
  1671. {
  1672. CLUSTER_RESOURCE_STATE resState = GetClusterResourceState( hResource,
  1673. szNodeBuf, &cbNodeBuf,
  1674. szGroupBuf, &cbNodeBuf );
  1675. if ( resState != ClusterResourceOnline )
  1676. return ERROR_SUCCESS;
  1677. //
  1678. // Now we will retrieve the drive properties and grab the partition info
  1679. //
  1680. DWORD dwBytes = 0;
  1681. LPBYTE pBuf = NULL;
  1682. try
  1683. {
  1684. dwErr = GetClusterResourceControl( hResource, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
  1685. &pBuf, &dwBytes );
  1686. if ( dwErr != ERROR_SUCCESS && dwErr != ERROR_MORE_DATA )
  1687. return dwErr;
  1688. if ( !pBuf )
  1689. return E_UNEXPECTED;
  1690. pInfo = (PCLUSPROP_PARTITION_INFO) ParseDiskInfo( pBuf, dwBytes, CLUSPROP_SYNTAX_PARTITION_INFO );
  1691. if ( !pInfo )
  1692. {
  1693. //
  1694. // failed to parse the property block - just skip the resource
  1695. //
  1696. LocalFree( pBuf );
  1697. return ERROR_SUCCESS;
  1698. }
  1699. //
  1700. // First, check the flags to make sure we are not dealing with removable device
  1701. //
  1702. if ( ! ( pInfo->dwFlags & CLUSPROP_PIFLAG_REMOVABLE ) &&
  1703. ( pInfo->dwFlags & CLUSPROP_PIFLAG_USABLE ) )
  1704. {
  1705. _tcsncpy( szLetter, pInfo->szDeviceName, MAX_PATH );
  1706. }
  1707. else
  1708. bSkipResource = TRUE;
  1709. }
  1710. catch (...)
  1711. {
  1712. }
  1713. LocalFree( pBuf );
  1714. //
  1715. // Add the resource to the map
  1716. //
  1717. if ( !bSkipResource )
  1718. pMap->insert( cDrvMapPair( szNameBuf, cPhysicalDriveInfo( szNameBuf, szNodeBuf, szGroupBuf, szLetter ) ) );
  1719. }
  1720. }
  1721. }
  1722. catch (...)
  1723. {
  1724. return E_UNEXPECTED;
  1725. }
  1726. return ERROR_SUCCESS;
  1727. }
  1728. //--------------------------------------------------------------------------------------
  1729. // Sql resource enumerator callback
  1730. //
  1731. DWORD SqlDepCallback( HRESOURCE hOriginal, HRESOURCE hResource, PVOID lpParams )
  1732. {
  1733. DWORD dwErr = 0;
  1734. HCLUSTER hCls = NULL;
  1735. cStrList *pList = NULL;
  1736. tstring sSqlInstance;
  1737. if ( IsBadReadPtr( lpParams, sizeof SQL_CALLBACK_DATA ) )
  1738. return E_INVALIDARG;
  1739. try
  1740. {
  1741. WCHAR szBuf[ 1024 ];
  1742. DWORD dwIdx = 0;
  1743. DWORD dwType;
  1744. DWORD cbBuf = DIM( szBuf );
  1745. hCls = ((LPSQL_CALLBACK_DATA) lpParams)->hCluster;
  1746. pList = ((LPSQL_CALLBACK_DATA) lpParams)->pSqlDependencies;
  1747. sSqlInstance = ((LPSQL_CALLBACK_DATA) lpParams)->sSqlInstanceName;
  1748. //
  1749. // if the resource is not a SQL Server, then we just skip it
  1750. //
  1751. if ( ! ResUtilResourceTypesEqual( RESTYPE_SQL, hResource ) )
  1752. return ERROR_SUCCESS;
  1753. //
  1754. // Do we need to check the intance name ?
  1755. //
  1756. if ( sSqlInstance.length() > 0 )
  1757. {
  1758. LPBYTE pBuf = NULL;
  1759. LPWSTR szVirtualName = NULL,
  1760. szInstanceName = NULL;
  1761. DWORD dwReturned = 0;
  1762. BOOL bSkipInstance = FALSE;
  1763. dwErr = GetClusterResourceControl( hResource, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  1764. &pBuf, &dwReturned );
  1765. if ( dwErr != ERROR_SUCCESS )
  1766. return dwErr;
  1767. try
  1768. {
  1769. dwErr = ResUtilFindSzProperty( pBuf, dwReturned, PROPNAME_VIRTUALSERVER, &szVirtualName );
  1770. if ( dwErr != ERROR_SUCCESS )
  1771. throw dwErr;
  1772. dwErr = ResUtilFindSzProperty( pBuf, dwReturned, PROPNAME_INSTANCENAME, &szInstanceName );
  1773. if ( dwErr != ERROR_SUCCESS )
  1774. throw dwErr;
  1775. //
  1776. // Do the instance names match ?
  1777. //
  1778. tstring szTmpInstance = szVirtualName;
  1779. szTmpInstance += TEXT( "\\" );
  1780. szTmpInstance += szInstanceName;
  1781. if ( _tcsicmp( sSqlInstance.c_str(), szTmpInstance.c_str() ) )
  1782. bSkipInstance = TRUE;
  1783. }
  1784. catch (...)
  1785. {
  1786. if ( dwErr == ERROR_SUCCESS )
  1787. dwErr = E_UNEXPECTED;
  1788. }
  1789. LocalFree( pBuf );
  1790. LocalFree( szVirtualName );
  1791. LocalFree( szInstanceName );
  1792. if ( dwErr != ERROR_SUCCESS )
  1793. return dwErr;
  1794. if ( bSkipInstance )
  1795. return ERROR_SUCCESS;
  1796. }
  1797. //
  1798. // Now enumerate the dependent resources
  1799. //
  1800. HRESENUM hEnum = ClusterResourceOpenEnum( hResource, CLUSTER_RESOURCE_ENUM_DEPENDS );
  1801. if ( !hEnum )
  1802. return ERROR_SUCCESS;
  1803. for ( dwErr = ClusterResourceEnum( hEnum, dwIdx, &dwType, szBuf, &cbBuf );
  1804. dwErr == ERROR_SUCCESS;
  1805. dwErr = ClusterResourceEnum( hEnum, ++dwIdx, &dwType, szBuf, &cbBuf ) )
  1806. {
  1807. cbBuf = DIM( szBuf );
  1808. pList->push_back( szBuf );
  1809. }
  1810. ClusterResourceCloseEnum( hEnum );
  1811. dwErr = ERROR_SUCCESS;
  1812. }
  1813. catch (...)
  1814. {
  1815. dwErr = E_UNEXPECTED;
  1816. }
  1817. return dwErr;
  1818. }
  1819. //---------------------------------------------------------------------------------------
  1820. // Filters out the specified instance of SqlServer and retrieves its owning node
  1821. //
  1822. static DWORD SqlCallback( HRESOURCE hOriginal, HRESOURCE hResource, PVOID lpParams )
  1823. {
  1824. DWORD dwErr = ERROR_SUCCESS;
  1825. if ( IsBadReadPtr( lpParams, sizeof SQL_NODE_CALLBACK_DATA ) )
  1826. return E_INVALIDARG;
  1827. try
  1828. {
  1829. WCHAR szBuf[ 1024 ];
  1830. DWORD cbBuf = DIM( szBuf );
  1831. LPBYTE pBuf = NULL;
  1832. LPWSTR szVirtualName = NULL,
  1833. szInstanceName = NULL;
  1834. DWORD dwReturned = 0;
  1835. BOOL bSkipInstance = FALSE;
  1836. tstring sSqlInstance = ((LPSQL_NODE_CALLBACK_DATA) lpParams)->sSqlInstanceName;
  1837. if ( sSqlInstance.length() == 0 )
  1838. return E_INVALIDARG;
  1839. ((LPSQL_NODE_CALLBACK_DATA) lpParams)->resState = ClusterResourceStateUnknown;
  1840. //
  1841. // if the resource is not a SQL Server, then we just skip it
  1842. //
  1843. if ( ! ResUtilResourceTypesEqual( RESTYPE_SQL, hResource ) )
  1844. return ERROR_SUCCESS;
  1845. dwErr = GetClusterResourceControl( hResource, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
  1846. &pBuf, &dwReturned );
  1847. if ( dwErr != ERROR_SUCCESS )
  1848. return dwErr;
  1849. try
  1850. {
  1851. dwErr = ResUtilFindSzProperty( pBuf, dwReturned, PROPNAME_VIRTUALSERVER, &szVirtualName );
  1852. if ( dwErr != ERROR_SUCCESS )
  1853. throw dwErr;
  1854. dwErr = ResUtilFindSzProperty( pBuf, dwReturned, PROPNAME_INSTANCENAME, &szInstanceName );
  1855. if ( dwErr != ERROR_SUCCESS )
  1856. throw dwErr;
  1857. //
  1858. // Do the instance names match ?
  1859. //
  1860. tstring szTmpInstance = szVirtualName;
  1861. szTmpInstance += TEXT( "\\" );
  1862. szTmpInstance += szInstanceName;
  1863. if ( _tcsicmp( sSqlInstance.c_str(), szTmpInstance.c_str() ) )
  1864. bSkipInstance = TRUE;
  1865. }
  1866. catch (...)
  1867. {
  1868. if ( dwErr == ERROR_SUCCESS )
  1869. dwErr = E_UNEXPECTED;
  1870. }
  1871. LocalFree( pBuf );
  1872. LocalFree( szVirtualName );
  1873. LocalFree( szInstanceName );
  1874. if ( dwErr != ERROR_SUCCESS )
  1875. return dwErr;
  1876. if ( bSkipInstance )
  1877. return ERROR_SUCCESS;
  1878. //
  1879. // Now get the node for the Sql server
  1880. //
  1881. CLUSTER_RESOURCE_STATE resState = GetClusterResourceState( hResource, szBuf, &cbBuf, NULL, NULL );
  1882. ((LPSQL_NODE_CALLBACK_DATA) lpParams)->resState = resState;
  1883. if ( resState == ClusterResourceStateUnknown )
  1884. return GetLastError();
  1885. ((LPSQL_NODE_CALLBACK_DATA) lpParams)->sNodeName = szBuf;
  1886. }
  1887. catch (...)
  1888. {
  1889. dwErr = E_UNEXPECTED;
  1890. }
  1891. return dwErr;
  1892. }
  1893. //---------------------------------------------------------------------------------------
  1894. // Clustering Helpers
  1895. //
  1896. LPBYTE ParseDiskInfo( PBYTE DiskInfo, DWORD DiskInfoSize, DWORD SyntaxValue )
  1897. {
  1898. CLUSPROP_BUFFER_HELPER ListEntry; // used to parse the value list
  1899. DWORD cbOffset = 0; // offset to next entry in the value list
  1900. DWORD cbPosition = 0; // tracks the advance through the value list buffer
  1901. LPBYTE returnPtr = NULL;
  1902. ListEntry.pb = DiskInfo;
  1903. while (TRUE)
  1904. {
  1905. if ( CLUSPROP_SYNTAX_ENDMARK == *ListEntry.pdw )
  1906. {
  1907. break;
  1908. }
  1909. cbOffset = ALIGN_CLUSPROP( ListEntry.pValue->cbLength + sizeof(CLUSPROP_VALUE) );
  1910. //
  1911. // Check for specific syntax in the property list.
  1912. //
  1913. if ( SyntaxValue == *ListEntry.pdw )
  1914. {
  1915. //
  1916. // Make sure the complete entry fits in the buffer specified.
  1917. //
  1918. if ( cbPosition + cbOffset > DiskInfoSize )
  1919. {
  1920. return NULL;
  1921. }
  1922. else
  1923. {
  1924. returnPtr = ListEntry.pb;
  1925. }
  1926. break;
  1927. }
  1928. //
  1929. // Verify that the offset to the next entry is
  1930. // within the value list buffer, then advance
  1931. // the CLUSPROP_BUFFER_HELPER pointer.
  1932. //
  1933. cbPosition += cbOffset;
  1934. if ( cbPosition > DiskInfoSize ) break;
  1935. ListEntry.pb += cbOffset;
  1936. }
  1937. return returnPtr;
  1938. } // ParseDiskInfo
  1939. BOOL IsInList( LPCTSTR szStrToFind, cStrList *pList, BOOL bIgnoreCase )
  1940. {
  1941. if ( IsBadReadPtr( pList, sizeof cStrList ) )
  1942. return FALSE;
  1943. BOOL bFound = FALSE;
  1944. for ( cStrList::size_type i = 0; ( i < pList->size() ) && !bFound ; i++ )
  1945. {
  1946. LPCTSTR szEntry = (*pList)[i].c_str();
  1947. if ( bIgnoreCase )
  1948. bFound = !_tcsicmp( szEntry, szStrToFind );
  1949. else
  1950. bFound = !_tcscmp( szEntry, szStrToFind );
  1951. }
  1952. return bFound;
  1953. }
  1954. DWORD GetClusterResourceControl( HRESOURCE hResource,
  1955. DWORD dwControlCode,
  1956. LPBYTE *pOutBuffer,
  1957. DWORD *dwBytesReturned )
  1958. {
  1959. DWORD dwError;
  1960. DWORD cbOutBufferSize = 0;
  1961. DWORD cbResultSize = 0;
  1962. LPBYTE tempOutBuffer = NULL;
  1963. dwError = ClusterResourceControl( hResource,
  1964. NULL,
  1965. dwControlCode,
  1966. NULL,
  1967. 0,
  1968. tempOutBuffer,
  1969. cbOutBufferSize,
  1970. &cbResultSize );
  1971. //
  1972. // Reallocation routine if buffer is too small
  1973. //
  1974. if ( ERROR_MORE_DATA == dwError || ERROR_SUCCESS == dwError )
  1975. {
  1976. cbOutBufferSize = cbResultSize;
  1977. tempOutBuffer = (LPBYTE) LocalAlloc( LPTR, cbResultSize + 2 );
  1978. dwError = ClusterResourceControl( hResource,
  1979. NULL,
  1980. dwControlCode,
  1981. NULL,
  1982. 0,
  1983. tempOutBuffer,
  1984. cbOutBufferSize,
  1985. &cbResultSize );
  1986. }
  1987. //
  1988. // On success, give the user the allocated buffer. The user is responsible
  1989. // for freeing this buffer. On failure, free the buffer and return a status.
  1990. //
  1991. if ( NO_ERROR == dwError )
  1992. {
  1993. *pOutBuffer = tempOutBuffer;
  1994. *dwBytesReturned = cbResultSize;
  1995. }
  1996. else
  1997. {
  1998. *pOutBuffer = NULL;
  1999. *dwBytesReturned = 0;
  2000. LocalFree( tempOutBuffer );
  2001. }
  2002. return dwError;
  2003. } // GetClusterResourceControl
  2004. //-------------------------------------------------------------------------------------
  2005. // Connect to the database instance and get the Schema Version
  2006. //
  2007. HRESULT GetDBSchemaVersion( LPCTSTR szInstanceName, LPTSTR szVerBuf, size_t cbVerBuf )
  2008. {
  2009. HRESULT hr = S_OK;
  2010. TCHAR szConnStr[ 256 ];
  2011. LPCTSTR szConnStrMask = TEXT( "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=uddi;Data Source=%s;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False" );
  2012. if ( IsBadWritePtr(szVerBuf, cbVerBuf * sizeof(TCHAR) ) || !cbVerBuf )
  2013. return E_INVALIDARG;
  2014. if ( IsBadStringPtr( szInstanceName, 128 ) )
  2015. return E_INVALIDARG;
  2016. _tcscpy( szVerBuf, _T("") );
  2017. try
  2018. {
  2019. _stprintf( szConnStr, szConnStrMask, szInstanceName );
  2020. net_config_get configGet;
  2021. configGet.m_connectionString = szConnStr;
  2022. Log( TEXT( "GetDBSchemaVersion: Using connection string: %s." ), szConnStr );
  2023. DBROWCOUNT rowCount;
  2024. hr = configGet.Open();
  2025. if( FAILED(hr) || 0 != configGet.m_RETURN_VALUE )
  2026. {
  2027. try
  2028. {
  2029. HandleOLEDBError( hr );
  2030. }
  2031. catch( ... )
  2032. {
  2033. // leave 'hr' the same.
  2034. }
  2035. }
  2036. bool bStop = false;
  2037. while( SUCCEEDED(hr) && hr != DB_S_NORESULT && !bStop )
  2038. {
  2039. if( NULL != configGet.GetInterface() )
  2040. {
  2041. HRESULT hr2 = configGet.Bind();
  2042. if( SUCCEEDED( hr2 ) )
  2043. {
  2044. while( S_OK == configGet.MoveNext() )
  2045. {
  2046. if ( _tcsicmp( configGet.m_configName, PROPNAME_DBSCHEMAVER ) )
  2047. continue;
  2048. _tcsncpy( szVerBuf, configGet.m_configValue, cbVerBuf );
  2049. bStop = true;
  2050. break;
  2051. }
  2052. }
  2053. }
  2054. if ( !bStop )
  2055. hr = configGet.GetNextResult( &rowCount );
  2056. }
  2057. }
  2058. catch (...)
  2059. {
  2060. Log( TEXT( "GetDBSchemaVersion: caught unexpected exception." ) );
  2061. hr = E_UNEXPECTED;
  2062. }
  2063. Log( TEXT( "GetDBSchemaVersion: Finished with HRESULT %x." ), hr );
  2064. return hr;
  2065. }
  2066. void HandleOLEDBError( HRESULT hrErr )
  2067. {
  2068. CDBErrorInfo ErrorInfo;
  2069. ULONG cRecords = 0;
  2070. HRESULT hr;
  2071. ULONG i;
  2072. CComBSTR bstrDesc, bstrHelpFile, bstrSource, bstrMsg;
  2073. GUID guid;
  2074. DWORD dwHelpContext;
  2075. WCHAR wszGuid[40];
  2076. USES_CONVERSION;
  2077. // If the user passed in an HRESULT then trace it
  2078. if( hrErr != S_OK )
  2079. {
  2080. TCHAR sz[ 256 ];
  2081. _sntprintf( sz, 256, _T("OLE DB Error Record dump for hr = 0x%x\n"), hrErr );
  2082. sz[ 255 ] = 0x00;
  2083. bstrMsg += sz;
  2084. }
  2085. LCID lcLocale = GetSystemDefaultLCID();
  2086. hr = ErrorInfo.GetErrorRecords(&cRecords);
  2087. if( FAILED(hr) && ( ErrorInfo.m_spErrorInfo == NULL ) )
  2088. {
  2089. TCHAR sz[ 256 ];
  2090. _sntprintf( sz, 256, _T("No OLE DB Error Information found: hr = 0x%x\n"), hr );
  2091. sz[ 255 ] = 0x00;
  2092. bstrMsg += sz;
  2093. }
  2094. else
  2095. {
  2096. for( i = 0; i < cRecords; i++ )
  2097. {
  2098. hr = ErrorInfo.GetAllErrorInfo(i, lcLocale, &bstrDesc, &bstrSource, &guid,
  2099. &dwHelpContext, &bstrHelpFile);
  2100. if( FAILED(hr) )
  2101. {
  2102. TCHAR sz[ 256 ];
  2103. _sntprintf( sz, 256, _T("OLE DB Error Record dump retrieval failed: hr = 0x%x\n"), hr );
  2104. sz[ 255 ] = 0x00;
  2105. bstrMsg += sz;
  2106. break;
  2107. }
  2108. StringFromGUID2( guid, wszGuid, sizeof(wszGuid) / sizeof(WCHAR) );
  2109. TCHAR sz[ 256 ];
  2110. _sntprintf(
  2111. sz, 256,
  2112. _T("Row #: %4d Source: \"%s\" Description: \"%s\" Help File: \"%s\" Help Context: %4d GUID: %s\n"),
  2113. i, OLE2T(bstrSource), OLE2T(bstrDesc), OLE2T(bstrHelpFile), dwHelpContext, OLE2T(wszGuid) );
  2114. sz[ 255 ] = 0x00;
  2115. bstrMsg += sz;
  2116. bstrSource.Empty();
  2117. bstrDesc.Empty();
  2118. bstrHelpFile.Empty();
  2119. }
  2120. bstrMsg += _T("OLE DB Error Record dump end\n");
  2121. }
  2122. Log( TEXT( "HandleOLEDBError: %s" ), bstrMsg );
  2123. }
  2124. //-------------------------------------------------------------------------------------
  2125. // Add user to service account in db.
  2126. //
  2127. HRESULT AddServiceAccount( LPCTSTR szInstanceName, LPCTSTR szUser )
  2128. {
  2129. HRESULT hr = S_OK;
  2130. TCHAR szConnStr[ 256 ];
  2131. LPCTSTR szConnStrMask = TEXT( "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=uddi;Data Source=%s;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False" );
  2132. Log( TEXT( "AddServiceAccount: Starting..." ) );
  2133. if ( IsBadStringPtr( szInstanceName, 128 ) )
  2134. return E_INVALIDARG;
  2135. try
  2136. {
  2137. _stprintf( szConnStr, szConnStrMask, szInstanceName );
  2138. Log( TEXT( "AddServiceAccount: Using connection string: %s." ), szConnStr );
  2139. ADM_addServiceAccount addServiceAccount;
  2140. addServiceAccount.m_connectionString = szConnStr;
  2141. _tcsncpy( addServiceAccount.m_accountName, szUser, 129 );
  2142. addServiceAccount.m_accountName[ 128 ] = '\0';
  2143. hr = addServiceAccount.Open();
  2144. if( FAILED(hr) || 0 != addServiceAccount.m_RETURNVALUE )
  2145. {
  2146. try
  2147. {
  2148. HandleOLEDBError( hr );
  2149. }
  2150. catch( ... )
  2151. {
  2152. // leave 'hr' the same.
  2153. }
  2154. }
  2155. }
  2156. catch (...)
  2157. {
  2158. Log( TEXT( "AddServiceAccount: caught unexpected exception." ) );
  2159. hr = E_UNEXPECTED;
  2160. }
  2161. Log( TEXT( "AddServiceAccount: Finished with HRESULT %x." ), hr );
  2162. return hr;
  2163. }