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.

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