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.

631 lines
18 KiB

  1. //-----------------------------------------------------------------------------------------
  2. // Go to "OCM" alias for assistance on this "technology"
  3. //
  4. //
  5. #ifndef WIN32_LEAN_AND_MEAN
  6. #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
  7. #endif
  8. #ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
  9. #define _WIN32_WINNT 0x0510 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
  10. #endif
  11. #include <windows.h>
  12. #include <windef.h>
  13. #include <tchar.h>
  14. #include <setupapi.h>
  15. #include <shellapi.h>
  16. #include "ocmanage.h"
  17. #include "uddiocm.h"
  18. #include "uddiinst.h"
  19. #include "ocmcallback.h"
  20. #include "appcompat.h"
  21. #include "..\shared\common.h"
  22. #include "resource.h"
  23. TCHAR *ocmmsg[100] =
  24. {
  25. TEXT( "OC_PREINITIALIZE" ),
  26. TEXT( "OC_INIT_COMPONENT" ),
  27. TEXT( "OC_SET_LANGUAGE" ),
  28. TEXT( "OC_QUERY_IMAGE" ),
  29. TEXT( "OC_REQUEST_PAGES" ),
  30. TEXT( "OC_QUERY_CHANGE_SEL_STATE" ),
  31. TEXT( "OC_CALC_DISK_SPACE" ),
  32. TEXT( "OC_QUEUE_FILE_OPS" ),
  33. TEXT( "OC_NOTIFICATION_FROM_QUEUE" ),
  34. TEXT( "OC_QUERY_STEP_COUNT" ),
  35. TEXT( "OC_COMPLETE_INSTALLATION" ),
  36. TEXT( "OC_CLEANUP" ),
  37. TEXT( "OC_QUERY_STATE" ),
  38. TEXT( "OC_NEED_MEDIA" ),
  39. TEXT( "OC_ABOUT_TO_COMMIT_QUEUE" ),
  40. TEXT( "OC_QUERY_SKIP_PAGE" ),
  41. TEXT( "OC_WIZARD_CREATED" ),
  42. TEXT( "OC_FILE_BUSY" ),
  43. TEXT( "OC_EXTRA_ROUTINES" ),
  44. TEXT( "OC_QUERY_IMAGE_EX" )
  45. };
  46. TCHAR *ocmpage[100] =
  47. {
  48. TEXT("WizPagesWelcome"),
  49. TEXT("WizPagesMode"),
  50. TEXT("WizPagesEarly"),
  51. TEXT("WizPagesPrenet"),
  52. TEXT("WizPagesPostnet"),
  53. TEXT("WizPagesLate"),
  54. TEXT("WizPagesFinal")
  55. };
  56. typedef struct
  57. {
  58. LPCTSTR szComponentName;
  59. LPCTSTR szSubcomponentName;
  60. UINT_PTR Param1;
  61. PVOID Param2;
  62. } OCM_CALLBACK_ARGS, *POCM_CALLBACK_ARGS;
  63. static DWORD UddiOcmPreinitialize ( OCM_CALLBACK_ARGS& args );
  64. static DWORD UddiOcmInitComponent ( OCM_CALLBACK_ARGS& args );
  65. static DWORD UddiOcmChangeSelectionState( OCM_CALLBACK_ARGS& args );
  66. static DWORD UddiOcmInstallUninstall ( OCM_CALLBACK_ARGS& args );
  67. static DWORD UddiOcmRequestPages ( OCM_CALLBACK_ARGS& args );
  68. static DWORD UddiOcmQueryState ( OCM_CALLBACK_ARGS& args );
  69. static DWORD UddiOcmCalcDiskSpace ( OCM_CALLBACK_ARGS& args );
  70. static DWORD UddiOcmQueueUDDIFiles ( OCM_CALLBACK_ARGS& args );
  71. static DWORD UddiOcmQueryStepCount ( OCM_CALLBACK_ARGS& args );
  72. //-----------------------------------------------------------------------------------------
  73. HINSTANCE g_hInstance = NULL;
  74. CUDDIInstall g_uddiComponents;
  75. static TCHAR g_szSetupPath[ MAX_PATH ];
  76. static TCHAR g_szUnattendPath[ MAX_PATH ];
  77. static HINF g_hComponent;
  78. static bool g_bUnattendMode = false;
  79. static bool g_bPerformedCompInstall = false;
  80. //-----------------------------------------------------------------------------------------
  81. BOOL APIENTRY DllMain( HINSTANCE hInstance,
  82. DWORD ul_reason_for_call,
  83. LPVOID lpReserved
  84. )
  85. {
  86. switch (ul_reason_for_call)
  87. {
  88. case DLL_PROCESS_ATTACH:
  89. g_hInstance = hInstance;
  90. g_uddiComponents.SetInstance( hInstance );
  91. ClearLog();
  92. break;
  93. case DLL_THREAD_ATTACH:
  94. case DLL_THREAD_DETACH:
  95. case DLL_PROCESS_DETACH:
  96. break;
  97. }
  98. return TRUE;
  99. }
  100. //-----------------------------------------------------------------------------------------
  101. DWORD __stdcall OcEntry(
  102. IN LPCTSTR szComponentName,
  103. IN LPCTSTR szSubcomponentName,
  104. IN UINT uMsgID,
  105. IN UINT_PTR Param1,
  106. IN OUT PVOID Param2
  107. )
  108. {
  109. if( g_bUnattendMode )
  110. return NO_ERROR;
  111. DWORD dwOcEntryReturn = 0;
  112. OCM_CALLBACK_ARGS args;
  113. args.Param1 = Param1;
  114. args.Param2 = Param2;
  115. args.szComponentName = szComponentName;
  116. args.szSubcomponentName = szSubcomponentName;
  117. MyOutputDebug( TEXT("--- Component: %15s Subcomponent: %15s Function: %s"),
  118. szComponentName,
  119. NULL == szSubcomponentName ? TEXT( "(NULL) ") : szSubcomponentName,
  120. ocmmsg[uMsgID]);
  121. switch(uMsgID)
  122. {
  123. case OC_PREINITIALIZE:
  124. dwOcEntryReturn = UddiOcmPreinitialize( args );
  125. break;
  126. case OC_INIT_COMPONENT:
  127. dwOcEntryReturn = UddiOcmInitComponent( args );
  128. break;
  129. case OC_CALC_DISK_SPACE:
  130. dwOcEntryReturn = UddiOcmCalcDiskSpace( args );
  131. break;
  132. case OC_QUERY_STEP_COUNT:
  133. dwOcEntryReturn = UddiOcmQueryStepCount( args );
  134. break;
  135. case OC_QUEUE_FILE_OPS:
  136. dwOcEntryReturn = UddiOcmQueueUDDIFiles( args );
  137. break;
  138. case OC_ABOUT_TO_COMMIT_QUEUE:
  139. break;
  140. case OC_COMPLETE_INSTALLATION:
  141. dwOcEntryReturn = UddiOcmInstallUninstall( args );
  142. break;
  143. case OC_WIZARD_CREATED:
  144. break;
  145. case OC_QUERY_STATE:
  146. dwOcEntryReturn = UddiOcmQueryState( args );
  147. break;
  148. case OC_REQUEST_PAGES:
  149. dwOcEntryReturn = UddiOcmRequestPages( args );
  150. break;
  151. case OC_QUERY_SKIP_PAGE:
  152. break;
  153. case OC_QUERY_CHANGE_SEL_STATE:
  154. dwOcEntryReturn = UddiOcmChangeSelectionState( args );
  155. break;
  156. default:
  157. break;
  158. }
  159. return dwOcEntryReturn;
  160. }
  161. //-----------------------------------------------------------------------------------------
  162. static DWORD UddiOcmPreinitialize( OCM_CALLBACK_ARGS& args )
  163. {
  164. DWORD dwOcEntryReturn = 0;
  165. #ifdef UNICODE
  166. dwOcEntryReturn = OCFLAG_UNICODE;
  167. #else
  168. dwOcEntryReturn = OCFLAG_ANSI;
  169. #endif
  170. return dwOcEntryReturn;
  171. }
  172. //-----------------------------------------------------------------------------------------
  173. static DWORD UddiOcmInitComponent( OCM_CALLBACK_ARGS& args )
  174. {
  175. PSETUP_INIT_COMPONENT pSetupInitComp = (PSETUP_INIT_COMPONENT) args.Param2;
  176. SETUP_DATA setupData = pSetupInitComp->SetupData;
  177. //
  178. // see if we are in unattended mode
  179. //
  180. if( SETUPOP_BATCH & setupData.OperationFlags )
  181. {
  182. _tcscpy( g_szUnattendPath, pSetupInitComp->SetupData.UnattendFile );
  183. g_bUnattendMode = true;
  184. Log( _T("*** UDDI does not install in unattended mode ***") );
  185. return NO_ERROR;
  186. }
  187. //
  188. // grab the handle to the uddi.inf file
  189. //
  190. g_hComponent = pSetupInitComp->ComponentInfHandle;
  191. //
  192. // save a copy of the source path (to the CDROM drive)
  193. //
  194. // MessageBox(NULL, TEXT( "attach debugger" ), TEXT( "debug uddi" ), MB_OK);
  195. _tcscpy( g_szSetupPath, pSetupInitComp->SetupData.SourcePath );
  196. //
  197. // save a copy of the callback pointers into the OCM
  198. //
  199. COCMCallback::SetOCMRoutines( &pSetupInitComp->HelperRoutines );
  200. //
  201. // if the db is already installed, the db instance name is stored in the registry.
  202. // get it and set it for use by the web installer (if the user chooses to install the web component).
  203. //
  204. if( g_uddiComponents.IsInstalled( UDDI_DB ) )
  205. {
  206. CDBInstance dbinstances;
  207. TCHAR szInstanceName[ 20 ];
  208. ULONG uLen = 20;
  209. bool bIsClustered = false;
  210. if( dbinstances.GetUDDIDBInstanceName( NULL, szInstanceName, &uLen, &bIsClustered ) )
  211. g_uddiComponents.SetDBInstanceName( NULL, szInstanceName, UDDI_NOT_INSTALLING_MSDE, bIsClustered );
  212. }
  213. //
  214. // Finally, check the OS flavor (Enterprise, Datacenter etc.)
  215. //
  216. g_uddiComponents.DetectOSFlavor();
  217. Log( _T( "OS Flavor Mask as reported by WMI: %#x" ), g_uddiComponents.GetOSSuiteMask() );
  218. return NO_ERROR;
  219. }
  220. //-----------------------------------------------------------------------------------------
  221. //
  222. // this function is called for each component and subcomponent
  223. //
  224. static DWORD UddiOcmQueryState( OCM_CALLBACK_ARGS& args )
  225. {
  226. if( args.szSubcomponentName && args.Param1 == OCSELSTATETYPE_ORIGINAL )
  227. {
  228. if ( g_uddiComponents.IsInstalled( (PTCHAR) args.szSubcomponentName ) )
  229. {
  230. MyOutputDebug( TEXT( "Reporting that component %s is ON"), args.szSubcomponentName );
  231. return SubcompOn;
  232. }
  233. else
  234. {
  235. MyOutputDebug( TEXT( "Reporting that component %s is OFF"), args.szSubcomponentName );
  236. return SubcompOff;
  237. }
  238. }
  239. return SubcompUseOcManagerDefault;
  240. }
  241. //-----------------------------------------------------------------------------------------
  242. //
  243. // This function is called for each component and subcomponent
  244. // We need to verify that IIS, if installed is not setup for IIS 5 compatability mode.
  245. // If so we will display a message to the user and uncheck the web component portion of the
  246. // install.
  247. //
  248. static DWORD UddiOcmChangeSelectionState( OCM_CALLBACK_ARGS& args )
  249. {
  250. bool bSelected = false;
  251. COCMCallback::QuerySelectionState( args.szSubcomponentName, bSelected );
  252. MyOutputDebug( TEXT( "requested selection state=%08x, flags=%08x, selected=%d" ), args.Param1 , args.Param2, bSelected );
  253. //
  254. // ignore if the component name is null
  255. //
  256. if( NULL == args.szSubcomponentName )
  257. return 0;
  258. //
  259. // ignore if this is the parent component
  260. //
  261. if( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddiservices" ) ) )
  262. return 1;
  263. //
  264. // if the user has selected the web component to install AND
  265. // IIS is set to "IIS 5.0 Application Compatibility Mode" then
  266. // raise an error and don't allow it
  267. //
  268. if( 1 == args.Param1 &&
  269. ( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddiweb" ) ) ||
  270. ( 0 == _tcscmp( args.szSubcomponentName, TEXT( "uddicombo" ) ) ) ) )
  271. {
  272. static bool bSkipOnce = false;
  273. //
  274. // if the web component was selected from the parent, then suppress one
  275. // of the two error messages (it gets called twice for some reason)
  276. //
  277. if( OCQ_DEPENDENT_SELECTION & ( DWORD_PTR ) args.Param2 )
  278. {
  279. bSkipOnce = !bSkipOnce;
  280. if( bSkipOnce )
  281. return 0;
  282. }
  283. bool bIsIIS5CompatMode;
  284. TCHAR szMsg[ 500 ];
  285. TCHAR szTitle[ 50 ];
  286. LoadString( g_hInstance, IDS_TITLE, szTitle, sizeof( szTitle ) / sizeof( TCHAR ) );
  287. HRESULT hr = IsIIS5CompatMode( &bIsIIS5CompatMode );
  288. if( SUCCEEDED( hr ) )
  289. {
  290. if( bIsIIS5CompatMode )
  291. {
  292. //
  293. // cannot install web component when IIS is in 5.0 compat mode
  294. // raise error and do not accept the change
  295. //
  296. LoadString( g_hInstance, IDS_IIS_ISOLATION_MODE_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
  297. MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
  298. Log( szMsg );
  299. return 0;
  300. }
  301. }
  302. else
  303. {
  304. //
  305. // error occurred getting the app compat mode setting.
  306. // tell the user why and tell OCM that we do not accept the change
  307. //
  308. // REGDB_E_CLASSNOTREG, CLASS_E_NOAGGREGATION, or E_NOINTERFACE
  309. //
  310. if( REGDB_E_CLASSNOTREG == hr )
  311. {
  312. Log( TEXT( "IIS is not installed on this machine" ) );
  313. // This is ok 'cause IIS gets installed if the UDDI web component is selected.
  314. }
  315. else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE( hr ) )
  316. {
  317. Log( TEXT( "WWW Services not installed on this machine." ) );
  318. // This is ok 'cause WWW Services installed if the UDDI web component is selected.
  319. }
  320. else if( ERROR_SERVICE_DISABLED == HRESULT_CODE( hr ) )
  321. {
  322. LoadString( g_hInstance, IDS_IIS_SERVICE_DISABLED, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
  323. MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
  324. Log( szMsg );
  325. return 0;
  326. }
  327. else
  328. {
  329. LoadString( g_hInstance, IDS_IIS_UNKNOWN_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) );
  330. MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONWARNING );
  331. Log( szMsg );
  332. return 0;
  333. }
  334. }
  335. }
  336. return 1; // indicates that this state change was ACCEPTED
  337. }
  338. //-----------------------------------------------------------------------------------------
  339. static DWORD UddiOcmRequestPages( OCM_CALLBACK_ARGS& args )
  340. {
  341. DWORD dwOcEntryReturn = NO_ERROR;
  342. dwOcEntryReturn = AddUDDIWizardPages(
  343. args.szComponentName,
  344. (WizardPagesType) args.Param1,
  345. (PSETUP_REQUEST_PAGES) args.Param2 );
  346. return dwOcEntryReturn; // return the number of pages that was added
  347. }
  348. //-----------------------------------------------------------------------------------------
  349. static DWORD UddiOcmInstallUninstall( OCM_CALLBACK_ARGS& args )
  350. {
  351. DWORD dwRet = ERROR_SUCCESS;
  352. //
  353. // for the root component OR if someone is trying
  354. // to install us unattended, simply return
  355. //
  356. if( NULL == args.szSubcomponentName )
  357. return ERROR_SUCCESS;
  358. //
  359. // uddiweb "needs" iis, as commanded in uddi.inf, and the only thing we know
  360. // for sure about OCM install order is that OCM will install IIS before it
  361. // installs uddiweb, so let's delay installing all the UDDI components until
  362. // the OCM calls for the installation of uddiweb, 'cause that way we can be sure
  363. // that IIS is already installed. No, that's not a hack.
  364. //
  365. //
  366. // All installation/uninstallation is deferred until this component is referenced
  367. // This ensures that the IIS dependency is in place prior to installation of any of our
  368. // components.
  369. //
  370. // TODO: Review whether this is necessary anymore. We now declare proper dependencies on netfx (.NET Framework)
  371. // that should make this synchronization unecessary.
  372. //
  373. if( !g_bPerformedCompInstall )
  374. {
  375. g_bPerformedCompInstall = true;
  376. Log( _T("Installing...") );
  377. //
  378. // Even though this method name is Install it handles both install and
  379. // uninstall.
  380. //
  381. dwRet = g_uddiComponents.Install();
  382. //
  383. // if we need a reboot, tell the OCM
  384. //
  385. if( ERROR_SUCCESS_REBOOT_REQUIRED == dwRet )
  386. {
  387. COCMCallback::SetReboot();
  388. //
  389. // mute the error, as it's actualy a "success with info" code
  390. //
  391. dwRet = ERROR_SUCCESS;
  392. }
  393. else if( ERROR_SUCCESS != dwRet )
  394. {
  395. TCHAR szWindowsDirectory[ MAX_PATH + 1 ];
  396. if( 0 == GetWindowsDirectory( szWindowsDirectory, MAX_PATH + 1 ) )
  397. {
  398. return GetLastError();
  399. }
  400. tstring cLogFile = szWindowsDirectory;
  401. cLogFile.append( TEXT( "\\" ) );
  402. cLogFile.append( UDDI_SETUP_LOG );
  403. TCHAR szMsg[ 500 ];
  404. TCHAR szTitle[ 50 ];
  405. if( !LoadString( g_hInstance, IDS_INSTALL_ERROR, szMsg, sizeof( szMsg ) / sizeof( TCHAR ) ) )
  406. return GetLastError();
  407. if( !LoadString( g_hInstance, IDS_TITLE, szTitle, sizeof( szTitle ) / sizeof( TCHAR ) ) )
  408. return GetLastError();
  409. tstring cMsg = szMsg;
  410. cMsg.append( cLogFile );
  411. MessageBox( NULL, cMsg.c_str(), szTitle, MB_OK | MB_ICONWARNING | MB_TOPMOST );
  412. }
  413. else
  414. {
  415. //
  416. // if we installed the Web components only, show the post-install notes
  417. //
  418. if( g_uddiComponents.IsInstalling( UDDI_WEB ) || g_uddiComponents.IsInstalling( UDDI_DB ) )
  419. {
  420. HINSTANCE hInstance = ShellExecute(
  421. GetActiveWindow(),
  422. TEXT( "open" ),
  423. TEXT( "postinstall.htm" ),
  424. NULL,
  425. TEXT( "\\inetpub\\uddi" ),
  426. SW_SHOWNORMAL);
  427. }
  428. }
  429. }
  430. //
  431. // on the Standard Server, we want to fail the whole installation if one component fails
  432. //
  433. return ERROR_SUCCESS;
  434. }
  435. //-----------------------------------------------------------------------------------------
  436. static DWORD UddiOcmQueryStepCount( OCM_CALLBACK_ARGS& args )
  437. {
  438. //
  439. // if this is the main component, tell it we
  440. // need four steps on the gauge
  441. //
  442. if( NULL == args.szSubcomponentName )
  443. return 4;
  444. return 0;
  445. }
  446. //-----------------------------------------------------------------------------------------
  447. static DWORD UddiOcmQueueUDDIFiles( OCM_CALLBACK_ARGS& args )
  448. {
  449. if( !args.szSubcomponentName )
  450. return 0;
  451. HSPFILEQ hFileQueue = ( HSPFILEQ ) args.Param2;
  452. BOOL bOK = TRUE;
  453. DWORD dwErrCode = 0;
  454. if( g_uddiComponents.IsInstalling( args.szSubcomponentName ) )
  455. {
  456. TCHAR szSectionName[ 100 ];
  457. _stprintf( szSectionName, TEXT( "Install.%s" ), args.szSubcomponentName );
  458. bOK = SetupInstallFilesFromInfSection(
  459. g_hComponent, // handle to the UDDI INF file
  460. NULL, // optional, layout INF handle
  461. hFileQueue, // handle to the file queue
  462. szSectionName, // name of the Install section
  463. NULL, // optional, root path to source files
  464. SP_COPY_NEWER | SP_COPY_NOSKIP // optional, specifies copy behavior
  465. );
  466. }
  467. UDDI_PACKAGE_ID pkgSubcompID = g_uddiComponents.GetPackageID( args.szSubcomponentName );
  468. if( pkgSubcompID == UDDI_DB || pkgSubcompID == UDDI_COMBO )
  469. {
  470. if( g_uddiComponents.IsInstalling( UDDI_MSDE ) )
  471. {
  472. //
  473. // copy over the msde msi file, it is stored as a different
  474. // name, and this will rename as it copies (and decomp if needed)
  475. //
  476. if( bOK )
  477. {
  478. //
  479. // this will copy over the cab file but NOT decomp the file.
  480. // the cab file MUST be named sqlrun.cab on the cd, because
  481. // the SP_COPY_NODECOMP flag foils the renaming scheme built
  482. // into the setup api's
  483. //
  484. bOK = SetupInstallFilesFromInfSection(
  485. g_hComponent, // handle to the INF file
  486. NULL, // optional, layout INF handle
  487. hFileQueue, // handle to the file queue
  488. TEXT( "Install.MSDE" ), // name of the Install section
  489. NULL, // optional, root path to source files
  490. SP_COPY_NEWER | SP_COPY_NODECOMP | SP_COPY_NOSKIP // optional, specifies copy behavior
  491. );
  492. }
  493. }
  494. }
  495. if( !bOK )
  496. {
  497. dwErrCode = GetLastError();
  498. LogError( TEXT( "Error copying the UDDI files from the Windows CD:" ), dwErrCode );
  499. }
  500. return dwErrCode;
  501. }
  502. //-----------------------------------------------------------------------------------------
  503. static DWORD UddiOcmCalcDiskSpace( OCM_CALLBACK_ARGS& args )
  504. {
  505. BOOL bOK;
  506. HDSKSPC hDiskSpace = ( HDSKSPC ) args.Param2;
  507. tstring cSection = TEXT( "Install." );
  508. cSection += args.szSubcomponentName;
  509. if( args.Param1 )
  510. {
  511. //
  512. // add component
  513. //
  514. bOK = SetupAddInstallSectionToDiskSpaceList(
  515. hDiskSpace,
  516. g_hComponent,
  517. NULL,
  518. cSection.c_str(),
  519. 0, 0);
  520. }
  521. else
  522. {
  523. //
  524. // remove component
  525. //
  526. bOK = SetupRemoveInstallSectionFromDiskSpaceList(
  527. hDiskSpace,
  528. g_hComponent,
  529. NULL,
  530. cSection.c_str(),
  531. 0, 0);
  532. }
  533. if( !bOK )
  534. {
  535. LogError( TEXT( "Error adding disk space requirements" ), GetLastError() ) ;
  536. }
  537. return NO_ERROR;
  538. }