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.

2683 lines
74 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. Params.c
  5. Abstract:
  6. Routines to write parameters file for use by text mode setup.
  7. Author:
  8. Ted Miller (tedm) 4 Nov 1996
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define DEF_INF_BUFFER_SIZE (1<<15) //32KB
  14. #define EMPTY_STRING TEXT("")
  15. // Global used in WriteParamsFile and AddExternalParams
  16. TCHAR ActualParamFile[MAX_PATH] = {'\0'};
  17. //
  18. // boot loader timeout value, in string form
  19. //
  20. TCHAR Timeout[32];
  21. #ifdef PRERELEASE
  22. //
  23. // if we're in PRERELEASE mode, we will make a /debug entry
  24. // in the OSLOADOPTIONSVARAPPEND entry.
  25. //
  26. BOOL AppendDebugDataToBoot = TRUE;
  27. #endif
  28. #if defined(UNICODE) && defined(_X86_)
  29. extern TCHAR g_MigDllAnswerFilePath[MAX_PATH];
  30. #endif
  31. DWORD
  32. PatchWinntSifFile(
  33. IN LPCTSTR Filename
  34. );
  35. BOOL
  36. AppendParamsFile(
  37. IN HWND ParentWindow,
  38. IN LPCTSTR ParametersFileIn,
  39. IN LPCTSTR ParametersFileOut
  40. );
  41. BOOL
  42. WriteCompatibilityData(
  43. IN LPCTSTR FileName
  44. );
  45. VOID
  46. WriteGUIModeInfOperations(
  47. IN LPCTSTR FileName
  48. );
  49. BOOL
  50. AddGUIModeCompatibilityInfsToCopyList();
  51. BOOL
  52. WriteTextmodeClobberData (
  53. IN LPCTSTR FileName
  54. );
  55. VOID
  56. SaveProxyForOobe(
  57. IN LPCTSTR FileName
  58. );
  59. #if defined(_X86_)
  60. VOID
  61. SaveDriveLetterInformation (
  62. IN LPCTSTR FileName
  63. );
  64. #endif
  65. PCTSTR
  66. pGetPfPath (
  67. IN HKEY hKey,
  68. IN PCTSTR ValueName
  69. )
  70. {
  71. DWORD Size;
  72. LONG rc;
  73. PBYTE Data;
  74. DWORD Type;
  75. UINT DriveType;
  76. TCHAR RootPath[] = TEXT("?:\\");
  77. PTSTR QuotedData;
  78. rc = RegQueryValueEx (
  79. hKey,
  80. ValueName,
  81. NULL, // lpReserved
  82. &Type,
  83. NULL,
  84. &Size
  85. );
  86. if (rc != ERROR_SUCCESS) {
  87. return NULL;
  88. }
  89. if (Type != REG_SZ && Type != REG_EXPAND_SZ) {
  90. return NULL;
  91. }
  92. Data = MALLOC(Size + sizeof (TCHAR));
  93. if (!Data) {
  94. return NULL;
  95. }
  96. rc = RegQueryValueEx (
  97. hKey,
  98. ValueName,
  99. NULL, // lpReserved
  100. NULL, // type
  101. Data,
  102. &Size
  103. );
  104. if (rc != ERROR_SUCCESS) {
  105. FREE(Data);
  106. return NULL;
  107. }
  108. *((PTSTR) (Data + Size)) = 0;
  109. //
  110. // Verify data is to a local path
  111. //
  112. RootPath[0] = *((PCTSTR) Data);
  113. if (RootPath[0] == TEXT('\\')) {
  114. DriveType = DRIVE_NO_ROOT_DIR;
  115. } else {
  116. DriveType = GetDriveType (RootPath);
  117. }
  118. if (DriveType != DRIVE_FIXED) {
  119. FREE(Data);
  120. return NULL;
  121. }
  122. QuotedData = (PTSTR) MALLOC(Size + sizeof (TCHAR) * 3);
  123. if (!QuotedData) {
  124. FREE(Data);
  125. return NULL;
  126. }
  127. *QuotedData = TEXT('\"');
  128. lstrcpy (QuotedData + 1, (PCTSTR) Data);
  129. lstrcat (QuotedData, TEXT("\""));
  130. FREE(Data);
  131. return (PCTSTR) QuotedData;
  132. }
  133. BOOL
  134. WriteHeadlessParameters(
  135. IN LPCTSTR FileName
  136. )
  137. /*++
  138. Routine Description:
  139. This routine writes the headless-specific parameters into the file
  140. that is used to pass information to text mode setup.
  141. Arguments:
  142. FileName - specifies the full Win32 filename to use for the file.
  143. Return Value:
  144. Boolean value indicating whether the file was written successfully.
  145. If not, the user will have been informed about why.
  146. --*/
  147. {
  148. BOOL ReturnVal = TRUE;
  149. //
  150. // ISSUE - why MAX_PATH*2 ?
  151. //
  152. TCHAR Text[MAX_PATH*2];
  153. //
  154. // Check the global and see if anyone has set any headless parameters.
  155. //
  156. if( HeadlessSelection[0] != TEXT('\0') ) {
  157. //
  158. // Write the settings into the unattend file so textmode will
  159. // fire up through up a headless port.
  160. //
  161. if( !WritePrivateProfileString(WINNT_DATA,WINNT_U_HEADLESS_REDIRECT,HeadlessSelection,FileName)) {
  162. ReturnVal = FALSE;
  163. }
  164. if( HeadlessBaudRate == 0 ) {
  165. wsprintf( Text, TEXT("%d"), 9600 );
  166. } else {
  167. wsprintf( Text, TEXT("%d"), HeadlessBaudRate );
  168. }
  169. if( !WritePrivateProfileString(WINNT_DATA,WINNT_U_HEADLESS_REDIRECTBAUDRATE,Text,FileName)) {
  170. ReturnVal = FALSE;
  171. }
  172. }
  173. return( ReturnVal );
  174. }
  175. BOOL WritePidToParametersFile(LPCTSTR Section, LPCTSTR Key, LPCTSTR FileName)
  176. {
  177. BOOL b = FALSE;
  178. LPTSTR Line = NULL;
  179. LPTSTR pid;
  180. if (g_EncryptedPID)
  181. {
  182. pid = g_EncryptedPID;
  183. }
  184. else
  185. {
  186. pid = ProductId;
  187. }
  188. Line = GlobalAlloc(GPTR, (lstrlen(pid) + 3) * sizeof(TCHAR));
  189. if (Line)
  190. {
  191. *Line = TEXT('\"');
  192. lstrcpy(&Line[1], pid);
  193. lstrcat(Line,TEXT("\""));
  194. b = WritePrivateProfileString(Section,Key,Line,FileName);
  195. GlobalFree(Line);
  196. }
  197. return b;
  198. }
  199. BOOL
  200. MigrateUnattendDataEntries(
  201. IN LPCTSTR FileName,
  202. IN LPTSTR UnattendedScriptFile
  203. )
  204. /*++
  205. Routine Description:
  206. This routine writes out the keys under [Data] section of an unattend file
  207. in to the winnt.sif file. This routine is specific to the following keys
  208. AutoPartition and
  209. UseBIOSToBoot
  210. Arguments:
  211. FileName - specifies the full Win32 filename to use for the file.
  212. UnattendedScriptFile - Unattend Script File.
  213. Return Value:
  214. TRUE/FALSE
  215. --*/
  216. {
  217. BOOL ReturnVal = FALSE;
  218. //
  219. // If Unattend file exists then migrate the keys under [Data] section.
  220. //
  221. if (UnattendedScriptFile){
  222. CONST ULONG BufSize = 256;
  223. PTSTR TmpString = (PTSTR)MALLOC(BufSize * sizeof (TCHAR));
  224. ReturnVal = TRUE;
  225. if( NULL != TmpString){
  226. //
  227. // Array of keys to be checked
  228. //
  229. LPCTSTR KeysToBeMigrated[] = { WINNT_D_AUTO_PART,
  230. WINNT_D_BIOSTOBOOT
  231. };
  232. LPCTSTR WinntDataSection = WINNT_DATA;
  233. ULONG i = 0;
  234. for(i=0; i < ARRAYSIZE(KeysToBeMigrated); i++){
  235. if(GetPrivateProfileString(WinntDataSection,
  236. KeysToBeMigrated[i],
  237. EMPTY_STRING,
  238. TmpString,
  239. BufSize,
  240. UnattendedScriptFile)){
  241. if (!WritePrivateProfileString( WinntDataSection,
  242. KeysToBeMigrated[i],
  243. TmpString,
  244. FileName)) {
  245. DWORD LastError = GetLastError();
  246. DebugLog ( Winnt32LogError,
  247. TEXT("MigrateUnattendDatEntries : Error writing to file %1, Section: %2, Key: %3"),
  248. 0,
  249. FileName,
  250. WinntDataSection,
  251. KeysToBeMigrated[i]);
  252. ReturnVal = FALSE;
  253. SetLastError(LastError);
  254. }
  255. }
  256. }
  257. FREE(TmpString);
  258. }else{
  259. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  260. ReturnVal = FALSE;
  261. }
  262. }
  263. SetLastError(ERROR_INVALID_PARAMETER);
  264. return ReturnVal;
  265. }
  266. BOOL
  267. DoWriteParametersFile(
  268. IN HWND ParentWindow,
  269. IN LPCTSTR FileName
  270. )
  271. /*++
  272. Routine Description:
  273. This routine generates a parameters file that is used to pass information
  274. to text mode setup.
  275. Arguments:
  276. ParentWindow - supplies window handle of window to be used as the
  277. parent/owner in case this routine puts up UI.
  278. FileName - specifies the full Win32 filename to use for the file.
  279. Return Value:
  280. Boolean value indicating whether the file was written successfully.
  281. If not, the user will have been informed about why.
  282. --*/
  283. {
  284. TCHAR FullPath[MAX_PATH], *t;
  285. TCHAR Text[MAX_PATH*2];
  286. LPTSTR OptionalDirString,OptDir;
  287. UINT OptionalDirLength;
  288. DWORD d=NO_ERROR;
  289. PVOID p;
  290. BOOL b;
  291. LONG l;
  292. HKEY hKey;
  293. PCTSTR PfPath;
  294. LONG rc;
  295. LPCTSTR WinntDataSection = WINNT_DATA;
  296. LPCTSTR WinntSetupSection = WINNT_SETUPPARAMS;
  297. LPCTSTR WinntAccessSection = WINNT_ACCESSIBILITY;
  298. LPCTSTR WinntSetupDataSection = TEXT("SetupData");
  299. #if defined(REMOTE_BOOT)
  300. LPCTSTR WinntUserDataSection = TEXT("UserData");
  301. #endif // defined(REMOTE_BOOT)
  302. LPCTSTR WinntUniqueId = WINNT_D_UNIQUEID;
  303. LPCTSTR WinntNull = WINNT_A_NULL;
  304. LPCTSTR WinntUserSection = WINNT_USERDATA;
  305. if( !FileName )
  306. d=ERROR_INVALID_PARAMETER;
  307. //
  308. // Make sure path for file is present, and form its fully qualified name.
  309. //
  310. if(d == NO_ERROR){
  311. StringCchCopy(FullPath, ARRAYSIZE(FullPath), FileName);
  312. if((t=_tcsrchr(FullPath,TEXT('\\')))) {
  313. *t= 0;
  314. d = CreateMultiLevelDirectory(FullPath);
  315. }else
  316. d=ERROR_INVALID_PARAMETER;
  317. }
  318. if(d != NO_ERROR) {
  319. MessageBoxFromMessageAndSystemError(
  320. ParentWindow,
  321. MSG_DIR_CREATE_FAILED,
  322. d,
  323. AppTitleStringId,
  324. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  325. FullPath
  326. );
  327. return(FALSE);
  328. }
  329. //
  330. // Get rid of any existing parameters file.
  331. //
  332. DeleteFile(FileName);
  333. #ifdef _X86_
  334. if (!ISNT()) {
  335. //
  336. // If this is a 9x machine, we need to preserve the drive letters, even
  337. // if it is an NT clean install.
  338. //
  339. SaveDriveLetterInformation (FileName);
  340. }
  341. #endif
  342. //
  343. // Value indicating that this is winnt/winnt32-based installation,
  344. // and on amd64/x86, value to indicate that this is a floppyless operation
  345. // as apropriate.
  346. //
  347. b = WritePrivateProfileString(WinntDataSection,WINNT_D_MSDOS,TEXT("1"),FileName);
  348. if (b && HideWinDir) {
  349. b = WritePrivateProfileString(WinntDataSection,TEXT("HideWinDir"),TEXT("1"),FileName);
  350. }
  351. if (!IsArc()) {
  352. #if defined(_AMD64_) || defined(_X86_)
  353. if(b && Floppyless) {
  354. b = WritePrivateProfileString(WinntDataSection,WINNT_D_FLOPPY,TEXT("1"),FileName);
  355. }
  356. if (b && BuildCmdcons) {
  357. b = WritePrivateProfileString(WinntDataSection,WINNT_D_CMDCONS,TEXT("1"),FileName);
  358. }
  359. #endif // defined(_AMD64_) || defined(_X86_)
  360. } // if (!IsArc())
  361. if(b && RunFromCD && !MakeLocalSource) {
  362. b = WritePrivateProfileString(WinntDataSection,WINNT_D_LOCALSRC_CD,TEXT("1"),FileName);
  363. }
  364. if (b) {
  365. b = WritePrivateProfileString(WinntDataSection,WINNT_D_AUTO_PART,ChoosePartition?TEXT("0"):TEXT("1"),FileName);
  366. }
  367. if (b && UseSignatures) {
  368. b = WritePrivateProfileString(WinntDataSection,TEXT("UseSignatures"),WINNT_A_YES,FileName);
  369. }
  370. if (b && InstallDir[0] && (ISNT() || !Upgrade)) {
  371. b = WritePrivateProfileString(WinntDataSection,WINNT_D_INSTALLDIR,InstallDir,FileName);
  372. }
  373. if (b && EulaComplete) {
  374. b = WritePrivateProfileString(WinntDataSection,WINNT_D_EULADONE,TEXT("1"),FileName);
  375. }
  376. if (b && NoLs && !MakeLocalSource) {
  377. b = WritePrivateProfileString(WinntDataSection,WINNT_D_NOLS,TEXT("1"),FileName);
  378. }
  379. if (b && UseBIOSToBoot) {
  380. b = WritePrivateProfileString(WinntDataSection,TEXT("UseBIOSToBoot"),TEXT("1"),FileName);
  381. }
  382. if (b && WriteAcpiHalValue && Upgrade) {
  383. if (AcpiHalValue) {
  384. b = WritePrivateProfileString(WinntDataSection,TEXT("AcpiHAL"),TEXT("1"),FileName);
  385. } else {
  386. b = WritePrivateProfileString(WinntDataSection,TEXT("AcpiHAL"),TEXT("0"),FileName);
  387. }
  388. }
  389. if (b && IgnoreExceptionPackages) {
  390. b = WritePrivateProfileString(WinntDataSection,TEXT("IgnoreExceptionPackages"),TEXT("1"),FileName);
  391. }
  392. #ifdef PRERELEASE
  393. if (b && AppendDebugDataToBoot) {
  394. if (!AsrQuickTest) {
  395. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVarAppend"),TEXT("/Debug"),FileName);
  396. }
  397. else {
  398. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVarAppend"),TEXT("/Debug /Baudrate=115200"),FileName);
  399. }
  400. }
  401. #endif
  402. if (b && AsrQuickTest) {
  403. wsprintf(Text, TEXT("%d"), AsrQuickTest);
  404. b = WritePrivateProfileString(WinntDataSection,TEXT("AsrMode"),Text,FileName);
  405. }
  406. if (b && (RunningBVTs || AsrQuickTest)) {
  407. if (lDebugBaudRate == 1394) {
  408. // kd via 1394
  409. lstrcpy(Text, TEXT("/debug /debugport=1394"));
  410. } else if (lDebugComPort == 0) {
  411. wsprintf(Text, TEXT("/debug /baudrate=%d"), lDebugBaudRate);
  412. } else {
  413. wsprintf(Text, TEXT("/debug /baudrate=%d /debugport=com%d"), lDebugBaudRate, lDebugComPort);
  414. }
  415. // write the string to OsLoadOptions so "textmode" setup to run under the debugger
  416. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptions"),Text,FileName);
  417. if (b) {
  418. // write the string to OsLoadOptionsVar so guimode setup to run under the debugger
  419. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("OsLoadOptionsVar"),Text,FileName);
  420. if (b) {
  421. // also run guimode's setup.exe under NTSD. The -isd switch is needed to ensure that setup.exe starts
  422. // without a global system manifest since winlogon spawns it with the CREATE_IGNORE_SYSTEM_DEFAULT flag,
  423. // and ntsd normall calls CreateProcess which would undo the above flag.
  424. b = WritePrivateProfileString(WinntSetupDataSection,TEXT("SetupCmdlinePrepend"),TEXT("ntsd -isd -odgGx"),FileName);
  425. }
  426. }
  427. }
  428. if (b && Timeout[0]) {
  429. b = WritePrivateProfileString(WinntSetupDataSection,WINNT_S_OSLOADTIMEOUT,Timeout,FileName);
  430. }
  431. if(b) {
  432. //
  433. // Write upgrade stuff. WinntUpgrade and Win95Upgrade will both be set,
  434. // and at most one of them will be set to yes.
  435. //
  436. if(b = WritePrivateProfileString(WinntDataSection,WINNT_D_NTUPGRADE,WINNT_A_NO,FileName)) {
  437. b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN95UPGRADE,WINNT_A_NO,FileName);
  438. }
  439. if(b) {
  440. wsprintf(Text,TEXT("%x"),GetVersion());
  441. b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_VER,Text,FileName);
  442. if(b && Upgrade) {
  443. b = WritePrivateProfileString(
  444. WinntDataSection,
  445. ISNT() ? WINNT_D_NTUPGRADE : WINNT_D_WIN95UPGRADE,
  446. WINNT_A_YES,
  447. FileName
  448. );
  449. MyGetWindowsDirectory(Text,MAX_PATH);
  450. Text[2] = 0;
  451. b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_DRIVE,Text,FileName);
  452. if(b) {
  453. Text[2] = TEXT('\\');
  454. b = WritePrivateProfileString(WinntDataSection,WINNT_D_WIN32_PATH,Text+2,FileName);
  455. }
  456. }
  457. }
  458. }
  459. //
  460. // Flags for Accessible Setup
  461. //
  462. AccessibleSetup = FALSE;
  463. if(!Upgrade) {
  464. if(b && AccessibleMagnifier) {
  465. b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_MAGNIFIER,
  466. TEXT("1"),FileName);
  467. AccessibleSetup = TRUE;
  468. }
  469. if(b && AccessibleReader) {
  470. b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_READER,
  471. TEXT("1"),FileName);
  472. AccessibleSetup = TRUE;
  473. }
  474. if(b && AccessibleKeyboard) {
  475. b = WritePrivateProfileString(WinntAccessSection,WINNT_D_ACC_KEYBOARD,
  476. TEXT("1"),FileName);
  477. AccessibleSetup = TRUE;
  478. }
  479. }
  480. if(b && AccessibleSetup && !UnattendedOperation) {
  481. UnattendedOperation = TRUE;
  482. UnattendedShutdownTimeout = 0;
  483. UnattendedScriptFile = MALLOC(MAX_PATH * sizeof(TCHAR));
  484. b = (UnattendedScriptFile != NULL);
  485. if(b) {
  486. lstrcpy(UnattendedScriptFile,NativeSourcePaths[0]);
  487. ConcatenatePaths(UnattendedScriptFile,AccessibleScriptFile,MAX_PATH);
  488. }
  489. }
  490. if(!b) {
  491. goto c1;
  492. }
  493. //
  494. // Value indicating we're automatically and quietly skipping missing files.
  495. //
  496. if(AutoSkipMissingFiles) {
  497. b = WritePrivateProfileString(WinntSetupSection,WINNT_S_SKIPMISSING,TEXT("1"),FileName);
  498. if(!b) {
  499. goto c1;
  500. }
  501. }
  502. //
  503. // Command to be executed at end of GUI setup, if any.
  504. //
  505. if(CmdToExecuteAtEndOfGui) {
  506. b = WritePrivateProfileString(
  507. WinntSetupSection,
  508. WINNT_S_USEREXECUTE,
  509. CmdToExecuteAtEndOfGui,
  510. FileName
  511. );
  512. if(!b) {
  513. goto c1;
  514. }
  515. }
  516. //
  517. // Ensure that Plug and Play state in upgraded os will be the same as the
  518. // original. Enables per-device settings to be preserved in the NT5+
  519. // upgrade scenario.
  520. //
  521. if (ISNT() && (BuildNumber > NT40) && Upgrade) {
  522. LPTSTR buffer = NULL;
  523. if (MigrateDeviceInstanceData(&buffer)) {
  524. WritePrivateProfileSection(WINNT_DEVICEINSTANCES,
  525. buffer,
  526. FileName);
  527. //
  528. // Free the allocated buffer that was returned
  529. //
  530. LocalFree(buffer);
  531. buffer = NULL;
  532. }
  533. if (MigrateClassKeys(&buffer)) {
  534. WritePrivateProfileSection(WINNT_CLASSKEYS,
  535. buffer,
  536. FileName);
  537. //
  538. // Free the allocated buffer that was returned
  539. //
  540. LocalFree(buffer);
  541. buffer = NULL;
  542. }
  543. if (MigrateHashValues(&buffer)) {
  544. WritePrivateProfileSection(WINNT_DEVICEHASHVALUES,
  545. buffer,
  546. FileName);
  547. //
  548. // Free the allocated buffer that was returned
  549. //
  550. LocalFree(buffer);
  551. buffer = NULL;
  552. }
  553. }
  554. //
  555. // Remember udf info. If there's a database file, stick a * on the end
  556. // of the ID before writing it.
  557. //
  558. if(UniquenessId) {
  559. d = lstrlen(UniquenessId);
  560. if(d >= (MAX_PATH-1)) {
  561. d--;
  562. }
  563. lstrcpyn(Text,UniquenessId,MAX_PATH-1);
  564. if(UniquenessDatabaseFile) {
  565. Text[d] = TEXT('*');
  566. Text[d+1] = 0;
  567. }
  568. b = WritePrivateProfileString(WinntDataSection,WINNT_D_UNIQUENESS,Text,FileName);
  569. if(!b) {
  570. goto c1;
  571. }
  572. if(UniquenessDatabaseFile) {
  573. if ('\0' == LocalSourceDirectory[0]) {
  574. MessageBoxFromMessage(
  575. ParentWindow,
  576. MSG_UDF_INVALID_USAGE,
  577. FALSE,
  578. AppTitleStringId,
  579. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  580. UniquenessDatabaseFile
  581. );
  582. goto c0;
  583. }
  584. lstrcpyn(Text,LocalSourceDirectory,MAX_PATH);
  585. ConcatenatePaths(Text,WINNT_UNIQUENESS_DB,MAX_PATH);
  586. CreateMultiLevelDirectory(LocalSourceDirectory);
  587. b = CopyFile(UniquenessDatabaseFile,Text,FALSE);
  588. if(!b) {
  589. MessageBoxFromMessageAndSystemError(
  590. ParentWindow,
  591. MSG_UDF_FILE_INVALID,
  592. GetLastError(),
  593. AppTitleStringId,
  594. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  595. UniquenessDatabaseFile
  596. );
  597. goto c0;
  598. }
  599. }
  600. }
  601. //
  602. // If any optional dirs are present then we want to generate
  603. // an entry in the sif file that contains a line that specifies them
  604. // in the form dir1*dir2*...*dirn
  605. //
  606. OptionalDirLength = 0;
  607. OptionalDirString = NULL;
  608. for(d=0; d<OptionalDirectoryCount; d++) {
  609. //
  610. // Ignore temp-only and oem directories here.
  611. //
  612. if(OptionalDirectoryFlags[d] & (OPTDIR_OEMSYS | OPTDIR_TEMPONLY | OPTDIR_OVERLAY)) {
  613. continue;
  614. }
  615. if (OptionalDirectoryFlags[d] & (OPTDIR_DEBUGGER)) {
  616. // hardcode the dest dir to "Debuggers"
  617. OptDir = TEXT("Debuggers");
  618. } else {
  619. if (OptionalDirectoryFlags[d] & OPTDIR_USE_TAIL_FOLDER_NAME) {
  620. //
  621. // create all copydir: directories in a subdirectory under target %windir%
  622. //
  623. OptDir = _tcsrchr (OptionalDirectories[d], TEXT('\\'));
  624. if (OptDir) {
  625. OptDir++;
  626. } else {
  627. OptDir = OptionalDirectories[d];
  628. }
  629. } else {
  630. OptDir = OptionalDirectories[d];
  631. }
  632. }
  633. //
  634. // support ".." syntax
  635. //
  636. while (_tcsstr(OptDir,TEXT("..\\"))) {
  637. OptDir += 3;
  638. }
  639. if(OptionalDirString) {
  640. p = REALLOC(
  641. OptionalDirString,
  642. (lstrlen(OptDir) + 2 + OptionalDirLength) * sizeof(TCHAR)
  643. );
  644. } else {
  645. p = MALLOC((lstrlen(OptDir)+2)*sizeof(TCHAR));
  646. }
  647. if(!p) {
  648. if(OptionalDirString) {
  649. FREE(OptionalDirString);
  650. }
  651. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  652. goto c1;
  653. }
  654. OptionalDirString = p;
  655. if(OptionalDirLength) {
  656. lstrcat(OptionalDirString,OptDir);
  657. } else {
  658. lstrcpy(OptionalDirString,OptDir);
  659. }
  660. lstrcat(OptionalDirString,TEXT("*"));
  661. OptionalDirLength = lstrlen(OptionalDirString);
  662. }
  663. if(OptionalDirString) {
  664. //
  665. // Remove trailing * if any
  666. //
  667. d = lstrlen(OptionalDirString);
  668. if(d && (OptionalDirString[d-1] == TEXT('*'))) {
  669. OptionalDirString[d-1] = 0;
  670. }
  671. b = WritePrivateProfileString(
  672. WinntSetupSection,
  673. WINNT_S_OPTIONALDIRS,
  674. OptionalDirString,
  675. FileName
  676. );
  677. d = GetLastError();
  678. FREE(OptionalDirString);
  679. if(!b) {
  680. SetLastError(d);
  681. goto c1;
  682. }
  683. }
  684. //
  685. // Slap a unique identifier into the registry.
  686. // We'll use this in unattended upgrade during text mode
  687. // to find this build.
  688. //
  689. // Pretty simple: we'll use a string that derives
  690. // from the sysroot, and some unique value based on
  691. // the current tick count.
  692. //
  693. l = RegCreateKeyEx(
  694. HKEY_LOCAL_MACHINE,
  695. TEXT("SYSTEM\\Setup"),
  696. 0,
  697. NULL,
  698. REG_OPTION_NON_VOLATILE,
  699. KEY_SET_VALUE,
  700. NULL,
  701. &hKey,
  702. &d
  703. );
  704. if(l != NO_ERROR) {
  705. SetLastError(l);
  706. goto c2;
  707. }
  708. d = MyGetWindowsDirectory(Text,MAX_PATH);
  709. if((d + 5) > MAX_PATH) {
  710. d = MAX_PATH - 5;
  711. }
  712. Text[d++] = TEXT('\\');
  713. Text[d++] = (TCHAR)(((GetTickCount() & 0x00f) >> 0) + 'A');
  714. Text[d++] = (TCHAR)(((GetTickCount() & 0x0f0) >> 4) + 'A');
  715. Text[d++] = (TCHAR)(((GetTickCount() & 0xf00) >> 8) + 'A');
  716. Text[d++] = 0;
  717. //
  718. // Set the value in the registry.
  719. //
  720. l = RegSetValueEx(hKey,WinntUniqueId,0,REG_SZ,(CONST BYTE *)Text,d*sizeof(TCHAR));
  721. if(l == NO_ERROR) {
  722. l = RegFlushKey (hKey);
  723. }
  724. RegCloseKey(hKey);
  725. if(l != NO_ERROR) {
  726. SetLastError(l);
  727. goto c2;
  728. }
  729. //
  730. // Stick the value in winnt.sif so we can correlate
  731. // later when we go to upgrade.
  732. //
  733. b = WritePrivateProfileString(WinntDataSection,WinntUniqueId,Text,FileName);
  734. if(!b) {
  735. goto c1;
  736. }
  737. //
  738. // Now write information about the source path(s) we used.
  739. // Use SourcePath[0].
  740. //
  741. // If the name starts with \\ then we assume it's UNC and
  742. // just use it directly. Otherwise we call MyGetDriveType on it
  743. // and if it's a network drive we get the UNC path.
  744. // Otherwise we just go ahead and save as-is.
  745. // Also save the type.
  746. //
  747. if((SourcePaths[0][0] == TEXT('\\')) && (SourcePaths[0][1] == TEXT('\\'))) {
  748. d = DRIVE_REMOTE;
  749. lstrcpy(Text,SourcePaths[0]);
  750. } else {
  751. if(GetFullPathName(SourcePaths[0],MAX_PATH,FullPath,(LPTSTR *)&p)) {
  752. if(FullPath[0] == TEXT('\\')) {
  753. //
  754. // Assume UNC, since a full path should normally start
  755. // with a drive letter.
  756. //
  757. d = DRIVE_REMOTE;
  758. lstrcpy(Text,FullPath);
  759. } else {
  760. d = MyGetDriveType(FullPath[0]);
  761. if((d == DRIVE_REMOTE) && (FullPath[1] == TEXT(':')) && (FullPath[2] == TEXT('\\'))) {
  762. //
  763. // Get actual UNC path.
  764. //
  765. FullPath[2] = 0;
  766. l = MAX_PATH;
  767. if(WNetGetConnection(FullPath,Text,(LPDWORD)&l) == NO_ERROR) {
  768. l = lstrlen(Text);
  769. if(l && (Text[l-1] != TEXT('\\')) && FullPath[3]) {
  770. Text[l] = TEXT('\\');
  771. Text[l+1] = 0;
  772. }
  773. StringCchCat(Text, ARRAYSIZE(Text), FullPath+3);
  774. } else {
  775. //
  776. // Strange case.
  777. //
  778. FullPath[2] = TEXT('\\');
  779. lstrcpy(Text,FullPath);
  780. d = DRIVE_UNKNOWN;
  781. }
  782. } else {
  783. //
  784. // Use as-is.
  785. //
  786. if(d == DRIVE_REMOTE) {
  787. d = DRIVE_UNKNOWN;
  788. }
  789. lstrcpy(Text,FullPath);
  790. }
  791. }
  792. } else {
  793. //
  794. // Type is unknown. Just use as-is.
  795. //
  796. d = DRIVE_UNKNOWN;
  797. lstrcpy(Text,SourcePaths[0]);
  798. }
  799. }
  800. //
  801. // In the preinstall case ignore all the above and
  802. // force gui setup to search for a CD.
  803. // This particular combination of values will do it.
  804. //
  805. if(OemPreinstall) {
  806. //
  807. // marcw (7-22-97) - Changed to fix alpha build break.
  808. // FirstFloppyDriveLetter is defined on amd64/X86s only.
  809. //
  810. if (!IsArc()) {
  811. #if defined(_AMD64_) || defined(_X86_)
  812. Text[0] = FirstFloppyDriveLetter;
  813. Text[1] = TEXT(':');
  814. Text[2] = TEXT('\\');
  815. Text[3] = 0;
  816. #endif // defined(_AMD64_) || defined(_X86_)
  817. } else {
  818. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  819. lstrcpy(Text,TEXT("A:\\"));
  820. #endif // UNICODE
  821. } // if (!IsArc())
  822. if (LocalSourceWithPlatform[0]) {
  823. ConcatenatePaths(
  824. Text,
  825. &LocalSourceWithPlatform[lstrlen(LocalSourceDirectory)],
  826. MAX_PATH
  827. );
  828. }
  829. d = DRIVE_CDROM;
  830. }
  831. b = WritePrivateProfileString(WinntDataSection,WINNT_D_ORI_SRCPATH,Text,FileName);
  832. if(!b) {
  833. goto c1;
  834. }
  835. #if defined(REMOTE_BOOT)
  836. //
  837. // If this is a remote boot upgrade, write the source path to SetupSourceDevice
  838. // under [SetupData]. We do NOT want the platform path here. Also write the
  839. // path to the machine directory to TargetNtPartition under [SetupData]. This
  840. // is just whatever \DosDevices\C: translates to. Finally, write the computer
  841. // name to ComputerName under [UserData].
  842. //
  843. if (RemoteBoot) {
  844. DWORD len;
  845. MYASSERT(d == DRIVE_REMOTE);
  846. MYASSERT((*Text == TEXT('\\')) && (*(Text + 1) == TEXT('\\')));
  847. lstrcpy(FullPath, TEXT("\\Device\\LanmanRedirector"));
  848. ConcatenatePaths(FullPath, Text+1, MAX_PATH);
  849. p = _tcsrchr(FullPath,TEXT('\\'));
  850. MYASSERT(p != NULL);
  851. *(LPTSTR)p = 0;
  852. b = WritePrivateProfileString(
  853. WinntSetupDataSection,
  854. TEXT("SetupSourceDevice"),
  855. FullPath,
  856. FileName);
  857. if(!b) {
  858. goto c1;
  859. }
  860. MyGetWindowsDirectory(Text, MAX_PATH);
  861. Text[2] = 0;
  862. len = QueryDosDevice(Text, Text, MAX_PATH);
  863. if (len == 0) {
  864. goto c1;
  865. }
  866. b = WritePrivateProfileString(
  867. WinntSetupDataSection,
  868. TEXT("TargetNtPartition"),
  869. Text,
  870. FileName);
  871. if(!b) {
  872. goto c1;
  873. }
  874. len = MAX_PATH;
  875. b = GetComputerName(Text, &len);
  876. if(!b) {
  877. goto c1;
  878. }
  879. b = WritePrivateProfileString(
  880. WinntUserDataSection,
  881. WINNT_US_COMPNAME,
  882. Text,
  883. FileName);
  884. if(!b) {
  885. goto c1;
  886. }
  887. }
  888. #endif // defined(REMOTE_BOOT)
  889. wsprintf(Text,TEXT("%u"),d);
  890. WritePrivateProfileString(WinntDataSection,WINNT_D_ORI_SRCTYPE,Text,FileName);
  891. if(!b) {
  892. goto c1;
  893. }
  894. #ifdef _X86_
  895. //
  896. // NT 4 and Win95 for NEC98 have 2 types Drive assing.
  897. // - NEC DOS Type(A: HD, B:HD,...X:FD)
  898. // - PC-AT Type(A:FD, B:FD, C:HD, D:HD, ....)
  899. //
  900. // Upgrade setup should be keep above drive assign and All setup should
  901. // be keep FT information.
  902. // Because some Applications have drive letter in own data file or registry.
  903. // NT5 setup for NEC98 have Drive assign type in winnt.sif section[data].
  904. // And this key is "DriveAssign_Nec98".
  905. // Value is "yes", It means NEC DOS Type assign.
  906. // Value is "no", It means PC-AT Type.
  907. // Now, This Key defined this place, but near future, this key move into
  908. // \nt\public\sdk\inc\setupbat.h, I hope.
  909. //
  910. // \textmode\kernel\spsetup.c has same defines.
  911. //
  912. #define WINNT_D_DRIVEASSIGN_NEC98_W L"DriveAssign_Nec98"
  913. #define WINNT_D_DRIVEASSIGN_NEC98_A "DriveAssign_Nec98"
  914. #ifdef UNICODE
  915. #define WINNT_D_DRIVEASSIGN_NEC98 WINNT_D_DRIVEASSIGN_NEC98_W
  916. #else
  917. #define WINNT_D_DRIVEASSIGN_NEC98 WINNT_D_DRIVEASSIGN_NEC98_A
  918. #endif
  919. if (IsNEC98()){
  920. if (IsDriveAssignNEC98() == TRUE){
  921. WritePrivateProfileString(WinntDataSection, WINNT_D_DRIVEASSIGN_NEC98, WINNT_A_YES, FileName);
  922. } else {
  923. WritePrivateProfileString(WinntDataSection, WINNT_D_DRIVEASSIGN_NEC98, WINNT_A_NO, FileName);
  924. }
  925. }
  926. #endif
  927. //
  928. // At this point we process the file, and surround all values with
  929. // double-quotes. This gets around certain problems in the various
  930. // inf parsers used in later stages of setup. Do this BEFORE appending
  931. // the unattend stript file, because some of the stuff in there expects
  932. // to be treated as multiple values, which double quotes ruin.
  933. //
  934. WritePrivateProfileString(NULL,NULL,NULL,FileName);
  935. d = PatchWinntSifFile(FileName);
  936. if(d != NO_ERROR) {
  937. SetLastError(d);
  938. goto c1;
  939. }
  940. //
  941. // Language options
  942. // Note: we don't want these values surrounded by double-quotes.
  943. //
  944. if( SaveLanguageParams( FileName ) ) {
  945. FreeLanguageData();
  946. } else {
  947. goto c1;
  948. }
  949. //
  950. // Append unattend script file if necessary.
  951. //
  952. if(UnattendedOperation && UnattendedScriptFile) {
  953. if (!MigrateUnattendDataEntries(FileName, UnattendedScriptFile)){
  954. goto c1;
  955. }
  956. if(!AppendParamsFile(ParentWindow,UnattendedScriptFile,FileName)) {
  957. return(FALSE);
  958. }
  959. }
  960. #if defined(UNICODE) && defined(_X86_)
  961. //
  962. // Append any migdll info.
  963. //
  964. if (Upgrade && ISNT() && *g_MigDllAnswerFilePath && FileExists (g_MigDllAnswerFilePath, NULL)) {
  965. AppendParamsFile (ParentWindow, g_MigDllAnswerFilePath, FileName);
  966. }
  967. #endif
  968. //
  969. // append DynamicUpdate data
  970. //
  971. if (!DynamicUpdateWriteParams (FileName)) {
  972. goto c1;
  973. }
  974. //
  975. // If we're explicitly in unattended mode then it's possible that
  976. // there is no [Unattended] section in winnt.sif yet, such as if
  977. // the user used the /unattend switch without specifying a file,
  978. // or if the file he did specify didn't have an [Unattended] section
  979. // for some reason.
  980. //
  981. // Also, make all upgrades unattended.
  982. //
  983. // Text mode setup kicks into unattended mode based on the presence
  984. // of the [Unattended] section.
  985. //
  986. if(UnattendedOperation || Upgrade) {
  987. if(!WritePrivateProfileString(WINNT_UNATTENDED,TEXT("unused"),TEXT("unused"),FileName)) {
  988. goto c1;
  989. }
  990. }
  991. //
  992. // Since several conditions can turn on UnattendedOperation, we keep track
  993. // of whether the user actually specified the "/unattend" switch separately.
  994. //
  995. if( UnattendSwitchSpecified ) {
  996. if(!WritePrivateProfileString(WinntDataSection,WINNT_D_UNATTEND_SWITCH,WINNT_A_YES,FileName)) {
  997. goto c1;
  998. }
  999. }
  1000. //
  1001. // set the NTFS conversion flag
  1002. //
  1003. GetPrivateProfileString(WINNT_UNATTENDED,TEXT("FileSystem"),TEXT(""),Text,sizeof(Text)/sizeof(TCHAR),FileName);
  1004. if (_tcslen(Text) == 0) {
  1005. if (ForceNTFSConversion) {
  1006. if(!WritePrivateProfileString(WinntDataSection,TEXT("FileSystem"),TEXT("ConvertNTFS"),FileName)) {
  1007. goto c1;
  1008. }
  1009. }
  1010. }
  1011. //
  1012. // Headless Stuff.
  1013. //
  1014. if( !WriteHeadlessParameters( FileName ) ) {
  1015. goto c1;
  1016. }
  1017. if ( (Upgrade) &&
  1018. !(ISNT() && (BuildNumber <= NT351)) ) {
  1019. //
  1020. // Save current Program Files directory
  1021. //
  1022. rc = RegOpenKeyEx (
  1023. HKEY_LOCAL_MACHINE,
  1024. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
  1025. 0, //ulOptions (reserved)
  1026. KEY_READ,
  1027. &hKey
  1028. );
  1029. if (rc != ERROR_SUCCESS) {
  1030. goto c1;
  1031. }
  1032. PfPath = pGetPfPath (hKey, TEXT("ProgramFilesDir"));
  1033. if (PfPath) {
  1034. if (!WritePrivateProfileString (
  1035. WINNT_UNATTENDED,
  1036. WINNT_U_PROGRAMFILESDIR,
  1037. PfPath,
  1038. FileName
  1039. )) {
  1040. goto c3;
  1041. }
  1042. FREE((PVOID) PfPath);
  1043. }
  1044. PfPath = pGetPfPath (hKey, TEXT("CommonFilesDir"));
  1045. if (PfPath) {
  1046. if (!WritePrivateProfileString (
  1047. WINNT_UNATTENDED,
  1048. WINNT_U_COMMONPROGRAMFILESDIR,
  1049. PfPath,
  1050. FileName
  1051. )) {
  1052. goto c3;
  1053. }
  1054. FREE((PVOID) PfPath);
  1055. }
  1056. #ifdef WX86
  1057. PfPath = pGetPfPath (hKey, TEXT("ProgramFilesDir (x86)"));
  1058. if (PfPath) {
  1059. if (!WritePrivateProfileString (
  1060. WINNT_UNATTENDED,
  1061. WINNT_U_PROGRAMFILESDIR_X86,
  1062. PfPath,
  1063. FileName
  1064. )) {
  1065. goto c3;
  1066. }
  1067. FREE((PVOID) PfPath);
  1068. }
  1069. PfPath = pGetPfPath (hKey, TEXT("CommonFilesDir (x86)"));
  1070. if (PfPath) {
  1071. if (!WritePrivateProfileString (
  1072. WINNT_UNATTENDED,
  1073. WINNT_U_COMMONPROGRAMFILESDIR_X86,
  1074. PfPath,
  1075. FileName
  1076. )) {
  1077. goto c3;
  1078. }
  1079. FREE((PVOID) PfPath);
  1080. }
  1081. #endif
  1082. RegCloseKey(hKey);
  1083. }
  1084. //
  1085. // value indicating the product ID
  1086. // we need to write this in after appending the unattend file data, since the
  1087. // product ID in the unattend file may have been incorrect, but this product ID
  1088. // has already been verified as valid. we need to make sure we surround the product ID with quotes
  1089. //
  1090. if (b ) {
  1091. // This will overwrite any existing "ProductID" entry. Which may have been added
  1092. // by merging the unattend file.
  1093. // If we don't do this. GUI mode overwrites the "ProductKey" with the entry
  1094. // under "ProductID".
  1095. b = WritePidToParametersFile(WinntUserSection,WINNT_US_PRODUCTID,FileName);
  1096. if (!b) {
  1097. goto c1;
  1098. }
  1099. b = WritePidToParametersFile(WinntUserSection,WINNT_US_PRODUCTKEY,FileName);
  1100. if (!b) {
  1101. goto c1;
  1102. }
  1103. }
  1104. //
  1105. // Do not save the proxy settings if we are running under WINPE.
  1106. //
  1107. if (!IsWinPEMode()){
  1108. SaveProxyForOobe(FileName);
  1109. }
  1110. return(TRUE);
  1111. c3:
  1112. FREE((PVOID) PfPath);
  1113. RegCloseKey(hKey);
  1114. c2:
  1115. MessageBoxFromMessageAndSystemError(
  1116. ParentWindow,
  1117. MSG_REGISTRY_ACCESS_ERROR,
  1118. GetLastError(),
  1119. AppTitleStringId,
  1120. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1121. NULL
  1122. );
  1123. goto c0;
  1124. c1:
  1125. MessageBoxFromMessageAndSystemError(
  1126. ParentWindow,
  1127. MSG_BOOT_FILE_ERROR,
  1128. GetLastError(),
  1129. AppTitleStringId,
  1130. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1131. FileName
  1132. );
  1133. c0:
  1134. return(FALSE);
  1135. }
  1136. DWORD
  1137. PatchWinntSifFile(
  1138. IN LPCTSTR Filename
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. This function works around the problems in the setupldr parser,
  1143. which cannot handle unquoted strings. Each line in the given file
  1144. is enclosed within quotation marks.
  1145. Arguments:
  1146. Filename - Name of the WINNT.SIF file
  1147. Return Value:
  1148. Boolean value indicating outcome. If FALSE the user is NOT
  1149. informed about why; the caller must do that.
  1150. --*/
  1151. {
  1152. PVOID Base;
  1153. HANDLE hMap,hFile;
  1154. DWORD Size;
  1155. DWORD d;
  1156. PCHAR End;
  1157. PCHAR p,q;
  1158. PCHAR o,a;
  1159. PCHAR Buffer;
  1160. int l1,l2;
  1161. int tryagain=0;
  1162. //
  1163. // Open the file.
  1164. //
  1165. d = MapFileForRead(Filename,&Size,&hFile,&hMap,&Base);
  1166. if(d != NO_ERROR) {
  1167. return(FALSE);
  1168. }
  1169. //
  1170. // Allocate the output buffer; the original size + extra space for quotes
  1171. //
  1172. Buffer = MALLOC(Size + Size / 4);
  1173. if(!Buffer) {
  1174. UnmapFile(hMap,Base);
  1175. CloseHandle(hFile);
  1176. return(ERROR_NOT_ENOUGH_MEMORY);
  1177. }
  1178. o = Buffer;
  1179. p = Base;
  1180. End = p+Size;
  1181. while(p < End) {
  1182. //
  1183. // Find end of line.
  1184. //
  1185. for(q=p; (q < End) && (*q != '\n'); q++) {
  1186. NOTHING;
  1187. }
  1188. //
  1189. // Find equals sign, if present
  1190. //
  1191. for(a=p; a<q; a++) {
  1192. if(*a == '=') {
  1193. break;
  1194. }
  1195. }
  1196. if(a >= q) {
  1197. a = NULL;
  1198. }
  1199. if(a) {
  1200. a++;
  1201. l1 = (int)(a - p);
  1202. l2 = (int)(q - a);
  1203. CopyMemory(o,p,l1);
  1204. o += l1;
  1205. *o++ = '\"';
  1206. CopyMemory(o,a,l2);
  1207. o += l2;
  1208. if(*(o-1) == '\r') {
  1209. o--;
  1210. }
  1211. *o++ = '\"';
  1212. *o++ = '\r';
  1213. *o++ = '\n';
  1214. } else {
  1215. l1 = (int)(q-p);
  1216. CopyMemory(o,p,l1);
  1217. o += l1;
  1218. *o++ = '\n';
  1219. }
  1220. //
  1221. // Skip to start of next line
  1222. //
  1223. p=q+1;
  1224. }
  1225. UnmapFile(hMap,Base);
  1226. CloseHandle(hFile);
  1227. SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
  1228. //
  1229. // We try opening the file thrice to get around the problem of anti-virus software
  1230. // that monitor files on the root of the system partition. The problem is that usually these
  1231. // s/w examine the files we touch and in somecases open it with exclusive access.
  1232. // We just need to wait for them to be done.
  1233. //
  1234. while( tryagain++ < 3 ){
  1235. hFile = CreateFile(
  1236. Filename,
  1237. GENERIC_WRITE,
  1238. FILE_SHARE_READ,
  1239. NULL,
  1240. CREATE_ALWAYS,
  1241. FILE_ATTRIBUTE_NORMAL,
  1242. NULL
  1243. );
  1244. if(hFile != INVALID_HANDLE_VALUE)
  1245. break;
  1246. Sleep(500);
  1247. }
  1248. if(hFile == INVALID_HANDLE_VALUE) {
  1249. d = GetLastError();
  1250. FREE(Buffer);
  1251. return(d);
  1252. }
  1253. d = WriteFile(hFile,Buffer,(DWORD)(o-Buffer),&Size,NULL) ? NO_ERROR : GetLastError();
  1254. CloseHandle(hFile);
  1255. FREE(Buffer);
  1256. return(d);
  1257. }
  1258. BOOL
  1259. AppendParamsFile(
  1260. IN HWND ParentWindow,
  1261. IN LPCTSTR ParametersFileIn,
  1262. IN LPCTSTR ParametersFileOut
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. Read an external file (such as an unattended script file)
  1267. and copy it section by section into the winnt.sif parameters
  1268. file. (The [Data] and [OemBootFiles] sections of the unattend file
  1269. are ignored.)
  1270. Arguments:
  1271. ParentWindow - supplies window handle of window to act as owner/parent
  1272. if this routine has to put up ui, such as when the script file
  1273. is bogus.
  1274. ParametersFileIn - supplies win32 filename of the file, such as
  1275. unattend.txt, being appended to winnt.sif.
  1276. ParametersFileOut - supplies win32 filename of the winnt.sif file
  1277. being generated.
  1278. Return Value:
  1279. Boolean value indicating outcome. If FALSE, the user will have been
  1280. informed of why.
  1281. --*/
  1282. {
  1283. TCHAR *SectionNames;
  1284. TCHAR *SectionData;
  1285. TCHAR *SectionName;
  1286. DWORD SectionNamesSize;
  1287. DWORD SectionDataSize;
  1288. DWORD d;
  1289. TCHAR TempFile[MAX_PATH] = TEXT("");
  1290. PCTSTR RealInputFile = NULL;
  1291. BOOL b;
  1292. PVOID p;
  1293. #define PROFILE_BUFSIZE 16384
  1294. #define PROFILE_BUFGROW 4096
  1295. //
  1296. // Allocate some memory for the required buffers
  1297. //
  1298. SectionNames = MALLOC(PROFILE_BUFSIZE * sizeof(TCHAR));
  1299. SectionData = MALLOC(PROFILE_BUFSIZE * sizeof(TCHAR));
  1300. if(!SectionNames || !SectionData) {
  1301. MessageBoxFromMessage(
  1302. ParentWindow,
  1303. MSG_OUT_OF_MEMORY,
  1304. FALSE,
  1305. AppTitleStringId,
  1306. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1307. );
  1308. b = FALSE;
  1309. goto c0;
  1310. }
  1311. *TempFile = 0;
  1312. RealInputFile = ParametersFileIn;
  1313. //
  1314. // There is a bug in Win9x's GetPrivateProfileSection() Such that if the file
  1315. // being queried exists on a read only share, it will not return the section strings.
  1316. // This is bad.
  1317. //
  1318. // To work around this, on win9x, we are going to make a temporary copy of the inf
  1319. // merge it in and then delete it.
  1320. //
  1321. #ifdef _X86_
  1322. if (!ISNT() && ParametersFileIn && FileExists (ParametersFileIn, NULL)) {
  1323. GetSystemDirectory (TempFile, MAX_PATH);
  1324. GetTempFileName (TempFile, TEXT("USF"), 0, TempFile);
  1325. CopyFile (ParametersFileIn, TempFile, FALSE);
  1326. RealInputFile = TempFile;
  1327. }
  1328. #endif
  1329. SectionNamesSize = PROFILE_BUFSIZE;
  1330. SectionDataSize = PROFILE_BUFSIZE;
  1331. //
  1332. // Retreive a list of section names in the unattend script file.
  1333. //
  1334. do {
  1335. d = GetPrivateProfileString(
  1336. NULL,
  1337. NULL,
  1338. TEXT(""),
  1339. SectionNames,
  1340. SectionNamesSize,
  1341. RealInputFile
  1342. );
  1343. if(!d) {
  1344. //
  1345. // No section names. Bogus file.
  1346. //
  1347. MessageBoxFromMessage(
  1348. ParentWindow,
  1349. MSG_UNATTEND_FILE_INVALID,
  1350. FALSE,
  1351. AppTitleStringId,
  1352. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1353. ParametersFileIn
  1354. );
  1355. b = FALSE;
  1356. goto c0;
  1357. }
  1358. if(d == (SectionNamesSize-2)) {
  1359. //
  1360. // Buffer was too small. Reallocate it and try again.
  1361. //
  1362. p = REALLOC(
  1363. SectionNames,
  1364. (SectionNamesSize+PROFILE_BUFGROW)*sizeof(TCHAR)
  1365. );
  1366. if(!p) {
  1367. MessageBoxFromMessage(
  1368. ParentWindow,
  1369. MSG_OUT_OF_MEMORY,
  1370. FALSE,
  1371. AppTitleStringId,
  1372. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1373. );
  1374. b = FALSE;
  1375. goto c0;
  1376. }
  1377. SectionNames = p;
  1378. SectionNamesSize += PROFILE_BUFGROW;
  1379. }
  1380. } while(d == (SectionNamesSize-2));
  1381. for(SectionName=SectionNames; *SectionName; SectionName+=lstrlen(SectionName)+1) {
  1382. //
  1383. // Ignore the [data] section in the source, as we do not
  1384. // want copy it into the target, because this would overwrite
  1385. // our internal settings.
  1386. // Ignore also [OemBootFiles]
  1387. //
  1388. if(lstrcmpi(SectionName,WINNT_DATA) && lstrcmpi(SectionName,WINNT_OEMBOOTFILES)) {
  1389. //
  1390. // Fetch the entire section and write it to the target file.
  1391. // Note that the section-based API call will leave double-quotes
  1392. // intact when we retrieve the data, which is what we want.
  1393. // Key-based API calls will strip quotes, which screws us.
  1394. //
  1395. while(GetPrivateProfileSection(
  1396. SectionName,
  1397. SectionData,
  1398. SectionDataSize,
  1399. RealInputFile
  1400. ) == (SectionDataSize-2)) {
  1401. //
  1402. // Reallocate the buffer and try again.
  1403. //
  1404. p = REALLOC(
  1405. SectionData,
  1406. (SectionDataSize+PROFILE_BUFGROW)*sizeof(TCHAR)
  1407. );
  1408. if(!p) {
  1409. MessageBoxFromMessage(
  1410. ParentWindow,
  1411. MSG_OUT_OF_MEMORY,
  1412. FALSE,
  1413. AppTitleStringId,
  1414. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1415. );
  1416. b = FALSE;
  1417. goto c0;
  1418. }
  1419. SectionData = 0;
  1420. SectionDataSize += PROFILE_BUFGROW;
  1421. }
  1422. //
  1423. // Write the entire section to the output file.
  1424. //
  1425. if(!WritePrivateProfileSection(SectionName,SectionData,ParametersFileOut)) {
  1426. MessageBoxFromMessageAndSystemError(
  1427. ParentWindow,
  1428. MSG_BOOT_FILE_ERROR,
  1429. GetLastError(),
  1430. AppTitleStringId,
  1431. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1432. ParametersFileOut
  1433. );
  1434. b = FALSE;
  1435. goto c0;
  1436. }
  1437. }
  1438. }
  1439. b = TRUE;
  1440. c0:
  1441. if(SectionNames) {
  1442. FREE(SectionNames);
  1443. }
  1444. if(SectionData) {
  1445. FREE(SectionData);
  1446. }
  1447. if (*TempFile) {
  1448. DeleteFile (TempFile);
  1449. }
  1450. return(b);
  1451. }
  1452. BOOL
  1453. WriteParametersFile(
  1454. IN HWND ParentWindow
  1455. )
  1456. {
  1457. TCHAR SysPartFile[MAX_PATH];
  1458. DWORD d;
  1459. BOOL b;
  1460. //
  1461. // Write the file out onto the root of the system partition drive
  1462. // and then move the file into place where it actually belongs.
  1463. //
  1464. #if defined(REMOTE_BOOT)
  1465. if (RemoteBoot) {
  1466. //
  1467. // For remote boot, put the file in the root of the machine directory
  1468. // and leave it there.
  1469. //
  1470. StringCchCopy(SysPartFile, ARRAYSIZE(SysPartFile), MachineDirectory);
  1471. StringCchCat(SysPartFile, ARRAYSIZE(SysPartFile), TEXT("\\"));
  1472. StringCchCat(SysPartFile, ARRAYSIZE(SysPartFile), WINNT_SIF_FILE);
  1473. StringCchCopy(ActualParamFile, ARRAYSIZE(ActualParamFile), SysPartFile);
  1474. } else
  1475. #endif // defined(REMOTE_BOOT)
  1476. {
  1477. if (!BuildSystemPartitionPathToFile (WINNT_SIF_FILE, SysPartFile, MAX_PATH)) {
  1478. return(FALSE); // this should never happen.
  1479. }
  1480. }
  1481. if(!DoWriteParametersFile(ParentWindow,SysPartFile)) {
  1482. return(FALSE);
  1483. }
  1484. #if defined(REMOTE_BOOT)
  1485. //
  1486. // For remote boot, leave the file in the root of the machine directory.
  1487. //
  1488. if (!RemoteBoot)
  1489. #endif // defined(REMOTE_BOOT)
  1490. {
  1491. if (!IsArc()) {
  1492. #if defined(_AMD64_) || defined(_X86_)
  1493. //
  1494. // In the amd64/x86 case this file belongs on the boot media
  1495. // somewhere. If we're generating floppyless boot media
  1496. // then move the file into place. Otherwise there's no point.
  1497. //
  1498. // In the non-floppyless case we keep the file around until later
  1499. // when the floppy-generation code gets to run.
  1500. //
  1501. if(MakeBootMedia) {
  1502. if(Floppyless) {
  1503. BuildSystemPartitionPathToFile (LOCAL_BOOT_DIR, ActualParamFile, MAX_PATH);
  1504. d = CreateMultiLevelDirectory(ActualParamFile);
  1505. if(d != NO_ERROR) {
  1506. MessageBoxFromMessageAndSystemError(
  1507. ParentWindow,
  1508. MSG_DIR_CREATE_FAILED,
  1509. d,
  1510. AppTitleStringId,
  1511. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1512. ActualParamFile
  1513. );
  1514. DeleteFile(SysPartFile);
  1515. return(FALSE);
  1516. }
  1517. ConcatenatePaths(ActualParamFile,WINNT_SIF_FILE,MAX_PATH);
  1518. //
  1519. // Move the file into its real location.
  1520. //
  1521. DeleteFile(ActualParamFile);
  1522. //
  1523. // On Windows 95, MoveFile fails in strange ways
  1524. // when the profile APIs have the file open (for instance,
  1525. // it will leave the src file and the dest file will be
  1526. // filled with garbage).
  1527. //
  1528. // Flush it.
  1529. //
  1530. WritePrivateProfileString(NULL,NULL,NULL,SysPartFile);
  1531. if (SysPartFile[0] == ActualParamFile[0]) {
  1532. b = MoveFile(SysPartFile,ActualParamFile);
  1533. } else {
  1534. b = CopyFile (SysPartFile, ActualParamFile, FALSE);
  1535. if (b) {
  1536. DeleteFile (SysPartFile);
  1537. }
  1538. }
  1539. if (!b) {
  1540. MessageBoxFromMessageAndSystemError(
  1541. ParentWindow,
  1542. MSG_BOOT_FILE_ERROR,
  1543. GetLastError(),
  1544. AppTitleStringId,
  1545. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1546. ActualParamFile
  1547. );
  1548. DeleteFile(SysPartFile);
  1549. return(FALSE);
  1550. }
  1551. }
  1552. } else {
  1553. DeleteFile(SysPartFile);
  1554. }
  1555. #endif // defined(_AMD64_) || defined(_X86_)
  1556. } else {
  1557. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  1558. //
  1559. // If we're making a local source, move the file there.
  1560. // Otherwise just leave it on the root of the system partition.
  1561. //
  1562. if(MakeLocalSource) {
  1563. d = CreateMultiLevelDirectory(LocalSourceWithPlatform);
  1564. if(d != NO_ERROR) {
  1565. MessageBoxFromMessageAndSystemError(
  1566. ParentWindow,
  1567. MSG_DIR_CREATE_FAILED,
  1568. d,
  1569. AppTitleStringId,
  1570. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1571. LocalSourceWithPlatform
  1572. );
  1573. DeleteFile(SysPartFile);
  1574. return(FALSE);
  1575. }
  1576. //
  1577. // Move the file into its real location.
  1578. //
  1579. StringCchPrintf(ActualParamFile, ARRAYSIZE(ActualParamFile), TEXT("%s\\%s"),LocalSourceWithPlatform,WINNT_SIF_FILE);
  1580. DeleteFile(ActualParamFile);
  1581. if(!MoveFile(SysPartFile,ActualParamFile)) {
  1582. MessageBoxFromMessageAndSystemError(
  1583. ParentWindow,
  1584. MSG_BOOT_FILE_ERROR,
  1585. GetLastError(),
  1586. AppTitleStringId,
  1587. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1588. ActualParamFile
  1589. );
  1590. DeleteFile(SysPartFile);
  1591. return(FALSE);
  1592. }
  1593. }
  1594. #endif // UNICODE
  1595. } // if (!IsArc())
  1596. }
  1597. return(TRUE);
  1598. }
  1599. #define MULTI_SZ_NEXT_STRING(x) ((x) + _tcslen(x) + 1)
  1600. BOOL
  1601. MergeINFFiles(
  1602. IN PCTSTR SourceFileName,
  1603. IN PCTSTR DestFileName
  1604. )
  1605. {
  1606. DWORD dwAttributes;
  1607. PTSTR pSectionsBuffer = NULL;
  1608. PTSTR pKeysBuffer = NULL;
  1609. PTSTR pString = NULL;
  1610. PTSTR pSection;
  1611. PTSTR pKey;
  1612. UINT sizeOfBuffer;
  1613. UINT sizeOfSectionBuffer;
  1614. BOOL bResult = FALSE;
  1615. MYASSERT (SourceFileName && DestFileName);
  1616. if(-1 == GetFileAttributes(SourceFileName)){
  1617. return TRUE;
  1618. }
  1619. __try{
  1620. //
  1621. // Allocate buffer for sections names.
  1622. //
  1623. sizeOfBuffer = 0;
  1624. do{
  1625. if(pSectionsBuffer){
  1626. FREE(pSectionsBuffer);
  1627. }
  1628. sizeOfBuffer += DEF_INF_BUFFER_SIZE;
  1629. pSectionsBuffer = (PTSTR)MALLOC(sizeOfBuffer * sizeof (TCHAR));
  1630. if(!pSectionsBuffer){
  1631. __leave;
  1632. }
  1633. }while((sizeOfBuffer - 2) ==
  1634. GetPrivateProfileSectionNames(pSectionsBuffer,
  1635. sizeOfBuffer,
  1636. SourceFileName));
  1637. sizeOfSectionBuffer = DEF_INF_BUFFER_SIZE;
  1638. pKeysBuffer = (PTSTR)MALLOC(sizeOfSectionBuffer * sizeof (TCHAR));
  1639. if(!pKeysBuffer){
  1640. __leave;
  1641. }
  1642. sizeOfBuffer = DEF_INF_BUFFER_SIZE;
  1643. pString = (PTSTR)MALLOC(sizeOfBuffer * sizeof (TCHAR));
  1644. if(!pString){
  1645. __leave;
  1646. }
  1647. for(pSection = pSectionsBuffer; pSection[0]; pSection = MULTI_SZ_NEXT_STRING(pSection)){
  1648. //
  1649. // Allocate buffer for entries names;
  1650. //
  1651. while((sizeOfSectionBuffer - 2) ==
  1652. GetPrivateProfileString(pSection,
  1653. NULL,
  1654. EMPTY_STRING,
  1655. pKeysBuffer,
  1656. sizeOfSectionBuffer,
  1657. SourceFileName)){
  1658. if(pKeysBuffer){
  1659. FREE(pKeysBuffer);
  1660. }
  1661. sizeOfSectionBuffer += DEF_INF_BUFFER_SIZE;
  1662. pKeysBuffer = (PTSTR)MALLOC(sizeOfSectionBuffer * sizeof (TCHAR));
  1663. if(!pKeysBuffer){
  1664. __leave;
  1665. }
  1666. };
  1667. for(pKey = pKeysBuffer; pKey[0]; pKey = MULTI_SZ_NEXT_STRING(pKey))
  1668. {
  1669. //
  1670. // Allocate buffer for value string;
  1671. //
  1672. GetPrivateProfileString(pSection,
  1673. pKey,
  1674. EMPTY_STRING,
  1675. pString,
  1676. sizeOfBuffer,
  1677. SourceFileName);
  1678. if (!WritePrivateProfileString(pSection, pKey, pString, DestFileName)) {
  1679. __leave;
  1680. }
  1681. }
  1682. }
  1683. bResult = TRUE;
  1684. }
  1685. __finally{
  1686. DWORD rc = GetLastError ();
  1687. if(pSectionsBuffer){
  1688. FREE(pSectionsBuffer);
  1689. }
  1690. if(pKeysBuffer){
  1691. FREE(pKeysBuffer);
  1692. }
  1693. if(pString){
  1694. FREE(pString);
  1695. }
  1696. SetLastError (rc);
  1697. }
  1698. return bResult;
  1699. }
  1700. BOOL
  1701. AddExternalParams (
  1702. IN HWND ParentWindow
  1703. )
  1704. {
  1705. DWORD rc = ERROR_SUCCESS;
  1706. static BOOL Done = FALSE;
  1707. if(Done) {
  1708. return(TRUE);
  1709. }
  1710. //
  1711. // Append external parameters if necessary.
  1712. //
  1713. if(Upgrade && UpgradeSupport.WriteParamsRoutine) {
  1714. rc = UpgradeSupport.WriteParamsRoutine(ActualParamFile);
  1715. if (rc != ERROR_SUCCESS) {
  1716. MessageBoxFromMessageAndSystemError(
  1717. ParentWindow,
  1718. MSG_BOOT_FILE_ERROR,
  1719. GetLastError(),
  1720. AppTitleStringId,
  1721. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1722. ActualParamFile
  1723. );
  1724. }
  1725. }
  1726. #if defined(UNICODE) && defined(_X86_)
  1727. //
  1728. // Merge NT migration unattented inf file with winnt.sif
  1729. //
  1730. if(Upgrade && !MergeINFFiles(g_MigDllAnswerFilePath, ActualParamFile)){
  1731. MessageBoxFromMessageAndSystemError(
  1732. ParentWindow,
  1733. MSG_BOOT_FILE_ERROR,
  1734. GetLastError(),
  1735. AppTitleStringId,
  1736. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1737. g_MigDllAnswerFilePath
  1738. );
  1739. }
  1740. #endif
  1741. //
  1742. // write the compatibility stuff in these cases
  1743. //
  1744. // 1. upgrade from downlevel NT platform
  1745. // 2. clean install
  1746. // 3. upgrade from current NT platform and we have NT5 compatibility items
  1747. //
  1748. // note that win9x has it's own upgrade code path.
  1749. //
  1750. if( (ISNT() && (BuildNumber <= NT40) && Upgrade)
  1751. || !Upgrade
  1752. || (ISNT() && Upgrade && AnyNt5CompatDlls) ){
  1753. //
  1754. // Disable stuff for <= NT4 case, clean install (unsupported arch. etc.)
  1755. // and NT5 upgrade with NT5 upgrade components set
  1756. //
  1757. WriteCompatibilityData( ActualParamFile );
  1758. WriteGUIModeInfOperations( ActualParamFile );
  1759. AddGUIModeCompatibilityInfsToCopyList();
  1760. }
  1761. if (ISNT() && Upgrade) {
  1762. if (!WriteTextmodeClobberData (ActualParamFile)) {
  1763. rc = GetLastError ();
  1764. }
  1765. }
  1766. Done = TRUE;
  1767. return rc == ERROR_SUCCESS;
  1768. }
  1769. BOOL
  1770. MyWritePrivateProfileString(
  1771. LPCTSTR lpAppName, // pointer to section name
  1772. LPCTSTR lpKeyName, // pointer to key name
  1773. LPCTSTR lpString, // pointer to string to add
  1774. LPCTSTR lpFileName // pointer to initialization filename
  1775. )
  1776. /*
  1777. Wrapper for WritePrivateProfileString to try more than once on instances
  1778. where we can't write to the winnt.sif file. This commonly occurs when
  1779. virus software monitors the root of C drive.
  1780. The problem is that usually these s/w examine the files we touch and in somecases open it
  1781. with exclusive access. We just need to wait for them to be done.
  1782. */
  1783. {
  1784. int i = 0;
  1785. BOOL ret = FALSE;
  1786. DWORD Err;
  1787. while(i++ < 3){
  1788. #ifdef UNICODE
  1789. #ifdef WritePrivateProfileStringW
  1790. #undef WritePrivateProfileStringW
  1791. if( !lpAppName && !lpKeyName && !lpString ){
  1792. WritePrivateProfileStringW( lpAppName, lpKeyName, lpString, lpFileName);
  1793. return FALSE;
  1794. }
  1795. if( ret = WritePrivateProfileStringW( lpAppName, lpKeyName, lpString, lpFileName) )
  1796. break;
  1797. #endif
  1798. #else
  1799. #ifdef WritePrivateProfileStringA
  1800. #undef WritePrivateProfileStringA
  1801. if( !lpAppName && !lpKeyName && !lpString ){
  1802. WritePrivateProfileStringA( lpAppName, lpKeyName, lpString, lpFileName);
  1803. return FALSE;
  1804. }
  1805. if( ret = WritePrivateProfileStringA( lpAppName, lpKeyName, lpString, lpFileName) )
  1806. break;
  1807. #endif
  1808. #endif
  1809. Sleep( 500 );
  1810. }
  1811. return ret;
  1812. }
  1813. VOID
  1814. FixWininetList(
  1815. LPTSTR List
  1816. )
  1817. {
  1818. PTCHAR t = List;
  1819. if (t != NULL)
  1820. {
  1821. while (*t)
  1822. {
  1823. if (*t == (TCHAR)' ')
  1824. {
  1825. *t = (TCHAR)';';
  1826. }
  1827. t++;
  1828. }
  1829. }
  1830. }
  1831. #ifdef UNICODE
  1832. LPWSTR
  1833. AnsiToText(
  1834. LPCSTR Ansi
  1835. )
  1836. {
  1837. int Length;
  1838. LPWSTR Unicode = NULL;
  1839. if (Ansi == NULL)
  1840. {
  1841. return NULL;
  1842. }
  1843. Length = MultiByteToWideChar(
  1844. CP_ACP,
  1845. 0,
  1846. Ansi,
  1847. -1,
  1848. NULL,
  1849. 0
  1850. );
  1851. if (Length > 0)
  1852. {
  1853. int i;
  1854. Unicode = (LPWSTR) GlobalAlloc(GPTR, Length * sizeof(WCHAR));
  1855. if (!Unicode) {
  1856. return NULL;
  1857. }
  1858. i = MultiByteToWideChar(
  1859. CP_ACP,
  1860. 0,
  1861. Ansi,
  1862. -1,
  1863. Unicode,
  1864. Length);
  1865. if (i == 0)
  1866. {
  1867. GlobalFree(Unicode);
  1868. Unicode = NULL;
  1869. }
  1870. }
  1871. return Unicode;
  1872. }
  1873. #else
  1874. LPSTR AnsiToText(
  1875. LPCSTR Ansi
  1876. )
  1877. /*++
  1878. Note:
  1879. Can't use DupString because the caller assume memory obtained from
  1880. GlobalAlloc.
  1881. --*/
  1882. {
  1883. LPSTR CopyOfAnsi = NULL;
  1884. if (Ansi != NULL)
  1885. {
  1886. CopyOfAnsi = GlobalAlloc(GPTR, (strlen(Ansi)+1) * sizeof(CHAR));
  1887. if (CopyOfAnsi)
  1888. {
  1889. strcpy(CopyOfAnsi, Ansi);
  1890. }
  1891. }
  1892. return CopyOfAnsi;
  1893. }
  1894. #endif
  1895. BOOL
  1896. QuoteString(
  1897. IN OUT LPTSTR* StringPointer
  1898. )
  1899. /*++
  1900. Routine Description:
  1901. Replace the input string with a double quoted one.
  1902. Arguments:
  1903. StringPointer - pointer to a string allocated by GlobalAlloc. The input
  1904. string is always free. If it is successful the new string, allocated
  1905. by GlobalAlloc, is returned; otherwise, NULL is returned.
  1906. Return:
  1907. TRUE - successfully quote a string
  1908. FALSE - otherwise
  1909. --*/
  1910. {
  1911. LPTSTR StringValue = *StringPointer;
  1912. LPTSTR QuotedString;
  1913. QuotedString = GlobalAlloc(GPTR, (lstrlen(StringValue) + 3) * sizeof(TCHAR));
  1914. if (QuotedString)
  1915. {
  1916. wsprintf(QuotedString, TEXT("\"%s\""), StringValue);
  1917. *StringPointer = QuotedString;
  1918. }
  1919. else
  1920. {
  1921. *StringPointer = NULL;
  1922. }
  1923. GlobalFree(StringValue);
  1924. return (*StringPointer != NULL);
  1925. }
  1926. VOID
  1927. SaveProxyForOobe(
  1928. IN LPCTSTR FileName
  1929. )
  1930. /*++
  1931. Routine Description:
  1932. Save the LAN http and https proxy settings, if any, for OOBE to use while
  1933. it is running in 'SYSTEM' context.
  1934. Arguments:
  1935. FileName - specifies the full Win32 filename for saving Setup settings.
  1936. --*/
  1937. {
  1938. typedef BOOL (WINAPI* PINTERNETQUERYOPTION)(
  1939. IN HINTERNET hInternet OPTIONAL,
  1940. IN DWORD dwOption,
  1941. OUT LPVOID lpBuffer OPTIONAL,
  1942. IN OUT LPDWORD lpdwBufferLength
  1943. );
  1944. HMODULE WinInetLib;
  1945. LPTSTR ProxyList = NULL;
  1946. LPTSTR ProxyOverride = NULL;
  1947. LPTSTR AutoConfigUrl = NULL;
  1948. LPTSTR AutoConfigUrl2 = NULL;
  1949. DWORD ProxyFlags = 0;
  1950. DWORD AutoDiscoveryFlags = 0;
  1951. TCHAR NumberStr[25];
  1952. BOOL Captured = FALSE;
  1953. WinInetLib = LoadLibrary(TEXT("WININET.DLL"));
  1954. //
  1955. // We prefer the INTERNET_OPTION_PER_CONNECTION_OPTION because we just
  1956. // want to save the LAN proxy settings and we want to know the auto proxy
  1957. // setting, but this option is not supported until IE 5.0
  1958. //
  1959. if (WinInetLib != NULL)
  1960. {
  1961. PINTERNETQUERYOPTION pInternetQueryOption;
  1962. pInternetQueryOption = (PINTERNETQUERYOPTION) GetProcAddress(
  1963. WinInetLib,
  1964. #ifdef UNICODE
  1965. "InternetQueryOptionW"
  1966. #else
  1967. "InternetQueryOptionA"
  1968. #endif
  1969. );
  1970. if (pInternetQueryOption)
  1971. {
  1972. INTERNET_PER_CONN_OPTION_LIST OptionList;
  1973. INTERNET_PER_CONN_OPTION Option[6];
  1974. DWORD BufferLength = sizeof(OptionList);
  1975. OptionList.dwSize = sizeof(OptionList);
  1976. OptionList.pszConnection = NULL;
  1977. OptionList.dwOptionCount = 6;
  1978. ZeroMemory(&Option, sizeof(Option));
  1979. Option[0].dwOption = INTERNET_PER_CONN_FLAGS;
  1980. Option[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
  1981. Option[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
  1982. Option[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
  1983. Option[4].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
  1984. Option[5].dwOption = INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL;
  1985. OptionList.pOptions = Option;
  1986. if (pInternetQueryOption(
  1987. NULL,
  1988. INTERNET_OPTION_PER_CONNECTION_OPTION,
  1989. &OptionList,
  1990. &BufferLength
  1991. ) == TRUE)
  1992. {
  1993. ProxyFlags = Option[0].Value.dwValue;
  1994. ProxyList = Option[1].Value.pszValue;
  1995. ProxyOverride = Option[2].Value.pszValue;
  1996. AutoConfigUrl = Option[3].Value.pszValue;
  1997. AutoDiscoveryFlags = Option[4].Value.dwValue;
  1998. AutoConfigUrl2 = Option[5].Value.pszValue;
  1999. Captured = TRUE;
  2000. }
  2001. else
  2002. {
  2003. INTERNET_PROXY_INFO* ProxyInfo = NULL;
  2004. DWORD BufferLength = 0;
  2005. //
  2006. // We obtain the ANSI string for INTERNET_OPTION_PROXY,
  2007. // even if we call InternetQueryOptionW.
  2008. //
  2009. // Proxy list returned from INTERNET_OPTION_PER_CONNECTION are
  2010. // delimited by ';', while that returned from INTERNET_OPTION_PROXY
  2011. // are delimited by ' '.
  2012. //
  2013. if (pInternetQueryOption(
  2014. NULL,
  2015. INTERNET_OPTION_PROXY,
  2016. ProxyInfo,
  2017. &BufferLength
  2018. ) == FALSE
  2019. &&
  2020. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2021. {
  2022. ProxyInfo = (INTERNET_PROXY_INFO*) GlobalAlloc(GPTR, BufferLength);
  2023. if (ProxyInfo)
  2024. {
  2025. if (pInternetQueryOption(
  2026. NULL,
  2027. INTERNET_OPTION_PROXY,
  2028. ProxyInfo,
  2029. &BufferLength
  2030. ) == TRUE)
  2031. {
  2032. //
  2033. // Map the values to INTERNET_OPTION_PER_CONN_OPTION
  2034. // We enable the auto proxy settings even though
  2035. // INTERNET_OPTION_PROXY doesn't have value relevant
  2036. // to auto proxy, because IE5 default to use auto proxy.
  2037. //
  2038. // PROXY_TYPE_DIRECT is always set because wininet
  2039. // return this flags whether inetcpl.cpl is set
  2040. // to use proxy or not.
  2041. //
  2042. ProxyFlags = PROXY_TYPE_DIRECT | PROXY_TYPE_AUTO_DETECT;
  2043. if (ProxyInfo->dwAccessType != INTERNET_OPEN_TYPE_DIRECT)
  2044. {
  2045. ProxyFlags |= PROXY_TYPE_PROXY;
  2046. }
  2047. ProxyList = AnsiToText((LPCSTR)ProxyInfo->lpszProxy);
  2048. FixWininetList(ProxyList);
  2049. ProxyOverride = AnsiToText((LPCSTR)ProxyInfo->lpszProxyBypass);
  2050. FixWininetList(ProxyOverride);
  2051. AutoDiscoveryFlags = 0;
  2052. Captured = TRUE;
  2053. }
  2054. GlobalFree(ProxyInfo);
  2055. }
  2056. }
  2057. }
  2058. }
  2059. FreeLibrary(WinInetLib);
  2060. }
  2061. if (Captured)
  2062. {
  2063. WritePrivateProfileString(
  2064. WINNT_OOBEPROXY,
  2065. WINNT_O_ENABLE_OOBEPROXY,
  2066. TEXT("1"),
  2067. FileName
  2068. );
  2069. if (ProxyList && QuoteString(&ProxyList))
  2070. {
  2071. WritePrivateProfileString(
  2072. WINNT_OOBEPROXY,
  2073. WINNT_O_PROXY_SERVER,
  2074. ProxyList,
  2075. FileName
  2076. );
  2077. GlobalFree(ProxyList);
  2078. }
  2079. //
  2080. // Fix the ProxyOverride to not have any "\r\n"s
  2081. //
  2082. if (ProxyOverride) {
  2083. ReplaceSubStr(ProxyOverride, TEXT("\r\n"), TEXT(";"));
  2084. }
  2085. if (ProxyOverride && QuoteString(&ProxyOverride))
  2086. {
  2087. WritePrivateProfileString(
  2088. WINNT_OOBEPROXY,
  2089. WINNT_O_PROXY_BYPASS,
  2090. ProxyOverride,
  2091. FileName
  2092. );
  2093. GlobalFree(ProxyOverride);
  2094. }
  2095. if (AutoConfigUrl && QuoteString(&AutoConfigUrl))
  2096. {
  2097. WritePrivateProfileString(
  2098. WINNT_OOBEPROXY,
  2099. WINNT_O_AUTOCONFIG_URL,
  2100. AutoConfigUrl,
  2101. FileName
  2102. );
  2103. GlobalFree(AutoConfigUrl);
  2104. }
  2105. if (AutoConfigUrl2 && QuoteString(&AutoConfigUrl2))
  2106. {
  2107. WritePrivateProfileString(
  2108. WINNT_OOBEPROXY,
  2109. WINNT_O_AUTOCONFIG_SECONDARY_URL,
  2110. AutoConfigUrl2,
  2111. FileName
  2112. );
  2113. GlobalFree(AutoConfigUrl2);
  2114. }
  2115. wsprintf(NumberStr, TEXT("%u"), ProxyFlags);
  2116. WritePrivateProfileString(
  2117. WINNT_OOBEPROXY,
  2118. WINNT_O_FLAGS,
  2119. NumberStr,
  2120. FileName
  2121. );
  2122. wsprintf(NumberStr, TEXT("%u"), AutoDiscoveryFlags);
  2123. WritePrivateProfileString(
  2124. WINNT_OOBEPROXY,
  2125. WINNT_O_AUTODISCOVERY_FLAGS,
  2126. NumberStr,
  2127. FileName
  2128. );
  2129. }
  2130. else
  2131. {
  2132. WritePrivateProfileString(
  2133. WINNT_OOBEPROXY,
  2134. WINNT_O_ENABLE_OOBEPROXY,
  2135. TEXT("0"),
  2136. FileName
  2137. );
  2138. }
  2139. }
  2140. #ifdef _X86_
  2141. BOOL
  2142. IsDriveAssignNEC98(
  2143. VOID
  2144. )
  2145. {
  2146. TCHAR sz95KeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion");
  2147. TCHAR sz95ValueName[] = TEXT("ATboot");
  2148. TCHAR szNTKeyName[] = TEXT("System\\setup");
  2149. TCHAR szNTValueName[] = TEXT("DriveLetter");
  2150. HKEY hKey;
  2151. DWORD type95 = REG_BINARY;
  2152. DWORD typeNT = REG_SZ;
  2153. TCHAR szData[5];
  2154. DWORD dwSize = 5;
  2155. DWORD rc;
  2156. if(ISNT()){
  2157. rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  2158. szNTKeyName,
  2159. 0, //ulOptions (reserved)
  2160. KEY_READ,
  2161. &hKey);
  2162. if (ERROR_SUCCESS != rc) {
  2163. return TRUE;
  2164. }
  2165. //
  2166. // Query key to get the subkey count and max string lengths
  2167. //
  2168. rc = RegQueryValueEx (hKey,
  2169. szNTValueName,
  2170. NULL, // lpReserved
  2171. &typeNT,
  2172. (LPBYTE) szData,
  2173. &dwSize);
  2174. if (ERROR_SUCCESS != rc) {
  2175. RegCloseKey(hKey);
  2176. return TRUE;
  2177. }
  2178. RegCloseKey(hKey);
  2179. if (szData[0] != L'C'){
  2180. // NEC DOS Type.
  2181. return TRUE;
  2182. }
  2183. } else { // It will be Win9x
  2184. rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  2185. sz95KeyName,
  2186. 0, //ulOptions (reserved)
  2187. KEY_READ,
  2188. &hKey);
  2189. if (ERROR_SUCCESS != rc) {
  2190. return TRUE;
  2191. }
  2192. //
  2193. // Query key to get the subkey count and max string lengths
  2194. //
  2195. rc = RegQueryValueEx (hKey,
  2196. sz95ValueName,
  2197. NULL, // lpReserved
  2198. &type95,
  2199. (LPBYTE) szData,
  2200. &dwSize);
  2201. if (ERROR_SUCCESS != rc) {
  2202. RegCloseKey(hKey);
  2203. return TRUE;
  2204. }
  2205. RegCloseKey(hKey);
  2206. if (szData[0] == 0){
  2207. // NEC DOS Type.
  2208. return TRUE;
  2209. }
  2210. }
  2211. return FALSE;
  2212. }
  2213. #endif