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.

738 lines
20 KiB

  1. /****************************************************************************
  2. Copyright (c) Microsoft Corporation 1997-1999
  3. All rights reserved
  4. ***************************************************************************/
  5. #include "pch.h"
  6. #include "dialogs.h"
  7. #include "check.h"
  8. #include "setup.h"
  9. #include "automate.h"
  10. DEFINE_MODULE("Main");
  11. // Globals
  12. HINSTANCE g_hinstance = NULL;
  13. OPTIONS g_Options;
  14. // Command line flags
  15. #define OPTION_UNKNOWN 0x00
  16. #define OPTION_VERSIONINGOVERRIDE 0x01
  17. #define OPTION_DEBUG 0x02
  18. #define OPTION_FUNC 0x03
  19. #define OPTION_CHECK 0x04
  20. #define OPTION_ADD 0x05
  21. #define OPTION_UPGRADE 0x06
  22. #define OPTION_AUTOMATED 0x08
  23. // Constants
  24. #define NUMBER_OF_PAGES 15
  25. //
  26. // Adds a page to the dialog.
  27. //
  28. void
  29. AddPage(
  30. LPPROPSHEETHEADER ppsh,
  31. UINT id,
  32. DLGPROC pfn,
  33. UINT idTitle,
  34. UINT idSubtitle )
  35. {
  36. PROPSHEETPAGE psp;
  37. TCHAR szTitle[ SMALL_BUFFER_SIZE ];
  38. TCHAR szSubTitle[ SMALL_BUFFER_SIZE ];
  39. ZeroMemory( &psp, sizeof(psp) );
  40. psp.dwSize = sizeof(psp);
  41. psp.dwFlags = PSP_DEFAULT | PSP_USETITLE;
  42. if ( id == IDD_WELCOME || id == IDD_WELCOME_ADD || id == IDD_WELCOME_CHECK )
  43. {
  44. psp.dwFlags |= PSP_HIDEHEADER;
  45. }
  46. else
  47. {
  48. psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  49. if ( idTitle )
  50. {
  51. DWORD dw;
  52. dw = LoadString( g_hinstance, idTitle, szTitle, ARRAYSIZE(szTitle) );
  53. Assert( dw );
  54. psp.pszHeaderTitle = szTitle;
  55. }
  56. else
  57. {
  58. psp.pszHeaderTitle = NULL;
  59. }
  60. if ( idSubtitle )
  61. {
  62. DWORD dw;
  63. dw = LoadString( g_hinstance, idSubtitle , szSubTitle, ARRAYSIZE(szSubTitle) );
  64. Assert( dw );
  65. psp.pszHeaderSubTitle = szSubTitle;
  66. }
  67. else
  68. {
  69. psp.pszHeaderSubTitle = NULL;
  70. }
  71. }
  72. psp.pszTitle = g_Options.fCheckServer
  73. ? MAKEINTRESOURCE( IDS_CHECK_SERVER_TITLE)
  74. : MAKEINTRESOURCE( IDS_APPNAME );
  75. psp.hInstance = ppsh->hInstance;
  76. psp.pszTemplate = MAKEINTRESOURCE(id);
  77. psp.pfnDlgProc = pfn;
  78. ppsh->phpage[ ppsh->nPages ] = CreatePropertySheetPage( &psp );
  79. if ( ppsh->phpage[ ppsh->nPages ] )
  80. ppsh->nPages++;
  81. }
  82. //
  83. // Creates the UI pages and kicks off the property sheet.
  84. //
  85. HRESULT
  86. WizardPages( )
  87. {
  88. TraceFunc( "WizardPages( )\n" );
  89. HRESULT hr = S_OK;
  90. HPROPSHEETPAGE rPages[ NUMBER_OF_PAGES ];
  91. PROPSHEETHEADER pshead;
  92. ZeroMemory( &pshead, sizeof(pshead) );
  93. pshead.dwSize = sizeof(pshead);
  94. pshead.dwFlags = PSH_WIZARD97 | PSH_PROPTITLE | PSH_USEHICON
  95. | PSH_WATERMARK | PSH_HEADER;
  96. pshead.hInstance = g_hinstance;
  97. pshead.pszCaption = g_Options.fCheckServer
  98. ? MAKEINTRESOURCE( IDS_CHECK_SERVER_TITLE)
  99. : MAKEINTRESOURCE( IDS_APPNAME );
  100. pshead.phpage = rPages;
  101. pshead.pszbmWatermark = MAKEINTRESOURCE( IDB_TITLEPAGE );
  102. pshead.pszbmHeader = MAKEINTRESOURCE( IDB_HEADER );
  103. AddPage( &pshead, IDD_WELCOME, WelcomeDlgProc, 0, 0 );
  104. AddPage( &pshead, IDD_WELCOME_ADD, AddWelcomeDlgProc, 0, 0 );
  105. AddPage( &pshead, IDD_WELCOME_CHECK, CheckWelcomeDlgProc, 0, 0 );
  106. AddPage( &pshead, IDD_EXAMINING_SERVER, ExamineServerDlgProc, IDS_EXAMINING_TITLE, IDS_EXAMINING_SUBTITLE );
  107. AddPage( &pshead, IDD_INTELLIMIRRORROOT, IntelliMirrorRootDlgProc, IDS_INTELLIMIRRORROOT_TITLE, IDS_INTELLIMIRRORROOT_SUBTITLE );
  108. AddPage( &pshead, IDD_SCP, SCPDlgProc, IDS_SCP_TITLE, IDS_SCP_SUBTITLE );
  109. AddPage( &pshead, IDD_OPTIONS, OptionsDlgProc, IDS_OPTIONS_TITLE, IDS_OPTIONS_SUBTITLE );
  110. AddPage( &pshead, IDD_IMAGESOURCE, ImageSourceDlgProc, IDS_IMAGESOURCE_TITLE, IDS_IMAGESOURCE_SUBTITLE );
  111. AddPage( &pshead, IDD_LANGUAGE, LanguageDlgProc, IDS_LANGUAGE_TITLE, IDS_LANGUAGE_SUBTITLE );
  112. AddPage( &pshead, IDD_OSDIRECTORY, OSDirectoryDlgProc, IDS_OSDIRECTORY_TITLE, IDS_OSDIRECTORY_SUBTITLE );
  113. AddPage( &pshead, IDD_DEFAULTSIF, DefaultSIFDlgProc, IDS_DEFAULTSIF_TITLE, IDS_DEFAULTSIF_SUBTITLE );
  114. AddPage( &pshead, IDD_SCREENS, ScreensDlgProc, IDS_SCREENS_TITLE, IDS_SCREENS_SUBTITLE );
  115. AddPage( &pshead, IDD_SUMMARY, SummaryDlgProc, IDS_SUMMARY_TITLE, IDS_SUMMARY_SUBTITLE );
  116. AddPage( &pshead, IDD_WARNING, WarningDlgProc, IDS_WARNING_TITLE, IDS_WARNING_SUBTITLE );
  117. AddPage( &pshead, IDD_SERVEROK, ServerOKDlgProc, IDS_SERVEROK_TITLE, IDS_SERVEROK_SUBTITLE );
  118. PropertySheet( &pshead );
  119. if ( g_Options.fAbort )
  120. {
  121. hr = S_FALSE;
  122. goto Error;
  123. }
  124. if ( g_Options.fError )
  125. {
  126. hr = E_FAIL;
  127. goto Error;
  128. }
  129. Error:
  130. RETURN(hr);
  131. }
  132. //
  133. // Initializes g_Options.
  134. //
  135. HRESULT
  136. InitializeOptions( void )
  137. {
  138. DWORD dw;
  139. LRESULT lResult;
  140. HKEY hkeySetup;
  141. TraceFunc( "InitializeOptions( )\n" );
  142. //
  143. // Initialize all variable to NULL strings or FALSE
  144. //
  145. memset( &g_Options, 0, sizeof(OPTIONS) );
  146. //
  147. // Load default strings
  148. //
  149. dw = LoadString( g_hinstance, IDS_DEFAULTSETUP,
  150. g_Options.szInstallationName, ARRAYSIZE(g_Options.szInstallationName) );
  151. Assert( dw );
  152. dw = LoadString( g_hinstance, IDS_UNKNOWN, g_Options.szLanguage, ARRAYSIZE(g_Options.szLanguage) );
  153. Assert( dw );
  154. wcscpy( g_Options.szSourcePath, L"C:\\" );
  155. for( ; g_Options.szSourcePath[0] <= L'Z'; g_Options.szSourcePath[0]++ )
  156. {
  157. UINT uDriveType;
  158. uDriveType = GetDriveType( g_Options.szSourcePath );
  159. if ( DRIVE_CDROM == uDriveType )
  160. break;
  161. }
  162. if ( g_Options.szSourcePath[0] > L'Z' ) {
  163. g_Options.szSourcePath[0] = L'\0';
  164. }
  165. g_Options.hinf = INVALID_HANDLE_VALUE;
  166. g_Options.fFirstTime = TRUE;
  167. lResult = RegOpenKey( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup", &hkeySetup );
  168. if ( lResult == ERROR_SUCCESS )
  169. {
  170. DWORD dwValue;
  171. DWORD cbValue;
  172. // Find out if we should authorize DCHP
  173. cbValue = sizeof(dwValue);
  174. lResult = RegQueryValueEx( hkeySetup, L"RemInst_DontAuthorizeDHCP", NULL, NULL, (LPBYTE)&dwValue, &cbValue );
  175. if ( lResult == ERROR_SUCCESS ) {
  176. g_Options.fDontAuthorizeDhcp = dwValue;
  177. }
  178. RegCloseKey( hkeySetup );
  179. }
  180. if (SUCCEEDED(GetSetRanFlag(TRUE, FALSE))) {
  181. g_Options.fFirstTime = FALSE;
  182. } else {
  183. g_Options.fFirstTime = TRUE;
  184. }
  185. HRETURN(S_OK);
  186. }
  187. //
  188. // IsWhiteSpace()
  189. //
  190. BOOL
  191. IsWhiteSpace( wchar_t ch )
  192. {
  193. if ( ch <=32 )
  194. return TRUE;
  195. return FALSE;
  196. }
  197. //
  198. // CheckWhichOption()
  199. DWORD
  200. CheckWhichOption(
  201. LPWSTR pszOption )
  202. {
  203. DWORD dw;
  204. WCHAR szOptionTag[ 64 ];
  205. if ( StrCmpNI( pszOption, L"xyzzy", 6 ) == 0 )
  206. return OPTION_VERSIONINGOVERRIDE;
  207. if ( StrCmpNI( pszOption, L"debug", 5 ) == 0 )
  208. return OPTION_DEBUG;
  209. if ( StrCmpNI( pszOption, L"func", 4 ) == 0 )
  210. return OPTION_FUNC;
  211. if ( StrCmpNI( pszOption, L"add", 3 ) == 0 )
  212. return OPTION_ADD;
  213. if ( StrCmpNI( pszOption, L"check", 5 ) == 0 )
  214. return OPTION_CHECK;
  215. if ( StrCmpNI( pszOption, L"upgrade", 7 ) == 0 )
  216. return OPTION_UPGRADE;
  217. if ( StrCmpNI( pszOption, L"auto", 4 ) == 0 )
  218. return OPTION_AUTOMATED;
  219. // Internationalized words
  220. dw = LoadString( g_hinstance, IDS_ADD, szOptionTag, ARRAYSIZE(szOptionTag) );
  221. Assert( dw );
  222. if ( StrCmpNIW( pszOption, szOptionTag, lstrlen(szOptionTag) == 0 ) )
  223. return OPTION_ADD;
  224. dw = LoadString( g_hinstance, IDS_CHECK, szOptionTag, ARRAYSIZE(szOptionTag) );
  225. Assert( dw );
  226. if ( StrCmpNI( pszOption, szOptionTag, lstrlen(szOptionTag) == 0 ) )
  227. return OPTION_CHECK;
  228. return OPTION_UNKNOWN;
  229. }
  230. //
  231. // ParseCommandLine()
  232. // Returns false if the call required useage to be printed else true
  233. //
  234. BOOL
  235. ParseCommandLine( LPWSTR lpCmdLine )
  236. {
  237. LPWSTR psz = lpCmdLine;
  238. while (*psz)
  239. {
  240. if ( *psz == L'/' || *psz == L'-' )
  241. {
  242. LPWSTR pszStartOption = ++psz;
  243. while (*psz && !IsWhiteSpace( *psz ) )
  244. psz++;
  245. *psz = L'\0'; // terminate
  246. switch ( CheckWhichOption( pszStartOption ) )
  247. {
  248. #ifdef DEBUG
  249. case OPTION_VERSIONINGOVERRIDE:
  250. g_Options.fServerCompatible = TRUE;
  251. break;
  252. case OPTION_DEBUG:
  253. g_dwTraceFlags |= TF_HRESULTS;
  254. break;
  255. case OPTION_FUNC:
  256. g_dwTraceFlags |= TF_FUNC;
  257. break;
  258. #endif
  259. case OPTION_ADD:
  260. g_Options.fAddOption = TRUE;
  261. break;
  262. case OPTION_AUTOMATED:
  263. {
  264. LPWSTR pszScriptFilename;
  265. UINT ErrLine;
  266. g_Options.fAutomated = TRUE;
  267. WCHAR UnattendedFile[MAX_PATH];
  268. LPWSTR p;
  269. //
  270. // get the script name
  271. //
  272. //
  273. // first eat all the whitespace
  274. //
  275. psz++;
  276. while(*psz && IsWhiteSpace( *psz )) {
  277. psz++;
  278. }
  279. //
  280. // now get the filename, which may or may not be quoted
  281. //
  282. if (*psz == L'\"') {
  283. pszScriptFilename = ++psz;
  284. while (*psz && ( L'\"' != *psz ) ) {
  285. psz++;
  286. }
  287. } else {
  288. pszScriptFilename = psz;
  289. while (*psz && !IsWhiteSpace( *psz ) ) {
  290. psz++;
  291. }
  292. }
  293. //
  294. // NULL terminate the filename and try to open the file as
  295. // an INF file
  296. //
  297. *psz = L'\0';
  298. g_Options.hinfAutomated = INVALID_HANDLE_VALUE;
  299. if( GetFullPathName( pszScriptFilename,
  300. MAX_PATH,
  301. UnattendedFile,
  302. &p ) ) {
  303. g_Options.hinfAutomated = SetupOpenInfFileW( UnattendedFile, NULL, INF_STYLE_WIN4, &ErrLine );
  304. }
  305. if ( g_Options.hinfAutomated == INVALID_HANDLE_VALUE ) {
  306. ErrorBox( NULL, L"RISETUP" );
  307. g_Options.fError = TRUE;
  308. return(FALSE);
  309. }
  310. }
  311. break;
  312. case OPTION_CHECK:
  313. g_Options.fCheckServer = TRUE;
  314. break;
  315. case OPTION_UPGRADE:
  316. g_Options.fUpgrade = TRUE;
  317. break;
  318. case OPTION_UNKNOWN :
  319. default :
  320. WCHAR szCaption[ SMALL_BUFFER_SIZE ];
  321. WCHAR szUsage[ SMALL_BUFFER_SIZE * 2 ];
  322. DWORD dw;
  323. dw = LoadStringW( g_hinstance, IDS_APPNAME, szCaption, ARRAYSIZE( szCaption ) );
  324. Assert( dw );
  325. dw = LoadStringW( g_hinstance, IDS_USAGE, szUsage, ARRAYSIZE( szUsage ));
  326. Assert( dw );
  327. MessageBoxW( NULL, szUsage, szCaption, MB_OK );
  328. return FALSE;
  329. }
  330. }
  331. psz++;
  332. }
  333. return TRUE;
  334. }
  335. //
  336. // DoSetup( )
  337. //
  338. HRESULT
  339. DoSetup( )
  340. {
  341. HRESULT hr = S_OK;
  342. INT iReturn;
  343. //
  344. // Setup dialog
  345. //
  346. iReturn = (INT)DialogBox( g_hinstance,
  347. MAKEINTRESOURCE(IDD_TASKS),
  348. NULL,
  349. SetupDlgProc );
  350. return hr;
  351. }
  352. //
  353. // CheckForReboot( )
  354. //
  355. void
  356. CheckForReboot( )
  357. {
  358. if ( !g_Options.fSISServiceInstalled )
  359. {
  360. MessageBoxFromStrings( NULL,
  361. IDS_MUST_REBOOT_TITLE,
  362. IDS_MUST_REBOOT_MESSAGE,
  363. MB_OK | MB_ICONEXCLAMATION );
  364. SetupPromptReboot( NULL, NULL, FALSE );
  365. }
  366. }
  367. //
  368. // RunningOnNTServer( )
  369. //
  370. BOOL
  371. RunningOnNTServer(void)
  372. {
  373. TraceFunc( "RunningOnNtServer()\n" );
  374. HKEY hkey;
  375. LONG lResult;
  376. WCHAR szProductType[50] = { 0 };
  377. DWORD dwType;
  378. DWORD dwSize = ARRAYSIZE(szProductType);
  379. BOOL fReturn = FALSE; // assume that we are not on NTServer.
  380. // Query the registry for the product type.
  381. lResult = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
  382. L"System\\CurrentControlSet\\Control\\ProductOptions",
  383. 0,
  384. KEY_READ,
  385. &hkey);
  386. Assert( lResult == ERROR_SUCCESS );
  387. if ( lResult != ERROR_SUCCESS )
  388. goto Error;
  389. lResult = RegQueryValueEx ( hkey,
  390. L"ProductType",
  391. NULL,
  392. &dwType,
  393. (LPBYTE) szProductType,
  394. &dwSize);
  395. Assert( lResult == ERROR_SUCCESS );
  396. RegCloseKey (hkey);
  397. if (lResult != ERROR_SUCCESS)
  398. goto Error;
  399. if ( _wcsicmp( szProductType, L"ServerNT" ) == 0 )
  400. {
  401. fReturn = TRUE; // yep. NT Server alright.
  402. }
  403. if ( _wcsicmp( szProductType, L"LanmanNT" ) == 0 )
  404. {
  405. fReturn = TRUE; // yep. NT Server alright.
  406. }
  407. Error:
  408. RETURN(fReturn);
  409. }
  410. //
  411. // WinMain()
  412. //
  413. int APIENTRY
  414. WinMain(
  415. HINSTANCE hInstance,
  416. HINSTANCE hPrevInstance,
  417. LPSTR lpCmdLine,
  418. int nCmdShow)
  419. {
  420. TraceFunc( "WinMain( ... )\n" );
  421. HANDLE hMutex;
  422. HRESULT hr = E_FAIL;
  423. WSADATA wsdata;
  424. LPWSTR pszCommandLine = GetCommandLine( );
  425. UNREFERENCED_PARAMETER(nCmdShow);
  426. UNREFERENCED_PARAMETER(lpCmdLine);
  427. UNREFERENCED_PARAMETER(hPrevInstance);
  428. TraceFunc( "WinMain( ... )\n" );
  429. g_hinstance = hInstance;
  430. INITIALIZE_TRACE_MEMORY_PROCESS;
  431. // allow only one instance running at a time
  432. hMutex = CreateMutex( NULL, TRUE, L"RemoteBootSetup.Mutext");
  433. if (GetLastError() == ERROR_ALREADY_EXISTS)
  434. {
  435. MessageBoxFromStrings( NULL,
  436. IDS_ALREADY_RUNNING_TITLE,
  437. IDS_ALREADY_RUNNING_MESSAGE,
  438. MB_OK | MB_ICONSTOP );
  439. goto Cleanup;
  440. }
  441. CoInitialize(NULL);
  442. WSAStartup( 0x02, &wsdata );
  443. if( !pSetupIsUserAdmin()
  444. || !pSetupDoesUserHavePrivilege(SE_SHUTDOWN_NAME)
  445. || !pSetupDoesUserHavePrivilege(SE_BACKUP_NAME)
  446. || !pSetupDoesUserHavePrivilege(SE_RESTORE_NAME)
  447. || !pSetupDoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) {
  448. MessageBoxFromStrings( NULL, IDS_MUST_BE_ADMINISTRATOR_CAPTION, IDS_MUST_BE_ADMINISTRATOR_TEXT, MB_OK );
  449. goto Cleanup;
  450. }
  451. if ( !RunningOnNTServer( ) )
  452. {
  453. MessageBoxFromStrings( NULL, IDS_NOT_RUNNING_ON_NT_SERVER_CAPTION, IDS_NOT_RUNNING_ON_NT_SERVER_TEXT, MB_OK );
  454. goto Cleanup;
  455. }
  456. hr = InitializeOptions( );
  457. if ( FAILED(hr) )
  458. goto Cleanup;
  459. if( !ParseCommandLine( pszCommandLine )) {
  460. goto Cleanup;
  461. }
  462. // Change SetupAPI to Non-backup mode.
  463. // also set a flag that makes it fail all signature checks.
  464. // since we're subject to non-driver signing policy and that
  465. // is set to ignore by default, this means that every copy
  466. // operation will generate a signature warning in setupapi.log
  467. // ...but the memory footprint and speed of risetup process
  468. // will both go down significantly since we won't drag the
  469. // crypto libraries into the process.
  470. //
  471. pSetupSetGlobalFlags( pSetupGetGlobalFlags( ) | PSPGF_NO_BACKUP | PSPGF_AUTOFAIL_VERIFIES );
  472. //
  473. // Go figure out a default for what processor we're
  474. // building an image for.
  475. //
  476. GetProcessorType();
  477. if ( !g_Options.fUpgrade && !g_Options.fAutomated )
  478. {
  479. hr = WizardPages( );
  480. if ( hr != S_OK ) {
  481. goto Cleanup;
  482. }
  483. hr = DoSetup( );
  484. if ( hr != S_OK ) {
  485. goto Cleanup;
  486. }
  487. //
  488. // We need to add in the entries so that ntlmv2 gets
  489. // enabled.
  490. //
  491. EnumAndOperate( g_Options.szOSChooserPath,
  492. L"login.osc",
  493. FixLoginOSC );
  494. CheckForReboot( );
  495. }
  496. else if ( g_Options.fAutomated )
  497. {
  498. if ( g_Options.fError ) {
  499. goto Cleanup;
  500. }
  501. hr = GetAutomatedOptions( );
  502. if ( hr != S_OK ) {
  503. goto Cleanup;
  504. }
  505. hr = FindImageSource( NULL );
  506. if ( hr != S_OK ) {
  507. MessageBoxFromStrings( NULL, IDS_FILE_NOT_FOUND_TITLE, IDS_FILE_NOT_FOUND_TEXT, MB_OK );
  508. goto Cleanup;
  509. }
  510. hr = CheckImageSource( NULL );
  511. if ( hr != S_OK ) {
  512. goto Cleanup;
  513. }
  514. hr = CheckInstallation( );
  515. if ( FAILED(hr) ) {
  516. goto Cleanup;
  517. }
  518. hr = DoSetup( );
  519. if ( hr != S_OK ) {
  520. goto Cleanup;
  521. }
  522. //
  523. // We need to add in the entries so that ntlmv2 gets
  524. // enabled.
  525. //
  526. EnumAndOperate( g_Options.szOSChooserPath,
  527. L"login.osc",
  528. FixLoginOSC );
  529. }
  530. else if ( g_Options.fUpgrade )
  531. {
  532. hr = UpdateRemoteInstallTree( );
  533. //
  534. // We need to add in the entries so that ntlmv2 gets
  535. // enabled.
  536. //
  537. EnumAndOperate( g_Options.szOSChooserPath,
  538. L"login.osc",
  539. FixLoginOSC );
  540. //
  541. // Generate the name of the SIS path and the set the proper
  542. // security for it
  543. //
  544. if (SUCCEEDED(hr)) {
  545. WCHAR sisPathName[MAX_PATH+1];
  546. hr = GetRemoteInstallShareInfo();
  547. if (SUCCEEDED(hr)) {
  548. hr = GetSisVolumePath(sisPathName,(sizeof(sisPathName)/sizeof(WCHAR)));
  549. if (SUCCEEDED(hr)) {
  550. hr = SetSISCommonStoreSecurity( sisPathName );
  551. }
  552. }
  553. }
  554. }
  555. else
  556. {
  557. AssertMsg( 0, "How did I get here?" );
  558. }
  559. Cleanup:
  560. CoUninitialize();
  561. if ( hMutex ) {
  562. CloseHandle( hMutex );
  563. }
  564. if ( g_Options.hinf != INVALID_HANDLE_VALUE ) {
  565. SetupCloseInfFile( g_Options.hinf );
  566. }
  567. UNINITIALIZE_TRACE_MEMORY;
  568. RETURN(hr);
  569. }
  570. // stolen from the CRT, used to shrink our code
  571. int _stdcall ModuleEntry(void)
  572. {
  573. int i;
  574. STARTUPINFO si;
  575. LPSTR pszCmdLine = GetCommandLineA();
  576. if ( *pszCmdLine == '\"' )
  577. {
  578. /*
  579. * Scan, and skip over, subsequent characters until
  580. * another double-quote or a null is encountered.
  581. */
  582. while ( *++pszCmdLine && (*pszCmdLine != '\"') );
  583. /*
  584. * If we stopped on a double-quote (usual case), skip
  585. * over it.
  586. */
  587. if ( *pszCmdLine == '\"' )
  588. pszCmdLine++;
  589. }
  590. else
  591. {
  592. while (*pszCmdLine > ' ')
  593. pszCmdLine++;
  594. }
  595. /*
  596. * Skip past any white space preceeding the second token.
  597. */
  598. while (*pszCmdLine && (*pszCmdLine <= ' '))
  599. {
  600. pszCmdLine++;
  601. }
  602. GetStartupInfo(&si);
  603. i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
  604. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  605. ExitProcess(i);
  606. }