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.

2669 lines
59 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. win95reg.c
  5. Abstract:
  6. Implements Win95-registry access functions callable from Win95 or WinNT.
  7. Author:
  8. MCondra, 16 Oct 1996
  9. Revision History:
  10. jimschm 11-Feb-1999 Rewrite of portions because of DBCS bugs
  11. and static array problems
  12. calinn 29-Jan-1998 Added Win95RegOpenKeyStr function
  13. --*/
  14. #include "pch.h"
  15. #define DBG_WIN95REG "Win95Reg"
  16. #ifdef UNICODE
  17. #error "UNICODE builds not supported"
  18. #endif
  19. //
  20. // Undefine tracking macros
  21. //
  22. #ifdef DEBUG
  23. #undef Win95RegOpenKeyExA
  24. #undef Win95RegOpenKeyExW
  25. #undef Win95RegCloseKey
  26. #endif
  27. //
  28. // Define globals for Win95 registry wrappers
  29. //
  30. #define DEFMAC(fn,name) P##fn Win95##name;
  31. REGWRAPPERS
  32. #undef DEFMAC
  33. #ifdef RegOpenKeyA
  34. #undef RegOpenKeyA
  35. #undef RegOpenKeyW
  36. #undef RegOpenKeyExA
  37. #undef RegOpenKeyExW
  38. #endif
  39. //
  40. // Declare VMM W versions
  41. //
  42. REG_ENUM_KEY_W pVmmRegEnumKeyW;
  43. REG_ENUM_KEY_EX_A pVmmRegEnumKeyExA;
  44. REG_ENUM_KEY_EX_W pVmmRegEnumKeyExW;
  45. REG_ENUM_VALUE_W pVmmRegEnumValueW;
  46. REG_LOAD_KEY_W pVmmRegLoadKeyW;
  47. REG_UNLOAD_KEY_W pVmmRegUnLoadKeyW;
  48. REG_OPEN_KEY_W pVmmRegOpenKeyW;
  49. REG_CLOSE_KEY pVmmRegCloseKey;
  50. REG_OPEN_KEY_EX_A pVmmRegOpenKeyExA;
  51. REG_OPEN_KEY_EX_W pVmmRegOpenKeyExW;
  52. REG_QUERY_INFO_KEY_W pVmmRegQueryInfoKeyW;
  53. REG_QUERY_VALUE_W pVmmRegQueryValueW;
  54. REG_QUERY_VALUE_EX_W pVmmRegQueryValueExW;
  55. VOID
  56. pCleanupTempUser (
  57. VOID
  58. );
  59. BOOL
  60. pIsCurrentUser (
  61. IN PCSTR UserNameAnsi
  62. );
  63. LONG
  64. pWin95RegSetCurrentUserCommonW (
  65. IN OUT PUSERPOSITION Pos,
  66. IN PCWSTR SystemHiveDir, OPTIONAL
  67. OUT PWSTR UserDatOut, OPTIONAL
  68. IN PCWSTR UserDat OPTIONAL
  69. );
  70. LONG
  71. pWin95RegSetCurrentUserCommonA (
  72. IN OUT PUSERPOSITION Pos,
  73. IN PCSTR SystemHiveDir, OPTIONAL
  74. OUT PSTR UserDatOut, OPTIONAL
  75. IN PCSTR UserDat OPTIONAL
  76. );
  77. LONG
  78. pReplaceWinDirInPath (
  79. IN PSTR ProfilePathMunged,
  80. IN PCSTR ProfilePath,
  81. IN PCSTR NewWinDir
  82. );
  83. DWORD
  84. pSetDefaultUserHelper (
  85. IN OUT PUSERPOSITION Pos,
  86. IN PCSTR SystemHiveDir, OPTIONAL
  87. IN PCSTR UserDatFromCaller, OPTIONAL
  88. OUT PSTR UserDatToCaller OPTIONAL
  89. );
  90. BOOL g_IsNt;
  91. CHAR g_SystemHiveDir[MAX_MBCHAR_PATH];
  92. CHAR g_SystemUserHive[MAX_MBCHAR_PATH];
  93. BOOL g_UnloadLastUser = FALSE;
  94. PCSTR g_UserKey;
  95. BOOL g_UseClassesRootHive = FALSE;
  96. HKEY g_ClassesRootKey = NULL;
  97. //
  98. // Wrappers of tracking API
  99. //
  100. LONG
  101. pOurRegOpenKeyExA (
  102. HKEY Key,
  103. PCSTR SubKey,
  104. DWORD Unused,
  105. REGSAM SamMask,
  106. PHKEY ResultPtr
  107. )
  108. {
  109. return TrackedRegOpenKeyExA (Key, SubKey, Unused, SamMask, ResultPtr);
  110. }
  111. LONG
  112. pOurRegOpenKeyA (
  113. HKEY Key,
  114. PCSTR SubKey,
  115. PHKEY Result
  116. )
  117. {
  118. return TrackedRegOpenKeyA (Key, SubKey, Result);
  119. }
  120. LONG
  121. WINAPI
  122. pOurCloseRegKey (
  123. HKEY Key
  124. )
  125. {
  126. return CloseRegKey (Key);
  127. }
  128. //
  129. // Platform-dependent functions
  130. //
  131. VOID
  132. InitWin95RegFnPointers (
  133. VOID
  134. )
  135. {
  136. OSVERSIONINFO vi;
  137. vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  138. GetVersionEx(&vi);
  139. g_IsNt = (vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
  140. if (g_IsNt) {
  141. //
  142. // Attach to VMM registry library
  143. //
  144. VMMRegLibAttach(0);
  145. //
  146. // Initialize global function pointers for NT
  147. //
  148. Win95RegFlushKey = VMMRegFlushKey;
  149. Win95RegEnumKeyA = VMMRegEnumKey;
  150. Win95RegEnumKeyW = pVmmRegEnumKeyW;
  151. Win95RegEnumKeyExA = pVmmRegEnumKeyExA;
  152. Win95RegEnumKeyExW = pVmmRegEnumKeyExW;
  153. Win95RegEnumValueA = VMMRegEnumValue;
  154. Win95RegEnumValueW = pVmmRegEnumValueW;
  155. Win95RegLoadKeyA = VMMRegLoadKey;
  156. Win95RegLoadKeyW = pVmmRegLoadKeyW;
  157. Win95RegUnLoadKeyA = VMMRegUnLoadKey;
  158. Win95RegUnLoadKeyW = pVmmRegUnLoadKeyW;
  159. Win95RegOpenKeyA = VMMRegOpenKey;
  160. Win95RegOpenKeyW = pVmmRegOpenKeyW;
  161. Win95RegOpenKeyExA = pVmmRegOpenKeyExA;
  162. Win95RegOpenKeyExW = pVmmRegOpenKeyExW;
  163. Win95RegCloseKey = pVmmRegCloseKey;
  164. Win95RegQueryInfoKeyA = VMMRegQueryInfoKey;
  165. Win95RegQueryInfoKeyW = pVmmRegQueryInfoKeyW;
  166. Win95RegQueryValueA = (PREG_QUERY_VALUE_A)VMMRegQueryValue;
  167. Win95RegQueryValueW = pVmmRegQueryValueW;
  168. Win95RegQueryValueExA = VMMRegQueryValueEx;
  169. Win95RegQueryValueExW = pVmmRegQueryValueExW;
  170. } else {
  171. //
  172. // Initialize global function pointers for NT
  173. //
  174. Win95RegFlushKey = RegFlushKey;
  175. Win95RegEnumKeyA = RegEnumKeyA;
  176. Win95RegEnumKeyW = RegEnumKeyW;
  177. Win95RegEnumKeyExA = RegEnumKeyExA;
  178. Win95RegEnumKeyExW = RegEnumKeyExW;
  179. Win95RegEnumValueA = RegEnumValueA;
  180. Win95RegEnumValueW = RegEnumValueW;
  181. Win95RegLoadKeyA = RegLoadKeyA;
  182. Win95RegLoadKeyW = RegLoadKeyW;
  183. Win95RegUnLoadKeyA = RegUnLoadKeyA;
  184. Win95RegUnLoadKeyW = RegUnLoadKeyW;
  185. Win95RegOpenKeyA = pOurRegOpenKeyA;
  186. Win95RegOpenKeyW = RegOpenKeyW;
  187. Win95RegOpenKeyExA = pOurRegOpenKeyExA;
  188. Win95RegOpenKeyExW = RegOpenKeyExW;
  189. Win95RegCloseKey = pOurCloseRegKey;
  190. Win95RegQueryInfoKeyA = RegQueryInfoKeyA;
  191. Win95RegQueryInfoKeyW = RegQueryInfoKeyW;
  192. Win95RegQueryValueA = RegQueryValueA;
  193. Win95RegQueryValueW = RegQueryValueW;
  194. Win95RegQueryValueExA = RegQueryValueExA;
  195. Win95RegQueryValueExW = RegQueryValueExW;
  196. //
  197. // Clear away HKLM\Migration
  198. //
  199. RegUnLoadKey(
  200. HKEY_LOCAL_MACHINE,
  201. S_MIGRATION
  202. );
  203. pSetupRegistryDelnode (
  204. HKEY_LOCAL_MACHINE,
  205. S_MIGRATION
  206. );
  207. }
  208. }
  209. VOID
  210. Win95RegTerminate (
  211. VOID
  212. )
  213. {
  214. #ifdef DEBUG
  215. DumpOpenKeys95();
  216. RegTrackTerminate95();
  217. #endif
  218. if (!g_IsNt) {
  219. pCleanupTempUser();
  220. } else {
  221. VMMRegLibDetach();
  222. }
  223. }
  224. BOOL
  225. WINAPI
  226. Win95Reg_Entry (
  227. HINSTANCE hInstance,
  228. DWORD dwReason,
  229. LPVOID lpReserved
  230. )
  231. {
  232. if (dwReason == DLL_PROCESS_ATTACH) {
  233. if(!pSetupInitializeUtils()) {
  234. return FALSE;
  235. }
  236. InitWin95RegFnPointers();
  237. } else if (dwReason == DLL_PROCESS_DETACH) {
  238. Win95RegTerminate();
  239. pSetupUninitializeUtils();
  240. }
  241. return TRUE;
  242. }
  243. LONG
  244. pVmmRegEnumKeyW (
  245. IN HKEY Key,
  246. IN DWORD Index,
  247. OUT PWSTR KeyName,
  248. IN DWORD KeyNameSize
  249. )
  250. {
  251. PSTR AnsiBuf;
  252. LONG rc;
  253. UINT Chars;
  254. AnsiBuf = AllocTextA (KeyNameSize);
  255. MYASSERT (AnsiBuf);
  256. rc = VMMRegEnumKey (Key, Index, AnsiBuf, KeyNameSize);
  257. if (rc == ERROR_SUCCESS) {
  258. Chars = CharCountA (AnsiBuf);
  259. //
  260. // Special case: if Chars is zero, then we have 1/2 of a DBCS char.
  261. //
  262. if (!Chars && *AnsiBuf) {
  263. if (KeyNameSize < 4) {
  264. rc = ERROR_MORE_DATA;
  265. }
  266. KeyName[0] = *AnsiBuf;
  267. KeyName[1] = 0;
  268. } else {
  269. //
  270. // Normal case
  271. //
  272. if (Chars >= KeyNameSize / sizeof (WCHAR)) {
  273. rc = ERROR_MORE_DATA;
  274. } else {
  275. KnownSizeDbcsToUnicodeN (KeyName, AnsiBuf, Chars);
  276. }
  277. }
  278. }
  279. FreeTextA (AnsiBuf);
  280. return rc;
  281. }
  282. LONG
  283. pVmmRegEnumValueW (
  284. IN HKEY Key,
  285. IN DWORD Index,
  286. OUT PWSTR ValueName,
  287. IN OUT PDWORD ValueNameChars,
  288. PDWORD Reserved,
  289. OUT PDWORD Type, OPTIONAL
  290. OUT PBYTE Data, OPTIONAL
  291. IN OUT PDWORD DataSize OPTIONAL
  292. )
  293. {
  294. PSTR AnsiValueName;
  295. LONG rc;
  296. PSTR AnsiData;
  297. UINT DataChars;
  298. UINT ValueChars;
  299. DWORD OurType;
  300. DWORD OrgValueNameChars;
  301. DWORD OrgDataSize;
  302. DWORD OurValueNameChars;
  303. DWORD OurValueNameCharsBackup;
  304. DWORD AnsiDataSize;
  305. BOOL HalfDbcs = FALSE;
  306. __try {
  307. MYASSERT (ValueNameChars);
  308. MYASSERT (ValueName);
  309. OrgValueNameChars = *ValueNameChars;
  310. OrgDataSize = DataSize ? *DataSize : 0;
  311. OurValueNameChars = min (*ValueNameChars, MAX_REGISTRY_VALUE_NAMEA);
  312. OurValueNameCharsBackup = OurValueNameChars;
  313. AnsiValueName = AllocTextA (OurValueNameChars);
  314. MYASSERT (AnsiValueName);
  315. AnsiData = NULL;
  316. if (Data) {
  317. MYASSERT (DataSize);
  318. AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
  319. } else if (DataSize) {
  320. //
  321. // Data is not specified; allocate a buffer for the
  322. // proper calculation of DataSize.
  323. //
  324. rc = VMMRegEnumValue (
  325. Key,
  326. Index,
  327. AnsiValueName,
  328. &OurValueNameChars,
  329. NULL,
  330. &OurType,
  331. NULL,
  332. DataSize
  333. );
  334. OurValueNameChars = OurValueNameCharsBackup;
  335. if (rc == ERROR_SUCCESS) {
  336. if (OurType == REG_SZ || OurType == REG_EXPAND_SZ || OurType == REG_MULTI_SZ) {
  337. *DataSize += 2;
  338. AnsiData = AllocTextA (*DataSize);
  339. }
  340. } else {
  341. //
  342. // Value name must be too small
  343. //
  344. __leave;
  345. }
  346. }
  347. rc = VMMRegEnumValue (
  348. Key,
  349. Index,
  350. AnsiValueName,
  351. &OurValueNameChars,
  352. NULL,
  353. &OurType,
  354. AnsiData,
  355. DataSize
  356. );
  357. if (DataSize) {
  358. AnsiDataSize = *DataSize;
  359. } else {
  360. AnsiDataSize = 0;
  361. }
  362. //
  363. // Return the type
  364. //
  365. if (Type) {
  366. *Type = OurType;
  367. }
  368. //
  369. // Return the sizes
  370. //
  371. if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) {
  372. //
  373. // The inbound value name size is in characters, including the nul.
  374. // The outbound value name size is also in characteres, excluding
  375. // the nul.
  376. //
  377. ValueChars = CharCountA (AnsiValueName);
  378. //
  379. // Special case: if ValueChars is zero, and AnsiValueName is
  380. // not empty, then we have half of a DBCS character.
  381. //
  382. if (!ValueChars && *AnsiValueName) {
  383. ValueChars = 1;
  384. HalfDbcs = TRUE;
  385. }
  386. *ValueNameChars = ValueChars;
  387. }
  388. if (DataSize) {
  389. if (rc == ERROR_SUCCESS) {
  390. //
  391. // The inbound data size is in bytes, including any nuls that apply.
  392. // The outbound data size is the same.
  393. //
  394. if (AnsiData) {
  395. MYASSERT (Data ||
  396. OurType == REG_SZ ||
  397. OurType == REG_EXPAND_SZ ||
  398. OurType == REG_MULTI_SZ
  399. );
  400. //
  401. // If the type is a string, then DataSize needs adjustment.
  402. //
  403. if (OurType == REG_SZ || OurType == REG_EXPAND_SZ || OurType == REG_MULTI_SZ) {
  404. DataChars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
  405. *DataSize = DataChars * sizeof (WCHAR);
  406. }
  407. }
  408. if (Data && *DataSize > OrgDataSize) {
  409. rc = ERROR_MORE_DATA;
  410. }
  411. } else if (rc == ERROR_MORE_DATA) {
  412. //
  413. // Get the correct DataSize value
  414. //
  415. pVmmRegEnumValueW (
  416. Key,
  417. Index,
  418. ValueName,
  419. ValueNameChars,
  420. NULL,
  421. NULL,
  422. NULL,
  423. DataSize
  424. );
  425. __leave;
  426. }
  427. }
  428. //
  429. // Convert the outbound strings
  430. //
  431. if (rc == ERROR_SUCCESS) {
  432. //
  433. // Convert value name
  434. //
  435. if (ValueChars >= OrgValueNameChars) {
  436. rc = ERROR_MORE_DATA;
  437. } else {
  438. if (!HalfDbcs) {
  439. KnownSizeDbcsToUnicodeN (ValueName, AnsiValueName, ValueChars);
  440. } else {
  441. ValueName[0] = *AnsiValueName;
  442. ValueName[1] = 0;
  443. }
  444. }
  445. //
  446. // Convert data
  447. //
  448. if (Data) {
  449. MYASSERT (AnsiData);
  450. if (OurType == REG_SZ ||
  451. OurType == REG_EXPAND_SZ ||
  452. OurType == REG_MULTI_SZ
  453. ) {
  454. DirectDbcsToUnicodeN (
  455. (PWSTR) Data,
  456. AnsiData,
  457. AnsiDataSize
  458. );
  459. } else {
  460. CopyMemory (Data, AnsiData, AnsiDataSize);
  461. }
  462. }
  463. }
  464. }
  465. __finally {
  466. FreeTextA (AnsiValueName);
  467. FreeTextA (AnsiData);
  468. }
  469. return rc;
  470. }
  471. LONG
  472. pVmmRegLoadKeyW (
  473. IN HKEY Key,
  474. IN PCWSTR SubKey,
  475. IN PCWSTR FileName
  476. )
  477. {
  478. PCSTR AnsiSubKey;
  479. PCSTR AnsiFileName;
  480. LONG rc;
  481. AnsiSubKey = ConvertWtoA (SubKey);
  482. AnsiFileName = ConvertWtoA (FileName);
  483. rc = VMMRegLoadKey (Key, AnsiSubKey, AnsiFileName);
  484. FreeConvertedStr (AnsiSubKey);
  485. FreeConvertedStr (AnsiFileName);
  486. return rc;
  487. }
  488. LONG
  489. pVmmRegUnLoadKeyW (
  490. IN HKEY Key,
  491. IN PCWSTR SubKey
  492. )
  493. {
  494. PCSTR AnsiSubKey;
  495. LONG rc;
  496. AnsiSubKey = ConvertWtoA (SubKey);
  497. rc = VMMRegUnLoadKey (Key, AnsiSubKey);
  498. FreeConvertedStr (AnsiSubKey);
  499. return rc;
  500. }
  501. LONG
  502. pVmmRegOpenKeyW (
  503. IN HKEY Key,
  504. IN PCWSTR SubKey,
  505. OUT HKEY *KeyPtr
  506. )
  507. {
  508. PCSTR AnsiSubKey;
  509. LONG rc;
  510. CHAR mappedSubKey[MAXIMUM_SUB_KEY_LENGTH];
  511. PCSTR MappedAnsiSubKey;
  512. MappedAnsiSubKey = AnsiSubKey = ConvertWtoA (SubKey);
  513. //
  514. // if g_UseClassesRootHive is set, then perform some translations
  515. //
  516. if (g_UseClassesRootHive) {
  517. if (Key == HKEY_LOCAL_MACHINE) {
  518. if (StringIMatchCharCountA (
  519. AnsiSubKey,
  520. "SOFTWARE\\Classes",
  521. sizeof ("SOFTWARE\\Classes") - 1
  522. )) {
  523. StringCopyByteCountA (
  524. mappedSubKey,
  525. AnsiSubKey + sizeof ("SOFTWARE\\Classes") - 1,
  526. MAXIMUM_SUB_KEY_LENGTH
  527. );
  528. Key = g_ClassesRootKey;
  529. MappedAnsiSubKey = mappedSubKey;
  530. if (*MappedAnsiSubKey == '\\') {
  531. MappedAnsiSubKey++;
  532. }
  533. }
  534. } else if (Key == HKEY_CLASSES_ROOT) {
  535. Key = g_ClassesRootKey;
  536. }
  537. }
  538. rc = VMMRegOpenKey (Key, MappedAnsiSubKey, KeyPtr);
  539. FreeConvertedStr (AnsiSubKey);
  540. return rc;
  541. }
  542. LONG
  543. pVmmRegCloseKey (
  544. IN HKEY Key
  545. )
  546. {
  547. if (g_UseClassesRootHive) {
  548. if (Key == g_ClassesRootKey) {
  549. return ERROR_SUCCESS;
  550. }
  551. }
  552. return VMMRegCloseKey (Key);
  553. }
  554. LONG
  555. pVmmRegEnumKeyExA (
  556. IN HKEY Key,
  557. IN DWORD Index,
  558. OUT PSTR KeyName,
  559. IN OUT PDWORD KeyNameSize,
  560. PDWORD Reserved,
  561. OUT PSTR Class, OPTIONAL
  562. IN OUT PDWORD ClassSize, OPTIONAL
  563. OUT PFILETIME LastWriteTime OPTIONAL
  564. )
  565. {
  566. LONG rc;
  567. MYASSERT (KeyNameSize);
  568. MYASSERT (KeyName);
  569. rc = VMMRegEnumKey (
  570. Key,
  571. Index,
  572. KeyName,
  573. *KeyNameSize
  574. );
  575. if (rc == ERROR_SUCCESS) {
  576. //
  577. // Return length of key name, excluding delimiter
  578. //
  579. *KeyNameSize = ByteCount (KeyName);
  580. //
  581. // Return zero-length class
  582. //
  583. if (Class && *ClassSize) {
  584. *Class = 0;
  585. }
  586. if (ClassSize) {
  587. *ClassSize = 0;
  588. }
  589. //
  590. // Stuff last-write time with zero
  591. //
  592. if (LastWriteTime) {
  593. ZeroMemory (LastWriteTime, sizeof (FILETIME));
  594. }
  595. } else {
  596. *KeyNameSize = MAX_PATH + 1;
  597. if (ClassSize) {
  598. *ClassSize = 0;
  599. }
  600. }
  601. return rc;
  602. }
  603. LONG
  604. pVmmRegEnumKeyExW (
  605. IN HKEY Key,
  606. IN DWORD Index,
  607. OUT PWSTR KeyName,
  608. IN OUT PDWORD KeyNameSize,
  609. PDWORD Reserved,
  610. OUT PWSTR Class, OPTIONAL
  611. IN OUT PDWORD ClassSize, OPTIONAL
  612. OUT PFILETIME LastWriteTime OPTIONAL
  613. )
  614. {
  615. LONG rc;
  616. PSTR AnsiKeyName;
  617. PSTR AnsiClass;
  618. UINT Chars;
  619. DWORD OrgKeyNameSize;
  620. DWORD OrgClassSize;
  621. BOOL HalfDbcs = FALSE;
  622. __try {
  623. MYASSERT (KeyName);
  624. MYASSERT (KeyNameSize);
  625. AnsiKeyName = AllocTextA (*KeyNameSize);
  626. if (Class) {
  627. MYASSERT (ClassSize);
  628. AnsiClass = AllocTextA (*ClassSize);
  629. } else {
  630. AnsiClass = NULL;
  631. }
  632. OrgKeyNameSize = *KeyNameSize;
  633. OrgClassSize = ClassSize ? *ClassSize : 0;
  634. rc = pVmmRegEnumKeyExA (
  635. Key,
  636. Index,
  637. AnsiKeyName,
  638. KeyNameSize,
  639. NULL,
  640. AnsiClass,
  641. ClassSize,
  642. LastWriteTime
  643. );
  644. if (rc == ERROR_SUCCESS) {
  645. Chars = CharCountA (AnsiKeyName);
  646. //
  647. // Special case: If Chars is zero, but AnsiKeyName is not empty,
  648. // then we have 1/2 of a DBCS character.
  649. //
  650. if (!Chars && *AnsiKeyName) {
  651. Chars = 1;
  652. HalfDbcs = TRUE;
  653. }
  654. *KeyNameSize = Chars;
  655. if (Chars >= OrgKeyNameSize / sizeof (WCHAR)) {
  656. rc = ERROR_MORE_DATA;
  657. __leave;
  658. }
  659. if (!HalfDbcs) {
  660. KnownSizeDbcsToUnicodeN (KeyName, AnsiKeyName, Chars);
  661. } else {
  662. KeyName[0] = *AnsiKeyName;
  663. KeyName[1] = 0;
  664. }
  665. HalfDbcs = FALSE;
  666. if (Class) {
  667. Chars = CharCountA (AnsiClass);
  668. //
  669. // Special case: If Chars is zero, but AnsiClass is not empty,
  670. // then we have 1/2 of a DBCS character.
  671. //
  672. if (!Chars && *AnsiClass) {
  673. Chars = 1;
  674. HalfDbcs = TRUE;
  675. }
  676. *ClassSize = Chars;
  677. if (Chars >= OrgClassSize / sizeof (WCHAR)) {
  678. rc = ERROR_MORE_DATA;
  679. __leave;
  680. }
  681. if (!HalfDbcs) {
  682. KnownSizeDbcsToUnicodeN (Class, AnsiClass, Chars);
  683. } else {
  684. Class[0] = *AnsiClass;
  685. Class[1] = 0;
  686. }
  687. }
  688. }
  689. }
  690. __finally {
  691. FreeTextA (AnsiKeyName);
  692. FreeTextA (AnsiClass);
  693. }
  694. return rc;
  695. }
  696. LONG
  697. pVmmRegOpenKeyExA (
  698. IN HKEY Key,
  699. IN PCSTR SubKey,
  700. IN DWORD Options,
  701. IN REGSAM SamDesired,
  702. OUT HKEY *KeyPtr
  703. )
  704. {
  705. CHAR mappedSubKey[MAXIMUM_SUB_KEY_LENGTH];
  706. PCSTR MappedSubKey = SubKey;
  707. //
  708. // if g_UseClassesRootHive is set, then perform some translations
  709. //
  710. if (g_UseClassesRootHive) {
  711. if (Key == HKEY_LOCAL_MACHINE) {
  712. if (StringIMatchByteCountA (
  713. SubKey,
  714. "SOFTWARE\\Classes",
  715. sizeof ("SOFTWARE\\Classes") - 1
  716. )) {
  717. StringCopyByteCountA (
  718. mappedSubKey,
  719. SubKey + sizeof ("SOFTWARE\\Classes") - 1,
  720. MAXIMUM_SUB_KEY_LENGTH
  721. );
  722. Key = g_ClassesRootKey;
  723. MappedSubKey = mappedSubKey;
  724. if (*MappedSubKey == '\\') {
  725. MappedSubKey++;
  726. }
  727. }
  728. } else if (Key == HKEY_CLASSES_ROOT) {
  729. Key = g_ClassesRootKey;
  730. }
  731. }
  732. return VMMRegOpenKey (Key, MappedSubKey, KeyPtr);
  733. }
  734. LONG
  735. pVmmRegOpenKeyExW (
  736. IN HKEY Key,
  737. IN PCWSTR SubKey,
  738. IN DWORD Options,
  739. IN REGSAM SamDesired,
  740. OUT HKEY *KeyPtr
  741. )
  742. {
  743. return pVmmRegOpenKeyW (Key, SubKey, KeyPtr);
  744. }
  745. LONG
  746. pVmmRegQueryInfoKeyW (
  747. IN HKEY Key,
  748. OUT PWSTR Class, OPTIONAL
  749. OUT PDWORD ClassSize, OPTIONAL
  750. OUT PDWORD Reserved, OPTIONAL
  751. OUT PDWORD SubKeys, OPTIONAL
  752. OUT PDWORD MaxSubKeyLen, OPTIONAL
  753. OUT PDWORD MaxClassLen, OPTIONAL
  754. OUT PDWORD Values, OPTIONAL
  755. OUT PDWORD MaxValueName, OPTIONAL
  756. OUT PDWORD MaxValueData, OPTIONAL
  757. OUT PVOID SecurityDescriptor, OPTIONAL
  758. OUT PVOID LastWriteTime OPTIONAL
  759. )
  760. {
  761. PSTR AnsiClass;
  762. LONG rc = ERROR_NOACCESS;
  763. UINT Chars;
  764. DWORD OrgClassSize;
  765. BOOL HalfDbcs = FALSE;
  766. __try {
  767. if (Class) {
  768. MYASSERT (ClassSize);
  769. AnsiClass = AllocTextA (*ClassSize);
  770. if (!AnsiClass) {
  771. __leave;
  772. }
  773. } else {
  774. AnsiClass = NULL;
  775. }
  776. OrgClassSize = ClassSize ? *ClassSize : 0;
  777. rc = VMMRegQueryInfoKey (
  778. Key,
  779. AnsiClass,
  780. ClassSize,
  781. Reserved,
  782. SubKeys,
  783. MaxSubKeyLen,
  784. MaxClassLen,
  785. Values,
  786. MaxValueName,
  787. MaxValueData,
  788. SecurityDescriptor,
  789. LastWriteTime
  790. );
  791. if (MaxValueData) {
  792. *MaxValueData *= 2;
  793. }
  794. if (rc == ERROR_SUCCESS) {
  795. if (Class) {
  796. Chars = CharCountA (AnsiClass);
  797. //
  798. // Special case: If Chars is zero, but AnsiClass is not empty,
  799. // then we have 1/2 of a DBCS character.
  800. //
  801. if (!Chars && *AnsiClass) {
  802. Chars = 1;
  803. HalfDbcs = TRUE;
  804. }
  805. *ClassSize = Chars;
  806. if (Chars >= OrgClassSize / sizeof (WCHAR)) {
  807. rc = ERROR_MORE_DATA;
  808. __leave;
  809. }
  810. if (!HalfDbcs) {
  811. KnownSizeDbcsToUnicodeN (Class, AnsiClass, Chars);
  812. } else {
  813. Class[0] = *AnsiClass;
  814. Class[1] = 0;
  815. }
  816. }
  817. }
  818. }
  819. __finally {
  820. FreeTextA (AnsiClass);
  821. }
  822. return rc;
  823. }
  824. LONG
  825. pVmmRegQueryValueW (
  826. IN HKEY Key,
  827. IN PCWSTR SubKey,
  828. OUT PWSTR Data, OPTIONAL
  829. IN OUT PLONG DataSize OPTIONAL
  830. )
  831. {
  832. PSTR AnsiData;
  833. PCSTR AnsiSubKey;
  834. LONG rc;
  835. UINT Chars;
  836. LONG OrgDataSize;
  837. DWORD AnsiDataSize;
  838. __try {
  839. AnsiSubKey = ConvertWtoA (SubKey);
  840. OrgDataSize = DataSize ? *DataSize : 0;
  841. AnsiData = NULL;
  842. if (Data) {
  843. MYASSERT (DataSize);
  844. AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
  845. } else if (DataSize) {
  846. //
  847. // Data is not specified; allocate a buffer for the
  848. // proper computation of DataSize.
  849. //
  850. rc = VMMRegQueryValue (
  851. Key,
  852. AnsiSubKey,
  853. NULL,
  854. DataSize
  855. );
  856. if (rc == ERROR_SUCCESS) {
  857. *DataSize += 2;
  858. AnsiData = AllocTextA (*DataSize);
  859. } else {
  860. //
  861. // An error usually means the sub key does not exist...
  862. //
  863. __leave;
  864. }
  865. }
  866. rc = VMMRegQueryValue (Key, AnsiSubKey, AnsiData, DataSize);
  867. if (DataSize) {
  868. AnsiDataSize = *DataSize;
  869. } else {
  870. AnsiDataSize = 0;
  871. }
  872. //
  873. // Adjust the outbound size
  874. //
  875. if (DataSize) {
  876. if (rc == ERROR_SUCCESS) {
  877. Chars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
  878. MYASSERT (DataSize);
  879. *DataSize = (Chars + 1) * sizeof (WCHAR);
  880. if (Data && *DataSize > OrgDataSize) {
  881. rc = ERROR_MORE_DATA;
  882. }
  883. } else if (rc == ERROR_MORE_DATA) {
  884. pVmmRegQueryValueW (Key, SubKey, NULL, DataSize);
  885. __leave;
  886. }
  887. }
  888. //
  889. // Convert the return strings
  890. //
  891. if (rc == ERROR_SUCCESS) {
  892. MYASSERT (AnsiData);
  893. if (Data) {
  894. DirectDbcsToUnicodeN ((PWSTR) Data, AnsiData, AnsiDataSize);
  895. } else {
  896. CopyMemory (Data, AnsiData, AnsiDataSize);
  897. }
  898. }
  899. }
  900. __finally {
  901. FreeTextA (AnsiData);
  902. FreeConvertedStr (AnsiSubKey);
  903. }
  904. return rc;
  905. }
  906. LONG
  907. pVmmRegQueryValueExW (
  908. IN HKEY Key,
  909. IN PCWSTR ValueName,
  910. PDWORD Reserved,
  911. OUT PDWORD Type, OPTIONAL
  912. OUT PBYTE Data, OPTIONAL
  913. IN OUT PDWORD DataSize OPTIONAL
  914. )
  915. {
  916. LONG rc;
  917. UINT Chars;
  918. PCSTR AnsiValueName;
  919. PSTR AnsiData;
  920. DWORD OurType;
  921. DWORD OrgDataSize;
  922. DWORD AnsiDataSize;
  923. __try {
  924. AnsiValueName = ConvertWtoA (ValueName);
  925. OrgDataSize = DataSize ? *DataSize : 0;
  926. AnsiData = NULL;
  927. if (Data) {
  928. MYASSERT (DataSize);
  929. AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
  930. } else if (DataSize) {
  931. //
  932. // Data is not specified; allocate a buffer for the
  933. // proper computation of DataSize.
  934. //
  935. rc = VMMRegQueryValueEx (
  936. Key,
  937. AnsiValueName,
  938. NULL,
  939. &OurType,
  940. NULL,
  941. DataSize
  942. );
  943. if (rc == ERROR_SUCCESS) {
  944. //
  945. // *DataSize is a byte count, but increase it to
  946. // accomodate multisz termination
  947. //
  948. *DataSize += 2;
  949. AnsiData = AllocTextA (*DataSize);
  950. } else {
  951. //
  952. // An error usually means the value does not exist...
  953. //
  954. __leave;
  955. }
  956. }
  957. rc = VMMRegQueryValueEx (
  958. Key,
  959. AnsiValueName,
  960. NULL,
  961. &OurType,
  962. AnsiData,
  963. DataSize
  964. );
  965. if (DataSize) {
  966. AnsiDataSize = *DataSize;
  967. } else {
  968. AnsiDataSize = 0;
  969. }
  970. //
  971. // Return the type
  972. //
  973. if (Type) {
  974. *Type = OurType;
  975. }
  976. //
  977. // Return the sizes
  978. //
  979. if (DataSize) {
  980. if (rc == ERROR_SUCCESS) {
  981. if (OurType == REG_SZ ||
  982. OurType == REG_EXPAND_SZ ||
  983. OurType == REG_MULTI_SZ
  984. ) {
  985. AnsiData[*DataSize] = 0;
  986. AnsiData[*DataSize + 1] = 0;
  987. Chars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
  988. *DataSize = Chars * sizeof (WCHAR);
  989. }
  990. if (Data && *DataSize > OrgDataSize) {
  991. rc = ERROR_MORE_DATA;
  992. }
  993. } else if (rc == ERROR_MORE_DATA) {
  994. //
  995. // Get the correct data size
  996. //
  997. pVmmRegQueryValueExW (
  998. Key,
  999. ValueName,
  1000. NULL,
  1001. NULL,
  1002. NULL,
  1003. DataSize
  1004. );
  1005. __leave;
  1006. }
  1007. }
  1008. //
  1009. // Convert the return strings
  1010. //
  1011. if (rc == ERROR_SUCCESS) {
  1012. if (Data) {
  1013. MYASSERT (AnsiData);
  1014. if (OurType == REG_SZ ||
  1015. OurType == REG_EXPAND_SZ ||
  1016. OurType == REG_MULTI_SZ
  1017. ) {
  1018. DirectDbcsToUnicodeN ((PWSTR) Data, AnsiData, AnsiDataSize);
  1019. } else {
  1020. CopyMemory (Data, AnsiData, AnsiDataSize);
  1021. }
  1022. }
  1023. }
  1024. }
  1025. __finally {
  1026. FreeConvertedStr (AnsiValueName);
  1027. FreeTextA (AnsiData);
  1028. }
  1029. return rc;
  1030. }
  1031. LONG
  1032. Win95RegInitA (
  1033. IN PCSTR SystemHiveDir,
  1034. IN BOOL UseClassesRootHive
  1035. )
  1036. {
  1037. LONG rc = ERROR_SUCCESS;
  1038. CHAR SystemDatPath[MAX_MBCHAR_PATH];
  1039. CHAR ConfigKey[MAX_REGISTRY_KEY];
  1040. CHAR ConfigVersion[256];
  1041. HKEY Key;
  1042. DWORD Size;
  1043. //
  1044. // Save the system hive dir
  1045. //
  1046. StringCopyA (g_SystemHiveDir, SystemHiveDir);
  1047. AppendWackA (g_SystemHiveDir);
  1048. //
  1049. // Save the system user.dat
  1050. //
  1051. StringCopyA (g_SystemUserHive, g_SystemHiveDir);
  1052. StringCatA (g_SystemUserHive, "user.dat");
  1053. //
  1054. // If NT, set up HKLM and HKU
  1055. //
  1056. if (g_IsNt) {
  1057. __try {
  1058. Key = NULL;
  1059. StringCopyA (SystemDatPath, g_SystemHiveDir);
  1060. StringCatA (SystemDatPath, "system.dat");
  1061. rc = VMMRegMapPredefKeyToFile (HKEY_LOCAL_MACHINE, SystemDatPath, 0);
  1062. if (rc != ERROR_SUCCESS) {
  1063. LOGA ((LOG_ERROR, "%s could not be loaded", SystemDatPath));
  1064. __leave;
  1065. }
  1066. if (UseClassesRootHive) {
  1067. StringCopyA (SystemDatPath, g_SystemHiveDir);
  1068. StringCatA (SystemDatPath, "classes.dat");
  1069. rc = VMMRegLoadKey (
  1070. HKEY_LOCAL_MACHINE,
  1071. "SOFTWARE$Classes",
  1072. SystemDatPath
  1073. );
  1074. if (rc != ERROR_SUCCESS) {
  1075. LOGA ((LOG_ERROR, "%s could not be loaded", SystemDatPath));
  1076. __leave;
  1077. }
  1078. rc = VMMRegOpenKey (
  1079. HKEY_LOCAL_MACHINE,
  1080. "SOFTWARE$Classes",
  1081. &g_ClassesRootKey
  1082. );
  1083. if (rc != ERROR_SUCCESS) {
  1084. LOGA ((LOG_ERROR, "%s could not be opened", "SOFTWARE$Classes"));
  1085. __leave;
  1086. }
  1087. g_UseClassesRootHive = TRUE;
  1088. }
  1089. rc = VMMRegMapPredefKeyToFile (HKEY_USERS, g_SystemUserHive, 0);
  1090. if (rc != ERROR_SUCCESS) {
  1091. LOGA ((LOG_ERROR, "%s could not be loaded", g_SystemUserHive));
  1092. __leave;
  1093. }
  1094. rc = Win95RegOpenKeyA (
  1095. HKEY_LOCAL_MACHINE,
  1096. "System\\CurrentControlSet\\control\\IDConfigDB",
  1097. &Key
  1098. );
  1099. if (rc != ERROR_SUCCESS) {
  1100. LOGA ((LOG_ERROR, "IDConfigDB could not be opened"));
  1101. __leave;
  1102. }
  1103. Size = sizeof (ConfigVersion);
  1104. rc = Win95RegQueryValueExA (
  1105. Key,
  1106. "CurrentConfig",
  1107. NULL,
  1108. NULL,
  1109. (PBYTE) ConfigVersion,
  1110. &Size
  1111. );
  1112. if (rc != ERROR_SUCCESS) {
  1113. LOGA ((LOG_ERROR, "CurrentConfig could not be queried"));
  1114. __leave;
  1115. }
  1116. StringCopyA (ConfigKey, "Config\\");
  1117. StringCatA (ConfigKey, ConfigVersion);
  1118. Win95RegCloseKey (Key);
  1119. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, ConfigKey, &Key);
  1120. if (rc != ERROR_SUCCESS) {
  1121. LOGA ((LOG_ERROR, "%s could not be opened", ConfigKey));
  1122. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, "Config", &Key);
  1123. if (rc != ERROR_SUCCESS) {
  1124. LOGA ((LOG_ERROR, "No Win9x hardware configuration keys available"));
  1125. Key = NULL;
  1126. __leave;
  1127. }
  1128. Size = 256;
  1129. rc = Win95RegEnumKeyExA (
  1130. Key,
  1131. 0,
  1132. ConfigVersion,
  1133. &Size,
  1134. NULL,
  1135. NULL,
  1136. NULL,
  1137. NULL
  1138. );
  1139. Win95RegCloseKey (Key);
  1140. if (rc != ERROR_SUCCESS) {
  1141. LOGA ((LOG_ERROR, "Can't enumerate Win9x hardware configuration keys"));
  1142. Key = NULL;
  1143. __leave;
  1144. }
  1145. StringCopyA (ConfigKey, "Config\\");
  1146. StringCatA (ConfigKey, ConfigVersion);
  1147. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, ConfigKey, &Key);
  1148. if (rc != ERROR_SUCCESS) {
  1149. LOGA ((LOG_ERROR, "Can't open enumerated Win9x hardware configuration key"));
  1150. Key = NULL;
  1151. __leave;
  1152. }
  1153. }
  1154. rc = VMMRegMapPredefKeyToKey (Key, HKEY_CURRENT_CONFIG);
  1155. if (rc != ERROR_SUCCESS) {
  1156. LOGA ((LOG_ERROR, "HKCC could not be mapped"));
  1157. __leave;
  1158. }
  1159. }
  1160. __finally {
  1161. if (Key) {
  1162. Win95RegCloseKey (Key);
  1163. }
  1164. }
  1165. }
  1166. if (rc != ERROR_SUCCESS) {
  1167. LOGA ((LOG_ERROR, "Registry files from previous operating system are damaged or missing"));
  1168. }
  1169. return rc;
  1170. }
  1171. LONG
  1172. Win95RegInitW (
  1173. IN PCWSTR SystemHiveDir,
  1174. IN BOOL UseClassesRootHive
  1175. )
  1176. {
  1177. LONG rc;
  1178. PCSTR AnsiSystemHiveDir;
  1179. AnsiSystemHiveDir = ConvertWtoA (SystemHiveDir);
  1180. //
  1181. // Call ANSI version of function
  1182. //
  1183. rc = Win95RegInitA (AnsiSystemHiveDir, UseClassesRootHive);
  1184. FreeConvertedStr (AnsiSystemHiveDir);
  1185. return rc;
  1186. }
  1187. #define GU_VALID 0x5538
  1188. LONG
  1189. Win95RegGetFirstUserA (
  1190. PUSERPOSITION Pos,
  1191. PSTR UserNameAnsi
  1192. )
  1193. {
  1194. DWORD rc = ERROR_SUCCESS;
  1195. DWORD Size;
  1196. DWORD Enabled;
  1197. HKEY Key;
  1198. MYASSERT (UserNameAnsi);
  1199. MYASSERT (Pos);
  1200. //
  1201. // Initialize profile enumeration state (USERPOSITION)
  1202. //
  1203. ZeroMemory (Pos, sizeof (USERPOSITION));
  1204. Pos->Valid = GU_VALID;
  1205. //
  1206. // See whether registry supports per-user profiles.
  1207. //
  1208. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, "Network\\Logon", &Key);
  1209. if (rc == ERROR_SUCCESS) {
  1210. Size = sizeof (DWORD);
  1211. rc = Win95RegQueryValueExA (
  1212. Key,
  1213. "UserProfiles",
  1214. NULL,
  1215. NULL,
  1216. (PBYTE) &Enabled,
  1217. &Size
  1218. );
  1219. Pos->UseProfile = (rc == ERROR_SUCCESS && Enabled);
  1220. //
  1221. // Identify the last logged-on user.
  1222. //
  1223. Size = sizeof (Pos->LastLoggedOnUserName);
  1224. rc = Win95RegQueryValueExA (
  1225. Key,
  1226. "UserName",
  1227. NULL,
  1228. NULL,
  1229. Pos->LastLoggedOnUserName,
  1230. &Size
  1231. );
  1232. if (rc == ERROR_SUCCESS) {
  1233. OemToCharA (Pos->LastLoggedOnUserName, Pos->LastLoggedOnUserName);
  1234. if (!Pos->UseProfile || Win95RegIsValidUser (NULL, Pos->LastLoggedOnUserName)) {
  1235. Pos->LastLoggedOnUserNameExists = TRUE;
  1236. } else {
  1237. Pos->LastLoggedOnUserName[0] = 0;
  1238. }
  1239. }
  1240. Win95RegCloseKey (Key);
  1241. }
  1242. //
  1243. // On a common-profile machine, we'll return the last logged-on user name.
  1244. // If no last logged-on user exists, or if the path to this registry value
  1245. // doesn't exist, we'll return "", meaning "no user". Both cases are considered
  1246. // valid.
  1247. //
  1248. if (!Pos->UseProfile) {
  1249. //
  1250. // Success.
  1251. //
  1252. _mbssafecpy (UserNameAnsi, Pos->LastLoggedOnUserName, MAX_USER_NAMEA);
  1253. //StringCopyA (UserNameAnsi, Pos->LastLoggedOnUserName);
  1254. if (UserNameAnsi[0]) {
  1255. Pos->NumPos = 1;
  1256. }
  1257. Pos->IsLastLoggedOnUserName = Pos->LastLoggedOnUserNameExists;
  1258. return ERROR_SUCCESS;
  1259. }
  1260. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &Key);
  1261. if (rc != ERROR_SUCCESS) {
  1262. Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
  1263. //
  1264. // This error code change was added by MikeCo. It likely doesn't
  1265. // do anything useful.
  1266. //
  1267. if (rc == ERROR_FILE_NOT_FOUND) {
  1268. rc = ERROR_SUCCESS;
  1269. }
  1270. } else {
  1271. //
  1272. // Find the first valid profile
  1273. //
  1274. Win95RegQueryInfoKeyA (Key, NULL, NULL, NULL, &Pos->NumPos, NULL, NULL,
  1275. NULL, NULL, NULL, NULL, NULL);
  1276. if (Pos->NumPos > 0) {
  1277. do {
  1278. Size = MAX_USER_NAMEA;
  1279. rc = Win95RegEnumKeyExA (
  1280. Key,
  1281. Pos->CurPos,
  1282. UserNameAnsi,
  1283. &Size,
  1284. NULL,
  1285. NULL,
  1286. NULL,
  1287. NULL
  1288. );
  1289. if (rc != ERROR_SUCCESS) {
  1290. Pos->NumPos = 0;
  1291. break;
  1292. }
  1293. if (Win95RegIsValidUser (Key, UserNameAnsi)) {
  1294. Pos->IsLastLoggedOnUserName = StringIMatch (
  1295. UserNameAnsi,
  1296. Pos->LastLoggedOnUserName
  1297. );
  1298. break;
  1299. }
  1300. Pos->CurPos++;
  1301. } while (Pos->CurPos < Pos->NumPos);
  1302. if (Pos->CurPos >= Pos->NumPos) {
  1303. Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
  1304. }
  1305. }
  1306. Win95RegCloseKey (Key);
  1307. }
  1308. DEBUGMSG_IF ((rc != ERROR_SUCCESS, DBG_ERROR, "WIN95REG: Error getting first user"));
  1309. return rc;
  1310. }
  1311. LONG
  1312. Win95RegGetNextUserA (
  1313. PUSERPOSITION Pos,
  1314. PSTR UserNameAnsi
  1315. )
  1316. {
  1317. DWORD Size;
  1318. LONG rc = ERROR_SUCCESS;
  1319. HKEY Key;
  1320. MYASSERT (Pos && GU_VALID == Pos->Valid);
  1321. MYASSERT (UserNameAnsi);
  1322. Pos->IsLastLoggedOnUserName = FALSE;
  1323. //
  1324. // On a common-profile machine, this function always returns
  1325. // "no more users", since the call to Win95RegGetFirstUserA/W
  1326. // returned the only named user (the logged-on user, if it
  1327. // exists).
  1328. //
  1329. if (!Pos->UseProfile) {
  1330. Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
  1331. return rc;
  1332. }
  1333. //
  1334. // Open key to profile list
  1335. //
  1336. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &Key);
  1337. if (rc != ERROR_SUCCESS) {
  1338. Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
  1339. } else {
  1340. Pos->CurPos++;
  1341. while (Pos->CurPos < Pos->NumPos) {
  1342. //
  1343. // Get first user's key name
  1344. //
  1345. Size = MAX_USER_NAMEA;
  1346. rc = Win95RegEnumKeyExA(
  1347. Key,
  1348. Pos->CurPos,
  1349. UserNameAnsi,
  1350. &Size,
  1351. NULL,
  1352. NULL,
  1353. NULL,
  1354. NULL
  1355. );
  1356. if (rc != ERROR_SUCCESS) {
  1357. Pos->NumPos = 0;
  1358. break;
  1359. }
  1360. if (Win95RegIsValidUser (Key, UserNameAnsi)) {
  1361. Pos->IsLastLoggedOnUserName = StringIMatch (
  1362. UserNameAnsi,
  1363. Pos->LastLoggedOnUserName
  1364. );
  1365. break;
  1366. }
  1367. Pos->CurPos++;
  1368. }
  1369. if (Pos->CurPos >= Pos->NumPos) {
  1370. Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
  1371. }
  1372. Win95RegCloseKey (Key);
  1373. }
  1374. DEBUGMSG_IF ((rc != ERROR_SUCCESS, DBG_ERROR, "WIN95REG: Error getting next user"));
  1375. return rc;
  1376. }
  1377. LONG
  1378. Win95RegGetFirstUserW (
  1379. PUSERPOSITION Pos,
  1380. PWSTR UserName
  1381. )
  1382. {
  1383. LONG rc;
  1384. CHAR AnsiUserName[MAX_USER_NAMEA];
  1385. PSTR p;
  1386. MYASSERT (Pos && UserName);
  1387. rc = Win95RegGetFirstUserA (Pos, AnsiUserName);
  1388. if (rc == ERROR_SUCCESS) {
  1389. if (CharCountA (AnsiUserName) > MAX_USER_NAMEW - 1) {
  1390. p = CharCountToPointerA (AnsiUserName, MAX_USER_NAMEW - 1);
  1391. *p = 0;
  1392. }
  1393. KnownSizeAtoW (UserName, AnsiUserName);
  1394. }
  1395. return rc;
  1396. }
  1397. LONG
  1398. Win95RegGetNextUserW (
  1399. PUSERPOSITION Pos,
  1400. PWSTR UserName
  1401. )
  1402. {
  1403. LONG rc;
  1404. CHAR AnsiUserName[MAX_USER_NAMEA];
  1405. PSTR p;
  1406. MYASSERT (Pos);
  1407. MYASSERT (UserName);
  1408. rc = Win95RegGetNextUserA (Pos, AnsiUserName);
  1409. if (rc == ERROR_SUCCESS) {
  1410. if (CharCountA (AnsiUserName) > MAX_USER_NAMEW - 1) {
  1411. p = CharCountToPointerA (AnsiUserName, MAX_USER_NAMEW - 1);
  1412. *p = 0;
  1413. }
  1414. KnownSizeAtoW (UserName, AnsiUserName);
  1415. }
  1416. return rc;
  1417. }
  1418. BOOL
  1419. pIsCurrentUser (
  1420. IN PCSTR UserNameAnsi
  1421. )
  1422. {
  1423. DWORD subKeys;
  1424. LONG rc;
  1425. HKEY win9xUpgKey;
  1426. CHAR userName[MAX_USER_NAME];
  1427. DWORD userNameSize;
  1428. BOOL result = FALSE;
  1429. HKEY profileKey;
  1430. rc = Win95RegOpenKeyA (
  1431. HKEY_LOCAL_MACHINE,
  1432. "Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\Win9xUpg",
  1433. &win9xUpgKey
  1434. );
  1435. if (rc != ERROR_SUCCESS) {
  1436. return FALSE;
  1437. }
  1438. userNameSize = ARRAYSIZE(userName);
  1439. rc = Win95RegQueryValueExA (
  1440. win9xUpgKey,
  1441. "CurrentUser",
  1442. NULL,
  1443. NULL,
  1444. (PBYTE) userName,
  1445. &userNameSize
  1446. );
  1447. if (rc == ERROR_SUCCESS) {
  1448. result = StringIMatchA (UserNameAnsi, userName);
  1449. }
  1450. Win95RegCloseKey (win9xUpgKey);
  1451. return result;
  1452. }
  1453. BOOL
  1454. Win95RegIsValidUser (
  1455. HKEY ProfileListKey, OPTIONAL
  1456. PSTR UserNameAnsi
  1457. )
  1458. {
  1459. HKEY UserProfileKey;
  1460. BOOL b = FALSE;
  1461. BOOL CloseProfileListKey = FALSE;
  1462. LONG rc;
  1463. if (!ProfileListKey) {
  1464. rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &ProfileListKey);
  1465. if (rc != ERROR_SUCCESS) {
  1466. return FALSE;
  1467. }
  1468. CloseProfileListKey = TRUE;
  1469. }
  1470. //
  1471. // Open the user key
  1472. //
  1473. rc = Win95RegOpenKeyA (
  1474. ProfileListKey,
  1475. UserNameAnsi,
  1476. &UserProfileKey
  1477. );
  1478. //
  1479. // Does ProfileImagePath exist?
  1480. // (The case where the user logged in but did not retain settings)
  1481. //
  1482. if (rc == ERROR_SUCCESS) {
  1483. rc = Win95RegQueryValueExA (
  1484. UserProfileKey,
  1485. S_PROFILEIMAGEPATH,
  1486. NULL,
  1487. NULL,
  1488. NULL,
  1489. NULL
  1490. );
  1491. if (rc == ERROR_SUCCESS) {
  1492. //
  1493. // Add other tests here
  1494. //
  1495. b = TRUE;
  1496. } else {
  1497. //
  1498. // Need to check if this is the current user. If it is, and we are
  1499. // here, then the user doing the upgrade chose not to save his/her
  1500. // settings.
  1501. //
  1502. b = pIsCurrentUser (UserNameAnsi);
  1503. }
  1504. Win95RegCloseKey (UserProfileKey);
  1505. }
  1506. if (CloseProfileListKey) {
  1507. Win95RegCloseKey (ProfileListKey);
  1508. }
  1509. return b;
  1510. }
  1511. VOID
  1512. pCleanupTempUser (
  1513. VOID
  1514. )
  1515. {
  1516. g_UserKey = NULL;
  1517. if (!g_UnloadLastUser) {
  1518. return;
  1519. }
  1520. //
  1521. // Unload temp user hive
  1522. //
  1523. RegUnLoadKey(
  1524. HKEY_LOCAL_MACHINE,
  1525. S_MIGRATION
  1526. );
  1527. pSetupRegistryDelnode (
  1528. HKEY_LOCAL_MACHINE,
  1529. S_MIGRATION
  1530. );
  1531. g_UnloadLastUser = FALSE;
  1532. }
  1533. VOID
  1534. pGetCurrentUserDatPath (
  1535. IN PCSTR BaseDir,
  1536. OUT PSTR PathSpec
  1537. )
  1538. {
  1539. CHAR UserNameAnsi[MAX_USER_NAMEA];
  1540. CHAR FullPath[MAX_MBCHAR_PATH];
  1541. CHAR RegKey[MAX_REGISTRY_KEY];
  1542. HKEY ProfileListKey;
  1543. PCSTR Data;
  1544. DWORD Size;
  1545. Size = ARRAYSIZE(UserNameAnsi);
  1546. if (!GetUserName (UserNameAnsi, &Size)) {
  1547. *UserNameAnsi = 0;
  1548. }
  1549. *FullPath = 0;
  1550. if (*UserNameAnsi) {
  1551. //
  1552. // Logged-in user case on a per-user profile machine. Look in
  1553. // Windows\CV\ProfileList\<user> for a ProfileImagePath value.
  1554. //
  1555. wsprintfA (RegKey, "%s\\%s", S_HKLM_PROFILELIST_KEY, UserNameAnsi);
  1556. ProfileListKey = OpenRegKeyStrA (RegKey);
  1557. if (!ProfileListKey) {
  1558. //
  1559. // No profile list!
  1560. //
  1561. DEBUGMSG ((DBG_WHOOPS, "pGetCurrentUserDatPath: No profile list found"));
  1562. } else {
  1563. //
  1564. // Get the ProfileImagePath value
  1565. //
  1566. Data = GetRegValueDataOfTypeA (ProfileListKey, S_PROFILEIMAGEPATH, REG_SZ);
  1567. if (Data) {
  1568. _mbssafecpy (FullPath, Data, sizeof (FullPath));
  1569. MemFree (g_hHeap, 0, Data);
  1570. }
  1571. ELSE_DEBUGMSG ((
  1572. DBG_WARNING,
  1573. "pGetCurrentUserDatPath: Profile for %s does not have a ProfileImagePath value",
  1574. UserNameAnsi
  1575. ));
  1576. CloseRegKey (ProfileListKey);
  1577. }
  1578. } else {
  1579. //
  1580. // Default user case. Prepare %windir%\user.dat.
  1581. //
  1582. StringCopyA (FullPath, BaseDir);
  1583. }
  1584. //
  1585. // Append user.dat
  1586. //
  1587. if (*FullPath) {
  1588. StringCopyA (AppendWackA (FullPath), "user.dat");
  1589. }
  1590. //
  1591. // Convert to short name
  1592. //
  1593. if (!(*FullPath) || !OurGetShortPathName (FullPath, PathSpec, MAX_TCHAR_PATH)) {
  1594. _mbssafecpy (PathSpec, FullPath, MAX_MBCHAR_PATH);
  1595. }
  1596. }
  1597. PCSTR
  1598. pLoadUserDat (
  1599. IN PCSTR BaseDir,
  1600. IN PCSTR UserDatSpec
  1601. )
  1602. {
  1603. CHAR ShortPath[MAX_MBCHAR_PATH];
  1604. CHAR CurrentUserDatPath[MAX_MBCHAR_PATH];
  1605. DWORD rc;
  1606. //
  1607. // Unload last user if necessary
  1608. //
  1609. pCleanupTempUser();
  1610. //
  1611. // Determine if it is necessary to load UserDatSpec. If not,
  1612. // return HKEY_CURRENT_USER. Otherwise, load the key into
  1613. // HKLM\Migration, then open it.
  1614. //
  1615. //
  1616. // Always use the short path name
  1617. //
  1618. if (!OurGetShortPathName (UserDatSpec, ShortPath, sizeof (ShortPath))) {
  1619. DEBUGMSG ((
  1620. DBG_WARNING,
  1621. "pLoadUserDat: Could not get short name for %s",
  1622. UserDatSpec
  1623. ));
  1624. return NULL;
  1625. }
  1626. //
  1627. // Per-user profiles are enabled. Determine if UserDatSpec
  1628. // has already been mapped to HKCU.
  1629. //
  1630. pGetCurrentUserDatPath (BaseDir, CurrentUserDatPath);
  1631. if (StringIMatch (ShortPath, CurrentUserDatPath)) {
  1632. //
  1633. // Yes -- return HKEY_CURRENT_USER
  1634. //
  1635. DEBUGMSG ((DBG_VERBOSE, "%s is the current user's hive.", CurrentUserDatPath));
  1636. return "HKCU";
  1637. }
  1638. //
  1639. // No -- load user.dat into HKLM\Migration
  1640. //
  1641. DEBUGMSG ((DBG_WIN95REG, "RegLoadKey: %s", ShortPath));
  1642. rc = RegLoadKey (
  1643. HKEY_LOCAL_MACHINE,
  1644. S_MIGRATION,
  1645. ShortPath
  1646. );
  1647. if (rc != ERROR_SUCCESS) {
  1648. SetLastError (rc);
  1649. DEBUGMSG ((
  1650. DBG_WARNING,
  1651. "pLoadUserDat: Could not load %s into HKLM\\Migration. Original Path: %s",
  1652. ShortPath,
  1653. UserDatSpec
  1654. ));
  1655. return NULL;
  1656. }
  1657. g_UnloadLastUser = TRUE;
  1658. return S_HKLM_MIGRATION;
  1659. }
  1660. LONG
  1661. Win95RegSetCurrentUserA (
  1662. IN OUT PUSERPOSITION Pos,
  1663. IN PCSTR SystemHiveDir, OPTIONAL
  1664. OUT PSTR UserDatOut OPTIONAL
  1665. )
  1666. {
  1667. return pWin95RegSetCurrentUserCommonA (Pos, SystemHiveDir, UserDatOut, NULL);
  1668. }
  1669. LONG
  1670. Win95RegSetCurrentUserW (
  1671. IN OUT PUSERPOSITION Pos,
  1672. IN PCWSTR SystemHiveDir, OPTIONAL
  1673. OUT PWSTR UserDatOut OPTIONAL
  1674. )
  1675. {
  1676. return pWin95RegSetCurrentUserCommonW (Pos, SystemHiveDir, UserDatOut, NULL);
  1677. }
  1678. LONG
  1679. Win95RegSetCurrentUserNtA (
  1680. IN OUT PUSERPOSITION Pos,
  1681. IN PCSTR UserDat
  1682. )
  1683. {
  1684. return pWin95RegSetCurrentUserCommonA (Pos, NULL, NULL, UserDat);
  1685. }
  1686. LONG
  1687. Win95RegSetCurrentUserNtW (
  1688. IN OUT PUSERPOSITION Pos,
  1689. IN PCWSTR UserDat
  1690. )
  1691. {
  1692. return pWin95RegSetCurrentUserCommonW (Pos, NULL, NULL, UserDat);
  1693. }
  1694. LONG
  1695. pWin95RegSetCurrentUserCommonW (
  1696. IN OUT PUSERPOSITION Pos,
  1697. IN PCWSTR SystemHiveDir, OPTIONAL
  1698. OUT PWSTR UserDatOut, OPTIONAL
  1699. IN PCWSTR UserDat OPTIONAL
  1700. )
  1701. {
  1702. LONG rc;
  1703. PCSTR AnsiSystemHiveDir;
  1704. PCSTR AnsiUserDat;
  1705. CHAR AnsiUserDatOut[MAX_MBCHAR_PATH];
  1706. PSTR p;
  1707. //
  1708. // Convert args to ANSI
  1709. //
  1710. if (UserDat) {
  1711. AnsiUserDat = ConvertWtoA (UserDat);
  1712. } else {
  1713. AnsiUserDat = NULL;
  1714. }
  1715. if (SystemHiveDir) {
  1716. AnsiSystemHiveDir = ConvertWtoA (UserDat);
  1717. } else {
  1718. AnsiSystemHiveDir = NULL;
  1719. }
  1720. //
  1721. // Call ANSI function
  1722. //
  1723. rc = pWin95RegSetCurrentUserCommonA (Pos, AnsiSystemHiveDir, AnsiUserDatOut, AnsiUserDat);
  1724. if (rc == ERROR_SUCCESS) {
  1725. //
  1726. // Convert OUT arg
  1727. //
  1728. if (UserDatOut) {
  1729. if (CharCountA (AnsiUserDatOut) > MAX_WCHAR_PATH - 1) {
  1730. p = CharCountToPointerA (AnsiUserDatOut, MAX_USER_NAMEW - 1);
  1731. *p = 0;
  1732. }
  1733. KnownSizeAtoW (UserDatOut, AnsiUserDatOut);
  1734. }
  1735. }
  1736. return rc;
  1737. }
  1738. DWORD
  1739. FindAndLoadHive (
  1740. IN OUT PUSERPOSITION Pos,
  1741. IN PCSTR SystemHiveDir, OPTIONAL
  1742. IN PCSTR UserDatFromCaller, OPTIONAL
  1743. OUT PSTR UserDatToCaller, OPTIONAL
  1744. IN BOOL MapTheHive
  1745. )
  1746. {
  1747. CHAR RegistryUserDatPath[MAX_MBCHAR_PATH];
  1748. CHAR ActualUserDatPath[MAX_MBCHAR_PATH];
  1749. CHAR UserNameAnsi[MAX_USER_NAMEA];
  1750. DWORD Size;
  1751. HKEY ProfileListKey;
  1752. HKEY UserKey = NULL;
  1753. CHAR WinDir[MAX_MBCHAR_PATH];
  1754. DWORD rc = ERROR_SUCCESS;
  1755. //
  1756. // 1. Determine the path to ActualUserDatPath
  1757. //
  1758. // 2. If user.dat is from registry and caller supplied alternate
  1759. // %windir%, replace the %windir% with SystemHiveDir
  1760. //
  1761. // 3. If caller wants final path, copy it to their buffer
  1762. //
  1763. // 4. On NT, map the hive as HKCU. On 95, load the key and open
  1764. // a reg handle.
  1765. //
  1766. if (UserDatFromCaller) {
  1767. //
  1768. // Caller says where to find user.dat
  1769. //
  1770. StringCopyA (ActualUserDatPath, UserDatFromCaller);
  1771. } else {
  1772. //
  1773. // System.dat says us where to find user.dat
  1774. //
  1775. rc = Win95RegOpenKeyA (
  1776. HKEY_LOCAL_MACHINE,
  1777. S_PROFILELIST_KEYA,
  1778. &ProfileListKey
  1779. );
  1780. if (rc != ERROR_SUCCESS) {
  1781. return rc;
  1782. }
  1783. //
  1784. // Get name of user
  1785. //
  1786. Size = ARRAYSIZE(UserNameAnsi);
  1787. rc = Win95RegEnumKeyExA (
  1788. ProfileListKey,
  1789. (DWORD) Pos->CurPos,
  1790. UserNameAnsi,
  1791. &Size,
  1792. NULL,
  1793. NULL,
  1794. NULL,
  1795. NULL
  1796. );
  1797. if (rc == ERROR_SUCCESS) {
  1798. //
  1799. // Open key to user
  1800. //
  1801. rc = Win95RegOpenKeyA (
  1802. ProfileListKey,
  1803. UserNameAnsi,
  1804. &UserKey
  1805. );
  1806. }
  1807. Win95RegCloseKey (ProfileListKey);
  1808. if (rc != ERROR_SUCCESS) {
  1809. return rc;
  1810. }
  1811. //
  1812. // Get user's profile path from registry. Optionally relocate it, if user
  1813. // supplied a replacement for WinDir.
  1814. //
  1815. Size = sizeof (RegistryUserDatPath);
  1816. rc = Win95RegQueryValueExA (
  1817. UserKey,
  1818. S_PROFILEIMAGEPATH,
  1819. NULL,
  1820. NULL,
  1821. RegistryUserDatPath,
  1822. &Size
  1823. );
  1824. Win95RegCloseKey (UserKey);
  1825. if (rc != ERROR_SUCCESS) {
  1826. if (!pIsCurrentUser (UserNameAnsi)) {
  1827. return rc;
  1828. }
  1829. return pSetDefaultUserHelper (
  1830. Pos,
  1831. SystemHiveDir,
  1832. UserDatFromCaller,
  1833. UserDatToCaller
  1834. );
  1835. }
  1836. //
  1837. // Substitute %WinDir% in path that registry supplied?
  1838. //
  1839. if (SystemHiveDir && *SystemHiveDir) {
  1840. //
  1841. // Munge profile path
  1842. //
  1843. rc = pReplaceWinDirInPath (
  1844. ActualUserDatPath,
  1845. RegistryUserDatPath,
  1846. SystemHiveDir
  1847. );
  1848. if (rc != ERROR_SUCCESS) {
  1849. return rc;
  1850. }
  1851. } else {
  1852. //
  1853. // Don't munge. Leave as is (correct behavior on Win95 with local profiles)
  1854. //
  1855. StringCopyA (ActualUserDatPath, RegistryUserDatPath);
  1856. }
  1857. //
  1858. // Add name of hive file, "\\user.dat"
  1859. //
  1860. StringCopyA (AppendWackA (ActualUserDatPath), "user.dat");
  1861. }
  1862. //
  1863. // Send path to caller if necessary
  1864. //
  1865. if (UserDatToCaller) {
  1866. _mbssafecpy (UserDatToCaller, ActualUserDatPath, MAX_MBCHAR_PATH);
  1867. }
  1868. if (MapTheHive) {
  1869. if (g_IsNt) {
  1870. //
  1871. // WinNT: Associate filename with HKCU
  1872. //
  1873. rc = VMMRegMapPredefKeyToFile (
  1874. HKEY_CURRENT_USER,
  1875. ActualUserDatPath,
  1876. 0
  1877. );
  1878. } else {
  1879. //
  1880. // Win9x: Load HKLM\Migration
  1881. //
  1882. if (!SystemHiveDir) {
  1883. if (!GetWindowsDirectory (WinDir, sizeof (WinDir))) {
  1884. rc = GetLastError ();
  1885. }
  1886. }
  1887. if (rc == ERROR_SUCCESS) {
  1888. g_UserKey = pLoadUserDat (
  1889. SystemHiveDir ? SystemHiveDir : WinDir,
  1890. ActualUserDatPath
  1891. );
  1892. if (!g_UserKey) {
  1893. rc = GetLastError();
  1894. }
  1895. }
  1896. }
  1897. }
  1898. return rc;
  1899. }
  1900. DWORD
  1901. pSetDefaultUserHelper (
  1902. IN OUT PUSERPOSITION Pos,
  1903. IN PCSTR SystemHiveDir, OPTIONAL
  1904. IN PCSTR UserDatFromCaller, OPTIONAL
  1905. OUT PSTR UserDatToCaller OPTIONAL
  1906. )
  1907. {
  1908. CHAR ActualUserDatPath[MAX_MBCHAR_PATH];
  1909. DWORD rc = ERROR_SUCCESS;
  1910. HKEY DefaultKey;
  1911. //
  1912. // Determine path to default user's user.dat
  1913. //
  1914. if (UserDatFromCaller) {
  1915. //
  1916. // Caller-supplied user.dat path
  1917. //
  1918. StringCopyA (ActualUserDatPath, UserDatFromCaller);
  1919. } else {
  1920. //
  1921. // Use the string received from Init
  1922. //
  1923. StringCopyA (ActualUserDatPath, g_SystemUserHive);
  1924. }
  1925. //
  1926. // NT: Map the user via VMMREG
  1927. // 9x: Load & open the user hive
  1928. //
  1929. if (g_IsNt) {
  1930. //
  1931. // NT: Map .Default into HKCU.
  1932. //
  1933. //
  1934. // Reload HKEY_USERS
  1935. //
  1936. rc = VMMRegMapPredefKeyToFile (
  1937. HKEY_USERS,
  1938. ActualUserDatPath,
  1939. 0
  1940. );
  1941. if (rc != ERROR_SUCCESS) {
  1942. SetLastError(rc);
  1943. DEBUGMSG ((
  1944. DBG_ERROR,
  1945. "pWin95RegSetCurrentUserCommonW: Cannot reload HKU from %s",
  1946. ActualUserDatPath
  1947. ));
  1948. return rc;
  1949. }
  1950. //
  1951. // Get handle to default profile
  1952. //
  1953. rc = Win95RegOpenKeyA (
  1954. HKEY_USERS,
  1955. ".Default",
  1956. &DefaultKey
  1957. );
  1958. if (rc != ERROR_SUCCESS) {
  1959. SetLastError(rc);
  1960. DEBUGMSG ((
  1961. DBG_ERROR,
  1962. "pWin95RegSetCurrentUserCommonW: Expected to find key HKU\\.Default in %s",
  1963. ActualUserDatPath
  1964. ));
  1965. return rc;
  1966. }
  1967. //
  1968. // Associate default profile with HKEY_CURRENT_USER
  1969. //
  1970. rc = VMMRegMapPredefKeyToKey (
  1971. DefaultKey,
  1972. HKEY_CURRENT_USER
  1973. );
  1974. Win95RegCloseKey (DefaultKey);
  1975. if (rc != ERROR_SUCCESS) {
  1976. SetLastError(rc);
  1977. DEBUGMSG((
  1978. DBG_ERROR,
  1979. "pWin95RegSetCurrentUserCommonW: Cannot map HKU\\.Default to HKCU from %s",
  1980. ActualUserDatPath
  1981. ));
  1982. return rc;
  1983. }
  1984. } else {
  1985. //
  1986. // Win9x: Return HKU\.Default
  1987. //
  1988. g_UserKey = S_HKU_DEFAULT;
  1989. }
  1990. //
  1991. // Send path to caller if necessary
  1992. //
  1993. if (UserDatToCaller) {
  1994. _mbssafecpy (UserDatToCaller, ActualUserDatPath, MAX_MBCHAR_PATH);
  1995. }
  1996. return rc;
  1997. }
  1998. LONG
  1999. pWin95RegSetCurrentUserCommonA (
  2000. IN OUT PUSERPOSITION Pos,
  2001. IN PCSTR SystemHiveDir, OPTIONAL
  2002. OUT PSTR UserDatOut, OPTIONAL
  2003. IN PCSTR UserDat OPTIONAL
  2004. )
  2005. {
  2006. MYASSERT (!Pos || GU_VALID == Pos->Valid);
  2007. //
  2008. // Process per-user user.dat if
  2009. // (A) caller does not want default user
  2010. // (B) machine has per-user profiles
  2011. // (C) current user position is valid
  2012. //
  2013. if (Pos && Pos->UseProfile && Pos->CurPos < Pos->NumPos) {
  2014. return (LONG) FindAndLoadHive (
  2015. Pos,
  2016. SystemHiveDir,
  2017. UserDat,
  2018. UserDatOut,
  2019. TRUE
  2020. );
  2021. }
  2022. //
  2023. // For all other cases, use a default profile
  2024. //
  2025. return (LONG) pSetDefaultUserHelper (
  2026. Pos,
  2027. SystemHiveDir,
  2028. UserDat,
  2029. UserDatOut
  2030. );
  2031. }
  2032. LONG
  2033. pReplaceWinDirInPath (
  2034. IN PSTR ProfilePathMunged,
  2035. IN PCSTR ProfilePath,
  2036. IN PCSTR NewWinDir
  2037. )
  2038. {
  2039. PSTR EndOfWinDir;
  2040. //
  2041. // Test assumptions about profile dir. Expect x:\windir\...
  2042. //
  2043. if (!isalpha(ProfilePath[0]) ||
  2044. ProfilePath[1] != ':' ||
  2045. ProfilePath[2] != '\\'
  2046. ) {
  2047. return ERROR_INVALID_DATA;
  2048. }
  2049. //
  2050. // Find the second slash (the first is at ptr+2)
  2051. //
  2052. EndOfWinDir = _mbschr (&ProfilePath[3], '\\');
  2053. if (!EndOfWinDir) {
  2054. return ERROR_INVALID_DATA;
  2055. }
  2056. //
  2057. // Make munged dir
  2058. //
  2059. StringCopyA (ProfilePathMunged, NewWinDir);
  2060. StringCopyA (AppendPathWack (ProfilePathMunged), _mbsinc (EndOfWinDir));
  2061. return ERROR_SUCCESS;
  2062. }