2670 lines
59 KiB
C
2670 lines
59 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
win95reg.c
|
|
|
|
Abstract:
|
|
|
|
Implements Win95-registry access functions callable from Win95 or WinNT.
|
|
|
|
Author:
|
|
|
|
MCondra, 16 Oct 1996
|
|
|
|
Revision History:
|
|
|
|
jimschm 11-Feb-1999 Rewrite of portions because of DBCS bugs
|
|
and static array problems
|
|
calinn 29-Jan-1998 Added Win95RegOpenKeyStr function
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#define DBG_WIN95REG "Win95Reg"
|
|
|
|
|
|
|
|
#ifdef UNICODE
|
|
#error "UNICODE builds not supported"
|
|
#endif
|
|
|
|
//
|
|
// Undefine tracking macros
|
|
//
|
|
|
|
#ifdef DEBUG
|
|
|
|
#undef Win95RegOpenKeyExA
|
|
#undef Win95RegOpenKeyExW
|
|
#undef Win95RegCloseKey
|
|
|
|
#endif
|
|
|
|
//
|
|
// Define globals for Win95 registry wrappers
|
|
//
|
|
|
|
#define DEFMAC(fn,name) P##fn Win95##name;
|
|
|
|
REGWRAPPERS
|
|
|
|
#undef DEFMAC
|
|
|
|
|
|
#ifdef RegOpenKeyA
|
|
|
|
#undef RegOpenKeyA
|
|
#undef RegOpenKeyW
|
|
#undef RegOpenKeyExA
|
|
#undef RegOpenKeyExW
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Declare VMM W versions
|
|
//
|
|
|
|
REG_ENUM_KEY_W pVmmRegEnumKeyW;
|
|
REG_ENUM_KEY_EX_A pVmmRegEnumKeyExA;
|
|
REG_ENUM_KEY_EX_W pVmmRegEnumKeyExW;
|
|
REG_ENUM_VALUE_W pVmmRegEnumValueW;
|
|
REG_LOAD_KEY_W pVmmRegLoadKeyW;
|
|
REG_UNLOAD_KEY_W pVmmRegUnLoadKeyW;
|
|
REG_OPEN_KEY_W pVmmRegOpenKeyW;
|
|
REG_CLOSE_KEY pVmmRegCloseKey;
|
|
REG_OPEN_KEY_EX_A pVmmRegOpenKeyExA;
|
|
REG_OPEN_KEY_EX_W pVmmRegOpenKeyExW;
|
|
REG_QUERY_INFO_KEY_W pVmmRegQueryInfoKeyW;
|
|
REG_QUERY_VALUE_W pVmmRegQueryValueW;
|
|
REG_QUERY_VALUE_EX_W pVmmRegQueryValueExW;
|
|
|
|
VOID
|
|
pCleanupTempUser (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pIsCurrentUser (
|
|
IN PCSTR UserNameAnsi
|
|
);
|
|
|
|
LONG
|
|
pWin95RegSetCurrentUserCommonW (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCWSTR SystemHiveDir, OPTIONAL
|
|
OUT PWSTR UserDatOut, OPTIONAL
|
|
IN PCWSTR UserDat OPTIONAL
|
|
);
|
|
|
|
LONG
|
|
pWin95RegSetCurrentUserCommonA (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
OUT PSTR UserDatOut, OPTIONAL
|
|
IN PCSTR UserDat OPTIONAL
|
|
);
|
|
|
|
LONG
|
|
pReplaceWinDirInPath (
|
|
IN PSTR ProfilePathMunged,
|
|
IN PCSTR ProfilePath,
|
|
IN PCSTR NewWinDir
|
|
);
|
|
|
|
DWORD
|
|
pSetDefaultUserHelper (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
IN PCSTR UserDatFromCaller, OPTIONAL
|
|
OUT PSTR UserDatToCaller OPTIONAL
|
|
);
|
|
|
|
|
|
BOOL g_IsNt;
|
|
CHAR g_SystemHiveDir[MAX_MBCHAR_PATH];
|
|
CHAR g_SystemUserHive[MAX_MBCHAR_PATH];
|
|
BOOL g_UnloadLastUser = FALSE;
|
|
PCSTR g_UserKey;
|
|
BOOL g_UseClassesRootHive = FALSE;
|
|
HKEY g_ClassesRootKey = NULL;
|
|
|
|
|
|
|
|
//
|
|
// Wrappers of tracking API
|
|
//
|
|
|
|
LONG
|
|
pOurRegOpenKeyExA (
|
|
HKEY Key,
|
|
PCSTR SubKey,
|
|
DWORD Unused,
|
|
REGSAM SamMask,
|
|
PHKEY ResultPtr
|
|
)
|
|
{
|
|
return TrackedRegOpenKeyExA (Key, SubKey, Unused, SamMask, ResultPtr);
|
|
}
|
|
|
|
LONG
|
|
pOurRegOpenKeyA (
|
|
HKEY Key,
|
|
PCSTR SubKey,
|
|
PHKEY Result
|
|
)
|
|
{
|
|
return TrackedRegOpenKeyA (Key, SubKey, Result);
|
|
}
|
|
|
|
|
|
LONG
|
|
WINAPI
|
|
pOurCloseRegKey (
|
|
HKEY Key
|
|
)
|
|
{
|
|
return CloseRegKey (Key);
|
|
}
|
|
|
|
|
|
//
|
|
// Platform-dependent functions
|
|
//
|
|
|
|
VOID
|
|
InitWin95RegFnPointers (
|
|
VOID
|
|
)
|
|
{
|
|
OSVERSIONINFO vi;
|
|
|
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&vi);
|
|
|
|
g_IsNt = (vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
|
|
|
if (g_IsNt) {
|
|
|
|
//
|
|
// Attach to VMM registry library
|
|
//
|
|
|
|
VMMRegLibAttach(0);
|
|
|
|
//
|
|
// Initialize global function pointers for NT
|
|
//
|
|
|
|
Win95RegFlushKey = VMMRegFlushKey;
|
|
|
|
Win95RegEnumKeyA = VMMRegEnumKey;
|
|
Win95RegEnumKeyW = pVmmRegEnumKeyW;
|
|
|
|
Win95RegEnumKeyExA = pVmmRegEnumKeyExA;
|
|
Win95RegEnumKeyExW = pVmmRegEnumKeyExW;
|
|
|
|
Win95RegEnumValueA = VMMRegEnumValue;
|
|
Win95RegEnumValueW = pVmmRegEnumValueW;
|
|
|
|
Win95RegLoadKeyA = VMMRegLoadKey;
|
|
Win95RegLoadKeyW = pVmmRegLoadKeyW;
|
|
|
|
Win95RegUnLoadKeyA = VMMRegUnLoadKey;
|
|
Win95RegUnLoadKeyW = pVmmRegUnLoadKeyW;
|
|
|
|
Win95RegOpenKeyA = VMMRegOpenKey;
|
|
Win95RegOpenKeyW = pVmmRegOpenKeyW;
|
|
|
|
Win95RegOpenKeyExA = pVmmRegOpenKeyExA;
|
|
Win95RegOpenKeyExW = pVmmRegOpenKeyExW;
|
|
|
|
Win95RegCloseKey = pVmmRegCloseKey;
|
|
|
|
Win95RegQueryInfoKeyA = VMMRegQueryInfoKey;
|
|
Win95RegQueryInfoKeyW = pVmmRegQueryInfoKeyW;
|
|
|
|
Win95RegQueryValueA = (PREG_QUERY_VALUE_A)VMMRegQueryValue;
|
|
Win95RegQueryValueW = pVmmRegQueryValueW;
|
|
|
|
Win95RegQueryValueExA = VMMRegQueryValueEx;
|
|
Win95RegQueryValueExW = pVmmRegQueryValueExW;
|
|
|
|
} else {
|
|
//
|
|
// Initialize global function pointers for NT
|
|
//
|
|
|
|
Win95RegFlushKey = RegFlushKey;
|
|
|
|
Win95RegEnumKeyA = RegEnumKeyA;
|
|
Win95RegEnumKeyW = RegEnumKeyW;
|
|
|
|
Win95RegEnumKeyExA = RegEnumKeyExA;
|
|
Win95RegEnumKeyExW = RegEnumKeyExW;
|
|
|
|
Win95RegEnumValueA = RegEnumValueA;
|
|
Win95RegEnumValueW = RegEnumValueW;
|
|
|
|
Win95RegLoadKeyA = RegLoadKeyA;
|
|
Win95RegLoadKeyW = RegLoadKeyW;
|
|
|
|
Win95RegUnLoadKeyA = RegUnLoadKeyA;
|
|
Win95RegUnLoadKeyW = RegUnLoadKeyW;
|
|
|
|
Win95RegOpenKeyA = pOurRegOpenKeyA;
|
|
Win95RegOpenKeyW = RegOpenKeyW;
|
|
|
|
Win95RegOpenKeyExA = pOurRegOpenKeyExA;
|
|
Win95RegOpenKeyExW = RegOpenKeyExW;
|
|
|
|
Win95RegCloseKey = pOurCloseRegKey;
|
|
|
|
Win95RegQueryInfoKeyA = RegQueryInfoKeyA;
|
|
Win95RegQueryInfoKeyW = RegQueryInfoKeyW;
|
|
|
|
Win95RegQueryValueA = RegQueryValueA;
|
|
Win95RegQueryValueW = RegQueryValueW;
|
|
|
|
Win95RegQueryValueExA = RegQueryValueExA;
|
|
Win95RegQueryValueExW = RegQueryValueExW;
|
|
|
|
//
|
|
// Clear away HKLM\Migration
|
|
//
|
|
|
|
RegUnLoadKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
S_MIGRATION
|
|
);
|
|
|
|
pSetupRegistryDelnode (
|
|
HKEY_LOCAL_MACHINE,
|
|
S_MIGRATION
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Win95RegTerminate (
|
|
VOID
|
|
)
|
|
{
|
|
#ifdef DEBUG
|
|
DumpOpenKeys95();
|
|
RegTrackTerminate95();
|
|
#endif
|
|
|
|
if (!g_IsNt) {
|
|
pCleanupTempUser();
|
|
} else {
|
|
VMMRegLibDetach();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
Win95Reg_Entry (
|
|
HINSTANCE hInstance,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
if (dwReason == DLL_PROCESS_ATTACH) {
|
|
if(!pSetupInitializeUtils()) {
|
|
return FALSE;
|
|
}
|
|
InitWin95RegFnPointers();
|
|
} else if (dwReason == DLL_PROCESS_DETACH) {
|
|
Win95RegTerminate();
|
|
pSetupUninitializeUtils();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegEnumKeyW (
|
|
IN HKEY Key,
|
|
IN DWORD Index,
|
|
OUT PWSTR KeyName,
|
|
IN DWORD KeyNameSize
|
|
)
|
|
{
|
|
PSTR AnsiBuf;
|
|
LONG rc;
|
|
UINT Chars;
|
|
|
|
AnsiBuf = AllocTextA (KeyNameSize);
|
|
MYASSERT (AnsiBuf);
|
|
|
|
rc = VMMRegEnumKey (Key, Index, AnsiBuf, KeyNameSize);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
Chars = CharCountA (AnsiBuf);
|
|
|
|
//
|
|
// Special case: if Chars is zero, then we have 1/2 of a DBCS char.
|
|
//
|
|
|
|
if (!Chars && *AnsiBuf) {
|
|
if (KeyNameSize < 4) {
|
|
rc = ERROR_MORE_DATA;
|
|
}
|
|
|
|
KeyName[0] = *AnsiBuf;
|
|
KeyName[1] = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Normal case
|
|
//
|
|
|
|
if (Chars >= KeyNameSize / sizeof (WCHAR)) {
|
|
rc = ERROR_MORE_DATA;
|
|
} else {
|
|
KnownSizeDbcsToUnicodeN (KeyName, AnsiBuf, Chars);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
FreeTextA (AnsiBuf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegEnumValueW (
|
|
IN HKEY Key,
|
|
IN DWORD Index,
|
|
OUT PWSTR ValueName,
|
|
IN OUT PDWORD ValueNameChars,
|
|
PDWORD Reserved,
|
|
OUT PDWORD Type, OPTIONAL
|
|
OUT PBYTE Data, OPTIONAL
|
|
IN OUT PDWORD DataSize OPTIONAL
|
|
)
|
|
{
|
|
PSTR AnsiValueName;
|
|
LONG rc;
|
|
PSTR AnsiData;
|
|
UINT DataChars;
|
|
UINT ValueChars;
|
|
DWORD OurType;
|
|
DWORD OrgValueNameChars;
|
|
DWORD OrgDataSize;
|
|
DWORD OurValueNameChars;
|
|
DWORD OurValueNameCharsBackup;
|
|
DWORD AnsiDataSize;
|
|
BOOL HalfDbcs = FALSE;
|
|
|
|
__try {
|
|
MYASSERT (ValueNameChars);
|
|
MYASSERT (ValueName);
|
|
|
|
OrgValueNameChars = *ValueNameChars;
|
|
OrgDataSize = DataSize ? *DataSize : 0;
|
|
|
|
OurValueNameChars = min (*ValueNameChars, MAX_REGISTRY_VALUE_NAMEA);
|
|
OurValueNameCharsBackup = OurValueNameChars;
|
|
|
|
AnsiValueName = AllocTextA (OurValueNameChars);
|
|
MYASSERT (AnsiValueName);
|
|
|
|
AnsiData = NULL;
|
|
|
|
if (Data) {
|
|
|
|
MYASSERT (DataSize);
|
|
AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
|
|
|
|
} else if (DataSize) {
|
|
|
|
//
|
|
// Data is not specified; allocate a buffer for the
|
|
// proper calculation of DataSize.
|
|
//
|
|
|
|
rc = VMMRegEnumValue (
|
|
Key,
|
|
Index,
|
|
AnsiValueName,
|
|
&OurValueNameChars,
|
|
NULL,
|
|
&OurType,
|
|
NULL,
|
|
DataSize
|
|
);
|
|
|
|
OurValueNameChars = OurValueNameCharsBackup;
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
if (OurType == REG_SZ || OurType == REG_EXPAND_SZ || OurType == REG_MULTI_SZ) {
|
|
*DataSize += 2;
|
|
AnsiData = AllocTextA (*DataSize);
|
|
}
|
|
} else {
|
|
//
|
|
// Value name must be too small
|
|
//
|
|
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
rc = VMMRegEnumValue (
|
|
Key,
|
|
Index,
|
|
AnsiValueName,
|
|
&OurValueNameChars,
|
|
NULL,
|
|
&OurType,
|
|
AnsiData,
|
|
DataSize
|
|
);
|
|
|
|
if (DataSize) {
|
|
AnsiDataSize = *DataSize;
|
|
} else {
|
|
AnsiDataSize = 0;
|
|
}
|
|
|
|
//
|
|
// Return the type
|
|
//
|
|
|
|
if (Type) {
|
|
*Type = OurType;
|
|
}
|
|
|
|
//
|
|
// Return the sizes
|
|
//
|
|
|
|
if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) {
|
|
|
|
//
|
|
// The inbound value name size is in characters, including the nul.
|
|
// The outbound value name size is also in characteres, excluding
|
|
// the nul.
|
|
//
|
|
|
|
ValueChars = CharCountA (AnsiValueName);
|
|
|
|
//
|
|
// Special case: if ValueChars is zero, and AnsiValueName is
|
|
// not empty, then we have half of a DBCS character.
|
|
//
|
|
|
|
if (!ValueChars && *AnsiValueName) {
|
|
ValueChars = 1;
|
|
HalfDbcs = TRUE;
|
|
}
|
|
|
|
*ValueNameChars = ValueChars;
|
|
}
|
|
|
|
if (DataSize) {
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// The inbound data size is in bytes, including any nuls that apply.
|
|
// The outbound data size is the same.
|
|
//
|
|
|
|
if (AnsiData) {
|
|
|
|
MYASSERT (Data ||
|
|
OurType == REG_SZ ||
|
|
OurType == REG_EXPAND_SZ ||
|
|
OurType == REG_MULTI_SZ
|
|
);
|
|
|
|
//
|
|
// If the type is a string, then DataSize needs adjustment.
|
|
//
|
|
|
|
if (OurType == REG_SZ || OurType == REG_EXPAND_SZ || OurType == REG_MULTI_SZ) {
|
|
DataChars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
|
|
*DataSize = DataChars * sizeof (WCHAR);
|
|
}
|
|
}
|
|
|
|
if (Data && *DataSize > OrgDataSize) {
|
|
rc = ERROR_MORE_DATA;
|
|
}
|
|
|
|
} else if (rc == ERROR_MORE_DATA) {
|
|
|
|
//
|
|
// Get the correct DataSize value
|
|
//
|
|
|
|
pVmmRegEnumValueW (
|
|
Key,
|
|
Index,
|
|
ValueName,
|
|
ValueNameChars,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DataSize
|
|
);
|
|
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert the outbound strings
|
|
//
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Convert value name
|
|
//
|
|
|
|
if (ValueChars >= OrgValueNameChars) {
|
|
rc = ERROR_MORE_DATA;
|
|
} else {
|
|
if (!HalfDbcs) {
|
|
KnownSizeDbcsToUnicodeN (ValueName, AnsiValueName, ValueChars);
|
|
} else {
|
|
ValueName[0] = *AnsiValueName;
|
|
ValueName[1] = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert data
|
|
//
|
|
|
|
if (Data) {
|
|
|
|
MYASSERT (AnsiData);
|
|
|
|
if (OurType == REG_SZ ||
|
|
OurType == REG_EXPAND_SZ ||
|
|
OurType == REG_MULTI_SZ
|
|
) {
|
|
|
|
DirectDbcsToUnicodeN (
|
|
(PWSTR) Data,
|
|
AnsiData,
|
|
AnsiDataSize
|
|
);
|
|
|
|
} else {
|
|
|
|
CopyMemory (Data, AnsiData, AnsiDataSize);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
|
|
FreeTextA (AnsiValueName);
|
|
FreeTextA (AnsiData);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegLoadKeyW (
|
|
IN HKEY Key,
|
|
IN PCWSTR SubKey,
|
|
IN PCWSTR FileName
|
|
)
|
|
{
|
|
PCSTR AnsiSubKey;
|
|
PCSTR AnsiFileName;
|
|
LONG rc;
|
|
|
|
AnsiSubKey = ConvertWtoA (SubKey);
|
|
AnsiFileName = ConvertWtoA (FileName);
|
|
|
|
rc = VMMRegLoadKey (Key, AnsiSubKey, AnsiFileName);
|
|
|
|
FreeConvertedStr (AnsiSubKey);
|
|
FreeConvertedStr (AnsiFileName);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegUnLoadKeyW (
|
|
IN HKEY Key,
|
|
IN PCWSTR SubKey
|
|
)
|
|
{
|
|
PCSTR AnsiSubKey;
|
|
LONG rc;
|
|
|
|
AnsiSubKey = ConvertWtoA (SubKey);
|
|
|
|
rc = VMMRegUnLoadKey (Key, AnsiSubKey);
|
|
|
|
FreeConvertedStr (AnsiSubKey);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegOpenKeyW (
|
|
IN HKEY Key,
|
|
IN PCWSTR SubKey,
|
|
OUT HKEY *KeyPtr
|
|
)
|
|
{
|
|
PCSTR AnsiSubKey;
|
|
LONG rc;
|
|
CHAR mappedSubKey[MAXIMUM_SUB_KEY_LENGTH];
|
|
PCSTR MappedAnsiSubKey;
|
|
|
|
MappedAnsiSubKey = AnsiSubKey = ConvertWtoA (SubKey);
|
|
//
|
|
// if g_UseClassesRootHive is set, then perform some translations
|
|
//
|
|
if (g_UseClassesRootHive) {
|
|
if (Key == HKEY_LOCAL_MACHINE) {
|
|
if (StringIMatchCharCountA (
|
|
AnsiSubKey,
|
|
"SOFTWARE\\Classes",
|
|
sizeof ("SOFTWARE\\Classes") - 1
|
|
)) {
|
|
|
|
StringCopyByteCountA (
|
|
mappedSubKey,
|
|
AnsiSubKey + sizeof ("SOFTWARE\\Classes") - 1,
|
|
MAXIMUM_SUB_KEY_LENGTH
|
|
);
|
|
|
|
Key = g_ClassesRootKey;
|
|
MappedAnsiSubKey = mappedSubKey;
|
|
if (*MappedAnsiSubKey == '\\') {
|
|
MappedAnsiSubKey++;
|
|
}
|
|
}
|
|
} else if (Key == HKEY_CLASSES_ROOT) {
|
|
Key = g_ClassesRootKey;
|
|
}
|
|
}
|
|
|
|
rc = VMMRegOpenKey (Key, MappedAnsiSubKey, KeyPtr);
|
|
|
|
FreeConvertedStr (AnsiSubKey);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegCloseKey (
|
|
IN HKEY Key
|
|
)
|
|
{
|
|
if (g_UseClassesRootHive) {
|
|
if (Key == g_ClassesRootKey) {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return VMMRegCloseKey (Key);
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegEnumKeyExA (
|
|
IN HKEY Key,
|
|
IN DWORD Index,
|
|
OUT PSTR KeyName,
|
|
IN OUT PDWORD KeyNameSize,
|
|
PDWORD Reserved,
|
|
OUT PSTR Class, OPTIONAL
|
|
IN OUT PDWORD ClassSize, OPTIONAL
|
|
OUT PFILETIME LastWriteTime OPTIONAL
|
|
)
|
|
{
|
|
LONG rc;
|
|
|
|
MYASSERT (KeyNameSize);
|
|
MYASSERT (KeyName);
|
|
|
|
rc = VMMRegEnumKey (
|
|
Key,
|
|
Index,
|
|
KeyName,
|
|
*KeyNameSize
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
//
|
|
// Return length of key name, excluding delimiter
|
|
//
|
|
*KeyNameSize = ByteCount (KeyName);
|
|
|
|
//
|
|
// Return zero-length class
|
|
//
|
|
if (Class && *ClassSize) {
|
|
*Class = 0;
|
|
}
|
|
|
|
if (ClassSize) {
|
|
*ClassSize = 0;
|
|
}
|
|
|
|
//
|
|
// Stuff last-write time with zero
|
|
//
|
|
if (LastWriteTime) {
|
|
ZeroMemory (LastWriteTime, sizeof (FILETIME));
|
|
}
|
|
|
|
} else {
|
|
*KeyNameSize = MAX_PATH + 1;
|
|
|
|
if (ClassSize) {
|
|
*ClassSize = 0;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegEnumKeyExW (
|
|
IN HKEY Key,
|
|
IN DWORD Index,
|
|
OUT PWSTR KeyName,
|
|
IN OUT PDWORD KeyNameSize,
|
|
PDWORD Reserved,
|
|
OUT PWSTR Class, OPTIONAL
|
|
IN OUT PDWORD ClassSize, OPTIONAL
|
|
OUT PFILETIME LastWriteTime OPTIONAL
|
|
)
|
|
{
|
|
LONG rc;
|
|
PSTR AnsiKeyName;
|
|
PSTR AnsiClass;
|
|
UINT Chars;
|
|
DWORD OrgKeyNameSize;
|
|
DWORD OrgClassSize;
|
|
BOOL HalfDbcs = FALSE;
|
|
|
|
__try {
|
|
MYASSERT (KeyName);
|
|
MYASSERT (KeyNameSize);
|
|
|
|
AnsiKeyName = AllocTextA (*KeyNameSize);
|
|
|
|
if (Class) {
|
|
MYASSERT (ClassSize);
|
|
AnsiClass = AllocTextA (*ClassSize);
|
|
} else {
|
|
AnsiClass = NULL;
|
|
}
|
|
|
|
OrgKeyNameSize = *KeyNameSize;
|
|
OrgClassSize = ClassSize ? *ClassSize : 0;
|
|
|
|
rc = pVmmRegEnumKeyExA (
|
|
Key,
|
|
Index,
|
|
AnsiKeyName,
|
|
KeyNameSize,
|
|
NULL,
|
|
AnsiClass,
|
|
ClassSize,
|
|
LastWriteTime
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
Chars = CharCountA (AnsiKeyName);
|
|
|
|
//
|
|
// Special case: If Chars is zero, but AnsiKeyName is not empty,
|
|
// then we have 1/2 of a DBCS character.
|
|
//
|
|
|
|
if (!Chars && *AnsiKeyName) {
|
|
Chars = 1;
|
|
HalfDbcs = TRUE;
|
|
}
|
|
|
|
*KeyNameSize = Chars;
|
|
|
|
if (Chars >= OrgKeyNameSize / sizeof (WCHAR)) {
|
|
rc = ERROR_MORE_DATA;
|
|
__leave;
|
|
}
|
|
|
|
if (!HalfDbcs) {
|
|
KnownSizeDbcsToUnicodeN (KeyName, AnsiKeyName, Chars);
|
|
} else {
|
|
KeyName[0] = *AnsiKeyName;
|
|
KeyName[1] = 0;
|
|
}
|
|
|
|
HalfDbcs = FALSE;
|
|
|
|
if (Class) {
|
|
|
|
Chars = CharCountA (AnsiClass);
|
|
|
|
//
|
|
// Special case: If Chars is zero, but AnsiClass is not empty,
|
|
// then we have 1/2 of a DBCS character.
|
|
//
|
|
|
|
if (!Chars && *AnsiClass) {
|
|
Chars = 1;
|
|
HalfDbcs = TRUE;
|
|
}
|
|
|
|
*ClassSize = Chars;
|
|
|
|
if (Chars >= OrgClassSize / sizeof (WCHAR)) {
|
|
rc = ERROR_MORE_DATA;
|
|
__leave;
|
|
}
|
|
|
|
if (!HalfDbcs) {
|
|
KnownSizeDbcsToUnicodeN (Class, AnsiClass, Chars);
|
|
} else {
|
|
Class[0] = *AnsiClass;
|
|
Class[1] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
FreeTextA (AnsiKeyName);
|
|
FreeTextA (AnsiClass);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegOpenKeyExA (
|
|
IN HKEY Key,
|
|
IN PCSTR SubKey,
|
|
IN DWORD Options,
|
|
IN REGSAM SamDesired,
|
|
OUT HKEY *KeyPtr
|
|
)
|
|
{
|
|
CHAR mappedSubKey[MAXIMUM_SUB_KEY_LENGTH];
|
|
PCSTR MappedSubKey = SubKey;
|
|
|
|
//
|
|
// if g_UseClassesRootHive is set, then perform some translations
|
|
//
|
|
if (g_UseClassesRootHive) {
|
|
if (Key == HKEY_LOCAL_MACHINE) {
|
|
if (StringIMatchByteCountA (
|
|
SubKey,
|
|
"SOFTWARE\\Classes",
|
|
sizeof ("SOFTWARE\\Classes") - 1
|
|
)) {
|
|
|
|
StringCopyByteCountA (
|
|
mappedSubKey,
|
|
SubKey + sizeof ("SOFTWARE\\Classes") - 1,
|
|
MAXIMUM_SUB_KEY_LENGTH
|
|
);
|
|
|
|
Key = g_ClassesRootKey;
|
|
MappedSubKey = mappedSubKey;
|
|
if (*MappedSubKey == '\\') {
|
|
MappedSubKey++;
|
|
}
|
|
}
|
|
} else if (Key == HKEY_CLASSES_ROOT) {
|
|
Key = g_ClassesRootKey;
|
|
}
|
|
}
|
|
|
|
return VMMRegOpenKey (Key, MappedSubKey, KeyPtr);
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegOpenKeyExW (
|
|
IN HKEY Key,
|
|
IN PCWSTR SubKey,
|
|
IN DWORD Options,
|
|
IN REGSAM SamDesired,
|
|
OUT HKEY *KeyPtr
|
|
)
|
|
{
|
|
return pVmmRegOpenKeyW (Key, SubKey, KeyPtr);
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegQueryInfoKeyW (
|
|
IN HKEY Key,
|
|
OUT PWSTR Class, OPTIONAL
|
|
OUT PDWORD ClassSize, OPTIONAL
|
|
OUT PDWORD Reserved, OPTIONAL
|
|
OUT PDWORD SubKeys, OPTIONAL
|
|
OUT PDWORD MaxSubKeyLen, OPTIONAL
|
|
OUT PDWORD MaxClassLen, OPTIONAL
|
|
OUT PDWORD Values, OPTIONAL
|
|
OUT PDWORD MaxValueName, OPTIONAL
|
|
OUT PDWORD MaxValueData, OPTIONAL
|
|
OUT PVOID SecurityDescriptor, OPTIONAL
|
|
OUT PVOID LastWriteTime OPTIONAL
|
|
)
|
|
{
|
|
PSTR AnsiClass;
|
|
LONG rc = ERROR_NOACCESS;
|
|
UINT Chars;
|
|
DWORD OrgClassSize;
|
|
BOOL HalfDbcs = FALSE;
|
|
|
|
__try {
|
|
|
|
if (Class) {
|
|
MYASSERT (ClassSize);
|
|
AnsiClass = AllocTextA (*ClassSize);
|
|
if (!AnsiClass) {
|
|
__leave;
|
|
}
|
|
} else {
|
|
AnsiClass = NULL;
|
|
}
|
|
|
|
OrgClassSize = ClassSize ? *ClassSize : 0;
|
|
|
|
rc = VMMRegQueryInfoKey (
|
|
Key,
|
|
AnsiClass,
|
|
ClassSize,
|
|
Reserved,
|
|
SubKeys,
|
|
MaxSubKeyLen,
|
|
MaxClassLen,
|
|
Values,
|
|
MaxValueName,
|
|
MaxValueData,
|
|
SecurityDescriptor,
|
|
LastWriteTime
|
|
);
|
|
|
|
if (MaxValueData) {
|
|
*MaxValueData *= 2;
|
|
}
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
if (Class) {
|
|
|
|
Chars = CharCountA (AnsiClass);
|
|
|
|
//
|
|
// Special case: If Chars is zero, but AnsiClass is not empty,
|
|
// then we have 1/2 of a DBCS character.
|
|
//
|
|
|
|
if (!Chars && *AnsiClass) {
|
|
Chars = 1;
|
|
HalfDbcs = TRUE;
|
|
}
|
|
|
|
*ClassSize = Chars;
|
|
|
|
if (Chars >= OrgClassSize / sizeof (WCHAR)) {
|
|
rc = ERROR_MORE_DATA;
|
|
__leave;
|
|
}
|
|
|
|
if (!HalfDbcs) {
|
|
KnownSizeDbcsToUnicodeN (Class, AnsiClass, Chars);
|
|
} else {
|
|
Class[0] = *AnsiClass;
|
|
Class[1] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
FreeTextA (AnsiClass);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegQueryValueW (
|
|
IN HKEY Key,
|
|
IN PCWSTR SubKey,
|
|
OUT PWSTR Data, OPTIONAL
|
|
IN OUT PLONG DataSize OPTIONAL
|
|
)
|
|
{
|
|
PSTR AnsiData;
|
|
PCSTR AnsiSubKey;
|
|
LONG rc;
|
|
UINT Chars;
|
|
LONG OrgDataSize;
|
|
DWORD AnsiDataSize;
|
|
|
|
__try {
|
|
AnsiSubKey = ConvertWtoA (SubKey);
|
|
OrgDataSize = DataSize ? *DataSize : 0;
|
|
AnsiData = NULL;
|
|
|
|
if (Data) {
|
|
|
|
MYASSERT (DataSize);
|
|
AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
|
|
|
|
} else if (DataSize) {
|
|
|
|
//
|
|
// Data is not specified; allocate a buffer for the
|
|
// proper computation of DataSize.
|
|
//
|
|
|
|
rc = VMMRegQueryValue (
|
|
Key,
|
|
AnsiSubKey,
|
|
NULL,
|
|
DataSize
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
*DataSize += 2;
|
|
AnsiData = AllocTextA (*DataSize);
|
|
|
|
} else {
|
|
//
|
|
// An error usually means the sub key does not exist...
|
|
//
|
|
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
rc = VMMRegQueryValue (Key, AnsiSubKey, AnsiData, DataSize);
|
|
|
|
if (DataSize) {
|
|
AnsiDataSize = *DataSize;
|
|
} else {
|
|
AnsiDataSize = 0;
|
|
}
|
|
|
|
//
|
|
// Adjust the outbound size
|
|
//
|
|
|
|
if (DataSize) {
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
Chars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
|
|
|
|
MYASSERT (DataSize);
|
|
*DataSize = (Chars + 1) * sizeof (WCHAR);
|
|
|
|
if (Data && *DataSize > OrgDataSize) {
|
|
rc = ERROR_MORE_DATA;
|
|
}
|
|
|
|
} else if (rc == ERROR_MORE_DATA) {
|
|
|
|
pVmmRegQueryValueW (Key, SubKey, NULL, DataSize);
|
|
__leave;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert the return strings
|
|
//
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
MYASSERT (AnsiData);
|
|
|
|
if (Data) {
|
|
|
|
DirectDbcsToUnicodeN ((PWSTR) Data, AnsiData, AnsiDataSize);
|
|
|
|
} else {
|
|
|
|
CopyMemory (Data, AnsiData, AnsiDataSize);
|
|
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
FreeTextA (AnsiData);
|
|
FreeConvertedStr (AnsiSubKey);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pVmmRegQueryValueExW (
|
|
IN HKEY Key,
|
|
IN PCWSTR ValueName,
|
|
PDWORD Reserved,
|
|
OUT PDWORD Type, OPTIONAL
|
|
OUT PBYTE Data, OPTIONAL
|
|
IN OUT PDWORD DataSize OPTIONAL
|
|
)
|
|
{
|
|
LONG rc;
|
|
UINT Chars;
|
|
PCSTR AnsiValueName;
|
|
PSTR AnsiData;
|
|
DWORD OurType;
|
|
DWORD OrgDataSize;
|
|
DWORD AnsiDataSize;
|
|
|
|
__try {
|
|
AnsiValueName = ConvertWtoA (ValueName);
|
|
OrgDataSize = DataSize ? *DataSize : 0;
|
|
AnsiData = NULL;
|
|
|
|
if (Data) {
|
|
|
|
MYASSERT (DataSize);
|
|
AnsiData = AllocTextA (*DataSize + sizeof (CHAR) * 2);
|
|
|
|
} else if (DataSize) {
|
|
|
|
//
|
|
// Data is not specified; allocate a buffer for the
|
|
// proper computation of DataSize.
|
|
//
|
|
|
|
rc = VMMRegQueryValueEx (
|
|
Key,
|
|
AnsiValueName,
|
|
NULL,
|
|
&OurType,
|
|
NULL,
|
|
DataSize
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// *DataSize is a byte count, but increase it to
|
|
// accomodate multisz termination
|
|
//
|
|
|
|
*DataSize += 2;
|
|
AnsiData = AllocTextA (*DataSize);
|
|
|
|
} else {
|
|
//
|
|
// An error usually means the value does not exist...
|
|
//
|
|
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
rc = VMMRegQueryValueEx (
|
|
Key,
|
|
AnsiValueName,
|
|
NULL,
|
|
&OurType,
|
|
AnsiData,
|
|
DataSize
|
|
);
|
|
|
|
if (DataSize) {
|
|
AnsiDataSize = *DataSize;
|
|
} else {
|
|
AnsiDataSize = 0;
|
|
}
|
|
|
|
//
|
|
// Return the type
|
|
//
|
|
|
|
if (Type) {
|
|
*Type = OurType;
|
|
}
|
|
|
|
//
|
|
// Return the sizes
|
|
//
|
|
|
|
if (DataSize) {
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
if (OurType == REG_SZ ||
|
|
OurType == REG_EXPAND_SZ ||
|
|
OurType == REG_MULTI_SZ
|
|
) {
|
|
|
|
AnsiData[*DataSize] = 0;
|
|
AnsiData[*DataSize + 1] = 0;
|
|
|
|
Chars = CharCountInByteRangeA (AnsiData, AnsiDataSize);
|
|
*DataSize = Chars * sizeof (WCHAR);
|
|
}
|
|
|
|
if (Data && *DataSize > OrgDataSize) {
|
|
rc = ERROR_MORE_DATA;
|
|
}
|
|
} else if (rc == ERROR_MORE_DATA) {
|
|
//
|
|
// Get the correct data size
|
|
//
|
|
|
|
pVmmRegQueryValueExW (
|
|
Key,
|
|
ValueName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
DataSize
|
|
);
|
|
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert the return strings
|
|
//
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
if (Data) {
|
|
|
|
MYASSERT (AnsiData);
|
|
|
|
if (OurType == REG_SZ ||
|
|
OurType == REG_EXPAND_SZ ||
|
|
OurType == REG_MULTI_SZ
|
|
) {
|
|
|
|
DirectDbcsToUnicodeN ((PWSTR) Data, AnsiData, AnsiDataSize);
|
|
|
|
} else {
|
|
|
|
CopyMemory (Data, AnsiData, AnsiDataSize);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
FreeConvertedStr (AnsiValueName);
|
|
FreeTextA (AnsiData);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
Win95RegInitA (
|
|
IN PCSTR SystemHiveDir,
|
|
IN BOOL UseClassesRootHive
|
|
)
|
|
{
|
|
LONG rc = ERROR_SUCCESS;
|
|
CHAR SystemDatPath[MAX_MBCHAR_PATH];
|
|
CHAR ConfigKey[MAX_REGISTRY_KEY];
|
|
CHAR ConfigVersion[256];
|
|
HKEY Key;
|
|
DWORD Size;
|
|
|
|
//
|
|
// Save the system hive dir
|
|
//
|
|
|
|
StringCopyA (g_SystemHiveDir, SystemHiveDir);
|
|
AppendWackA (g_SystemHiveDir);
|
|
|
|
//
|
|
// Save the system user.dat
|
|
//
|
|
|
|
StringCopyA (g_SystemUserHive, g_SystemHiveDir);
|
|
StringCatA (g_SystemUserHive, "user.dat");
|
|
|
|
//
|
|
// If NT, set up HKLM and HKU
|
|
//
|
|
|
|
if (g_IsNt) {
|
|
|
|
__try {
|
|
Key = NULL;
|
|
|
|
StringCopyA (SystemDatPath, g_SystemHiveDir);
|
|
StringCatA (SystemDatPath, "system.dat");
|
|
|
|
rc = VMMRegMapPredefKeyToFile (HKEY_LOCAL_MACHINE, SystemDatPath, 0);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "%s could not be loaded", SystemDatPath));
|
|
__leave;
|
|
}
|
|
|
|
if (UseClassesRootHive) {
|
|
|
|
StringCopyA (SystemDatPath, g_SystemHiveDir);
|
|
StringCatA (SystemDatPath, "classes.dat");
|
|
|
|
rc = VMMRegLoadKey (
|
|
HKEY_LOCAL_MACHINE,
|
|
"SOFTWARE$Classes",
|
|
SystemDatPath
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "%s could not be loaded", SystemDatPath));
|
|
__leave;
|
|
}
|
|
|
|
rc = VMMRegOpenKey (
|
|
HKEY_LOCAL_MACHINE,
|
|
"SOFTWARE$Classes",
|
|
&g_ClassesRootKey
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "%s could not be opened", "SOFTWARE$Classes"));
|
|
__leave;
|
|
}
|
|
|
|
g_UseClassesRootHive = TRUE;
|
|
}
|
|
|
|
rc = VMMRegMapPredefKeyToFile (HKEY_USERS, g_SystemUserHive, 0);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "%s could not be loaded", g_SystemUserHive));
|
|
__leave;
|
|
}
|
|
|
|
rc = Win95RegOpenKeyA (
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\control\\IDConfigDB",
|
|
&Key
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "IDConfigDB could not be opened"));
|
|
__leave;
|
|
}
|
|
|
|
Size = sizeof (ConfigVersion);
|
|
|
|
rc = Win95RegQueryValueExA (
|
|
Key,
|
|
"CurrentConfig",
|
|
NULL,
|
|
NULL,
|
|
(PBYTE) ConfigVersion,
|
|
&Size
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "CurrentConfig could not be queried"));
|
|
__leave;
|
|
}
|
|
|
|
StringCopyA (ConfigKey, "Config\\");
|
|
StringCatA (ConfigKey, ConfigVersion);
|
|
|
|
Win95RegCloseKey (Key);
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, ConfigKey, &Key);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "%s could not be opened", ConfigKey));
|
|
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, "Config", &Key);
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "No Win9x hardware configuration keys available"));
|
|
Key = NULL;
|
|
__leave;
|
|
}
|
|
|
|
Size = 256;
|
|
rc = Win95RegEnumKeyExA (
|
|
Key,
|
|
0,
|
|
ConfigVersion,
|
|
&Size,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Win95RegCloseKey (Key);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "Can't enumerate Win9x hardware configuration keys"));
|
|
Key = NULL;
|
|
__leave;
|
|
}
|
|
|
|
StringCopyA (ConfigKey, "Config\\");
|
|
StringCatA (ConfigKey, ConfigVersion);
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, ConfigKey, &Key);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "Can't open enumerated Win9x hardware configuration key"));
|
|
Key = NULL;
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
rc = VMMRegMapPredefKeyToKey (Key, HKEY_CURRENT_CONFIG);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "HKCC could not be mapped"));
|
|
__leave;
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
if (Key) {
|
|
Win95RegCloseKey (Key);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOGA ((LOG_ERROR, "Registry files from previous operating system are damaged or missing"));
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegInitW (
|
|
IN PCWSTR SystemHiveDir,
|
|
IN BOOL UseClassesRootHive
|
|
)
|
|
{
|
|
LONG rc;
|
|
PCSTR AnsiSystemHiveDir;
|
|
|
|
AnsiSystemHiveDir = ConvertWtoA (SystemHiveDir);
|
|
|
|
//
|
|
// Call ANSI version of function
|
|
//
|
|
rc = Win95RegInitA (AnsiSystemHiveDir, UseClassesRootHive);
|
|
|
|
FreeConvertedStr (AnsiSystemHiveDir);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
#define GU_VALID 0x5538
|
|
|
|
LONG
|
|
Win95RegGetFirstUserA (
|
|
PUSERPOSITION Pos,
|
|
PSTR UserNameAnsi
|
|
)
|
|
{
|
|
DWORD rc = ERROR_SUCCESS;
|
|
DWORD Size;
|
|
DWORD Enabled;
|
|
HKEY Key;
|
|
|
|
MYASSERT (UserNameAnsi);
|
|
MYASSERT (Pos);
|
|
|
|
//
|
|
// Initialize profile enumeration state (USERPOSITION)
|
|
//
|
|
ZeroMemory (Pos, sizeof (USERPOSITION));
|
|
Pos->Valid = GU_VALID;
|
|
|
|
//
|
|
// See whether registry supports per-user profiles.
|
|
//
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, "Network\\Logon", &Key);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
Size = sizeof (DWORD);
|
|
|
|
rc = Win95RegQueryValueExA (
|
|
Key,
|
|
"UserProfiles",
|
|
NULL,
|
|
NULL,
|
|
(PBYTE) &Enabled,
|
|
&Size
|
|
);
|
|
|
|
Pos->UseProfile = (rc == ERROR_SUCCESS && Enabled);
|
|
|
|
//
|
|
// Identify the last logged-on user.
|
|
//
|
|
|
|
Size = sizeof (Pos->LastLoggedOnUserName);
|
|
rc = Win95RegQueryValueExA (
|
|
Key,
|
|
"UserName",
|
|
NULL,
|
|
NULL,
|
|
Pos->LastLoggedOnUserName,
|
|
&Size
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
OemToCharA (Pos->LastLoggedOnUserName, Pos->LastLoggedOnUserName);
|
|
|
|
if (!Pos->UseProfile || Win95RegIsValidUser (NULL, Pos->LastLoggedOnUserName)) {
|
|
Pos->LastLoggedOnUserNameExists = TRUE;
|
|
} else {
|
|
Pos->LastLoggedOnUserName[0] = 0;
|
|
}
|
|
}
|
|
|
|
Win95RegCloseKey (Key);
|
|
}
|
|
|
|
//
|
|
// On a common-profile machine, we'll return the last logged-on user name.
|
|
// If no last logged-on user exists, or if the path to this registry value
|
|
// doesn't exist, we'll return "", meaning "no user". Both cases are considered
|
|
// valid.
|
|
//
|
|
|
|
if (!Pos->UseProfile) {
|
|
//
|
|
// Success.
|
|
//
|
|
|
|
_mbssafecpy (UserNameAnsi, Pos->LastLoggedOnUserName, MAX_USER_NAMEA);
|
|
//StringCopyA (UserNameAnsi, Pos->LastLoggedOnUserName);
|
|
|
|
if (UserNameAnsi[0]) {
|
|
Pos->NumPos = 1;
|
|
}
|
|
|
|
Pos->IsLastLoggedOnUserName = Pos->LastLoggedOnUserNameExists;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &Key);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
|
|
Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
|
|
|
|
//
|
|
// This error code change was added by MikeCo. It likely doesn't
|
|
// do anything useful.
|
|
//
|
|
|
|
if (rc == ERROR_FILE_NOT_FOUND) {
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Find the first valid profile
|
|
//
|
|
|
|
Win95RegQueryInfoKeyA (Key, NULL, NULL, NULL, &Pos->NumPos, NULL, NULL,
|
|
NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (Pos->NumPos > 0) {
|
|
|
|
do {
|
|
|
|
Size = MAX_USER_NAMEA;
|
|
|
|
rc = Win95RegEnumKeyExA (
|
|
Key,
|
|
Pos->CurPos,
|
|
UserNameAnsi,
|
|
&Size,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
Pos->NumPos = 0;
|
|
break;
|
|
}
|
|
|
|
if (Win95RegIsValidUser (Key, UserNameAnsi)) {
|
|
|
|
Pos->IsLastLoggedOnUserName = StringIMatch (
|
|
UserNameAnsi,
|
|
Pos->LastLoggedOnUserName
|
|
);
|
|
break;
|
|
|
|
}
|
|
|
|
Pos->CurPos++;
|
|
|
|
} while (Pos->CurPos < Pos->NumPos);
|
|
|
|
if (Pos->CurPos >= Pos->NumPos) {
|
|
Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
|
|
}
|
|
}
|
|
|
|
Win95RegCloseKey (Key);
|
|
}
|
|
|
|
DEBUGMSG_IF ((rc != ERROR_SUCCESS, DBG_ERROR, "WIN95REG: Error getting first user"));
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegGetNextUserA (
|
|
PUSERPOSITION Pos,
|
|
PSTR UserNameAnsi
|
|
)
|
|
{
|
|
DWORD Size;
|
|
LONG rc = ERROR_SUCCESS;
|
|
HKEY Key;
|
|
|
|
MYASSERT (Pos && GU_VALID == Pos->Valid);
|
|
MYASSERT (UserNameAnsi);
|
|
|
|
Pos->IsLastLoggedOnUserName = FALSE;
|
|
|
|
//
|
|
// On a common-profile machine, this function always returns
|
|
// "no more users", since the call to Win95RegGetFirstUserA/W
|
|
// returned the only named user (the logged-on user, if it
|
|
// exists).
|
|
//
|
|
if (!Pos->UseProfile) {
|
|
Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Open key to profile list
|
|
//
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &Key);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
|
|
} else {
|
|
|
|
Pos->CurPos++;
|
|
|
|
while (Pos->CurPos < Pos->NumPos) {
|
|
|
|
//
|
|
// Get first user's key name
|
|
//
|
|
Size = MAX_USER_NAMEA;
|
|
|
|
rc = Win95RegEnumKeyExA(
|
|
Key,
|
|
Pos->CurPos,
|
|
UserNameAnsi,
|
|
&Size,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
Pos->NumPos = 0;
|
|
break;
|
|
}
|
|
|
|
if (Win95RegIsValidUser (Key, UserNameAnsi)) {
|
|
|
|
Pos->IsLastLoggedOnUserName = StringIMatch (
|
|
UserNameAnsi,
|
|
Pos->LastLoggedOnUserName
|
|
);
|
|
break;
|
|
|
|
}
|
|
|
|
Pos->CurPos++;
|
|
}
|
|
|
|
if (Pos->CurPos >= Pos->NumPos) {
|
|
Pos->NumPos = 0; // causes Win95RegHaveUser to return FALSE
|
|
}
|
|
|
|
Win95RegCloseKey (Key);
|
|
}
|
|
|
|
DEBUGMSG_IF ((rc != ERROR_SUCCESS, DBG_ERROR, "WIN95REG: Error getting next user"));
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegGetFirstUserW (
|
|
PUSERPOSITION Pos,
|
|
PWSTR UserName
|
|
)
|
|
{
|
|
LONG rc;
|
|
CHAR AnsiUserName[MAX_USER_NAMEA];
|
|
PSTR p;
|
|
|
|
MYASSERT (Pos && UserName);
|
|
|
|
rc = Win95RegGetFirstUserA (Pos, AnsiUserName);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
if (CharCountA (AnsiUserName) > MAX_USER_NAMEW - 1) {
|
|
p = CharCountToPointerA (AnsiUserName, MAX_USER_NAMEW - 1);
|
|
*p = 0;
|
|
}
|
|
|
|
KnownSizeAtoW (UserName, AnsiUserName);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegGetNextUserW (
|
|
PUSERPOSITION Pos,
|
|
PWSTR UserName
|
|
)
|
|
{
|
|
LONG rc;
|
|
CHAR AnsiUserName[MAX_USER_NAMEA];
|
|
PSTR p;
|
|
|
|
MYASSERT (Pos);
|
|
MYASSERT (UserName);
|
|
|
|
rc = Win95RegGetNextUserA (Pos, AnsiUserName);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
if (CharCountA (AnsiUserName) > MAX_USER_NAMEW - 1) {
|
|
p = CharCountToPointerA (AnsiUserName, MAX_USER_NAMEW - 1);
|
|
*p = 0;
|
|
}
|
|
|
|
KnownSizeAtoW (UserName, AnsiUserName);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pIsCurrentUser (
|
|
IN PCSTR UserNameAnsi
|
|
)
|
|
{
|
|
DWORD subKeys;
|
|
LONG rc;
|
|
HKEY win9xUpgKey;
|
|
CHAR userName[MAX_USER_NAME];
|
|
DWORD userNameSize;
|
|
BOOL result = FALSE;
|
|
HKEY profileKey;
|
|
|
|
rc = Win95RegOpenKeyA (
|
|
HKEY_LOCAL_MACHINE,
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\Win9xUpg",
|
|
&win9xUpgKey
|
|
);
|
|
if (rc != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
userNameSize = ARRAYSIZE(userName);
|
|
|
|
rc = Win95RegQueryValueExA (
|
|
win9xUpgKey,
|
|
"CurrentUser",
|
|
NULL,
|
|
NULL,
|
|
(PBYTE) userName,
|
|
&userNameSize
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
result = StringIMatchA (UserNameAnsi, userName);
|
|
}
|
|
|
|
Win95RegCloseKey (win9xUpgKey);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
Win95RegIsValidUser (
|
|
HKEY ProfileListKey, OPTIONAL
|
|
PSTR UserNameAnsi
|
|
)
|
|
{
|
|
HKEY UserProfileKey;
|
|
BOOL b = FALSE;
|
|
BOOL CloseProfileListKey = FALSE;
|
|
LONG rc;
|
|
|
|
if (!ProfileListKey) {
|
|
rc = Win95RegOpenKeyA (HKEY_LOCAL_MACHINE, S_PROFILELIST_KEYA, &ProfileListKey);
|
|
if (rc != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
CloseProfileListKey = TRUE;
|
|
}
|
|
|
|
//
|
|
// Open the user key
|
|
//
|
|
rc = Win95RegOpenKeyA (
|
|
ProfileListKey,
|
|
UserNameAnsi,
|
|
&UserProfileKey
|
|
);
|
|
|
|
//
|
|
// Does ProfileImagePath exist?
|
|
// (The case where the user logged in but did not retain settings)
|
|
//
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
rc = Win95RegQueryValueExA (
|
|
UserProfileKey,
|
|
S_PROFILEIMAGEPATH,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
//
|
|
// Add other tests here
|
|
//
|
|
|
|
b = TRUE;
|
|
|
|
} else {
|
|
//
|
|
// Need to check if this is the current user. If it is, and we are
|
|
// here, then the user doing the upgrade chose not to save his/her
|
|
// settings.
|
|
//
|
|
|
|
b = pIsCurrentUser (UserNameAnsi);
|
|
}
|
|
|
|
Win95RegCloseKey (UserProfileKey);
|
|
}
|
|
|
|
if (CloseProfileListKey) {
|
|
Win95RegCloseKey (ProfileListKey);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
pCleanupTempUser (
|
|
VOID
|
|
)
|
|
{
|
|
g_UserKey = NULL;
|
|
|
|
if (!g_UnloadLastUser) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Unload temp user hive
|
|
//
|
|
|
|
RegUnLoadKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
S_MIGRATION
|
|
);
|
|
|
|
pSetupRegistryDelnode (
|
|
HKEY_LOCAL_MACHINE,
|
|
S_MIGRATION
|
|
);
|
|
|
|
g_UnloadLastUser = FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
pGetCurrentUserDatPath (
|
|
IN PCSTR BaseDir,
|
|
OUT PSTR PathSpec
|
|
)
|
|
{
|
|
CHAR UserNameAnsi[MAX_USER_NAMEA];
|
|
CHAR FullPath[MAX_MBCHAR_PATH];
|
|
CHAR RegKey[MAX_REGISTRY_KEY];
|
|
HKEY ProfileListKey;
|
|
PCSTR Data;
|
|
DWORD Size;
|
|
|
|
Size = ARRAYSIZE(UserNameAnsi);
|
|
|
|
if (!GetUserName (UserNameAnsi, &Size)) {
|
|
*UserNameAnsi = 0;
|
|
}
|
|
|
|
*FullPath = 0;
|
|
|
|
if (*UserNameAnsi) {
|
|
//
|
|
// Logged-in user case on a per-user profile machine. Look in
|
|
// Windows\CV\ProfileList\<user> for a ProfileImagePath value.
|
|
//
|
|
|
|
wsprintfA (RegKey, "%s\\%s", S_HKLM_PROFILELIST_KEY, UserNameAnsi);
|
|
|
|
ProfileListKey = OpenRegKeyStrA (RegKey);
|
|
if (!ProfileListKey) {
|
|
//
|
|
// No profile list!
|
|
//
|
|
|
|
DEBUGMSG ((DBG_WHOOPS, "pGetCurrentUserDatPath: No profile list found"));
|
|
} else {
|
|
//
|
|
// Get the ProfileImagePath value
|
|
//
|
|
|
|
Data = GetRegValueDataOfTypeA (ProfileListKey, S_PROFILEIMAGEPATH, REG_SZ);
|
|
|
|
if (Data) {
|
|
_mbssafecpy (FullPath, Data, sizeof (FullPath));
|
|
MemFree (g_hHeap, 0, Data);
|
|
}
|
|
ELSE_DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"pGetCurrentUserDatPath: Profile for %s does not have a ProfileImagePath value",
|
|
UserNameAnsi
|
|
));
|
|
|
|
CloseRegKey (ProfileListKey);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Default user case. Prepare %windir%\user.dat.
|
|
//
|
|
|
|
StringCopyA (FullPath, BaseDir);
|
|
}
|
|
|
|
//
|
|
// Append user.dat
|
|
//
|
|
|
|
if (*FullPath) {
|
|
StringCopyA (AppendWackA (FullPath), "user.dat");
|
|
}
|
|
|
|
//
|
|
// Convert to short name
|
|
//
|
|
|
|
if (!(*FullPath) || !OurGetShortPathName (FullPath, PathSpec, MAX_TCHAR_PATH)) {
|
|
_mbssafecpy (PathSpec, FullPath, MAX_MBCHAR_PATH);
|
|
}
|
|
}
|
|
|
|
|
|
PCSTR
|
|
pLoadUserDat (
|
|
IN PCSTR BaseDir,
|
|
IN PCSTR UserDatSpec
|
|
)
|
|
{
|
|
CHAR ShortPath[MAX_MBCHAR_PATH];
|
|
CHAR CurrentUserDatPath[MAX_MBCHAR_PATH];
|
|
DWORD rc;
|
|
|
|
//
|
|
// Unload last user if necessary
|
|
//
|
|
|
|
pCleanupTempUser();
|
|
|
|
//
|
|
// Determine if it is necessary to load UserDatSpec. If not,
|
|
// return HKEY_CURRENT_USER. Otherwise, load the key into
|
|
// HKLM\Migration, then open it.
|
|
//
|
|
|
|
//
|
|
// Always use the short path name
|
|
//
|
|
|
|
if (!OurGetShortPathName (UserDatSpec, ShortPath, sizeof (ShortPath))) {
|
|
DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"pLoadUserDat: Could not get short name for %s",
|
|
UserDatSpec
|
|
));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Per-user profiles are enabled. Determine if UserDatSpec
|
|
// has already been mapped to HKCU.
|
|
//
|
|
|
|
pGetCurrentUserDatPath (BaseDir, CurrentUserDatPath);
|
|
|
|
if (StringIMatch (ShortPath, CurrentUserDatPath)) {
|
|
//
|
|
// Yes -- return HKEY_CURRENT_USER
|
|
//
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "%s is the current user's hive.", CurrentUserDatPath));
|
|
return "HKCU";
|
|
}
|
|
|
|
//
|
|
// No -- load user.dat into HKLM\Migration
|
|
//
|
|
|
|
DEBUGMSG ((DBG_WIN95REG, "RegLoadKey: %s", ShortPath));
|
|
|
|
rc = RegLoadKey (
|
|
HKEY_LOCAL_MACHINE,
|
|
S_MIGRATION,
|
|
ShortPath
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
|
|
SetLastError (rc);
|
|
|
|
DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"pLoadUserDat: Could not load %s into HKLM\\Migration. Original Path: %s",
|
|
ShortPath,
|
|
UserDatSpec
|
|
));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
g_UnloadLastUser = TRUE;
|
|
|
|
return S_HKLM_MIGRATION;
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegSetCurrentUserA (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
OUT PSTR UserDatOut OPTIONAL
|
|
)
|
|
{
|
|
return pWin95RegSetCurrentUserCommonA (Pos, SystemHiveDir, UserDatOut, NULL);
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegSetCurrentUserW (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCWSTR SystemHiveDir, OPTIONAL
|
|
OUT PWSTR UserDatOut OPTIONAL
|
|
)
|
|
{
|
|
return pWin95RegSetCurrentUserCommonW (Pos, SystemHiveDir, UserDatOut, NULL);
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegSetCurrentUserNtA (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR UserDat
|
|
)
|
|
{
|
|
return pWin95RegSetCurrentUserCommonA (Pos, NULL, NULL, UserDat);
|
|
}
|
|
|
|
|
|
LONG
|
|
Win95RegSetCurrentUserNtW (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCWSTR UserDat
|
|
)
|
|
{
|
|
return pWin95RegSetCurrentUserCommonW (Pos, NULL, NULL, UserDat);
|
|
}
|
|
|
|
|
|
LONG
|
|
pWin95RegSetCurrentUserCommonW (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCWSTR SystemHiveDir, OPTIONAL
|
|
OUT PWSTR UserDatOut, OPTIONAL
|
|
IN PCWSTR UserDat OPTIONAL
|
|
)
|
|
{
|
|
LONG rc;
|
|
PCSTR AnsiSystemHiveDir;
|
|
PCSTR AnsiUserDat;
|
|
CHAR AnsiUserDatOut[MAX_MBCHAR_PATH];
|
|
PSTR p;
|
|
|
|
//
|
|
// Convert args to ANSI
|
|
//
|
|
|
|
if (UserDat) {
|
|
AnsiUserDat = ConvertWtoA (UserDat);
|
|
} else {
|
|
AnsiUserDat = NULL;
|
|
}
|
|
|
|
if (SystemHiveDir) {
|
|
AnsiSystemHiveDir = ConvertWtoA (UserDat);
|
|
} else {
|
|
AnsiSystemHiveDir = NULL;
|
|
}
|
|
|
|
//
|
|
// Call ANSI function
|
|
//
|
|
rc = pWin95RegSetCurrentUserCommonA (Pos, AnsiSystemHiveDir, AnsiUserDatOut, AnsiUserDat);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Convert OUT arg
|
|
//
|
|
|
|
if (UserDatOut) {
|
|
if (CharCountA (AnsiUserDatOut) > MAX_WCHAR_PATH - 1) {
|
|
p = CharCountToPointerA (AnsiUserDatOut, MAX_USER_NAMEW - 1);
|
|
*p = 0;
|
|
}
|
|
|
|
KnownSizeAtoW (UserDatOut, AnsiUserDatOut);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
FindAndLoadHive (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
IN PCSTR UserDatFromCaller, OPTIONAL
|
|
OUT PSTR UserDatToCaller, OPTIONAL
|
|
IN BOOL MapTheHive
|
|
)
|
|
{
|
|
CHAR RegistryUserDatPath[MAX_MBCHAR_PATH];
|
|
CHAR ActualUserDatPath[MAX_MBCHAR_PATH];
|
|
CHAR UserNameAnsi[MAX_USER_NAMEA];
|
|
DWORD Size;
|
|
HKEY ProfileListKey;
|
|
HKEY UserKey = NULL;
|
|
CHAR WinDir[MAX_MBCHAR_PATH];
|
|
DWORD rc = ERROR_SUCCESS;
|
|
|
|
//
|
|
// 1. Determine the path to ActualUserDatPath
|
|
//
|
|
// 2. If user.dat is from registry and caller supplied alternate
|
|
// %windir%, replace the %windir% with SystemHiveDir
|
|
//
|
|
// 3. If caller wants final path, copy it to their buffer
|
|
//
|
|
// 4. On NT, map the hive as HKCU. On 95, load the key and open
|
|
// a reg handle.
|
|
//
|
|
|
|
|
|
if (UserDatFromCaller) {
|
|
//
|
|
// Caller says where to find user.dat
|
|
//
|
|
|
|
StringCopyA (ActualUserDatPath, UserDatFromCaller);
|
|
|
|
} else {
|
|
//
|
|
// System.dat says us where to find user.dat
|
|
//
|
|
|
|
rc = Win95RegOpenKeyA (
|
|
HKEY_LOCAL_MACHINE,
|
|
S_PROFILELIST_KEYA,
|
|
&ProfileListKey
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Get name of user
|
|
//
|
|
|
|
Size = ARRAYSIZE(UserNameAnsi);
|
|
rc = Win95RegEnumKeyExA (
|
|
ProfileListKey,
|
|
(DWORD) Pos->CurPos,
|
|
UserNameAnsi,
|
|
&Size,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
//
|
|
// Open key to user
|
|
//
|
|
|
|
rc = Win95RegOpenKeyA (
|
|
ProfileListKey,
|
|
UserNameAnsi,
|
|
&UserKey
|
|
);
|
|
}
|
|
|
|
Win95RegCloseKey (ProfileListKey);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Get user's profile path from registry. Optionally relocate it, if user
|
|
// supplied a replacement for WinDir.
|
|
//
|
|
|
|
Size = sizeof (RegistryUserDatPath);
|
|
rc = Win95RegQueryValueExA (
|
|
UserKey,
|
|
S_PROFILEIMAGEPATH,
|
|
NULL,
|
|
NULL,
|
|
RegistryUserDatPath,
|
|
&Size
|
|
);
|
|
|
|
Win95RegCloseKey (UserKey);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
if (!pIsCurrentUser (UserNameAnsi)) {
|
|
return rc;
|
|
}
|
|
|
|
return pSetDefaultUserHelper (
|
|
Pos,
|
|
SystemHiveDir,
|
|
UserDatFromCaller,
|
|
UserDatToCaller
|
|
);
|
|
}
|
|
|
|
//
|
|
// Substitute %WinDir% in path that registry supplied?
|
|
//
|
|
|
|
if (SystemHiveDir && *SystemHiveDir) {
|
|
//
|
|
// Munge profile path
|
|
//
|
|
|
|
rc = pReplaceWinDirInPath (
|
|
ActualUserDatPath,
|
|
RegistryUserDatPath,
|
|
SystemHiveDir
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
return rc;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Don't munge. Leave as is (correct behavior on Win95 with local profiles)
|
|
//
|
|
|
|
StringCopyA (ActualUserDatPath, RegistryUserDatPath);
|
|
}
|
|
|
|
//
|
|
// Add name of hive file, "\\user.dat"
|
|
//
|
|
|
|
StringCopyA (AppendWackA (ActualUserDatPath), "user.dat");
|
|
|
|
}
|
|
|
|
//
|
|
// Send path to caller if necessary
|
|
//
|
|
|
|
if (UserDatToCaller) {
|
|
_mbssafecpy (UserDatToCaller, ActualUserDatPath, MAX_MBCHAR_PATH);
|
|
}
|
|
|
|
if (MapTheHive) {
|
|
if (g_IsNt) {
|
|
|
|
//
|
|
// WinNT: Associate filename with HKCU
|
|
//
|
|
|
|
rc = VMMRegMapPredefKeyToFile (
|
|
HKEY_CURRENT_USER,
|
|
ActualUserDatPath,
|
|
0
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Win9x: Load HKLM\Migration
|
|
//
|
|
|
|
if (!SystemHiveDir) {
|
|
if (!GetWindowsDirectory (WinDir, sizeof (WinDir))) {
|
|
rc = GetLastError ();
|
|
}
|
|
}
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
g_UserKey = pLoadUserDat (
|
|
SystemHiveDir ? SystemHiveDir : WinDir,
|
|
ActualUserDatPath
|
|
);
|
|
|
|
if (!g_UserKey) {
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
DWORD
|
|
pSetDefaultUserHelper (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
IN PCSTR UserDatFromCaller, OPTIONAL
|
|
OUT PSTR UserDatToCaller OPTIONAL
|
|
)
|
|
{
|
|
CHAR ActualUserDatPath[MAX_MBCHAR_PATH];
|
|
DWORD rc = ERROR_SUCCESS;
|
|
HKEY DefaultKey;
|
|
|
|
//
|
|
// Determine path to default user's user.dat
|
|
//
|
|
|
|
if (UserDatFromCaller) {
|
|
|
|
//
|
|
// Caller-supplied user.dat path
|
|
//
|
|
|
|
StringCopyA (ActualUserDatPath, UserDatFromCaller);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Use the string received from Init
|
|
//
|
|
|
|
StringCopyA (ActualUserDatPath, g_SystemUserHive);
|
|
}
|
|
|
|
//
|
|
// NT: Map the user via VMMREG
|
|
// 9x: Load & open the user hive
|
|
//
|
|
|
|
if (g_IsNt) {
|
|
|
|
//
|
|
// NT: Map .Default into HKCU.
|
|
//
|
|
|
|
//
|
|
// Reload HKEY_USERS
|
|
//
|
|
|
|
rc = VMMRegMapPredefKeyToFile (
|
|
HKEY_USERS,
|
|
ActualUserDatPath,
|
|
0
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError(rc);
|
|
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"pWin95RegSetCurrentUserCommonW: Cannot reload HKU from %s",
|
|
ActualUserDatPath
|
|
));
|
|
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Get handle to default profile
|
|
//
|
|
|
|
rc = Win95RegOpenKeyA (
|
|
HKEY_USERS,
|
|
".Default",
|
|
&DefaultKey
|
|
);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError(rc);
|
|
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"pWin95RegSetCurrentUserCommonW: Expected to find key HKU\\.Default in %s",
|
|
ActualUserDatPath
|
|
));
|
|
|
|
return rc;
|
|
}
|
|
|
|
//
|
|
// Associate default profile with HKEY_CURRENT_USER
|
|
//
|
|
|
|
rc = VMMRegMapPredefKeyToKey (
|
|
DefaultKey,
|
|
HKEY_CURRENT_USER
|
|
);
|
|
|
|
Win95RegCloseKey (DefaultKey);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
SetLastError(rc);
|
|
|
|
DEBUGMSG((
|
|
DBG_ERROR,
|
|
"pWin95RegSetCurrentUserCommonW: Cannot map HKU\\.Default to HKCU from %s",
|
|
ActualUserDatPath
|
|
));
|
|
|
|
return rc;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Win9x: Return HKU\.Default
|
|
//
|
|
|
|
g_UserKey = S_HKU_DEFAULT;
|
|
}
|
|
|
|
//
|
|
// Send path to caller if necessary
|
|
//
|
|
|
|
if (UserDatToCaller) {
|
|
_mbssafecpy (UserDatToCaller, ActualUserDatPath, MAX_MBCHAR_PATH);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
pWin95RegSetCurrentUserCommonA (
|
|
IN OUT PUSERPOSITION Pos,
|
|
IN PCSTR SystemHiveDir, OPTIONAL
|
|
OUT PSTR UserDatOut, OPTIONAL
|
|
IN PCSTR UserDat OPTIONAL
|
|
)
|
|
{
|
|
|
|
MYASSERT (!Pos || GU_VALID == Pos->Valid);
|
|
|
|
//
|
|
// Process per-user user.dat if
|
|
// (A) caller does not want default user
|
|
// (B) machine has per-user profiles
|
|
// (C) current user position is valid
|
|
//
|
|
|
|
if (Pos && Pos->UseProfile && Pos->CurPos < Pos->NumPos) {
|
|
return (LONG) FindAndLoadHive (
|
|
Pos,
|
|
SystemHiveDir,
|
|
UserDat,
|
|
UserDatOut,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
//
|
|
// For all other cases, use a default profile
|
|
//
|
|
|
|
return (LONG) pSetDefaultUserHelper (
|
|
Pos,
|
|
SystemHiveDir,
|
|
UserDat,
|
|
UserDatOut
|
|
);
|
|
|
|
}
|
|
|
|
|
|
LONG
|
|
pReplaceWinDirInPath (
|
|
IN PSTR ProfilePathMunged,
|
|
IN PCSTR ProfilePath,
|
|
IN PCSTR NewWinDir
|
|
)
|
|
{
|
|
PSTR EndOfWinDir;
|
|
|
|
//
|
|
// Test assumptions about profile dir. Expect x:\windir\...
|
|
//
|
|
if (!isalpha(ProfilePath[0]) ||
|
|
ProfilePath[1] != ':' ||
|
|
ProfilePath[2] != '\\'
|
|
) {
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
//
|
|
// Find the second slash (the first is at ptr+2)
|
|
//
|
|
EndOfWinDir = _mbschr (&ProfilePath[3], '\\');
|
|
if (!EndOfWinDir) {
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
//
|
|
// Make munged dir
|
|
//
|
|
StringCopyA (ProfilePathMunged, NewWinDir);
|
|
StringCopyA (AppendPathWack (ProfilePathMunged), _mbsinc (EndOfWinDir));
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|