Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

809 lines
20 KiB

  1. /****************************************************************************
  2. Copyright (c) Microsoft Corporation 1998
  3. All rights reserved
  4. ***************************************************************************/
  5. #include "pch.h"
  6. #include "utils.h"
  7. #include "callback.h"
  8. #include "welcome.h"
  9. #include "compat.h"
  10. #include "serverdlg.h"
  11. #include "directory.h"
  12. #include "sif.h"
  13. #include "complete.h"
  14. #include "summary.h"
  15. #include "tasks.h"
  16. #include "setupdlg.h"
  17. #include "appldlg.h"
  18. #include "setup.h"
  19. #include "errorlog.h"
  20. // Must have this...
  21. extern "C" {
  22. #include <sysprep_.h>
  23. #include <spapip.h>
  24. //
  25. // SYSPREP globals
  26. //
  27. BOOL NoSidGen = FALSE; // always generate new SID
  28. BOOL PnP = FALSE; // always PNP the system
  29. BOOL FactoryPreinstall = FALSE; // NOT a Factory Pre-Install case
  30. BOOL bMiniSetup = TRUE; // Run Mini-Setup, not MSOOBE
  31. HINSTANCE ghInstance = NULL; // Global instance handle
  32. }
  33. DEFINE_MODULE("RIPREP");
  34. // Globals
  35. HINSTANCE g_hinstance = NULL;
  36. WCHAR g_ServerName[ MAX_PATH ];
  37. WCHAR g_MirrorDir[ MAX_PATH ];
  38. WCHAR g_Language[ MAX_PATH ];
  39. WCHAR g_ImageName[ MAX_PATH ];
  40. WCHAR g_Architecture[ 16 ];
  41. WCHAR g_Description[ REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT ];
  42. WCHAR g_HelpText[ REMOTE_INSTALL_MAX_HELPTEXT_CHAR_COUNT ];
  43. WCHAR g_SystemRoot[ MAX_PATH ] = L"Mirror1\\userdata\\winnt";
  44. WCHAR g_WinntDirectory[ MAX_PATH ];
  45. WCHAR g_HalName[32];
  46. WCHAR g_ProductId[4];
  47. DWORD g_dwWinntDirLength;
  48. BOOLEAN g_fQuietFlag = FALSE;
  49. BOOLEAN g_fErrorOccurred = FALSE;
  50. BOOLEAN g_fRebootOnExit = FALSE;
  51. DWORD g_dwLogFileStartLow;
  52. DWORD g_dwLogFileStartHigh;
  53. PCRITICAL_SECTION g_pLogCritSect = NULL;
  54. HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  55. OSVERSIONINFO OsVersion;
  56. BOOLEAN g_CommandLineArgsValid = TRUE;
  57. BOOLEAN g_OEMDesktop = FALSE;
  58. // Constants
  59. #define NUMBER_OF_PAGES 15
  60. #define SMALL_BUFFER_SIZE 256
  61. #define OPTION_UNKNOWN 0
  62. #define OPTION_DEBUG 1
  63. #define OPTION_FUNC 2
  64. #define OPTION_QUIET 3
  65. #define OPTION_PNP 4
  66. #define OPTION_OEMDESKTOP 5
  67. //
  68. // Adds a page to the dialog.
  69. //
  70. void
  71. AddPage(
  72. LPPROPSHEETHEADER ppsh,
  73. UINT id,
  74. DLGPROC pfn,
  75. UINT idTitle,
  76. UINT idSubtitle )
  77. {
  78. PROPSHEETPAGE psp;
  79. TCHAR szTitle[ SMALL_BUFFER_SIZE ];
  80. TCHAR szSubTitle[ SMALL_BUFFER_SIZE ];
  81. ZeroMemory( &psp, sizeof(psp) );
  82. psp.dwSize = sizeof(psp);
  83. psp.dwFlags = PSP_DEFAULT | PSP_USETITLE;
  84. if ( id == IDD_WELCOME || id == IDD_COMPLETE )
  85. {
  86. psp.dwFlags |= PSP_HIDEHEADER;
  87. }
  88. else
  89. {
  90. psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  91. if ( idTitle )
  92. {
  93. DWORD dw;
  94. dw = LoadString( g_hinstance, idTitle, szTitle, ARRAYSIZE(szTitle) );
  95. Assert( dw );
  96. psp.pszHeaderTitle = szTitle;
  97. }
  98. else
  99. {
  100. psp.pszHeaderTitle = NULL;
  101. }
  102. if ( idSubtitle )
  103. {
  104. DWORD dw;
  105. dw = LoadString( g_hinstance, idSubtitle , szSubTitle, ARRAYSIZE(szSubTitle) );
  106. Assert( dw );
  107. psp.pszHeaderSubTitle = szSubTitle;
  108. }
  109. else
  110. {
  111. psp.pszHeaderSubTitle = NULL;
  112. }
  113. }
  114. psp.pszTitle = MAKEINTRESOURCE( IDS_APPNAME );
  115. psp.hInstance = ppsh->hInstance;
  116. psp.pszTemplate = MAKEINTRESOURCE(id);
  117. psp.pfnDlgProc = pfn;
  118. ppsh->phpage[ ppsh->nPages ] = CreatePropertySheetPage( &psp );
  119. if ( ppsh->phpage[ ppsh->nPages ] )
  120. ppsh->nPages++;
  121. }
  122. //
  123. // Creates the UI pages and kicks off the property sheet.
  124. //
  125. HRESULT
  126. WizardPages( )
  127. {
  128. TraceFunc( "WizardPages( )\n" );
  129. HRESULT hr;
  130. HPROPSHEETPAGE rPages[ NUMBER_OF_PAGES ];
  131. PROPSHEETHEADER pshead;
  132. INT_PTR iResult;
  133. ZeroMemory( &pshead, sizeof(pshead) );
  134. pshead.dwSize = sizeof(pshead);
  135. pshead.dwFlags = PSH_WIZARD97 | PSH_PROPTITLE | PSH_USEHICON
  136. | PSH_WATERMARK | PSH_HEADER;
  137. pshead.hInstance = g_hinstance;
  138. pshead.pszCaption = MAKEINTRESOURCE( IDS_APPNAME );
  139. pshead.phpage = rPages;
  140. pshead.pszbmWatermark = MAKEINTRESOURCE( IDB_TITLEPAGE );
  141. pshead.pszbmHeader = MAKEINTRESOURCE( IDB_HEADER );
  142. AddPage( &pshead, IDD_WELCOME, WelcomeDlgProc, 0, 0 );
  143. AddPage( &pshead, IDD_SERVER, ServerDlgProc, IDS_SERVER_TITLE, IDS_SERVER_SUBTITLE );
  144. AddPage( &pshead, IDD_OSDIRECTORY, DirectoryDlgProc, IDS_DIRECTORY_TITLE, IDS_DIRECTORY_SUBTITLE );
  145. AddPage( &pshead, IDD_DEFAULTSIF, SIFDlgProc, IDS_SIF_TITLE, IDS_SIF_SUBTITLE );
  146. AddPage( &pshead, IDD_COMPAT, CompatibilityDlgProc, IDS_COMPAT_TITLE, IDS_COMPAT_SUBTITLE );
  147. AddPage( &pshead, IDD_STOPSVCWRN, StopServiceWrnDlgProc, IDS_STOPSVC_TITLE, IDS_STOPSVC_SUBTITLE );
  148. AddPage( &pshead, IDD_STOPSVC, DoStopServiceDlgProc, IDS_STOPSVC_TITLE, IDS_STOPSVC_SUBTITLE );
  149. AddPage( &pshead, IDD_APPLICATIONS_RUNNING, ApplicationDlgProc, IDS_APPLICATION_TITLE, IDS_APPLICATION_SUBTITLE );
  150. AddPage( &pshead, IDD_SUMMARY, SummaryDlgProc, IDS_FINISH_TITLE, IDS_FINISH_SUBTITLE );
  151. AddPage( &pshead, IDD_COMPLETE, CompleteDlgProc, 0, 0 );
  152. iResult = PropertySheet( &pshead );
  153. switch(iResult)
  154. {
  155. case 0:
  156. hr = E_FAIL;
  157. break;
  158. default:
  159. hr = S_OK;
  160. break;
  161. }
  162. RETURN(hr);
  163. }
  164. //
  165. // IsWhiteSpace()
  166. //
  167. BOOL
  168. IsWhiteSpace( WCHAR ch )
  169. {
  170. if ( ch <=32 )
  171. return TRUE;
  172. return FALSE;
  173. }
  174. //
  175. // CheckWhichOption()
  176. DWORD
  177. CheckWhichOption(
  178. LPWSTR pszOption )
  179. {
  180. WCHAR szOptions[ 32 ];
  181. DWORD dw;
  182. #ifdef DEBUG
  183. if ( StrCmpNI( pszOption, L"debug", 5 ) == 0 )
  184. return OPTION_DEBUG;
  185. if ( StrCmpNI( pszOption, L"func", 4 ) == 0 )
  186. return OPTION_FUNC;
  187. #endif
  188. // Check for quiet flag
  189. dw = LoadString( g_hinstance, IDS_QUIET, szOptions, ARRAYSIZE( szOptions ) );
  190. Assert( dw );
  191. if ( StrCmpNI( pszOption, szOptions, wcslen(szOptions) ) == 0 )
  192. return OPTION_QUIET;
  193. if ( StrCmpNI( pszOption, L"PNP", 3 ) == 0 )
  194. return OPTION_PNP;
  195. //
  196. // By default, the Setup guys are going to remove all the desktop icons
  197. // during MiniSetup. We'd like to keep those around for riprep installs,
  198. // so by default, we're going to set some registry keys to keep the
  199. // user's desktop around. However, if the user gives us a -OEMDesktop flag,
  200. // then don't set these flags and allow the desktop to be cleaned up.
  201. //
  202. if( StrCmpNI( pszOption, L"OEMDesktop", 10 ) == 0 ) {
  203. return OPTION_OEMDESKTOP;
  204. }
  205. return OPTION_UNKNOWN;
  206. }
  207. //
  208. // ParseCommandLine()
  209. //
  210. void
  211. ParseCommandLine( LPWSTR lpCmdLine )
  212. {
  213. WCHAR szPath[ MAX_PATH ];
  214. LPWSTR psz = NULL;
  215. BOOL endOfCommandLine;
  216. //
  217. // Check to see if the command line has the servername on it.
  218. //
  219. g_ServerName[0] = L'\0';
  220. if ( lpCmdLine[0] == L'\\' && lpCmdLine[1] == L'\\' )
  221. {
  222. psz = StrChr( &lpCmdLine[2], L'\\' );
  223. if ( psz && psz != &lpCmdLine[2] )
  224. {
  225. ZeroMemory( g_ServerName, sizeof(g_ServerName) );
  226. wcsncpy( g_ServerName, &lpCmdLine[2], (DWORD)(psz - &lpCmdLine[2]) );
  227. }
  228. }
  229. // See if it is a quoted path as well
  230. if ( lpCmdLine[0] == L'\"' && lpCmdLine[1] == L'\\' && lpCmdLine[2] == L'\\' )
  231. {
  232. psz = StrChr( &lpCmdLine[3], L'\\' );
  233. if ( psz && psz != &lpCmdLine[3] )
  234. {
  235. ZeroMemory( g_ServerName, sizeof(g_ServerName) );
  236. wcsncpy( g_ServerName, &lpCmdLine[3], (DWORD)(psz - &lpCmdLine[3]) );
  237. }
  238. }
  239. // See if there is a whitespace break
  240. psz = StrChr( lpCmdLine, L' ' );
  241. if ( psz )
  242. { // yes... search backwards from the whitespace for a slash.
  243. psz = StrRChr( lpCmdLine, psz, L'\\' );
  244. }
  245. else
  246. { // no... search backwards from the end of the command line for a slash.
  247. psz = StrRChr( lpCmdLine, &lpCmdLine[ wcslen( lpCmdLine ) ], L'\\' );
  248. }
  249. // Found the starting path, now try to set the current directory
  250. // to this.
  251. if ( psz )
  252. {
  253. ZeroMemory( szPath, sizeof(szPath) );
  254. wcsncpy( szPath, lpCmdLine, (DWORD)(psz - lpCmdLine) );
  255. // If quoted, add a trailing quote to the path
  256. if ( lpCmdLine[0] == L'\"' ) {
  257. wcscat( szPath, L"\"" );
  258. }
  259. DebugMsg( "Set CD to %s\n", szPath );
  260. SetCurrentDirectory( szPath );
  261. }
  262. // Parse for command line arguments
  263. if (!psz) {
  264. psz = lpCmdLine;
  265. }
  266. endOfCommandLine = FALSE;
  267. while (!endOfCommandLine && (*psz != L'\0'))
  268. {
  269. if ( *psz == '/' || *psz == '-' )
  270. {
  271. LPWSTR pszStartOption = ++psz;
  272. while (*psz && !IsWhiteSpace( *psz ) )
  273. psz++;
  274. if (*psz == L'\0') {
  275. endOfCommandLine = TRUE;
  276. } else {
  277. *psz = '\0'; // terminate
  278. }
  279. switch ( CheckWhichOption( pszStartOption ) )
  280. {
  281. #ifdef DEBUG
  282. case OPTION_DEBUG:
  283. g_dwTraceFlags |= 0x80000000; // not defined, but not zero either
  284. break;
  285. case OPTION_FUNC:
  286. g_dwTraceFlags |= TF_FUNC;
  287. break;
  288. #endif
  289. case OPTION_QUIET:
  290. g_fQuietFlag = TRUE;
  291. break;
  292. case OPTION_PNP:
  293. PnP = !PnP; // toggle
  294. break;
  295. case OPTION_OEMDESKTOP:
  296. g_OEMDesktop = TRUE; // The user want to clean the desktop.
  297. break;
  298. case OPTION_UNKNOWN:
  299. MessageBoxFromMessage(
  300. NULL,
  301. MSG_USAGE,
  302. FALSE,
  303. MAKEINTRESOURCE(IDS_APPNAME),
  304. MB_OK );
  305. g_CommandLineArgsValid = FALSE;
  306. }
  307. }
  308. psz++;
  309. }
  310. }
  311. //
  312. // GetWorkstationLanguage( )
  313. //
  314. DWORD
  315. GetWorkstationLanguage( )
  316. {
  317. TraceFunc( "GetWorkstationLanguage( )\n" );
  318. DWORD dwErr = ERROR_SUCCESS;
  319. LANGID langID = GetSystemDefaultLangID( );
  320. UINT uResult = GetLocaleInfo( langID, LOCALE_SENGLANGUAGE, g_Language, ARRAYSIZE(g_Language) );
  321. if ( uResult == 0 )
  322. {
  323. DWORD dw;
  324. dwErr = GetLastError( );
  325. dw = LoadString( g_hinstance, IDS_DEFAULT_LANGUAGE, g_Language, ARRAYSIZE(g_Language));
  326. Assert( dw );
  327. }
  328. RETURN(dwErr);
  329. }
  330. BOOLEAN
  331. GetInstalledProductType(
  332. PDWORD Type,
  333. PDWORD Mask );
  334. //
  335. // GetProductSKUNumber
  336. //
  337. DWORD
  338. GetProductSKUNumber(
  339. VOID
  340. )
  341. /*++
  342. Routine Description:
  343. Determine SKU number of installation, which should match the
  344. producttype value in txtsetup.sif
  345. Arguments:
  346. none.
  347. Return value:
  348. product sku number. if it fails, we set the return value to 0, which
  349. is the sku code for professional.
  350. --*/
  351. {
  352. TraceFunc( "GetProductSKUNumber( )\n" );
  353. DWORD ProductType, ProductSuiteMask;
  354. if (!GetInstalledProductType( &ProductType, &ProductSuiteMask )) {
  355. return 0;
  356. }
  357. if (ProductType == VER_NT_SERVER) {
  358. if (ProductSuiteMask & VER_SUITE_DATACENTER) {
  359. return 3;
  360. }
  361. if (ProductSuiteMask & VER_SUITE_ENTERPRISE) {
  362. return 2;
  363. }
  364. return 1;
  365. }
  366. if (ProductSuiteMask & VER_SUITE_PERSONAL) {
  367. return 4;
  368. }
  369. return 0;
  370. }
  371. //
  372. // GetHalName( )
  373. //
  374. DWORD
  375. GetHalName(
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. Determine the actual name of the HAL running on the system.
  381. The actual name of the hal is stored in the originalfilename
  382. in the version resource.
  383. Arguments:
  384. none.
  385. Return value:
  386. Win32 error code indicating outcome.
  387. --*/
  388. {
  389. TraceFunc( "GetHalName( )\n" );
  390. DWORD dwErr = ERROR_GEN_FAILURE;
  391. WCHAR HalPath[MAX_PATH];
  392. DWORD VersionHandle;
  393. DWORD FileVersionInfoSize;
  394. PVOID VersionInfo = NULL;
  395. DWORD *Language,LanguageSize;
  396. WCHAR OriginalFileNameString[64];
  397. PWSTR ActualHalName;
  398. //
  399. // the hal is in system32 directory, build a path to it.
  400. //
  401. if (!GetSystemDirectory(HalPath,ARRAYSIZE(HalPath))) {
  402. dwErr = GetLastError();
  403. goto exit;
  404. }
  405. wcscat(HalPath, L"\\hal.dll" );
  406. //
  407. // you must call GetFileVersionInfoSize,GetFileVersionInfo before
  408. // you can call VerQueryValue()
  409. //
  410. FileVersionInfoSize = GetFileVersionInfoSize(HalPath, &VersionHandle);
  411. if (FileVersionInfoSize == 0) {
  412. goto exit;
  413. }
  414. VersionInfo = LocalAlloc( LPTR, FileVersionInfoSize );
  415. if (VersionInfo == NULL) {
  416. goto exit;
  417. }
  418. if (!GetFileVersionInfo(
  419. HalPath,
  420. 0, //ignored
  421. FileVersionInfoSize,
  422. VersionInfo)) {
  423. goto exit;
  424. }
  425. //
  426. // ok, get the language of the file so we can look in the correct
  427. // StringFileInfo section for the file name
  428. //
  429. if (!VerQueryValue(
  430. VersionInfo,
  431. L"\\VarFileInfo\\Translation",
  432. (LPVOID*)&Language,
  433. (PUINT)&LanguageSize)) {
  434. goto exit;
  435. }
  436. wsprintf(
  437. OriginalFileNameString,
  438. L"\\StringFileInfo\\%04x%04x\\OriginalFilename",
  439. LOWORD(*Language),
  440. HIWORD(*Language));
  441. //
  442. // now retreive the actual OriginalFilename.
  443. //
  444. if (!VerQueryValue(
  445. VersionInfo,
  446. OriginalFileNameString,
  447. (LPVOID*)&ActualHalName,
  448. (PUINT)&LanguageSize)) {
  449. goto exit;
  450. }
  451. //
  452. // store this off in a global so we can use it later on
  453. //
  454. wcscpy(g_HalName ,ActualHalName);
  455. dwErr = ERROR_SUCCESS;
  456. exit:
  457. if (VersionInfo) {
  458. LocalFree( VersionInfo );
  459. }
  460. RETURN(dwErr);
  461. }
  462. //
  463. // VerifyWorkstation( )
  464. //
  465. BOOL
  466. VerifyWorkstation( )
  467. {
  468. TraceFunc( "VerifyWorkstation( )\n" );
  469. HKEY hkey;
  470. LONG lResult;
  471. WCHAR szProductType[50] = { 0 };
  472. DWORD dwType;
  473. DWORD dwSize = ARRAYSIZE(szProductType);
  474. BOOL fReturn = TRUE; // assume that we are not on NTServer.
  475. // Query the registry for the product type.
  476. lResult = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  477. L"System\\CurrentControlSet\\Control\\ProductOptions",
  478. 0,
  479. KEY_READ,
  480. &hkey);
  481. Assert( lResult == ERROR_SUCCESS );
  482. if ( lResult != ERROR_SUCCESS )
  483. goto Error;
  484. lResult = RegQueryValueEx ( hkey,
  485. L"ProductType",
  486. NULL,
  487. &dwType,
  488. (LPBYTE) szProductType,
  489. &dwSize);
  490. Assert( lResult == ERROR_SUCCESS );
  491. RegCloseKey (hkey);
  492. if (lResult != ERROR_SUCCESS)
  493. goto Error;
  494. if ( StrCmpI( szProductType, L"ServerNT" ) == 0 )
  495. {
  496. fReturn = FALSE; // NT Server
  497. }
  498. if ( StrCmpI( szProductType, L"LanmanNT" ) == 0 )
  499. {
  500. fReturn = FALSE; // NT Server
  501. }
  502. Error:
  503. RETURN(fReturn);
  504. }
  505. //
  506. // CheckUserPermissions( )
  507. //
  508. BOOL
  509. CheckUserPermissions( )
  510. {
  511. TraceFunc( "CheckUserPermissions( )\n" );
  512. if( !pSetupIsUserAdmin()
  513. || !pSetupDoesUserHavePrivilege(SE_SHUTDOWN_NAME)
  514. || !pSetupDoesUserHavePrivilege(SE_BACKUP_NAME)
  515. || !pSetupDoesUserHavePrivilege(SE_RESTORE_NAME)
  516. || !pSetupDoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) {
  517. RETURN(FALSE);
  518. }
  519. RETURN(TRUE);
  520. }
  521. //
  522. // GetProcessorType( )
  523. //
  524. DWORD
  525. GetProcessorType( )
  526. {
  527. TraceFunc( "GetProcessorType( )\n" );
  528. DWORD dwErr = ERROR_INVALID_PARAMETER;
  529. SYSTEM_INFO si;
  530. GetSystemInfo( &si );
  531. switch (si.wProcessorArchitecture)
  532. {
  533. case PROCESSOR_ARCHITECTURE_ALPHA:
  534. wcscpy( g_Architecture, L"Alpha" );
  535. break;
  536. case PROCESSOR_ARCHITECTURE_INTEL:
  537. dwErr = ERROR_SUCCESS;
  538. wcscpy( g_Architecture, L"i386" );
  539. break;
  540. case PROCESSOR_ARCHITECTURE_IA64:
  541. //dwErr = ERROR_SUCCESS;
  542. wcscpy( g_Architecture, L"ia64" );
  543. break;
  544. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  545. default:
  546. break;
  547. }
  548. RETURN(dwErr);
  549. }
  550. //
  551. // WinMain()
  552. //
  553. int APIENTRY
  554. WinMain(
  555. HINSTANCE hInstance,
  556. HINSTANCE hPrevInstance,
  557. LPSTR lpCmdLine,
  558. int nCmdShow)
  559. {
  560. TraceFunc( "WinMain( ... )\n" );
  561. HANDLE hMutex;
  562. HRESULT hr = E_FAIL;
  563. IMIRROR_CALLBACK Callbacks;
  564. HWND hwndTasks = NULL;
  565. LPWSTR pszCommandLine = GetCommandLine( );
  566. BOOL fDC = FALSE;
  567. g_hinstance = hInstance;
  568. ghInstance = hInstance;
  569. INITIALIZE_TRACE_MEMORY_PROCESS;
  570. pSetupInitializeUtils();
  571. // allow only one instance running at a time
  572. hMutex = CreateMutex( NULL, TRUE, L"RIPREP.Mutext");
  573. if (GetLastError() == ERROR_ALREADY_EXISTS)
  574. {
  575. MessageBoxFromStrings( NULL,
  576. IDS_ALREADY_RUNNING_TITLE,
  577. IDS_ALREADY_RUNNING_MESSAGE,
  578. MB_OK | MB_ICONSTOP );
  579. goto Cleanup;
  580. }
  581. // parse command line arguments
  582. ParseCommandLine( pszCommandLine );
  583. if (!g_CommandLineArgsValid) {
  584. goto Cleanup;
  585. }
  586. //
  587. // Gather os version info.
  588. //
  589. OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  590. GetVersionEx(&OsVersion);
  591. // determine the language of the workstation
  592. GetWorkstationLanguage( );
  593. if (ERROR_SUCCESS != GetHalName()) {
  594. MessageBoxFromStrings( NULL, IDS_INVALID_ARCHITECTURE_TITLE, IDS_INVALID_ARCHITECTURE_TEXT, MB_OK );
  595. goto Cleanup;
  596. }
  597. wsprintf( g_ProductId, L"%d", GetProductSKUNumber() );
  598. ProcessCompatibilityData();
  599. // determine the processor type
  600. if ( GetProcessorType( ) != ERROR_SUCCESS )
  601. {
  602. MessageBoxFromStrings( NULL, IDS_INVALID_ARCHITECTURE_TITLE, IDS_INVALID_ARCHITECTURE_TEXT, MB_OK );
  603. goto Cleanup;
  604. }
  605. if ( !CheckUserPermissions( ) )
  606. {
  607. MessageBoxFromStrings( NULL, IDS_MUST_BE_ADMINISTRATOR_TITLE, IDS_MUST_BE_ADMINISTRATOR_TEXT, MB_OK );
  608. goto Cleanup;
  609. }
  610. #if 0
  611. //
  612. // No longer limited to only workstation - adamba 4/6/00
  613. //
  614. if ( !VerifyWorkstation( ) )
  615. {
  616. MessageBoxFromStrings( NULL, IDS_MUST_BE_WORKSTATION_TITLE, IDS_MUST_BE_WORKSTATION_TEXT, MB_OK );
  617. goto Cleanup;
  618. }
  619. #endif
  620. // get the name of the "Winnt" directory
  621. GetEnvironmentVariable( L"windir", g_WinntDirectory, ARRAYSIZE(g_WinntDirectory));
  622. g_dwWinntDirLength = wcslen( g_WinntDirectory );
  623. // setup IMIRROR.DLL callbacks
  624. Callbacks.Context = 0;
  625. Callbacks.ErrorFn = &ConvTestErrorFn;
  626. Callbacks.GetSetupFn = &ConvTestGetSetupFn;
  627. Callbacks.NowDoingFn = &ConvTestNowDoingFn;
  628. Callbacks.FileCreateFn = &ConvTestFileCreateFn;
  629. Callbacks.RegSaveErrorFn = NULL;
  630. Callbacks.ReinitFn = &ConvTestReinitFn;
  631. Callbacks.GetMirrorDirFn = &ConvTestGetMirrorDirFn;
  632. Callbacks.SetSystemDirFn = &ConvTestSetSystemFn;
  633. Callbacks.AddToDoFn = &ConvAddToDoItemFn;
  634. Callbacks.RemoveToDoFn = &ConvRemoveToDoItemFn;
  635. Callbacks.RebootFn = &ConvRebootFn;
  636. IMirrorInitCallback(&Callbacks);
  637. // show property pages
  638. hr = WizardPages( );
  639. if ( hr != S_OK )
  640. goto Cleanup;
  641. // complete tasks... ignore the return code, not important
  642. BeginProcess( hwndTasks );
  643. // Display any errors recorded in the log, unless we are supposed
  644. // to reboot now.
  645. if ( g_fErrorOccurred && !g_fRebootOnExit )
  646. {
  647. HINSTANCE hRichedDLL;
  648. // Make sure the RichEdit control has been initialized.
  649. // Simply LoadLibbing it does this for us.
  650. hRichedDLL = LoadLibrary( L"RICHED32.DLL" );
  651. if ( hRichedDLL != NULL )
  652. {
  653. DialogBox( g_hinstance, MAKEINTRESOURCE( IDD_VIEWERRORS ), g_hMainWindow, ErrorsDlgProc );
  654. FreeLibrary (hRichedDLL);
  655. }
  656. }
  657. Cleanup:
  658. if (g_hCompatibilityInf != INVALID_HANDLE_VALUE) {
  659. SetupCloseInfFile( g_hCompatibilityInf );
  660. }
  661. CleanupCompatibilityData();
  662. if ( hMutex )
  663. CloseHandle( hMutex );
  664. pSetupUninitializeUtils();
  665. UNINITIALIZE_TRACE_MEMORY;
  666. if ( g_fRebootOnExit ) {
  667. (VOID)DoShutdown(TRUE); // TRUE tells it to restart
  668. }
  669. RETURN(hr);
  670. }