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.

3665 lines
97 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Routines for manupilating the configuration registry.
  7. Entry points:
  8. SaveHive
  9. SetEnvironmentVariableInRegistry
  10. Author:
  11. Ted Miller (tedm) 5-Apr-1995
  12. Revision History:
  13. --*/
  14. #include "setupp.h"
  15. #pragma hdrstop
  16. #ifdef _WIN64
  17. #include <shlwapi.h>
  18. #endif
  19. //
  20. // Names of frequently used keys, values.
  21. //
  22. PCWSTR ControlKeyName = L"SYSTEM\\CurrentControlSet\\Control";
  23. PCWSTR SessionManagerKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager";
  24. PCWSTR EnvironmentKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
  25. PCWSTR WinntSoftwareKeyName = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
  26. PCWSTR MemoryManagementKeyName = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management";
  27. PCWSTR WindowsCurrentVersionKeyName = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
  28. PCWSTR IEProductVersionKeyName = L"Software\\Microsoft\\Internet Explorer\\Registration";
  29. PCWSTR szBootExecute = L"BootExecute";
  30. PCWSTR szRegisteredProcessors = L"RegisteredProcessors";
  31. PCWSTR szLicensedProcessors = L"LicensedProcessors";
  32. PCWSTR szRegisteredOwner = L"RegisteredOwner";
  33. PCWSTR szRegisteredOrganization = L"RegisteredOrganization";
  34. PCWSTR szCurrentProductId = L"CurrentProductId";
  35. //
  36. // Logging constants used only in this module.
  37. //
  38. PCWSTR szRegSaveKey = L"RegSaveKey";
  39. //
  40. // Number of processors to enable in server case.
  41. //
  42. #define SERVER_PROCESSOR_LICENSE (2)
  43. //
  44. // Table telling us the info needed in order to save and
  45. // replace the system hives at the end of setup.
  46. //
  47. struct {
  48. //
  49. // Key and subkey that is at the root of the hive.
  50. //
  51. HKEY RootKey;
  52. PCWSTR Subkey;
  53. //
  54. // Name active hive has in the config directory.
  55. //
  56. PCWSTR Hive;
  57. //
  58. // Name to use for new hive file, that will be the hive
  59. // at next boot.
  60. //
  61. PCWSTR NewHive;
  62. //
  63. // Name to use for current hive file, that will be deleted
  64. // on next boot.
  65. //
  66. PCWSTR DeleteHive;
  67. } HiveTable[3] = {
  68. //
  69. // System hive.
  70. //
  71. { HKEY_LOCAL_MACHINE, L"SYSTEM" , L"SYSTEM" , L"SYS$$$$$.$$$", L"SYS$$$$$.DEL" },
  72. //
  73. // Software hive
  74. //
  75. { HKEY_LOCAL_MACHINE, L"SOFTWARE", L"SOFTWARE", L"SOF$$$$$.$$$", L"SOF$$$$$.DEL" },
  76. //
  77. // Default user hive
  78. //
  79. { HKEY_USERS , L".DEFAULT", L"DEFAULT" , L"DEF$$$$$.$$$", L"DEF$$$$$.DEL" }
  80. };
  81. BOOL
  82. SaveHive(
  83. IN HKEY RootKey,
  84. IN PCWSTR Subkey,
  85. IN PCWSTR Filename,
  86. IN DWORD Format
  87. )
  88. /*++
  89. Routine Description:
  90. Save a hive into a disk file.
  91. Arguments:
  92. RootKey - supplies root key for hive to be saved, ie,
  93. HKEY_LOCAL_MACHINE or HKEY_USERS
  94. Subkey - supplies name of subkey for hive to be saved, such as
  95. SYSTEM, SOFTWARE, or .DEFAULT.
  96. Filename - supplies the name of the file to be created. If it exists
  97. it is overwritten.
  98. Return Value:
  99. Boolean value indicating outcome.
  100. --*/
  101. {
  102. LONG rc;
  103. HKEY hkey;
  104. BOOL b;
  105. b = FALSE;
  106. //
  107. // Open the key.
  108. //
  109. rc = RegOpenKeyEx(RootKey,Subkey,0,KEY_READ,&hkey);
  110. if(rc != NO_ERROR) {
  111. SetuplogError(
  112. LogSevError,
  113. SETUPLOG_USE_MESSAGEID,
  114. MSG_LOG_SAVEHIVE_FAIL,
  115. Subkey,
  116. Filename, NULL,
  117. SETUPLOG_USE_MESSAGEID,
  118. MSG_LOG_X_RETURNED_WINERR,
  119. szRegOpenKeyEx,
  120. rc,
  121. NULL,NULL);
  122. goto err1;
  123. }
  124. //
  125. // Delete the file if it's there.
  126. //
  127. if(FileExists(Filename,NULL)) {
  128. SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
  129. DeleteFile(Filename);
  130. }
  131. //
  132. // Enable backup privilege. Ignore any error.
  133. //
  134. pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE);
  135. //
  136. // Do the save.
  137. //
  138. rc = RegSaveKeyEx(hkey,Filename,NULL,Format);
  139. if(rc != NO_ERROR) {
  140. SetuplogError(
  141. LogSevError,
  142. SETUPLOG_USE_MESSAGEID,
  143. MSG_LOG_SAVEHIVE_FAIL,
  144. Subkey,
  145. Filename, NULL,
  146. SETUPLOG_USE_MESSAGEID,
  147. MSG_LOG_X_RETURNED_WINERR,
  148. szRegSaveKey,
  149. rc,
  150. NULL,NULL);
  151. goto err2;
  152. }
  153. b = TRUE;
  154. err2:
  155. RegCloseKey(hkey);
  156. err1:
  157. return(b);
  158. }
  159. BOOL
  160. SetEnvironmentVariableInRegistry(
  161. IN PCWSTR Name,
  162. IN PCWSTR Value,
  163. IN BOOL SystemWide
  164. )
  165. {
  166. HKEY hKey,hRootKey;
  167. PCWSTR Subkey;
  168. DWORD dwDisp;
  169. LONG rc;
  170. BOOL b;
  171. b = FALSE;
  172. //
  173. // Check if the caller wants to modify a system environment variable
  174. // or a user environment variable. Accordingly find out the right
  175. // place in the registry to look.
  176. //
  177. if(SystemWide) {
  178. hRootKey = HKEY_LOCAL_MACHINE;
  179. Subkey = EnvironmentKeyName;
  180. } else {
  181. hRootKey = HKEY_CURRENT_USER;
  182. Subkey = L"Environment";
  183. }
  184. //
  185. // Open the environment variable key.
  186. //
  187. rc = RegCreateKeyEx(hRootKey,Subkey,0,NULL,REG_OPTION_NON_VOLATILE,
  188. KEY_WRITE,NULL,&hKey,&dwDisp);
  189. if(rc != NO_ERROR) {
  190. SetuplogError(
  191. LogSevWarning,
  192. SETUPLOG_USE_MESSAGEID,
  193. MSG_LOG_SETENV_FAIL,
  194. Name, NULL,
  195. SETUPLOG_USE_MESSAGEID,
  196. MSG_LOG_X_PARAM_RETURNED_WINERR,
  197. szRegOpenKeyEx,
  198. rc,
  199. Subkey,
  200. NULL,NULL);
  201. goto err0;
  202. }
  203. //
  204. // Write the value given.
  205. //
  206. rc = RegSetValueEx(
  207. hKey,
  208. Name,
  209. 0,
  210. REG_EXPAND_SZ,
  211. (PBYTE)Value,
  212. (lstrlen(Value)+1)*sizeof(WCHAR)
  213. );
  214. if(rc != NO_ERROR) {
  215. SetuplogError(
  216. LogSevWarning,
  217. SETUPLOG_USE_MESSAGEID,
  218. MSG_LOG_SETENV_FAIL,
  219. Name, NULL,
  220. SETUPLOG_USE_MESSAGEID,
  221. MSG_LOG_X_PARAM_RETURNED_WINERR,
  222. szRegSetValueEx,
  223. rc,
  224. Subkey,
  225. NULL,NULL);
  226. goto err1;
  227. }
  228. //
  229. // Send a WM_WININICHANGE message so that progman picks up the new
  230. // variable
  231. //
  232. SendMessageTimeout(
  233. (HWND)-1,
  234. WM_WININICHANGE,
  235. 0L,
  236. (LPARAM)"Environment",
  237. SMTO_ABORTIFHUNG,
  238. 1000,
  239. NULL
  240. );
  241. b = TRUE;
  242. err1:
  243. RegCloseKey(hKey);
  244. err0:
  245. return(b);
  246. }
  247. #ifdef _WIN64
  248. typedef struct _SUBST_STRING {
  249. BOOL ExpandEnvironmentVars;
  250. PTSTR InputString;
  251. PTSTR ExclusionString;
  252. PTSTR OutputString;
  253. PTSTR SourceInputString;
  254. PTSTR SourceExclusionString;
  255. PTSTR SourceOutputString;
  256. } SUBST_STRING,*PSUBST_STRING;
  257. //
  258. // note that WOW64 does file system redirection of system32, but it does NOT do
  259. // redirection of program files, etc. So we must substitute in the 32 bit
  260. // environment variables in those cases where WOW64 does not do it for us
  261. // automatically
  262. //
  263. SUBST_STRING StringArray[] = {
  264. //
  265. // order of these 2 is important!
  266. //
  267. { FALSE,
  268. NULL,
  269. NULL,
  270. NULL,
  271. TEXT("%CommonProgramFiles%"),
  272. TEXT("%CommonProgramFiles(x86)%"),
  273. TEXT("%CommonProgramFiles(x86)%")
  274. },
  275. { FALSE,
  276. NULL,
  277. NULL,
  278. NULL,
  279. TEXT("%ProgramFiles%"),
  280. TEXT("%ProgramFiles(x86)%"),
  281. TEXT("%ProgramFiles(x86)%")
  282. },
  283. { TRUE,
  284. NULL,
  285. NULL,
  286. NULL,
  287. TEXT("%CommonProgramFiles%"),
  288. TEXT("%CommonProgramFiles(x86)%"),
  289. TEXT("%CommonProgramFiles(x86)%")
  290. },
  291. { TRUE,
  292. NULL,
  293. NULL,
  294. NULL,
  295. TEXT("%ProgramFiles%"),
  296. TEXT("%ProgramFiles(x86)%"),
  297. TEXT("%ProgramFiles(x86)%")
  298. }
  299. } ;
  300. BOOL
  301. pDoWow64SubstitutionHelper(
  302. IN OUT PTSTR String
  303. )
  304. /*++
  305. Routine Description:
  306. This routine filters and outputs the input line. It looks for a string
  307. pattern that matches one of a known list of strings, and replaces the
  308. known string with a substitution string.
  309. Arguments:
  310. String - input string to be searched. We edit this string
  311. in-place if we find a match.
  312. Return Value:
  313. Boolean indicating outcome.
  314. --*/
  315. {
  316. WCHAR ScratchBuffer[MAX_PATH];
  317. DWORD i;
  318. PTSTR p,q;
  319. TCHAR c;
  320. for (i = 0; i< sizeof(StringArray)/sizeof(SUBST_STRING); i++) {
  321. if (!StrStrI(String,StringArray[i].ExclusionString) &&
  322. (p = StrStrI(String,StringArray[i].InputString))) {
  323. //
  324. // if we found a hit, then find the end of the string
  325. // and concatenate that to our source string, which gives
  326. // the resultant string with substitutions.
  327. //
  328. q = p + wcslen(StringArray[i].InputString);
  329. c = *p;
  330. *p = TEXT('\0');
  331. wcscpy(ScratchBuffer,String);
  332. *p = c;
  333. wcscat(ScratchBuffer,StringArray[i].OutputString);
  334. wcscat(ScratchBuffer,q);
  335. wcscpy(String,ScratchBuffer);
  336. //
  337. // recursively call in case there are more strings.
  338. //
  339. pDoWow64SubstitutionHelper(String);
  340. break;
  341. }
  342. }
  343. return(TRUE);
  344. }
  345. BOOL
  346. pDoWow64Substitution(
  347. IN PCWSTR InputString,
  348. OUT PWSTR OutputString
  349. )
  350. {
  351. DWORD i;
  352. WCHAR Buffer[MAX_PATH];
  353. BOOL RetVal;
  354. //
  355. // set up our global array of substitution strings
  356. //
  357. for (i = 0; i<sizeof(StringArray) / sizeof(SUBST_STRING);i++) {
  358. if (StringArray[i].ExpandEnvironmentVars) {
  359. ExpandEnvironmentStrings(
  360. StringArray[i].SourceInputString,
  361. Buffer,
  362. sizeof(Buffer)/sizeof(WCHAR));
  363. StringArray[i].InputString = pSetupDuplicateString( Buffer );
  364. if (!StringArray[i].InputString) {
  365. RetVal = FALSE;
  366. goto exit;
  367. }
  368. ExpandEnvironmentStrings(
  369. StringArray[i].SourceExclusionString,
  370. Buffer,
  371. sizeof(Buffer)/sizeof(WCHAR));
  372. StringArray[i].ExclusionString = pSetupDuplicateString( Buffer );
  373. if (!StringArray[i].ExclusionString) {
  374. RetVal = FALSE;
  375. goto exit;
  376. }
  377. ExpandEnvironmentStrings(
  378. StringArray[i].SourceOutputString,
  379. Buffer,
  380. sizeof(Buffer)/sizeof(WCHAR));
  381. StringArray[i].OutputString = pSetupDuplicateString( Buffer );
  382. if (!StringArray[i].OutputString) {
  383. RetVal = FALSE;
  384. goto exit;
  385. }
  386. } else {
  387. StringArray[i].InputString = pSetupDuplicateString(StringArray[i].SourceInputString);
  388. if (!StringArray[i].InputString) {
  389. RetVal = FALSE;
  390. goto exit;
  391. }
  392. StringArray[i].ExclusionString = pSetupDuplicateString(StringArray[i].SourceExclusionString);
  393. if (!StringArray[i].ExclusionString) {
  394. RetVal = FALSE;
  395. goto exit;
  396. }
  397. StringArray[i].OutputString = pSetupDuplicateString(StringArray[i].SourceOutputString);
  398. if (!StringArray[i].OutputString) {
  399. RetVal = FALSE;
  400. goto exit;
  401. }
  402. }
  403. }
  404. //
  405. // do the recursive inplace substition
  406. //
  407. wcscpy(OutputString, InputString);
  408. RetVal = pDoWow64SubstitutionHelper( OutputString );
  409. //
  410. // clean up our global array of substitution strings
  411. //
  412. exit:
  413. for (i = 0; i<sizeof(StringArray)/sizeof(SUBST_STRING);i++) {
  414. if (StringArray[i].InputString) {
  415. MyFree(StringArray[i].InputString);
  416. StringArray[i].InputString = NULL;
  417. }
  418. if (StringArray[i].ExclusionString) {
  419. MyFree(StringArray[i].ExclusionString);
  420. StringArray[i].ExclusionString = NULL;
  421. }
  422. if (StringArray[i].OutputString) {
  423. MyFree(StringArray[i].OutputString);
  424. StringArray[i].OutputString = NULL;
  425. }
  426. }
  427. return(RetVal);
  428. }
  429. PWSTR
  430. pMungeDataForWow64(
  431. IN DWORD DataType,
  432. IN PCWSTR Data,
  433. IN DWORD DataSize,
  434. OUT PDWORD NewSize
  435. )
  436. /*++
  437. Routine Description:
  438. This routine patches an in string for wow64 so that it is in proper format
  439. for 32 bit programs.
  440. This involves looking for strings that are different on 64 bits and 32 bits
  441. and substituting the 32 bit equivalent for the 64 bit entry.
  442. Arguments:
  443. DataType - REG_XXX constant describing the data. we only support strings
  444. types
  445. Data - pointer to the data to be munged
  446. DataSize - size of the data to be converted in bytes
  447. NewSize - size of the new string in bytes
  448. Return Value:
  449. A pointer to the converted data string on success, and NULL on failure.
  450. --*/
  451. {
  452. PWSTR pNewData,q;
  453. PCWSTR p;
  454. DWORD ScratchSize;
  455. switch (DataType) {
  456. case REG_SZ:
  457. case REG_EXPAND_SZ:
  458. //
  459. // just allocate twice the original size, and that should be plenty of
  460. // room.
  461. //
  462. pNewData = MyMalloc(DataSize * 2);
  463. if (!pNewData) {
  464. goto exit;
  465. }
  466. pDoWow64Substitution(Data,pNewData);
  467. *NewSize = sizeof(WCHAR)*(wcslen(pNewData) +1);
  468. break;
  469. case REG_MULTI_SZ:
  470. //
  471. // just allocate twice the original size, and that should be plenty of
  472. // room.
  473. //
  474. pNewData = MyMalloc(DataSize * 2);
  475. if (!pNewData) {
  476. goto exit;
  477. }
  478. RtlZeroMemory(pNewData,DataSize * 2);
  479. p = Data;
  480. q = pNewData;
  481. ScratchSize = 1; // for the double-null terminator
  482. while (p) {
  483. pDoWow64Substitution(p,q);
  484. ScratchSize += wcslen(q) + 1;
  485. p += wcslen(p) + 1;
  486. q += wcslen(q) + 1;
  487. }
  488. *NewSize = ScratchSize * sizeof(WCHAR);
  489. break;
  490. default:
  491. MYASSERT(FALSE && "invalid data type in pMungeDataForWow64");
  492. pNewData = NULL;
  493. break;
  494. }
  495. exit:
  496. return(pNewData);
  497. }
  498. UINT
  499. SetGroupOfValues_32(
  500. IN HKEY RootKey,
  501. IN PCWSTR SubkeyName,
  502. IN PREGVALITEM ValueList,
  503. IN UINT ValueCount
  504. )
  505. {
  506. UINT i;
  507. LONG rc;
  508. HKEY hkey;
  509. DWORD ActionTaken;
  510. UINT RememberedRc;
  511. WCHAR String[MAX_PATH];
  512. wcscpy(String,SubkeyName);
  513. for (i = 0; i< wcslen(String); i++) {
  514. CharUpper(&String[i]);
  515. }
  516. //
  517. // only write registry stuff under HKLM\software
  518. //
  519. if ((RootKey != HKEY_LOCAL_MACHINE) ||
  520. (NULL == StrStrI(String,L"SOFTWARE\\"))) {
  521. SetupDebugPrint2(
  522. L"Setup: skipping creation of 32 bit registry key for data under %x \\ %s \n",
  523. RootKey,
  524. SubkeyName );
  525. return(ERROR_SUCCESS);
  526. }
  527. //
  528. // Open/create the key first.
  529. //
  530. rc = RegCreateKeyEx(
  531. RootKey,
  532. SubkeyName,
  533. 0,
  534. NULL,
  535. REG_OPTION_NON_VOLATILE,
  536. KEY_WOW64_32KEY | KEY_SET_VALUE,
  537. NULL,
  538. &hkey,
  539. &ActionTaken
  540. );
  541. if(rc != NO_ERROR) {
  542. SetuplogError(
  543. LogSevError,
  544. SETUPLOG_USE_MESSAGEID,
  545. MSG_LOG_REGKEY_FAIL,
  546. SubkeyName, NULL,
  547. SETUPLOG_USE_MESSAGEID,
  548. rc, NULL, NULL
  549. );
  550. return(rc);
  551. }
  552. RememberedRc = NO_ERROR;
  553. //
  554. // Set all values in the given list.
  555. //
  556. for(i=0; i<ValueCount; i++) {
  557. PWSTR NewData = NULL,OldData = NULL;
  558. DWORD OldSize, NewSize;
  559. if (ValueList[i].Type == REG_SZ ||
  560. ValueList[i].Type == REG_EXPAND_SZ ||
  561. ValueList[i].Type == REG_MULTI_SZ) {
  562. OldData = ValueList[i].Data;
  563. OldSize = ValueList[i].Size;
  564. NewData = pMungeDataForWow64(
  565. ValueList[i].Type,
  566. ValueList[i].Data,
  567. ValueList[i].Size,
  568. &NewSize
  569. );
  570. if (NewData) {
  571. ValueList[i].Data = (PVOID)NewData;
  572. ValueList[i].Size = NewSize;
  573. }
  574. }
  575. rc = RegSetValueEx(
  576. hkey,
  577. ValueList[i].Name,
  578. 0,
  579. ValueList[i].Type,
  580. (CONST BYTE *)ValueList[i].Data,
  581. ValueList[i].Size
  582. );
  583. if (NewData) {
  584. MyFree(NewData);
  585. ValueList[i].Data = (PVOID)OldData;
  586. ValueList[i].Size = OldSize;
  587. }
  588. if(rc != NO_ERROR) {
  589. SetuplogError(
  590. LogSevError,
  591. SETUPLOG_USE_MESSAGEID,
  592. MSG_LOG_REGVALUE_FAIL,
  593. SubkeyName,
  594. ValueList[i].Name, NULL,
  595. SETUPLOG_USE_MESSAGEID,
  596. rc, NULL, NULL
  597. );
  598. RememberedRc = rc;
  599. }
  600. }
  601. RegCloseKey(hkey);
  602. return(RememberedRc);
  603. }
  604. #endif
  605. UINT
  606. SetGroupOfValues(
  607. IN HKEY RootKey,
  608. IN PCWSTR SubkeyName,
  609. IN PREGVALITEM ValueList,
  610. IN UINT ValueCount
  611. )
  612. {
  613. UINT i;
  614. LONG rc;
  615. HKEY hkey;
  616. DWORD ActionTaken;
  617. UINT RememberedRc;
  618. //
  619. // Open/create the key first.
  620. //
  621. rc = RegCreateKeyEx(
  622. RootKey,
  623. SubkeyName,
  624. 0,
  625. NULL,
  626. REG_OPTION_NON_VOLATILE,
  627. KEY_SET_VALUE,
  628. NULL,
  629. &hkey,
  630. &ActionTaken
  631. );
  632. if(rc != NO_ERROR) {
  633. SetuplogError(
  634. LogSevError,
  635. SETUPLOG_USE_MESSAGEID,
  636. MSG_LOG_REGKEY_FAIL,
  637. SubkeyName, NULL,
  638. SETUPLOG_USE_MESSAGEID,
  639. rc, NULL, NULL
  640. );
  641. return(rc);
  642. }
  643. RememberedRc = NO_ERROR;
  644. //
  645. // Set all values in the given list.
  646. //
  647. for(i=0; i<ValueCount; i++) {
  648. rc = RegSetValueEx(
  649. hkey,
  650. ValueList[i].Name,
  651. 0,
  652. ValueList[i].Type,
  653. (CONST BYTE *)ValueList[i].Data,
  654. ValueList[i].Size
  655. );
  656. if(rc != NO_ERROR) {
  657. SetuplogError(
  658. LogSevError,
  659. SETUPLOG_USE_MESSAGEID,
  660. MSG_LOG_REGVALUE_FAIL,
  661. SubkeyName,
  662. ValueList[i].Name, NULL,
  663. SETUPLOG_USE_MESSAGEID,
  664. rc, NULL, NULL
  665. );
  666. RememberedRc = rc;
  667. }
  668. }
  669. RegCloseKey(hkey);
  670. #ifdef _WIN64
  671. rc = SetGroupOfValues_32(
  672. RootKey,
  673. SubkeyName,
  674. ValueList,
  675. ValueCount);
  676. if (rc != NO_ERROR) {
  677. RememberedRc = rc;
  678. }
  679. #endif
  680. return(RememberedRc);
  681. }
  682. BOOL
  683. CreateWindowsNtSoftwareEntry(
  684. IN BOOL FirstPass
  685. )
  686. {
  687. WCHAR Path[MAX_PATH];
  688. time_t DateVal;
  689. BOOL b;
  690. REGVALITEM SoftwareKeyItems[4];
  691. PWSTR Source;
  692. unsigned PlatformNameLength;
  693. unsigned PathLength;
  694. int PlatformOffset;
  695. DWORD Result;
  696. b = TRUE;
  697. if(FirstPass) {
  698. //
  699. // First pass occurs before net setup, and they want
  700. // the actual path where the files are located *right now*.
  701. // So we write that into the legacy source path value
  702. // in the registry.
  703. //
  704. SoftwareKeyItems[0].Name = REGSTR_VAL_SRCPATH;
  705. SoftwareKeyItems[0].Data = LegacySourcePath;
  706. SoftwareKeyItems[0].Size = (lstrlen(LegacySourcePath)+1)*sizeof(WCHAR);
  707. SoftwareKeyItems[0].Type = REG_SZ;
  708. //
  709. // Set up fields for PathName value
  710. //
  711. Path[0] = '\0';
  712. Result = GetWindowsDirectory(Path,MAX_PATH);
  713. if( Result == 0) {
  714. MYASSERT(FALSE);
  715. return FALSE;
  716. }
  717. SoftwareKeyItems[1].Name = L"PathName";
  718. SoftwareKeyItems[1].Data = Path;
  719. SoftwareKeyItems[1].Size = (lstrlen(Path)+1)*sizeof(WCHAR);
  720. SoftwareKeyItems[1].Type = REG_SZ;
  721. //
  722. // Set up fields for SoftwareType value
  723. //
  724. SoftwareKeyItems[2].Name = L"SoftwareType";
  725. SoftwareKeyItems[2].Data = L"SYSTEM";
  726. SoftwareKeyItems[2].Size = sizeof(L"SYSTEM");
  727. SoftwareKeyItems[2].Type = REG_SZ;
  728. //
  729. // Set up fields for InstallDate value
  730. // (we no longer set this value here because this function is called before
  731. // the Date/Time wizard page is executed. This value entry is now set by
  732. // CreateInstallDateEntry(), which is always called after the Date/Time page
  733. // is executed, when the user can no longer go back this page)
  734. //
  735. // time(&DateVal);
  736. // SoftwareKeyItems[3].Name = L"InstallDate";
  737. // SoftwareKeyItems[3].Data = &DateVal;
  738. // SoftwareKeyItems[3].Size = sizeof(DWORD);
  739. // SoftwareKeyItems[3].Type = REG_DWORD;
  740. //
  741. //
  742. // Write values into the registry.
  743. //
  744. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,SoftwareKeyItems,3) != NO_ERROR) {
  745. b = FALSE;
  746. }
  747. //
  748. // In addition we will populate the MRU list with a reasonable source path
  749. // which for now is the actual source path where files are located,
  750. // ie the CD-ROM or the temporary local source. Thus in the winnt/winnt32
  751. // case the user wouldn't see any UNC paths yet in any prompts that might
  752. // occur between now and pass 2 of this routine. Such paths aren't accessible
  753. // now anyway.
  754. //
  755. // Ditto for the 'SourcePath' value entry under
  756. // HKLM\Software\Microsoft\Windows\CurrentVersion\Setup that is expected by
  757. // setupapi.dll/Win95 apps.
  758. //
  759. // The 'ServicePackSourcePath' is the same as the sourcepath for gui-mode setup.
  760. // We assume that the user has overlaid a service pack at the source location.
  761. // If it's retail media, this is technically incorrect, but it doesn't matter
  762. // since nothing will want to use the servicepack source anyway. The service
  763. // pack update program will update this location if it is run.
  764. //
  765. if(!SetupAddToSourceList(SRCLIST_SYSTEM,SourcePath)) {
  766. b = FALSE;
  767. }
  768. SoftwareKeyItems[0].Name = REGSTR_VAL_SRCPATH;
  769. SoftwareKeyItems[0].Data = SourcePath;
  770. SoftwareKeyItems[0].Size = (lstrlen(SourcePath)+1)*sizeof(WCHAR);
  771. SoftwareKeyItems[0].Type = REG_SZ;
  772. SoftwareKeyItems[1].Name = REGSTR_VAL_SVCPAKSRCPATH;
  773. SoftwareKeyItems[1].Data = SourcePath;
  774. SoftwareKeyItems[1].Size = (lstrlen(SourcePath)+1)*sizeof(WCHAR);
  775. SoftwareKeyItems[1].Type = REG_SZ;
  776. PathLength = gInstallingFromCD ? 1 : 0;
  777. SoftwareKeyItems[2].Name = L"CDInstall";
  778. SoftwareKeyItems[2].Data = &PathLength;
  779. SoftwareKeyItems[2].Size = sizeof(DWORD);
  780. SoftwareKeyItems[2].Type = REG_DWORD;
  781. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,REGSTR_PATH_SETUP REGSTR_KEY_SETUP,SoftwareKeyItems,3) != NO_ERROR) {
  782. b = FALSE;
  783. }
  784. #ifdef _X86_
  785. //
  786. // NEC98
  787. //
  788. // If this is system setup and using local copy, platform-specific extension
  789. // must be "nec98".
  790. //
  791. if (IsNEC_98 && SourcePath[0] && SourcePath[1] == L':' && SourcePath[2] == L'\\' && !lstrcmpi(SourcePath+2, pwLocalSource)) {
  792. SoftwareKeyItems[0].Name = L"ForcePlatform";
  793. SoftwareKeyItems[0].Data = L"nec98";
  794. SoftwareKeyItems[0].Size = (lstrlen(L"nec98")+1)*sizeof(WCHAR);
  795. SoftwareKeyItems[0].Type = REG_SZ;
  796. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,TEXT("System\\Setup"),SoftwareKeyItems,1) != NO_ERROR) {
  797. b = FALSE;
  798. }
  799. }
  800. #endif
  801. } else {
  802. //
  803. // Not first pass. This occurs after network installation.
  804. // In the case where we are winnt-based, we need to fix up source paths
  805. // to point at the "real" location where files can be obtained -- ie,
  806. // a network share saved away for us by winnt/winnt32. If we are installing
  807. // from CD then the path we wrote during FirstPass is fine so we don't
  808. // bother changing it.
  809. //
  810. if(WinntBased) {
  811. //
  812. // Remove local source directory from MRU list.
  813. // Ignore errors.
  814. //
  815. SetupRemoveFromSourceList(SRCLIST_SYSTEM,SourcePath);
  816. lstrcpy(Path,OriginalSourcePath);
  817. //
  818. // Update legacy source path.
  819. //
  820. SoftwareKeyItems[0].Name = REGSTR_VAL_SRCPATH;
  821. SoftwareKeyItems[0].Data = Path;
  822. SoftwareKeyItems[0].Size = (lstrlen(Path)+1)*sizeof(WCHAR);
  823. SoftwareKeyItems[0].Type = REG_SZ;
  824. SoftwareKeyItems[1].Name = REGSTR_VAL_SVCPAKSRCPATH;
  825. SoftwareKeyItems[1].Data = Path;
  826. SoftwareKeyItems[1].Size = (lstrlen(Path)+1)*sizeof(WCHAR);
  827. SoftwareKeyItems[1].Type = REG_SZ;
  828. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,SoftwareKeyItems,1) != NO_ERROR) {
  829. b = FALSE;
  830. }
  831. //
  832. // Strip off platform-specific extension if it exists.
  833. //
  834. PathLength = lstrlen(Path);
  835. PlatformNameLength = lstrlen(PlatformName);
  836. PlatformOffset = PathLength - PlatformNameLength;
  837. if((PlatformOffset > 0)
  838. && (Path[PlatformOffset-1] == L'\\')
  839. && !lstrcmpi(Path+PlatformOffset,PlatformName)) {
  840. Path[PlatformOffset-1] = 0;
  841. SoftwareKeyItems[0].Size -= (PlatformNameLength+1)*sizeof(WCHAR);
  842. SoftwareKeyItems[1].Size -= (PlatformNameLength+1)*sizeof(WCHAR);
  843. }
  844. //
  845. // Add "real" path to MRU list and update setupapi.dll/Win95
  846. // SourcePath value.
  847. //
  848. if(!SetupAddToSourceList(SRCLIST_SYSTEM,Path)) {
  849. b = FALSE;
  850. }
  851. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,REGSTR_PATH_SETUP REGSTR_KEY_SETUP,SoftwareKeyItems,2) != NO_ERROR) {
  852. b = FALSE;
  853. }
  854. }
  855. }
  856. return(b);
  857. }
  858. BOOL
  859. StoreNameOrgInRegistry(
  860. PWSTR NameOrgName,
  861. PWSTR NameOrgOrg
  862. )
  863. {
  864. DWORD d;
  865. REGVALITEM SoftwareKeyItems[2];
  866. MYASSERT(!Upgrade);
  867. SoftwareKeyItems[0].Name = szRegisteredOwner;
  868. SoftwareKeyItems[0].Data = NameOrgName;
  869. SoftwareKeyItems[0].Size = (lstrlen(NameOrgName)+1)*sizeof(WCHAR);
  870. SoftwareKeyItems[0].Type = REG_SZ;
  871. SoftwareKeyItems[1].Name = szRegisteredOrganization;
  872. SoftwareKeyItems[1].Data = NameOrgOrg;
  873. SoftwareKeyItems[1].Size = (lstrlen(NameOrgOrg)+1)*sizeof(WCHAR);
  874. SoftwareKeyItems[1].Type = REG_SZ;
  875. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,SoftwareKeyItems,2);
  876. return(d == NO_ERROR);
  877. }
  878. BOOL
  879. SetUpEvaluationSKUStuff(
  880. VOID
  881. )
  882. {
  883. FILETIME FileTime;
  884. DWORD EvalValues[3];
  885. DWORD d;
  886. REGVALITEM Value;
  887. HKEY hkey;
  888. ULONGLONG SKUData;
  889. DWORD DataType;
  890. DWORD DataSize;
  891. time_t RawLinkTime;
  892. SYSTEMTIME SystemTime;
  893. struct tm *LinkTime;
  894. int delta;
  895. PIMAGE_NT_HEADERS NtHeaders;
  896. //
  897. // Fetch the evaulation time in minutes from the registry.
  898. // An evaluation time of 0 means indefinite.
  899. // This value was passed in from text mode in a special way
  900. // (ie, not via the text file that contains our params,
  901. // since that's not secure enough).
  902. //
  903. EvalValues[1] = 0;
  904. d = RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,KEY_READ,&hkey);
  905. if(d == NO_ERROR) {
  906. DataSize = sizeof(ULONGLONG);
  907. d = RegQueryValueEx(hkey,L"SystemPrefix",NULL,&DataType,(PBYTE)&SKUData,&DataSize);
  908. if(d == NO_ERROR) {
  909. //
  910. // Do not change this line without changing SpSaveSKUStuff() in
  911. // text setup (spconfig.c).
  912. //
  913. EvalValues[1] = (DWORD)(SKUData >> 13);
  914. }
  915. RegCloseKey(hkey);
  916. }
  917. //
  918. // Verify that the clock seems right in the eval unit case.
  919. // This helps protect against prople discovering that their
  920. // clock is wrong later and changing it, which expires their
  921. // eval unit.
  922. //
  923. if(EvalValues[1]) {
  924. //
  925. // Get the link time of our dll and convert to
  926. // a form where we have the year separated out.
  927. //
  928. try {
  929. if( NtHeaders = RtlImageNtHeader(MyModuleHandle) ) {
  930. RawLinkTime = NtHeaders->FileHeader.TimeDateStamp;
  931. } else {
  932. RawLinkTime = 0;
  933. }
  934. RawLinkTime = RtlImageNtHeader(MyModuleHandle)->FileHeader.TimeDateStamp;
  935. } except(EXCEPTION_EXECUTE_HANDLER) {
  936. RawLinkTime = 0;
  937. }
  938. if(RawLinkTime && (LinkTime = gmtime(&RawLinkTime))) {
  939. GetLocalTime(&SystemTime);
  940. delta = (SystemTime.wYear - 1900) - LinkTime->tm_year;
  941. //
  942. // If the year of the current time is more than one year less then
  943. // the year the dll was linked, or more than three years more,
  944. // assume the user's clock is out of whack.
  945. //
  946. if((delta < -1) || (delta > 3)) {
  947. extern PCWSTR DateTimeCpl;
  948. MessageBoxFromMessage(
  949. MainWindowHandle,
  950. MSG_EVAL_UNIT_CLOCK_SEEMS_WRONG,
  951. NULL,
  952. IDS_WINNT_SETUP,
  953. MB_OK | MB_ICONWARNING
  954. );
  955. InvokeControlPanelApplet(DateTimeCpl,L"",0,L"");
  956. }
  957. }
  958. }
  959. //
  960. // Get current date/time and put into array in format
  961. // expected by the system code that reads it.
  962. //
  963. GetSystemTimeAsFileTime(&FileTime);
  964. EvalValues[0] = FileTime.dwLowDateTime;
  965. EvalValues[2] = FileTime.dwHighDateTime;
  966. //
  967. // Write value into registry.
  968. //
  969. Value.Name = L"PriorityQuantumMatrix";
  970. Value.Data = EvalValues;
  971. Value.Size = sizeof(EvalValues);
  972. Value.Type = REG_BINARY;
  973. d = SetGroupOfValues(
  974. HKEY_LOCAL_MACHINE,
  975. L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Executive",
  976. &Value,
  977. 1
  978. );
  979. return(d == NO_ERROR);
  980. }
  981. BOOL
  982. ReadAndParseProcessorLicenseInfo(
  983. PDWORD LicensedProcessors,
  984. PLARGE_INTEGER pSKUData
  985. )
  986. {
  987. DWORD d;
  988. REGVALITEM Value;
  989. HKEY hkey;
  990. LARGE_INTEGER SKUData;
  991. DWORD DataType;
  992. DWORD DataSize;
  993. DWORD NumberOfProcessors;
  994. //
  995. // Fetch the SKU Data from the registry
  996. //
  997. d = RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"System\\Setup",0,KEY_READ,&hkey);
  998. if(d == NO_ERROR) {
  999. DataSize = sizeof(ULONGLONG);
  1000. d = RegQueryValueEx(hkey,L"SystemPrefix",NULL,&DataType,(PBYTE)&SKUData,&DataSize);
  1001. if(d == NO_ERROR) {
  1002. //
  1003. // The SKU Data contains several pieces of information.
  1004. //
  1005. // The registered processor related pieces are
  1006. //
  1007. // Bits 5 - 9 : The maximum number of processors that the system is licensed
  1008. // to use. The value stored is actually ~(MaxProcessors-1)
  1009. //
  1010. //
  1011. // Compute Licensed Processors
  1012. //
  1013. NumberOfProcessors = SKUData.LowPart;
  1014. NumberOfProcessors = NumberOfProcessors >> 5;
  1015. NumberOfProcessors = ~NumberOfProcessors;
  1016. NumberOfProcessors = NumberOfProcessors & 0x0000001f;
  1017. NumberOfProcessors++;
  1018. *LicensedProcessors = NumberOfProcessors;
  1019. }
  1020. RegCloseKey(hkey);
  1021. }
  1022. *pSKUData = SKUData;
  1023. return(d == NO_ERROR);
  1024. }
  1025. BOOL
  1026. IsStandardServerSKU(
  1027. PBOOL pIsServer
  1028. )
  1029. {
  1030. BOOL fReturnValue = (BOOL) FALSE;
  1031. OSVERSIONINFOEX VersionInfo;
  1032. BOOL IsServer = FALSE;
  1033. //
  1034. // get the current SKU.
  1035. //
  1036. VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
  1037. if (GetVersionEx((OSVERSIONINFO *)&VersionInfo)) {
  1038. fReturnValue = TRUE;
  1039. //
  1040. // is it some sort of server SKU?
  1041. //
  1042. if (VersionInfo.wProductType != VER_NT_WORKSTATION) {
  1043. //
  1044. // standard server or a server variant?
  1045. //
  1046. if ((VersionInfo.wSuiteMask & (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER)) == 0) {
  1047. //
  1048. // it's standard server
  1049. //
  1050. IsServer = TRUE;
  1051. }
  1052. }
  1053. *pIsServer = IsServer;
  1054. }
  1055. return(fReturnValue);
  1056. }
  1057. BOOL
  1058. SetEnabledProcessorCount(
  1059. VOID
  1060. )
  1061. {
  1062. DWORD d;
  1063. REGVALITEM RegistryItem;
  1064. HKEY hkey;
  1065. DWORD Size;
  1066. DWORD Type;
  1067. DWORD OriginalLicensedProcessors;
  1068. DWORD LicensedProcessors;
  1069. LARGE_INTEGER SKUData;
  1070. BOOL IsServer = FALSE;
  1071. if ( !ReadAndParseProcessorLicenseInfo(&OriginalLicensedProcessors,&SKUData) ) {
  1072. return FALSE;
  1073. }
  1074. LicensedProcessors = OriginalLicensedProcessors;
  1075. if(Upgrade) {
  1076. //
  1077. // During an upgrade, do not let the user go backwards.
  1078. // (except for standard server SKU)
  1079. //
  1080. if (!IsStandardServerSKU(&IsServer) || IsServer == FALSE) {
  1081. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,SessionManagerKeyName,0,KEY_QUERY_VALUE,&hkey) == NO_ERROR) {
  1082. Size = sizeof(d);
  1083. if((RegQueryValueEx(hkey,szLicensedProcessors,NULL,&Type,(LPBYTE)&d,&Size) == NO_ERROR)
  1084. && (Type == REG_DWORD)
  1085. && (d >= LicensedProcessors)) {
  1086. LicensedProcessors = d;
  1087. }
  1088. RegCloseKey(hkey);
  1089. }
  1090. }
  1091. }
  1092. d = LicensedProcessors;
  1093. RegistryItem.Data = &d;
  1094. RegistryItem.Size = sizeof(DWORD);
  1095. RegistryItem.Type = REG_DWORD;
  1096. RegistryItem.Name = szRegisteredProcessors;
  1097. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,SessionManagerKeyName,&RegistryItem,1);
  1098. if ( d == NO_ERROR ) {
  1099. RegistryItem.Data = &LicensedProcessors;
  1100. RegistryItem.Size = sizeof(DWORD);
  1101. RegistryItem.Type = REG_DWORD;
  1102. RegistryItem.Name = szLicensedProcessors;
  1103. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,SessionManagerKeyName,&RegistryItem,1);
  1104. }
  1105. if ( d == NO_ERROR && LicensedProcessors >= OriginalLicensedProcessors) {
  1106. //
  1107. // need to update SKUData to reflect the fact the we are running with
  1108. // a licensed processor count that is different from what is programmed
  1109. // in the hives.
  1110. //
  1111. //
  1112. // Convert Licensed Processors to Registry Format
  1113. //
  1114. LicensedProcessors--;
  1115. LicensedProcessors = ~LicensedProcessors;
  1116. LicensedProcessors = LicensedProcessors << 5;
  1117. LicensedProcessors &= 0x000003e0;
  1118. //
  1119. // Store NumberOfProcessors into the registry
  1120. //
  1121. SKUData.LowPart &= ~0x000003e0;
  1122. SKUData.LowPart |= LicensedProcessors;
  1123. RegistryItem.Data = &SKUData;
  1124. RegistryItem.Size = sizeof(SKUData);
  1125. RegistryItem.Type = REG_BINARY;
  1126. RegistryItem.Name = L"SystemPrefix";
  1127. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,L"SYSTEM\\Setup",&RegistryItem,1);
  1128. }
  1129. return(d == NO_ERROR);
  1130. }
  1131. #ifdef PRERELEASE
  1132. UINT
  1133. ValidateGroupOfValues(
  1134. IN HKEY RootKey,
  1135. IN PCWSTR SubkeyName,
  1136. IN PREGVALITEM ValueList,
  1137. IN UINT ValueCount
  1138. )
  1139. {
  1140. UINT i;
  1141. LONG rc;
  1142. HKEY hkey;
  1143. UINT RememberedRc;
  1144. //
  1145. // Open the key first.
  1146. //
  1147. rc = RegOpenKeyEx(
  1148. RootKey,
  1149. SubkeyName,
  1150. 0,
  1151. KEY_READ,
  1152. &hkey
  1153. );
  1154. if(rc != NO_ERROR)
  1155. {
  1156. SetupDebugPrint2(L"RegOpenKeyEx failed on key:%s errorcode: %d\n",
  1157. SubkeyName, rc);
  1158. return(FALSE);
  1159. }
  1160. RememberedRc = NO_ERROR;
  1161. //
  1162. // Query all values in the given list.
  1163. //
  1164. for(i=0; i<ValueCount; i++) {
  1165. DWORD size;
  1166. DWORD dontcare;
  1167. BYTE *data;
  1168. size = ValueList[i].Size;
  1169. data = LocalAlloc(LPTR, size);
  1170. if (data)
  1171. {
  1172. rc = RegQueryValueEx(
  1173. hkey,
  1174. ValueList[i].Name,
  1175. NULL,
  1176. &dontcare,
  1177. data,
  1178. &size
  1179. );
  1180. if (rc == ERROR_SUCCESS)
  1181. {
  1182. // See if the data we read is the same then what is in the registery
  1183. if (memcmp(data, ValueList[i].Data, size) != 0)
  1184. {
  1185. // Data is different that what we expect.
  1186. SetupDebugPrint2(L"ValidateGroupOfValues, data difference for key:%s Valuename:%s\n",
  1187. SubkeyName, ValueList[i].Name);
  1188. }
  1189. }
  1190. else
  1191. {
  1192. SetupDebugPrint3(L"RegQueryValueEx failed on key:%s Valuename:%s, errorcode: %d\n",
  1193. SubkeyName, ValueList[i].Name, rc);
  1194. RememberedRc = rc;
  1195. }
  1196. LocalFree(data);
  1197. }
  1198. }
  1199. RegCloseKey(hkey);
  1200. return(RememberedRc == NO_ERROR);
  1201. }
  1202. void ValidateProductIDInReg()
  1203. {
  1204. REGVALITEM RegistryItem[2];
  1205. RegistryItem[0].Name = L"ProductId";
  1206. RegistryItem[0].Data = ProductId20FromProductId30;
  1207. RegistryItem[0].Type = REG_SZ;
  1208. RegistryItem[0].Size = (lstrlen(ProductId20FromProductId30)+1)*sizeof(WCHAR);
  1209. ValidateGroupOfValues(HKEY_LOCAL_MACHINE,WindowsCurrentVersionKeyName,&RegistryItem[0],1);
  1210. RegistryItem[1].Name = L"DigitalProductId";
  1211. RegistryItem[1].Data = DigitalProductId;
  1212. RegistryItem[1].Type = REG_BINARY;
  1213. RegistryItem[1].Size = (DWORD)*DigitalProductId;
  1214. ValidateGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,&RegistryItem[0],2);
  1215. ValidateGroupOfValues(HKEY_LOCAL_MACHINE,IEProductVersionKeyName,&RegistryItem[0],2);
  1216. return;
  1217. }
  1218. #endif
  1219. BOOL
  1220. SetProductIdInRegistry(
  1221. VOID
  1222. )
  1223. {
  1224. DWORD d;
  1225. REGVALITEM RegistryItem[2];
  1226. BEGIN_SECTION(L"SetProductIdInRegistry");
  1227. if (*ProductId20FromProductId30 == L'\0')
  1228. {
  1229. SetupDebugPrint(L"ProductId20FromProductId30 is empty\n");
  1230. }
  1231. RegistryItem[0].Name = L"ProductId";
  1232. RegistryItem[0].Data = ProductId20FromProductId30;
  1233. RegistryItem[0].Type = REG_SZ;
  1234. RegistryItem[0].Size = (lstrlen(ProductId20FromProductId30)+1)*sizeof(WCHAR);
  1235. // SetGroupOfValues is logging it's errors
  1236. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,WindowsCurrentVersionKeyName,&RegistryItem[0],1);
  1237. if (*DigitalProductId == 0)
  1238. {
  1239. SetupDebugPrint(L"DigitalProductId is empty\n");
  1240. }
  1241. //
  1242. // first dword of the binary blob is the size
  1243. //
  1244. RegistryItem[1].Name = L"DigitalProductId";
  1245. RegistryItem[1].Data = DigitalProductId;
  1246. RegistryItem[1].Type = REG_BINARY;
  1247. RegistryItem[1].Size = (DWORD)*DigitalProductId;
  1248. if (d == NO_ERROR) {
  1249. // SetGroupOfValues is logging it's errors
  1250. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,&RegistryItem[0],2);
  1251. }
  1252. if (d == NO_ERROR) {
  1253. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,IEProductVersionKeyName,&RegistryItem[0],2);
  1254. }
  1255. #ifdef PRERELEASE
  1256. ValidateProductIDInReg();
  1257. #endif
  1258. END_SECTION(L"SetProductIdInRegistry");
  1259. return(d == NO_ERROR);
  1260. }
  1261. DWORD
  1262. SetCurrentProductIdInRegistry(
  1263. VOID
  1264. )
  1265. {
  1266. DWORD d;
  1267. REGVALITEM RegistryItem[1];
  1268. BEGIN_SECTION(L"SetCurrentProductIdInRegistry");
  1269. if (*ProductId20FromProductId30 == L'\0')
  1270. {
  1271. SetupDebugPrint(L"ProductId20FromProductId30 is empty\n");
  1272. }
  1273. RegistryItem[0].Name = szCurrentProductId;
  1274. RegistryItem[0].Data = ProductId20FromProductId30;
  1275. RegistryItem[0].Type = REG_SZ;
  1276. RegistryItem[0].Size = (lstrlen(ProductId20FromProductId30)+1)*sizeof(WCHAR);
  1277. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,&RegistryItem[0],1);
  1278. END_SECTION(L"SetCurrentProductIdInRegistry");
  1279. return(d);
  1280. }
  1281. VOID
  1282. DeleteCurrentProductIdInRegistry(
  1283. VOID
  1284. )
  1285. {
  1286. HKEY hKey = 0;
  1287. ULONG Error;
  1288. BEGIN_SECTION(L"DeleteCurrentProductIdInRegistry");
  1289. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1290. WinntSoftwareKeyName,
  1291. 0,
  1292. KEY_SET_VALUE,
  1293. &hKey );
  1294. if (Error == NO_ERROR) {
  1295. Error = RegDeleteValue(hKey, szCurrentProductId);
  1296. }
  1297. if (hKey) {
  1298. RegCloseKey(hKey);
  1299. }
  1300. END_SECTION(L"DeleteCurrentProductIdInRegistry");
  1301. }
  1302. BOOL
  1303. SetProductTypeInRegistry(
  1304. VOID
  1305. )
  1306. {
  1307. WCHAR ProductTypeName[24];
  1308. REGVALITEM RegistryItem;
  1309. DWORD d;
  1310. ProductTypeName[0] = '\0';
  1311. SetUpProductTypeName(ProductTypeName,sizeof(ProductTypeName)/sizeof(WCHAR));
  1312. RegistryItem.Data = ProductTypeName;
  1313. RegistryItem.Size = (lstrlen(ProductTypeName)+1)*sizeof(WCHAR);
  1314. RegistryItem.Type = REG_SZ;
  1315. RegistryItem.Name = L"ProductType";
  1316. if( MiniSetup ) {
  1317. d = NO_ERROR;
  1318. } else {
  1319. d = SetGroupOfValues(
  1320. HKEY_LOCAL_MACHINE,
  1321. L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  1322. &RegistryItem,
  1323. 1
  1324. );
  1325. }
  1326. return(d == NO_ERROR);
  1327. }
  1328. BOOL
  1329. SetAutoAdminLogonInRegistry(
  1330. LPWSTR Username,
  1331. LPWSTR Password
  1332. )
  1333. {
  1334. #define AnswerBufLen (4*MAX_PATH)
  1335. #define NumberOfEntries 5
  1336. REGVALITEM RegistryItem[NumberOfEntries];
  1337. DWORD d;
  1338. WCHAR AnswerFile[AnswerBufLen];
  1339. WCHAR Answer[AnswerBufLen];
  1340. DWORD zero = 0;
  1341. DWORD NumberOfEntriesSet = 4;
  1342. RegistryItem[0].Data = L"1";
  1343. RegistryItem[0].Size = (lstrlen(RegistryItem[0].Data)+1)*sizeof(WCHAR);
  1344. RegistryItem[0].Type = REG_SZ;
  1345. RegistryItem[0].Name = L"AutoAdminLogon";
  1346. RegistryItem[1].Data = Username;
  1347. RegistryItem[1].Size = (lstrlen(RegistryItem[1].Data)+1)*sizeof(WCHAR);
  1348. RegistryItem[1].Type = REG_SZ;
  1349. RegistryItem[1].Name = L"DefaultUserName";
  1350. RegistryItem[2].Data = Password;
  1351. RegistryItem[2].Size = (lstrlen(RegistryItem[2].Data)+1)*sizeof(WCHAR);
  1352. RegistryItem[2].Type = REG_SZ;
  1353. RegistryItem[2].Name = L"DefaultPassword";
  1354. RegistryItem[3].Data = Win32ComputerName;
  1355. RegistryItem[3].Size = (lstrlen(RegistryItem[3].Data)+1)*sizeof(WCHAR);
  1356. RegistryItem[3].Type = REG_SZ;
  1357. RegistryItem[3].Name = L"DefaultDomainName";
  1358. if (Win95Upgrade)
  1359. {
  1360. //
  1361. // To support autologon for 9x upgrade to HOME test automation
  1362. //
  1363. RegistryItem[4].Data = &zero;
  1364. RegistryItem[4].Size = sizeof(zero);
  1365. RegistryItem[4].Type = REG_DWORD;
  1366. RegistryItem[4].Name = L"LogonType";
  1367. NumberOfEntriesSet = 5;
  1368. }
  1369. d = SetGroupOfValues(
  1370. HKEY_LOCAL_MACHINE,
  1371. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  1372. RegistryItem,
  1373. NumberOfEntriesSet
  1374. );
  1375. if( d != NO_ERROR ) {
  1376. return FALSE;
  1377. }
  1378. //
  1379. // Now set the AutoLogonCount entry if it's in the unattend file.
  1380. //
  1381. //
  1382. // Pickup the answer file.
  1383. //
  1384. GetSystemDirectory(AnswerFile,MAX_PATH);
  1385. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  1386. //
  1387. // Is AutoLogonCount specified?
  1388. //
  1389. if( GetPrivateProfileString( WINNT_GUIUNATTENDED,
  1390. TEXT("AutoLogonCount"),
  1391. pwNull,
  1392. Answer,
  1393. AnswerBufLen,
  1394. AnswerFile ) ) {
  1395. if( lstrcmp( pwNull, Answer ) ) {
  1396. DWORD Val;
  1397. //
  1398. // We got an answer. If it's valid, then set it.
  1399. //
  1400. Val = wcstoul(Answer,NULL,10);
  1401. RegistryItem[0].Data = &Val;
  1402. RegistryItem[0].Size = sizeof(DWORD);
  1403. RegistryItem[0].Type = REG_DWORD;
  1404. RegistryItem[0].Name = TEXT("AutoLogonCount");
  1405. d = SetGroupOfValues(
  1406. HKEY_LOCAL_MACHINE,
  1407. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  1408. RegistryItem,
  1409. 1 );
  1410. }
  1411. }
  1412. return(d == NO_ERROR);
  1413. }
  1414. BOOL
  1415. SetProfilesDirInRegistry(
  1416. LPWSTR ProfilesDir
  1417. )
  1418. {
  1419. REGVALITEM RegistryItem[1];
  1420. DWORD d;
  1421. RegistryItem[0].Data = ProfilesDir;
  1422. RegistryItem[0].Size = (lstrlen(RegistryItem[0].Data)+1)*sizeof(WCHAR);
  1423. RegistryItem[0].Type = REG_EXPAND_SZ;
  1424. RegistryItem[0].Name = L"ProfilesDirectory";
  1425. d = SetGroupOfValues(
  1426. HKEY_LOCAL_MACHINE,
  1427. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
  1428. RegistryItem,
  1429. 1
  1430. );
  1431. return(d == NO_ERROR);
  1432. }
  1433. BOOL
  1434. ResetSetupInProgress(
  1435. VOID
  1436. )
  1437. {
  1438. REGVALITEM RegistryItems[2];
  1439. DWORD Zero;
  1440. DWORD d;
  1441. Zero = 0;
  1442. RegistryItems[0].Name = L"SystemSetupInProgress";
  1443. RegistryItems[0].Data = &Zero;
  1444. RegistryItems[0].Size = sizeof(DWORD);
  1445. RegistryItems[0].Type = REG_DWORD;
  1446. if(Upgrade) {
  1447. RegistryItems[1].Name = L"UpgradeInProgress";
  1448. RegistryItems[1].Data = &Zero;
  1449. RegistryItems[1].Size = sizeof(DWORD);
  1450. RegistryItems[1].Type = REG_DWORD;
  1451. }
  1452. d = SetGroupOfValues(
  1453. HKEY_LOCAL_MACHINE,
  1454. L"SYSTEM\\Setup",
  1455. RegistryItems,
  1456. Upgrade ? 2 : 1
  1457. );
  1458. return(d == NO_ERROR);
  1459. }
  1460. BOOL
  1461. RemoveRestartStuff(
  1462. VOID
  1463. )
  1464. {
  1465. #define AnswerBufLen (4*MAX_PATH)
  1466. HKEY hKeySetup;
  1467. DWORD rc;
  1468. BOOL AnyErrors;
  1469. PWSTR *MultiSz;
  1470. UINT Count;
  1471. UINT i;
  1472. BOOL Found;
  1473. WCHAR c;
  1474. UINT Type;
  1475. WCHAR AnswerFile[AnswerBufLen];
  1476. WCHAR Answer[AnswerBufLen];
  1477. AnyErrors = FALSE;
  1478. //
  1479. // Delete the 'RestartSetup' value.
  1480. //
  1481. rc = (DWORD)RegOpenKeyEx(
  1482. HKEY_LOCAL_MACHINE,
  1483. L"System\\Setup",
  1484. 0,
  1485. KEY_SET_VALUE | KEY_QUERY_VALUE,
  1486. &hKeySetup
  1487. );
  1488. if(rc == NO_ERROR) {
  1489. rc = (DWORD)RegDeleteValue(hKeySetup,L"RestartSetup");
  1490. if((rc != NO_ERROR) && (rc != ERROR_FILE_NOT_FOUND)) {
  1491. AnyErrors = TRUE;
  1492. }
  1493. RegCloseKey(hKeySetup);
  1494. } else {
  1495. AnyErrors = TRUE;
  1496. }
  1497. if(AnyErrors) {
  1498. SetuplogError(
  1499. LogSevError,
  1500. SETUPLOG_USE_MESSAGEID,
  1501. MSG_LOG_REMOVE_RESTART_FAIL,
  1502. rc,
  1503. NULL,NULL);
  1504. return FALSE;
  1505. }
  1506. //
  1507. // Take care of the MiniSetup-specific items...
  1508. //
  1509. if( MiniSetup ) {
  1510. BOOLEAN FixupSourcePath;
  1511. //
  1512. // We've set a registry key specific to MiniSetup to
  1513. // signal lsass to skip generating a new SID. He
  1514. // wanted to because he thinks we're setting up
  1515. // a machine. We need to delete that key now.
  1516. //
  1517. rc = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1518. L"System\\Setup",
  1519. 0,
  1520. KEY_SET_VALUE | KEY_QUERY_VALUE,
  1521. &hKeySetup );
  1522. if(rc == NO_ERROR) {
  1523. // There are reboot cases where OOBE doesn't want these values
  1524. // modified. OOBE is responsible for setting them appropriately
  1525. // during its cleanup.
  1526. //
  1527. if (! OobeSetup)
  1528. {
  1529. //
  1530. // Set HKLM\System\Setup\SetupType Key to SETUPTYPE_NOREBOOT
  1531. //
  1532. rc = 0;
  1533. RegSetValueEx( hKeySetup,
  1534. TEXT( "SetupType" ),
  1535. 0,
  1536. REG_DWORD,
  1537. (CONST BYTE *)&rc,
  1538. sizeof(DWORD));
  1539. RegDeleteValue(hKeySetup,L"MiniSetupInProgress");
  1540. }
  1541. RegDeleteValue(hKeySetup,L"MiniSetupDoPnP");
  1542. RegCloseKey(hKeySetup);
  1543. } else {
  1544. AnyErrors = TRUE;
  1545. }
  1546. if(AnyErrors) {
  1547. //
  1548. // No. This is a don't-care failure.
  1549. //
  1550. }
  1551. //
  1552. // Now fixup the SourcePath entry.
  1553. //
  1554. // For the MiniSetup case, we'll use an unattend key to determine
  1555. // how to set the sourcepath. The possible scenarios are:
  1556. // [Unattended]
  1557. // ResetSourcePath=* This will indicate that we should
  1558. // not modify the existing source path
  1559. //
  1560. // ResetSourcePath="my_path" This will indicate that we should use
  1561. // this as our new source path.
  1562. //
  1563. // <nothing> Reset the source path to the CDROM.
  1564. //
  1565. //
  1566. //
  1567. // Pickup the answer file.
  1568. //
  1569. GetSystemDirectory(AnswerFile,MAX_PATH);
  1570. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  1571. //
  1572. // Assume we need to fixup the sourcepath.
  1573. //
  1574. FixupSourcePath = TRUE;
  1575. //
  1576. // Go retrieve this key from the unattend file.
  1577. //
  1578. if( GetPrivateProfileString( pwUnattended,
  1579. TEXT("ResetSourcePath"),
  1580. pwNull,
  1581. Answer,
  1582. AnswerBufLen,
  1583. AnswerFile ) ) {
  1584. //
  1585. // We got an answer. See what he wants us to do.
  1586. //
  1587. if( !wcscmp( L"*", Answer ) ) {
  1588. //
  1589. // He gave us a "*", so don't change anything.
  1590. //
  1591. FixupSourcePath = FALSE;
  1592. } else {
  1593. //
  1594. // We'll be using the contents of Answer for the
  1595. // new source path.
  1596. //
  1597. FixupSourcePath = TRUE;
  1598. }
  1599. } else {
  1600. //
  1601. // Reset the source path to the first CDROM.
  1602. // Assume conservatively that we don't have a CDROM, and
  1603. // in that case, we won't be resetting the source path.
  1604. //
  1605. FixupSourcePath = FALSE;
  1606. //
  1607. // Don't change the sourcepath if the directory specified in
  1608. // the key exists.
  1609. //
  1610. rc = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1611. L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
  1612. 0,
  1613. KEY_SET_VALUE | KEY_QUERY_VALUE,
  1614. &hKeySetup );
  1615. if( rc == NO_ERROR ) {
  1616. TCHAR CurrentSourcePath[MAX_PATH] = L"";
  1617. DWORD Size = sizeof(CurrentSourcePath);
  1618. DWORD dwAttr;
  1619. UINT OldMode;
  1620. //
  1621. // Avoid system popups.
  1622. //
  1623. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1624. //
  1625. // Read the current value.
  1626. //
  1627. rc = RegQueryValueEx( hKeySetup,
  1628. TEXT("SourcePath"),
  1629. 0,
  1630. 0,
  1631. (LPBYTE)CurrentSourcePath,
  1632. &Size);
  1633. // Set up the ARCH_DIR based on the current binary architecture
  1634. //
  1635. #ifdef _X86_
  1636. #define ARCH_DIR L"i386"
  1637. #else
  1638. #define ARCH_DIR L"ia64"
  1639. #endif
  1640. //
  1641. // If the current directory (with arch) exists and it is on a fixed disk and it
  1642. // is not a root directory then don't change it, otherwise change it.
  1643. //
  1644. if ( !((rc == NO_ERROR) &&
  1645. (CurrentSourcePath[0]) &&
  1646. (CurrentSourcePath[1] == L':') &&
  1647. (MyGetDriveType(CurrentSourcePath[0]) == DRIVE_FIXED) &&
  1648. (pSetupConcatenatePaths(CurrentSourcePath, ARCH_DIR, MAX_PATH, NULL)) &&
  1649. ((dwAttr = GetFileAttributes(CurrentSourcePath)) != 0xFFFFFFFF) &&
  1650. (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
  1651. )
  1652. ) {
  1653. Type = DRIVE_CDROM;
  1654. wcscpy( Answer, L"A:\\" );
  1655. for( c = L'A'; c <= L'Z'; c++ ) {
  1656. if( MyGetDriveType(c) == DRIVE_CDROM ) {
  1657. //
  1658. // Got it. Remember the drive letter for
  1659. // the CDROM and break.
  1660. //
  1661. Answer[0] = c;
  1662. FixupSourcePath = TRUE;
  1663. break;
  1664. }
  1665. }
  1666. }
  1667. SetErrorMode(OldMode);
  1668. RegCloseKey( hKeySetup );
  1669. }
  1670. }
  1671. if( FixupSourcePath ) {
  1672. //
  1673. // If we get here, then Answer contains the new source path.
  1674. //
  1675. rc = (DWORD)RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1676. L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup",
  1677. 0,
  1678. KEY_SET_VALUE | KEY_QUERY_VALUE,
  1679. &hKeySetup );
  1680. if( rc == NO_ERROR ) {
  1681. //
  1682. // Set the value. Ignore the return.
  1683. //
  1684. RegSetValueEx( hKeySetup,
  1685. TEXT("SourcePath" ),
  1686. 0,
  1687. REG_SZ,
  1688. (LPBYTE)Answer,
  1689. (lstrlen(Answer)+1) * sizeof(WCHAR) );
  1690. RegSetValueEx( hKeySetup,
  1691. TEXT("ServicePackSourcePath" ),
  1692. 0,
  1693. REG_SZ,
  1694. (LPBYTE)Answer,
  1695. (lstrlen(Answer)+1) * sizeof(WCHAR) );
  1696. //
  1697. // Now we need to determine if the drive we're setting him to
  1698. // is a CDROM.
  1699. //
  1700. if( (Answer[1] == L':') &&
  1701. (MyGetDriveType(Answer[0]) == DRIVE_CDROM) ) {
  1702. rc = 1;
  1703. RegSetValueEx( hKeySetup,
  1704. TEXT("CDInstall" ),
  1705. 0,
  1706. REG_DWORD,
  1707. (CONST BYTE *)&rc,
  1708. sizeof(DWORD));
  1709. }
  1710. RegCloseKey( hKeySetup );
  1711. }
  1712. }
  1713. }
  1714. //
  1715. // See if we need to disable the Admin account. Only do this if
  1716. // the user asked us to *and* the machine has been joined to a
  1717. // domain.
  1718. //
  1719. GetSystemDirectory(AnswerFile,MAX_PATH);
  1720. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  1721. if( GetPrivateProfileString( pwData,
  1722. TEXT("DisableAdminAccountOnDomainJoin"),
  1723. pwNull,
  1724. Answer,
  1725. AnswerBufLen,
  1726. AnswerFile ) ) {
  1727. if( wcscmp( L"", Answer ) ) {
  1728. PWSTR SpecifiedDomain = NULL;
  1729. NETSETUP_JOIN_STATUS JoinStatus;
  1730. //
  1731. // See if we're in a domain.
  1732. //
  1733. rc = NetGetJoinInformation( NULL,
  1734. &SpecifiedDomain,
  1735. &JoinStatus );
  1736. if( SpecifiedDomain ) {
  1737. NetApiBufferFree( SpecifiedDomain );
  1738. }
  1739. if( (rc == NO_ERROR) &&
  1740. (JoinStatus == NetSetupDomainName) ) {
  1741. //
  1742. // Yes. Go disable the Admin account.
  1743. //
  1744. DisableLocalAdminAccount();
  1745. }
  1746. }
  1747. }
  1748. //
  1749. // Remove sprestrt.exe from the session manager execute list.
  1750. //
  1751. rc = pSetupQueryMultiSzValueToArray(
  1752. HKEY_LOCAL_MACHINE,
  1753. SessionManagerKeyName,
  1754. szBootExecute,
  1755. &MultiSz,
  1756. &Count,
  1757. TRUE
  1758. );
  1759. if(rc == NO_ERROR) {
  1760. Found = FALSE;
  1761. for(i=0; i<Count && !Found; i++) {
  1762. if(!_wcsnicmp(MultiSz[i],L"sprestrt",8)) {
  1763. //
  1764. // Found it, remove it.
  1765. //
  1766. Found = TRUE;
  1767. MyFree(MultiSz[i]);
  1768. MoveMemory(&MultiSz[i],&MultiSz[i+1],((Count-i)-1)*sizeof(PWSTR));
  1769. Count--;
  1770. }
  1771. }
  1772. if(Found) {
  1773. rc = pSetupSetArrayToMultiSzValue(
  1774. HKEY_LOCAL_MACHINE,
  1775. SessionManagerKeyName,
  1776. szBootExecute,
  1777. MultiSz,
  1778. Count
  1779. );
  1780. if(rc != NO_ERROR) {
  1781. AnyErrors = TRUE;
  1782. }
  1783. }
  1784. pSetupFreeStringArray(MultiSz,Count);
  1785. }
  1786. if(AnyErrors) {
  1787. SetuplogError(
  1788. LogSevError,
  1789. SETUPLOG_USE_MESSAGEID,
  1790. MSG_LOG_REMOVE_RESTART_FAIL,
  1791. rc,
  1792. NULL,NULL);
  1793. }
  1794. return(!AnyErrors);
  1795. }
  1796. BOOL
  1797. MakeWowEntry(
  1798. VOID
  1799. )
  1800. {
  1801. REGVALITEM RegistryItem;
  1802. WCHAR WowSize[256];
  1803. DWORD d;
  1804. #ifdef _X86_
  1805. lstrcpy(WowSize,L"16");
  1806. #else
  1807. lstrcpy(WowSize,L"0");
  1808. #endif
  1809. RegistryItem.Name = L"wowsize";
  1810. RegistryItem.Data = WowSize;
  1811. RegistryItem.Size = (lstrlen(WowSize)+1)*sizeof(WCHAR);
  1812. RegistryItem.Type = REG_SZ;
  1813. d = SetGroupOfValues(
  1814. HKEY_LOCAL_MACHINE,
  1815. L"SYSTEM\\CurrentControlSet\\Control\\WOW",
  1816. &RegistryItem,
  1817. 1
  1818. );
  1819. return(d == NO_ERROR);
  1820. }
  1821. VOID
  1822. RestoreOldPathVariable(
  1823. VOID
  1824. )
  1825. {
  1826. HKEY hkey;
  1827. LONG rc;
  1828. DWORD Size;
  1829. DWORD BufferSize;
  1830. PWSTR Data;
  1831. DWORD Type;
  1832. BOOL b;
  1833. b = FALSE;
  1834. rc = RegOpenKeyEx(
  1835. HKEY_LOCAL_MACHINE,
  1836. EnvironmentKeyName,
  1837. 0,
  1838. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1839. &hkey
  1840. );
  1841. if(rc == NO_ERROR) {
  1842. Size = 0;
  1843. rc = RegQueryValueEx(hkey,L"OldPath",NULL,&Type,NULL,&Size);
  1844. if(rc == NO_ERROR) {
  1845. BufferSize = Size;
  1846. if(Data = MyMalloc(BufferSize)) {
  1847. rc = RegQueryValueEx(hkey,L"OldPath",NULL,&Type,(LPBYTE)Data,&Size);
  1848. if(rc == NO_ERROR) {
  1849. if( Data && *Data )
  1850. rc = RegSetValueEx(hkey,L"Path",0,Type,(LPBYTE)Data,Size);
  1851. rc = RegDeleteValue(hkey,L"OldPath");
  1852. if(rc == NO_ERROR) {
  1853. b = TRUE;
  1854. }
  1855. }
  1856. MyFree(Data);
  1857. }
  1858. }
  1859. RegCloseKey(hkey);
  1860. }
  1861. if( rc != NO_ERROR ){
  1862. SetupDebugPrint1(L"Setup: (non-critical error) Could not restore PATH variable - Error %lx\n", rc );
  1863. SetuplogError(
  1864. LogSevError,
  1865. SETUPLOG_USE_MESSAGEID,
  1866. MSG_RESTORE_PATH_FAILURE,
  1867. NULL,NULL);
  1868. }
  1869. return;
  1870. }
  1871. BOOL
  1872. FixQuotaEntries(
  1873. VOID
  1874. )
  1875. {
  1876. BOOL b;
  1877. HKEY key1,key2;
  1878. LONG rc,rc1,rc2;
  1879. PCWSTR szPagedPoolSize = L"PagedPoolSize";
  1880. PCWSTR szRegistryLimit = L"RegistrySizeLimit";
  1881. DWORD Size;
  1882. DWORD Type;
  1883. DWORD PoolSize,RegistryLimit;
  1884. MYASSERT(Upgrade);
  1885. if(ISDC(ProductType)) {
  1886. b = FALSE;
  1887. //
  1888. // Open keys.
  1889. //
  1890. rc = RegOpenKeyEx(
  1891. HKEY_LOCAL_MACHINE,
  1892. MemoryManagementKeyName,
  1893. 0,
  1894. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1895. &key1
  1896. );
  1897. if(rc == NO_ERROR) {
  1898. rc = RegOpenKeyEx(
  1899. HKEY_LOCAL_MACHINE,
  1900. ControlKeyName,
  1901. 0,
  1902. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1903. &key2
  1904. );
  1905. if(rc == NO_ERROR) {
  1906. b = TRUE;
  1907. //
  1908. // Read paged pool size and registry limit. If either is not present,
  1909. // then we're done.
  1910. //
  1911. Size = sizeof(DWORD);
  1912. rc1 = RegQueryValueEx(
  1913. key1,
  1914. szPagedPoolSize,
  1915. NULL,
  1916. &Type,
  1917. (LPBYTE)&PoolSize,
  1918. &Size
  1919. );
  1920. Size = sizeof(DWORD);
  1921. rc2 = RegQueryValueEx(
  1922. key2,
  1923. szRegistryLimit,
  1924. NULL,
  1925. &Type,
  1926. (LPBYTE)&RegistryLimit,
  1927. &Size
  1928. );
  1929. if((rc1 == NO_ERROR) && (rc2 == NO_ERROR)
  1930. && (PoolSize == (48*1024*1024))
  1931. && (RegistryLimit == (24*1024*1024))) {
  1932. //
  1933. // Values are in bogus state. Clean them up.
  1934. //
  1935. PoolSize = 0;
  1936. RegistryLimit = 0;
  1937. rc1 = RegSetValueEx(
  1938. key1,
  1939. szPagedPoolSize,
  1940. 0,
  1941. REG_DWORD,
  1942. (CONST BYTE *)&PoolSize,
  1943. sizeof(DWORD)
  1944. );
  1945. rc2 = RegSetValueEx(
  1946. key2,
  1947. szRegistryLimit,
  1948. 0,
  1949. REG_DWORD,
  1950. (CONST BYTE *)&RegistryLimit,
  1951. sizeof(DWORD)
  1952. );
  1953. if((rc1 != NO_ERROR) || (rc2 != NO_ERROR)) {
  1954. b = FALSE;
  1955. }
  1956. }
  1957. RegCloseKey(key2);
  1958. }
  1959. RegCloseKey(key1);
  1960. }
  1961. } else {
  1962. b = TRUE;
  1963. }
  1964. return(b);
  1965. }
  1966. //
  1967. // Stamps the current build number into the .default hive
  1968. // which is then saved into the Default User hive
  1969. //
  1970. BOOL
  1971. StampBuildNumber(
  1972. VOID
  1973. )
  1974. {
  1975. OSVERSIONINFO ver;
  1976. HKEY hKeyWinlogon;
  1977. DWORD dwVer, dwDisp;
  1978. LONG lResult;
  1979. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1980. if (!GetVersionEx(&ver)) {
  1981. return FALSE;
  1982. }
  1983. dwVer = LOWORD(ver.dwBuildNumber);
  1984. lResult = RegCreateKeyEx (HKEY_USERS,
  1985. TEXT(".DEFAULT\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  1986. 0,
  1987. NULL,
  1988. REG_OPTION_NON_VOLATILE,
  1989. KEY_WRITE,
  1990. NULL,
  1991. &hKeyWinlogon,
  1992. &dwDisp);
  1993. if (lResult != ERROR_SUCCESS) {
  1994. return FALSE;
  1995. }
  1996. RegSetValueEx (hKeyWinlogon, TEXT("BuildNumber"), 0, REG_DWORD,
  1997. (LPBYTE) &dwVer, sizeof(dwVer));
  1998. RegCloseKey (hKeyWinlogon);
  1999. return TRUE;
  2000. }
  2001. VOID
  2002. pCheckAnswerFileForProgramFiles (
  2003. IN OUT PWSTR PfPath,
  2004. IN UINT UnattendId
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. pCheckAnswerFileForProgramFiles checks the unattend.txt data structure to
  2009. see if the user supplied a new value for one of the paths of program files.
  2010. If an entry is specified, it is validated, and the directory is created if
  2011. it does not already exist.
  2012. Arguments:
  2013. PfPath - Specifies the current program files path, receives the new
  2014. path.
  2015. UnattendId - Specifies which unattend.txt entry to process. This is a
  2016. constant defined in unattend.h.
  2017. Return Value:
  2018. None.
  2019. --*/
  2020. {
  2021. DWORD Attributes;
  2022. WCHAR Path[MAX_PATH / 2];
  2023. WCHAR fullPath[MAX_PATH];
  2024. if (Unattended) {
  2025. //
  2026. // If an answer file setting exists for this unattend ID,
  2027. // test the path, and if it does not exist, try creating it.
  2028. // If the path is an actual local directory, then use it.
  2029. //
  2030. if (UnattendAnswerTable[UnattendId].Present) {
  2031. lstrcpyn (Path, UnattendAnswerTable[UnattendId].Answer.String, ARRAYSIZE(Path));
  2032. *fullPath = 0;
  2033. GetFullPathName (Path, ARRAYSIZE(fullPath), fullPath, NULL);
  2034. Attributes = GetFileAttributes (fullPath);
  2035. if (Attributes == 0xFFFFFFFF) {
  2036. CreateDirectory (fullPath, NULL);
  2037. Attributes = GetFileAttributes (fullPath);
  2038. }
  2039. if (Attributes != 0xFFFFFFFF && (Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  2040. lstrcpy (PfPath, fullPath);
  2041. }
  2042. }
  2043. }
  2044. }
  2045. BOOL
  2046. SetProgramFilesDirInRegistry(
  2047. VOID
  2048. )
  2049. {
  2050. DWORD d;
  2051. #if defined(WX86) || defined(_WIN64) // non-x86 platforms that have WX86 defined
  2052. REGVALITEM RegistryItem[4];
  2053. #else
  2054. REGVALITEM RegistryItem[2];
  2055. #endif
  2056. WCHAR DirPath0[ MAX_PATH + 1 ];
  2057. WCHAR DirPath1[ MAX_PATH + 1 ];
  2058. #if defined(WX86) || defined(_WIN64)
  2059. WCHAR DirPath2[ MAX_PATH + 1 ];
  2060. WCHAR DirPath3[ MAX_PATH + 1 ];
  2061. #endif
  2062. WCHAR DirName[ MAX_PATH + 1 ];
  2063. DWORD Result;
  2064. //
  2065. // Get the letter of the drive where the system is installed
  2066. //
  2067. Result = GetWindowsDirectory(DirPath0, sizeof(DirPath0)/sizeof(WCHAR));
  2068. if( Result == 0) {
  2069. MYASSERT(FALSE);
  2070. return FALSE;
  2071. }
  2072. DirPath0[3] = (WCHAR)'\0';
  2073. #if defined(WX86) || defined(_WIN64)
  2074. lstrcpy(DirPath2, DirPath0);
  2075. #endif
  2076. //
  2077. // Get the name of the 'Program Files' directory
  2078. //
  2079. LoadString(MyModuleHandle,
  2080. IDS_PROGRAM_FILES_DIRECTORY,
  2081. DirName,
  2082. MAX_PATH+1);
  2083. //
  2084. // Build the full path
  2085. //
  2086. lstrcat( DirPath0, DirName );
  2087. lstrcpy( DirPath1, DirPath0 );
  2088. #if defined(WX86) || defined(_WIN64)
  2089. //
  2090. // Get the name of the 'Program Files (x86)' directory
  2091. //
  2092. LoadString(MyModuleHandle,
  2093. IDS_PROGRAM_FILES_DIRECTORY_WX86,
  2094. DirName,
  2095. MAX_PATH+1);
  2096. //
  2097. // Build the full path
  2098. //
  2099. lstrcat( DirPath2, DirName );
  2100. lstrcpy( DirPath3, DirPath2 );
  2101. #endif
  2102. //
  2103. // Put it on the registry
  2104. //
  2105. pCheckAnswerFileForProgramFiles (DirPath0, UAE_PROGRAMFILES);
  2106. RegistryItem[0].Name = L"ProgramFilesDir";
  2107. RegistryItem[0].Data = DirPath0;
  2108. RegistryItem[0].Type = REG_SZ;
  2109. RegistryItem[0].Size = (lstrlen(DirPath0)+1)*sizeof(WCHAR);
  2110. //
  2111. // Get the name of the 'Common Files' directory
  2112. //
  2113. LoadString(MyModuleHandle,
  2114. IDS_COMMON_FILES_DIRECTORY,
  2115. DirName,
  2116. MAX_PATH+1);
  2117. //
  2118. // Build the full path
  2119. //
  2120. lstrcat( DirPath1, L"\\" );
  2121. lstrcat( DirPath1, DirName );
  2122. //
  2123. // Put it on the registry
  2124. //
  2125. pCheckAnswerFileForProgramFiles (DirPath1, UAE_COMMONPROGRAMFILES);
  2126. RegistryItem[1].Name = L"CommonFilesDir";
  2127. RegistryItem[1].Data = DirPath1;
  2128. RegistryItem[1].Type = REG_SZ;
  2129. RegistryItem[1].Size = (lstrlen(DirPath1)+1)*sizeof(WCHAR);
  2130. #if defined(WX86) || defined(_WIN64)
  2131. SetEnvironmentVariableW (L"ProgramFiles(x86)", DirPath2);
  2132. SetEnvironmentVariableW (L"CommonProgramFiles(x86)", DirPath3);
  2133. //
  2134. // Put it on the registry
  2135. //
  2136. pCheckAnswerFileForProgramFiles (DirPath2, UAE_PROGRAMFILES_X86);
  2137. RegistryItem[2].Name = L"ProgramFilesDir (x86)";
  2138. RegistryItem[2].Data = DirPath2;
  2139. RegistryItem[2].Type = REG_SZ;
  2140. RegistryItem[2].Size = (lstrlen(DirPath2)+1)*sizeof(WCHAR);
  2141. //
  2142. // Build the full path
  2143. //
  2144. lstrcat( DirPath3, L"\\" );
  2145. lstrcat( DirPath3, DirName );
  2146. //
  2147. // Put it on the registry
  2148. //
  2149. pCheckAnswerFileForProgramFiles (DirPath3, UAE_COMMONPROGRAMFILES_X86);
  2150. RegistryItem[3].Name = L"CommonFilesDir (x86)";
  2151. RegistryItem[3].Data = DirPath3;
  2152. RegistryItem[3].Type = REG_SZ;
  2153. RegistryItem[3].Size = (lstrlen(DirPath3)+1)*sizeof(WCHAR);
  2154. #endif
  2155. d = SetGroupOfValues(HKEY_LOCAL_MACHINE,
  2156. WindowsCurrentVersionKeyName,
  2157. RegistryItem,
  2158. sizeof(RegistryItem)/sizeof(REGVALITEM));
  2159. //
  2160. // Set the ProgramFiles and wx86 Program Files environment
  2161. // variable in setup's process so that ExpandEnvironmentStrings
  2162. // can be used later.
  2163. //
  2164. SetEnvironmentVariableW (L"ProgramFiles", DirPath0);
  2165. SetEnvironmentVariableW (L"CommonProgramFiles", DirPath1);
  2166. #if defined(WX86) || defined(_WIN64)
  2167. //
  2168. // also set programfiles and commonprogramfiles for 32 bit applications on
  2169. // the machine
  2170. //
  2171. RegistryItem[2].Name = L"ProgramFilesDir";
  2172. RegistryItem[3].Name = L"CommonFilesDir";
  2173. SetGroupOfValues_32(HKEY_LOCAL_MACHINE,
  2174. WindowsCurrentVersionKeyName,
  2175. &RegistryItem[2],
  2176. 2 );
  2177. #endif
  2178. return (d == NO_ERROR);
  2179. }
  2180. BOOL
  2181. SaveAndReplaceSystemHives(
  2182. VOID
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. Saave the system hives listed on HiveTable.
  2187. This is the remove fragmentation from the current system hives.
  2188. The hives that are successfully saved, will be used later on, to replace
  2189. the current system hives.
  2190. Arguments:
  2191. None.
  2192. Return Value:
  2193. Boolean value indicating outcome.
  2194. --*/
  2195. {
  2196. int i;
  2197. WCHAR Name1[MAX_PATH],Name2[MAX_PATH];
  2198. PWSTR p, q;
  2199. LONG Error;
  2200. HKEY Key;
  2201. BOOL b = TRUE;
  2202. //
  2203. // Initialize buffers with path to the config directory
  2204. GetSystemDirectory(Name1,MAX_PATH);
  2205. pSetupConcatenatePaths(Name1,L"CONFIG\\",MAX_PATH,NULL);
  2206. lstrcpy(Name2,Name1);
  2207. //
  2208. // Remember the position of file names in the buffers
  2209. //
  2210. p = Name1 + lstrlen( Name1 );
  2211. q = Name2 + lstrlen( Name2 );
  2212. //
  2213. // Delete the files that need to be deleted before they
  2214. // are even created. This is done before the system hive
  2215. // is saved, because the list of files to be deleted on
  2216. // reboot is stored in the system hive.
  2217. //
  2218. for(i=0; i<sizeof(HiveTable)/sizeof(HiveTable[0]); i++) {
  2219. lstrcpy(p, HiveTable[i].NewHive);
  2220. lstrcpy(q, HiveTable[i].DeleteHive);
  2221. Error = MoveFileEx( Name1, NULL, MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT );
  2222. lstrcat(Name1,L".LOG");
  2223. Error = MoveFileEx( Name1, NULL, MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT );
  2224. Error = MoveFileEx( Name2, NULL, MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT );
  2225. }
  2226. //
  2227. // Enable backup privilege. Ignore any error.
  2228. //
  2229. pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE);
  2230. for(i=0; i<sizeof(HiveTable)/sizeof(HiveTable[0]); i++) {
  2231. //
  2232. // Build the name for the new hive
  2233. //
  2234. lstrcpy(p,HiveTable[i].NewHive);
  2235. lstrcpy(q,HiveTable[i].DeleteHive);
  2236. //
  2237. // Attempt to save the hive
  2238. //
  2239. if( !SaveHive( HiveTable[i].RootKey,
  2240. HiveTable[i].Subkey,
  2241. Name1,
  2242. REG_LATEST_FORMAT // latest format available for local hives
  2243. ) ) {
  2244. b = FALSE;
  2245. continue;
  2246. }
  2247. if(FileExists(Name2,NULL)) {
  2248. //
  2249. // If the file exists, then delete it
  2250. //
  2251. SetFileAttributes(Name2,FILE_ATTRIBUTE_NORMAL);
  2252. DeleteFile(Name2);
  2253. }
  2254. //
  2255. // Now replace the current system hive with the one just saved
  2256. //
  2257. Error = RegReplaceKey( HiveTable[i].RootKey,
  2258. HiveTable[i].Subkey,
  2259. Name1,
  2260. Name2 );
  2261. if( Error != ERROR_SUCCESS ) {
  2262. b = FALSE;
  2263. }
  2264. }
  2265. return(b);
  2266. }
  2267. BOOL
  2268. CreateInstallDateEntry(
  2269. )
  2270. {
  2271. WCHAR Path[MAX_PATH];
  2272. time_t DateVal;
  2273. BOOL b;
  2274. REGVALITEM SoftwareKeyItems[1];
  2275. b = TRUE;
  2276. //
  2277. // Set up fields for InstallDate value.
  2278. // This can be set only after the Date/Time wizard page was executed, otherwise the Date/Time info
  2279. // may be wrong.
  2280. //
  2281. time(&DateVal);
  2282. SoftwareKeyItems[0].Name = L"InstallDate";
  2283. SoftwareKeyItems[0].Data = &DateVal;
  2284. SoftwareKeyItems[0].Size = sizeof(DWORD);
  2285. SoftwareKeyItems[0].Type = REG_DWORD;
  2286. //
  2287. // Write values into the registry.
  2288. //
  2289. if(SetGroupOfValues(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,SoftwareKeyItems,1) != NO_ERROR) {
  2290. b = FALSE;
  2291. }
  2292. return(b);
  2293. }
  2294. VOID
  2295. ConfigureSystemFileProtection(
  2296. VOID
  2297. )
  2298. /*++
  2299. Routine Description:
  2300. This routine looks in the unattend file to see if there are any entries
  2301. that may need to be set in the registry for the SFP (dll cache).
  2302. Arguments:
  2303. None.
  2304. Returns:
  2305. None.
  2306. --*/
  2307. {
  2308. #define AnswerBufLen (4*MAX_PATH)
  2309. WCHAR AnswerFile[AnswerBufLen];
  2310. WCHAR Answer[AnswerBufLen];
  2311. DWORD d;
  2312. HKEY hKey;
  2313. //
  2314. // Pickup the answer file.
  2315. //
  2316. GetSystemDirectory(AnswerFile,MAX_PATH);
  2317. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  2318. //
  2319. // Open the target registry entry.
  2320. //
  2321. if (RegOpenKey( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", &hKey ) != ERROR_SUCCESS) {
  2322. return;
  2323. }
  2324. //
  2325. // we look for the following keys in the [SystemFileProtection] section:
  2326. //
  2327. // SFCQuota = <hex value>, default to 0x32
  2328. // SFCShowProgress = <0|1>, default to 0
  2329. // SFCDllCacheDir = <string>, default to "%systemroot%\system32\dllcache"
  2330. //
  2331. //
  2332. // SFCQuota
  2333. //
  2334. if( GetPrivateProfileString( TEXT("SystemFileProtection"),
  2335. TEXT("SFCQuota"),
  2336. pwNull,
  2337. Answer,
  2338. AnswerBufLen,
  2339. AnswerFile ) ) {
  2340. if( lstrcmp( pwNull, Answer ) ) {
  2341. //
  2342. // We got an answer. If it's valid, then set it.
  2343. //
  2344. d = wcstoul(Answer,NULL,16);
  2345. RegSetValueEx( hKey,
  2346. TEXT("SFCQuota"),
  2347. 0,
  2348. REG_DWORD,
  2349. (CONST BYTE *)&d,
  2350. sizeof(DWORD) );
  2351. }
  2352. }
  2353. //
  2354. // SFCShowProgress
  2355. //
  2356. if( GetPrivateProfileString( TEXT("SystemFileProtection"),
  2357. TEXT("SFCShowProgress"),
  2358. pwNull,
  2359. Answer,
  2360. AnswerBufLen,
  2361. AnswerFile ) ) {
  2362. if( lstrcmp( pwNull, Answer ) ) {
  2363. //
  2364. // We got an answer. If it's valid, then set it.
  2365. //
  2366. d = wcstoul(Answer,NULL,10);
  2367. if( d <= 1 ) {
  2368. RegSetValueEx( hKey,
  2369. TEXT("SFCShowProgress"),
  2370. 0,
  2371. REG_DWORD,
  2372. (CONST BYTE *)&d,
  2373. sizeof(DWORD) );
  2374. }
  2375. }
  2376. }
  2377. //
  2378. // SFCDllCacheDir
  2379. //
  2380. if( GetPrivateProfileString( TEXT("SystemFileProtection"),
  2381. TEXT("SFCDllCacheDir"),
  2382. pwNull,
  2383. Answer,
  2384. AnswerBufLen,
  2385. AnswerFile ) ) {
  2386. if( lstrcmp( pwNull, Answer ) ) {
  2387. //
  2388. // We got an answer. If it's valid, then set it.
  2389. //
  2390. RegSetValueEx( hKey,
  2391. TEXT("SFCDllCacheDir"),
  2392. 0,
  2393. REG_EXPAND_SZ,
  2394. (CONST BYTE *)Answer,
  2395. (lstrlen(Answer)+1)*sizeof(WCHAR) );
  2396. }
  2397. }
  2398. RegCloseKey( hKey );
  2399. }
  2400. DWORD
  2401. QueryValueInHKLM (
  2402. IN PWCH KeyName OPTIONAL,
  2403. IN PWCH ValueName,
  2404. OUT PDWORD ValueType,
  2405. OUT PVOID *ValueData,
  2406. OUT PDWORD ValueDataLength
  2407. )
  2408. /*++
  2409. Routine Description:
  2410. Queries the data for a value in HKLM.
  2411. Arguments:
  2412. KeyName - pointer to name of the key containing the value.
  2413. ValueName - pointer to name of the value.
  2414. ValueType - returns the type of the value data.
  2415. ValueData - returns a pointer to value data. This buffer must be
  2416. freed by the caller using MyFree.
  2417. ValueDataLength - length in bytes of ValueData.
  2418. Return Value:
  2419. DWORD - Win32 status of the operation.
  2420. --*/
  2421. {
  2422. HKEY hkey;
  2423. DWORD disposition;
  2424. DWORD error;
  2425. //
  2426. // Open the parent key.
  2427. //
  2428. if ( (KeyName == NULL) || (wcslen(KeyName) == 0) ) {
  2429. hkey = HKEY_LOCAL_MACHINE;
  2430. } else {
  2431. error = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  2432. KeyName,
  2433. 0,
  2434. NULL,
  2435. REG_OPTION_NON_VOLATILE,
  2436. KEY_READ,
  2437. NULL,
  2438. &hkey,
  2439. &disposition );
  2440. if ( error != ERROR_SUCCESS ) {
  2441. return error;
  2442. }
  2443. }
  2444. //
  2445. // Query the value to get the length of its data.
  2446. //
  2447. *ValueDataLength = 0;
  2448. *ValueData = NULL;
  2449. error = RegQueryValueEx( hkey,
  2450. ValueName,
  2451. NULL,
  2452. ValueType,
  2453. NULL,
  2454. ValueDataLength );
  2455. //
  2456. // Allocate a buffer to hold the value data.
  2457. //
  2458. if ( error == NO_ERROR ) {
  2459. *ValueData = MyMalloc( *ValueDataLength );
  2460. if ( *ValueData == NULL ) {
  2461. error = ERROR_NOT_ENOUGH_MEMORY;
  2462. }
  2463. }
  2464. //
  2465. // Query the value again, this time retrieving the data.
  2466. //
  2467. if ( error == NO_ERROR ) {
  2468. error = RegQueryValueEx( hkey,
  2469. ValueName,
  2470. NULL,
  2471. ValueType,
  2472. *ValueData,
  2473. ValueDataLength );
  2474. if ( error != NO_ERROR ) {
  2475. MyFree( *ValueData );
  2476. }
  2477. }
  2478. //
  2479. // Close the parent key.
  2480. //
  2481. if ( hkey != HKEY_CURRENT_USER ) {
  2482. RegCloseKey( hkey );
  2483. }
  2484. return error;
  2485. }
  2486. DWORD
  2487. MyCopyKeyRecursive(
  2488. IN HKEY DestRootKey,
  2489. IN HKEY SourceRootKey
  2490. )
  2491. /*++
  2492. Routine Description:
  2493. This function will duplicate one key (and all its subkeys)
  2494. to another key.
  2495. Arguments:
  2496. DestRootKey - Root of the destination registry key.
  2497. SourceRootKey - Root of the source registry key.
  2498. Return Value:
  2499. ReturnCode
  2500. --*/
  2501. {
  2502. PWCH SubKeyName;
  2503. DWORD SubKeyNameLength;
  2504. PVOID DataBuffer;
  2505. DWORD DataLength;
  2506. DWORD maxValueDataLength;
  2507. DWORD maxValueNameLength;
  2508. DWORD maxKeyNameLength;
  2509. ULONG Index;
  2510. DWORD rc = NO_ERROR;
  2511. FILETIME ftLastWriteTime;
  2512. HKEY hSubDestKey, hSubSourceKey;
  2513. DWORD dwDisp;
  2514. DWORD Type;
  2515. //
  2516. // Query information about the key that we'll be inspecting.
  2517. //
  2518. rc = RegQueryInfoKey( SourceRootKey,
  2519. NULL,
  2520. NULL,
  2521. NULL,
  2522. NULL,
  2523. &maxKeyNameLength,
  2524. NULL,
  2525. NULL,
  2526. &maxValueNameLength,
  2527. &maxValueDataLength,
  2528. NULL,
  2529. NULL );
  2530. if( rc != NO_ERROR ) {
  2531. SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegQueryInfoKey failed (%d)", rc );
  2532. return rc;
  2533. }
  2534. //
  2535. // Enumerate all keys in the source and recursively create
  2536. // them in the destination.
  2537. //
  2538. for( Index = 0; ; Index++ ) {
  2539. //
  2540. // Allocate a buffer large enough to hold the longest
  2541. // key name.
  2542. //
  2543. SubKeyName = NULL;
  2544. SubKeyName = MyMalloc( (maxKeyNameLength+2) * sizeof(WCHAR) );
  2545. SubKeyNameLength = (maxKeyNameLength+2);
  2546. if( !SubKeyName ) {
  2547. return ERROR_NOT_ENOUGH_MEMORY;
  2548. }
  2549. rc = RegEnumKeyEx( SourceRootKey,
  2550. Index,
  2551. SubKeyName,
  2552. &SubKeyNameLength,
  2553. NULL,
  2554. NULL,
  2555. NULL,
  2556. &ftLastWriteTime );
  2557. //
  2558. // Did we error?
  2559. //
  2560. if( rc != ERROR_SUCCESS ) {
  2561. //
  2562. // Are we done?
  2563. //
  2564. if( rc == ERROR_NO_MORE_ITEMS ) {
  2565. rc = ERROR_SUCCESS;
  2566. } else {
  2567. SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegEnumKeyEx failed (%d)", rc );
  2568. }
  2569. break;
  2570. }
  2571. hSubDestKey = NULL;
  2572. hSubSourceKey = NULL;
  2573. //
  2574. // Create the key in the destination, and call
  2575. // ourselves again.
  2576. //
  2577. rc = RegCreateKeyEx( DestRootKey,
  2578. SubKeyName,
  2579. 0,
  2580. NULL,
  2581. REG_OPTION_NON_VOLATILE,
  2582. KEY_WRITE,
  2583. NULL,
  2584. &hSubDestKey,
  2585. &dwDisp );
  2586. if( rc == ERROR_SUCCESS ) {
  2587. rc = RegOpenKeyEx( SourceRootKey,
  2588. SubKeyName,
  2589. 0,
  2590. KEY_READ,
  2591. &hSubSourceKey );
  2592. } else {
  2593. SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegCreateKeyEx failed to create %ws (%d)", SubKeyName, rc );
  2594. }
  2595. if( rc == ERROR_SUCCESS ) {
  2596. rc = MyCopyKeyRecursive( hSubDestKey,
  2597. hSubSourceKey );
  2598. } else {
  2599. SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegOpenKeyEx failed to open %ws (%d)", SubKeyName, rc );
  2600. }
  2601. //
  2602. // Clean up and do the loop again.
  2603. //
  2604. if( hSubDestKey ) {
  2605. RegCloseKey( hSubDestKey );
  2606. hSubDestKey = NULL;
  2607. }
  2608. if( hSubSourceKey ) {
  2609. RegCloseKey( hSubSourceKey );
  2610. hSubSourceKey = NULL;
  2611. }
  2612. if( SubKeyName ) {
  2613. MyFree( SubKeyName );
  2614. SubKeyName = NULL;
  2615. }
  2616. }
  2617. //
  2618. // Enumerate all the value keys in the source and copy them all
  2619. // into the destination key.
  2620. //
  2621. for( Index = 0; ; Index++ ) {
  2622. //
  2623. // Allocate a buffers large enough to hold the longest
  2624. // name and data
  2625. //
  2626. SubKeyName = NULL;
  2627. SubKeyName = MyMalloc( (maxValueNameLength+2) * sizeof(WCHAR) );
  2628. SubKeyNameLength = (maxValueNameLength+2);
  2629. if( !SubKeyName ) {
  2630. return ERROR_NOT_ENOUGH_MEMORY;
  2631. }
  2632. DataBuffer = NULL;
  2633. DataBuffer = MyMalloc( maxValueDataLength+2 );
  2634. DataLength = maxValueDataLength+2;
  2635. if( !DataBuffer ) {
  2636. return ERROR_NOT_ENOUGH_MEMORY;
  2637. }
  2638. rc = RegEnumValue( SourceRootKey,
  2639. Index,
  2640. SubKeyName,
  2641. &SubKeyNameLength,
  2642. NULL,
  2643. &Type,
  2644. DataBuffer,
  2645. &DataLength );
  2646. //
  2647. // Did we error?
  2648. //
  2649. if( rc != ERROR_SUCCESS ) {
  2650. //
  2651. // Are we done?
  2652. //
  2653. if( rc == ERROR_NO_MORE_ITEMS ) {
  2654. rc = ERROR_SUCCESS;
  2655. } else {
  2656. SetupDebugPrint1( L"Setup: MyCopyKeyRecursive - RegEnumValue failed (%d)", rc );
  2657. }
  2658. break;
  2659. }
  2660. hSubDestKey = NULL;
  2661. hSubSourceKey = NULL;
  2662. //
  2663. // Create the value key in the destination.
  2664. //
  2665. rc = RegSetValueEx( DestRootKey,
  2666. SubKeyName,
  2667. 0,
  2668. Type,
  2669. DataBuffer,
  2670. DataLength );
  2671. if( rc != ERROR_SUCCESS ) {
  2672. SetupDebugPrint2( L"Setup: MyCopyKeyRecursive - RegSetValueEx failed to set %ws (%d)", SubKeyName, rc );
  2673. }
  2674. //
  2675. // Clean up and do the loop again.
  2676. //
  2677. if( SubKeyName ) {
  2678. MyFree( SubKeyName );
  2679. SubKeyName = NULL;
  2680. }
  2681. if( DataBuffer ) {
  2682. MyFree( DataBuffer );
  2683. DataBuffer = NULL;
  2684. }
  2685. }
  2686. return rc;
  2687. }
  2688. DWORD
  2689. MyCopyKey (
  2690. IN HKEY DestRootKey,
  2691. IN PCWSTR DestKeyName,
  2692. IN HKEY SourceRootKey,
  2693. IN PCWSTR SourceKeyName
  2694. )
  2695. /*++
  2696. Routine Description:
  2697. This function will duplicate one key (and all its subkeys)
  2698. to another key.
  2699. Note that we're not just going to lay the new key ontop of
  2700. the destination. We're going to actually replace the destination
  2701. with the source.
  2702. Arguments:
  2703. DestRootKey - Root of the destination registry key.
  2704. DestKeyName - Name of teh source registry key.
  2705. SourceRootKey - Root of the source registry key.
  2706. SourceKeyName - Name of teh source registry key.
  2707. Return Value:
  2708. ReturnCode
  2709. --*/
  2710. {
  2711. UINT i;
  2712. HKEY hDestKey = NULL, hSourceKey = NULL;
  2713. DWORD ActionTaken;
  2714. UINT RememberedRc;
  2715. DWORD rc = NO_ERROR;
  2716. //
  2717. // Don't accept any NULL parameters.
  2718. //
  2719. if( (SourceRootKey == NULL ) ||
  2720. (SourceKeyName == NULL ) ||
  2721. (DestRootKey == NULL ) ||
  2722. (DestKeyName == NULL ) ) {
  2723. return ERROR_INVALID_PARAMETER;
  2724. }
  2725. //
  2726. // Open our source key.
  2727. //
  2728. rc = RegOpenKeyEx( SourceRootKey,
  2729. SourceKeyName,
  2730. 0,
  2731. KEY_ENUMERATE_SUB_KEYS | KEY_READ,
  2732. &hSourceKey );
  2733. if( rc != NO_ERROR ) {
  2734. SetupDebugPrint2( L"Setup: MyCopyKey - Failed to open %ws (%d)", SourceKeyName, rc );
  2735. return rc;
  2736. }
  2737. //
  2738. // Remove the destination key.
  2739. //
  2740. if( rc == NO_ERROR ) {
  2741. pSetupRegistryDelnode( DestRootKey,
  2742. DestKeyName );
  2743. }
  2744. //
  2745. // Now copy over the source key into the destination key.
  2746. //
  2747. //
  2748. // Open/create the key first.
  2749. //
  2750. if( rc == NO_ERROR ) {
  2751. rc = RegCreateKeyEx( DestRootKey,
  2752. DestKeyName,
  2753. 0,
  2754. NULL,
  2755. REG_OPTION_NON_VOLATILE,
  2756. KEY_SET_VALUE,
  2757. NULL,
  2758. &hDestKey,
  2759. &ActionTaken );
  2760. if( rc != NO_ERROR ) {
  2761. SetupDebugPrint2( L"Setup: MyCopyKey - Failed to create %ws (%d)", DestKeyName, rc );
  2762. }
  2763. }
  2764. //
  2765. // We've got handles to both keys, now we're ready to call
  2766. // our worker.
  2767. //
  2768. if( rc == NO_ERROR ) {
  2769. rc = MyCopyKeyRecursive( hDestKey,
  2770. hSourceKey );
  2771. if( rc != NO_ERROR ) {
  2772. SetupDebugPrint1( L"Setup: MyCopyKey - MyCopyKeyRecursive failed (%d)", rc );
  2773. }
  2774. }
  2775. //
  2776. // Clean up and exit.
  2777. //
  2778. if( hSourceKey ) {
  2779. RegCloseKey( hSourceKey );
  2780. }
  2781. if( hDestKey ) {
  2782. RegCloseKey( hDestKey );
  2783. }
  2784. return rc;
  2785. }
  2786. DWORD
  2787. FixupUserHives(
  2788. VOID
  2789. )
  2790. /*++
  2791. Routine Description:
  2792. This function will take some of the changes we've made to
  2793. the default hive and copy them into the various user hives.
  2794. Arguments:
  2795. NONE
  2796. Return Value:
  2797. ReturnCode
  2798. --*/
  2799. {
  2800. DWORD rc = ERROR_SUCCESS;
  2801. WCHAR ProfilesDir[MAX_PATH*2];
  2802. WCHAR HiveName[MAX_PATH*2];
  2803. WCHAR ValueBuffer[MAX_PATH*2];
  2804. DWORD dwSize;
  2805. HANDLE FindHandle;
  2806. WIN32_FIND_DATA FileData;
  2807. DWORD Type, DataSize;
  2808. HKEY TmpKey1, TmpKey2;
  2809. pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE);
  2810. //
  2811. // Take care of every profile we find.
  2812. //
  2813. dwSize = (MAX_PATH * 2);
  2814. if( GetProfilesDirectory( ProfilesDir, &dwSize ) ) {
  2815. pSetupConcatenatePaths( ProfilesDir, L"\\*", (MAX_PATH*2), NULL );
  2816. FindHandle = FindFirstFile( ProfilesDir, &FileData );
  2817. if( FindHandle != INVALID_HANDLE_VALUE ) {
  2818. do {
  2819. //
  2820. // We got something, but remember that we only want directories.
  2821. //
  2822. if( (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  2823. (wcscmp(FileData.cFileName,L".")) &&
  2824. (wcscmp(FileData.cFileName,L"..")) ) {
  2825. //
  2826. // He's a directory and he's not parent or current.
  2827. // Generate a path to his hive.
  2828. //
  2829. dwSize = (MAX_PATH * 2);
  2830. GetProfilesDirectory( HiveName, &dwSize );
  2831. pSetupConcatenatePaths( HiveName, FileData.cFileName, (MAX_PATH*2), NULL );
  2832. pSetupConcatenatePaths( HiveName, L"\\NTUSER.DAT", (MAX_PATH*2), NULL );
  2833. rc = RegLoadKey( HKEY_LOCAL_MACHINE,
  2834. L"MiniSetupTemp",
  2835. HiveName );
  2836. if( rc == ERROR_SUCCESS ) {
  2837. //
  2838. // Take care of the 'International' key
  2839. //
  2840. rc = MyCopyKey( HKEY_LOCAL_MACHINE,
  2841. L"MiniSetupTemp\\Control Panel\\International",
  2842. HKEY_CURRENT_USER,
  2843. L"Control Panel\\International" );
  2844. if( rc != ERROR_SUCCESS ) {
  2845. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Control Panel\\International in %ws (%d)", HiveName, rc );
  2846. }
  2847. //
  2848. // Take care of the 'Keyboard Layout' key
  2849. //
  2850. rc = MyCopyKey( HKEY_LOCAL_MACHINE,
  2851. L"MiniSetupTemp\\Keyboard Layout",
  2852. HKEY_CURRENT_USER,
  2853. L"Keyboard Layout" );
  2854. if( rc != ERROR_SUCCESS ) {
  2855. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Keyboard Layout in %ws (%d)", HiveName, rc );
  2856. }
  2857. //
  2858. // Take care of the 'Input Method' key
  2859. //
  2860. rc = MyCopyKey( HKEY_LOCAL_MACHINE,
  2861. L"MiniSetupTemp\\Control Panel\\Input Method",
  2862. HKEY_CURRENT_USER,
  2863. L"Control Panel\\Input Method" );
  2864. if( rc != ERROR_SUCCESS ) {
  2865. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to update Input Method in %ws (%d)", HiveName, rc );
  2866. }
  2867. //
  2868. // If the user has modified the internationalization settings
  2869. // in intl.cpl, then there's likely a 'Run' key. We need to migrate that
  2870. // too. We need to be careful here though. The established users may already
  2871. // have value keys set under here. We only need to set *our* single value
  2872. // key under here. That value is called 'internat.exe'. If it's there, we
  2873. // need to prop it out to the hives we're modifying.
  2874. //
  2875. rc = RegOpenKeyEx( HKEY_CURRENT_USER,
  2876. REGSTR_PATH_RUN,
  2877. 0,
  2878. KEY_READ,
  2879. &TmpKey1 );
  2880. if( rc != ERROR_SUCCESS ) {
  2881. SetupDebugPrint1( L"Setup: FixupUserHive - Failed to open Run key (%d)", rc );
  2882. } else {
  2883. DataSize = sizeof(ValueBuffer);
  2884. rc = RegQueryValueEx( TmpKey1,
  2885. L"internat.exe",
  2886. NULL,
  2887. &Type,
  2888. (PBYTE)ValueBuffer,
  2889. &DataSize );
  2890. RegCloseKey( TmpKey1 );
  2891. if( rc == ERROR_SUCCESS ) {
  2892. //
  2893. // It's there. Prop it into the existing hives too.
  2894. // We can't just use RegSetValueEx though because that API
  2895. // may tell us we succeeded, when in fact if the key doesn't
  2896. // exist, we won't set it. To fix that, first create the
  2897. // key.
  2898. //
  2899. rc = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,
  2900. TEXT("MiniSetupTemp\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
  2901. 0,
  2902. NULL,
  2903. REG_OPTION_NON_VOLATILE,
  2904. KEY_WRITE,
  2905. NULL,
  2906. &TmpKey1,
  2907. &DataSize);
  2908. if( rc == ERROR_SUCCESS ) {
  2909. wcscpy( ValueBuffer, L"internat.exe" );
  2910. rc = RegSetValueEx( TmpKey1,
  2911. L"Internat.exe",
  2912. 0,
  2913. REG_SZ,
  2914. (LPBYTE)ValueBuffer,
  2915. (lstrlen(ValueBuffer)+1)*sizeof(WCHAR) );
  2916. RegCloseKey( TmpKey1 );
  2917. if( rc != ERROR_SUCCESS ) {
  2918. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to set internat.exe key in hive %ws (%d)", HiveName, rc );
  2919. }
  2920. } else {
  2921. SetupDebugPrint1( L"Setup: FixupUserHive - Failed to create MiniSetupTemp\\Software\\Microsoft\\Windows\\CurrentVersion\\Run key (%d)", rc );
  2922. }
  2923. }
  2924. }
  2925. rc = RegUnLoadKey( HKEY_LOCAL_MACHINE,
  2926. L"MiniSetupTemp" );
  2927. if( rc != ERROR_SUCCESS ) {
  2928. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to unload %ws (%d)", HiveName, rc );
  2929. }
  2930. } else {
  2931. SetupDebugPrint2( L"Setup: FixupUserHive - Failed to load %ws (%d)", HiveName, rc );
  2932. }
  2933. }
  2934. } while( FindNextFile( FindHandle, &FileData ) );
  2935. }
  2936. } else {
  2937. SetupDebugPrint( L"Setup: FixupUserHive - Failed to get Profiles path." );
  2938. }
  2939. return rc;
  2940. }
  2941. void LogPidValues()
  2942. {
  2943. LONG rc;
  2944. HKEY hkey = NULL;
  2945. WCHAR RegProductId[MAX_PRODUCT_ID+1];
  2946. BYTE RegDigitalProductId[DIGITALPIDMAXLEN];
  2947. DWORD Size;
  2948. DWORD Type;
  2949. #ifdef PRERELEASE
  2950. ValidateProductIDInReg();
  2951. #endif
  2952. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,WinntSoftwareKeyName,0,KEY_READ,&hkey);
  2953. if (rc == ERROR_SUCCESS)
  2954. {
  2955. *RegProductId = L'\0';
  2956. Size = sizeof(RegProductId);
  2957. rc = RegQueryValueEx(hkey,L"ProductId",NULL,&Type,(PBYTE)RegProductId,&Size);
  2958. if (rc == ERROR_SUCCESS)
  2959. {
  2960. if (*RegProductId == L'\0')
  2961. {
  2962. SetupDebugPrint(L"LogPidValues: ProductId20FromProductId30 is empty\n");
  2963. }
  2964. else
  2965. {
  2966. SetupDebugPrint(L"LogPidValues: ProductId20FromProductId30 is NOT empty\n");
  2967. }
  2968. }
  2969. else
  2970. {
  2971. SetupDebugPrint1(L"LogPidValues: RegQueryValueEx on ProductId failed. Error code:%d\n",rc);
  2972. }
  2973. *RegDigitalProductId = 0;
  2974. Size = sizeof(RegDigitalProductId);
  2975. rc = RegQueryValueEx(hkey,L"DigitalProductId",NULL,&Type,(PBYTE)RegDigitalProductId,&Size);
  2976. if (rc == ERROR_SUCCESS)
  2977. {
  2978. if (*RegDigitalProductId == 0)
  2979. {
  2980. SetupDebugPrint(L"LogPidValues: DigitalProductId is empty\n");
  2981. }
  2982. else
  2983. {
  2984. SetupDebugPrint(L"LogPidValues: DigitalProductId is NOT empty\n");
  2985. }
  2986. }
  2987. else
  2988. {
  2989. SetupDebugPrint1(L"LogPidValues: RegQueryValueEx on DigitalProductId failed. Error code:%d\n",rc);
  2990. }
  2991. RegCloseKey(hkey);
  2992. }
  2993. else
  2994. {
  2995. SetupDebugPrint1(L"LogPidValues: RegOpenKeyEx on %1 failed\n",WindowsCurrentVersionKeyName);
  2996. }
  2997. }