2112 lines
52 KiB
C
2112 lines
52 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
merge.c
|
|
|
|
Abstract:
|
|
|
|
Registry merge code
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 17-Feb-1997
|
|
|
|
Revision History:
|
|
|
|
jimschm 23-Sep-1998 String mapping mechanism
|
|
jimschm 24-Mar-1998 Added more complex hkcr processing
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "mergep.h"
|
|
|
|
static PCTSTR g_InfFileName;
|
|
|
|
BOOL g_ProcessRenameTable = FALSE;
|
|
DWORD g_ProgressBarCounter;
|
|
HKEY g_DuHandle;
|
|
|
|
BOOL
|
|
pForceCopy (
|
|
HINF InfFile
|
|
);
|
|
|
|
BOOL
|
|
pForceCopyFromMemDb (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pCreateRenameTable (
|
|
IN HINF InfFile,
|
|
OUT PVOID *RenameTablePtr
|
|
);
|
|
|
|
BOOL
|
|
pProcessRenameTable (
|
|
IN PVOID RenameTable
|
|
);
|
|
|
|
BOOL
|
|
pSpecialConversion (
|
|
IN HINF InfFile,
|
|
IN PCTSTR User,
|
|
IN PVOID RenameTable
|
|
);
|
|
|
|
BOOL
|
|
pProcessSuppressList (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
);
|
|
|
|
BOOL
|
|
pProcessHardwareSuppressList (
|
|
IN HINF InfFile
|
|
);
|
|
|
|
BOOL
|
|
pSuppressNTDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
);
|
|
|
|
BOOL
|
|
pDontCombineWithDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
);
|
|
|
|
BOOL
|
|
pForceNTDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
);
|
|
|
|
BOOL
|
|
pForceNTDefaultsHack (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
);
|
|
|
|
BOOL
|
|
pMergeWin95WithUser (
|
|
IN PVOID RenameTable
|
|
);
|
|
|
|
BOOL
|
|
pSpecialConversionNT (
|
|
IN HINF InfFile,
|
|
IN PCTSTR User,
|
|
IN BOOL PerUser
|
|
);
|
|
|
|
BOOL
|
|
pMergeNTDefaultsWithUser (
|
|
IN HINF InfFile
|
|
);
|
|
|
|
BOOL
|
|
pCopyWin95ToSystem (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pMergeWin95WithSystem (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pDeleteAfterMigration (
|
|
IN HINF InfFile
|
|
);
|
|
|
|
FILTERRETURN
|
|
SuppressFilter95 (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
);
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
POOLHANDLE g_TempPool;
|
|
POOLHANDLE g_RenamePool;
|
|
PMAPSTRUCT g_CompleteMatchMap;
|
|
PMAPSTRUCT g_SubStringMap;
|
|
|
|
BOOL
|
|
WINAPI
|
|
Merge_Entry (
|
|
IN HINSTANCE hinstDLL,
|
|
IN DWORD dwReason,
|
|
IN PVOID lpv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DllMain is called after the C runtime is initialized, and its purpose
|
|
is to initialize the globals for this process.
|
|
|
|
Arguments:
|
|
|
|
hinstDLL - (OS-supplied) Instance handle for the DLL
|
|
dwReason - (OS-supplied) Type of initialization or termination
|
|
lpv - (OS-supplied) Unused
|
|
|
|
Return Value:
|
|
|
|
TRUE because DLL always initializes properly.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
if(!pSetupInitializeUtils()) {
|
|
return FALSE;
|
|
}
|
|
g_CompleteMatchMap = CreateStringMapping();
|
|
g_SubStringMap = CreateStringMapping();
|
|
break;
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
DestroyStringMapping (g_CompleteMatchMap);
|
|
DestroyStringMapping (g_SubStringMap);
|
|
pSetupUninitializeUtils();
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MergeRegistry (
|
|
IN PCTSTR FileName,
|
|
IN PCTSTR User
|
|
)
|
|
{
|
|
HINF hInf; // handle to the INF being processed
|
|
BOOL b = FALSE; // Return value
|
|
PVOID RenameTable = NULL;
|
|
BOOL LogonAccount = FALSE;
|
|
BOOL DefaultUserAccount = FALSE;
|
|
|
|
g_ProgressBarCounter = 0;
|
|
|
|
//
|
|
// Open the INF
|
|
//
|
|
|
|
g_InfFileName = FileName;
|
|
hInf = InfOpenInfFile (FileName);
|
|
|
|
if (hInf == INVALID_HANDLE_VALUE) {
|
|
LOG ((LOG_ERROR, "MergeRegistry: SetupOpenInfFile failed for %s", FileName));
|
|
return FALSE;
|
|
}
|
|
|
|
g_TempPool = PoolMemInitNamedPool ("Merge: temp pool");
|
|
g_RenamePool = PoolMemInitNamedPool ("Merge: Rename pool");
|
|
|
|
if (!g_TempPool || !g_RenamePool) {
|
|
DEBUGMSG ((DBG_ERROR, "MergeRegistry: Can't init pool"));
|
|
goto c0;
|
|
}
|
|
|
|
PoolMemSetMinimumGrowthSize (g_TempPool, 16384);
|
|
|
|
if (User) {
|
|
SetCurrentUserW (g_FixedUserName);
|
|
}
|
|
|
|
//
|
|
// Perform forced copy of Win95 registry, build rename table,
|
|
// execute registry value conversions, convert types, and mark
|
|
// specified keys as suppressed.
|
|
//
|
|
|
|
if (!pForceCopy (hInf)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!User) {
|
|
if (!pForceCopyFromMemDb ()) {
|
|
goto c0;
|
|
}
|
|
}
|
|
|
|
if (!pCreateRenameTable (hInf, &RenameTable)) {
|
|
goto c0;
|
|
}
|
|
|
|
//
|
|
// Identify the logon account or default user account
|
|
//
|
|
|
|
if (User) {
|
|
if (*User == 0 || StringIMatch (User, S_DOT_DEFAULT)) {
|
|
|
|
DEBUGMSG ((DBG_NAUSEA, "The logon user account is indicated by user name '%s'", User));
|
|
LogonAccount = TRUE;
|
|
|
|
} else if (StringIMatch (User, S_DEFAULT_USER)) {
|
|
|
|
DEBUGMSG ((DBG_NAUSEA, "The default user account template is indicated by user name '%s'", User));
|
|
DefaultUserAccount = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare flags for registry merging
|
|
//
|
|
|
|
if (!pProcessSuppressList (hInf, S_MERGE_WIN9X_SUPPRESS)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (User) {
|
|
//
|
|
// These functions read usermig.inf and set flags
|
|
// for the keys, key trees or values, as specified in
|
|
// the INF.
|
|
//
|
|
|
|
if (!pSuppressNTDefaults (hInf, S_MERGE_WINNT_SUPPRESS)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pDontCombineWithDefaults (hInf, S_MERGE_DONT_COMBINE_WITH_DEFAULT)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pForceNTDefaults (hInf, S_MERGE_FORCE_NT_DEFAULTS)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (LogonAccount) {
|
|
if (!pProcessSuppressList (hInf, S_MERGE_WIN9X_SUPPRESS_LU)) {
|
|
goto c0;
|
|
}
|
|
}
|
|
|
|
if (DefaultUserAccount) {
|
|
if (!pProcessSuppressList (hInf, S_MERGE_WIN9X_SUPPRESS_DU)) {
|
|
goto c0;
|
|
}
|
|
}
|
|
|
|
g_DuHandle = OpenRegKeyStr (L"hklm\\" S_MAPPED_DEFAULT_USER_KEY);
|
|
|
|
} else {
|
|
if (!pForceNTDefaults (hInf, S_MERGE_FORCE_NT_DEFAULTS)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pProcessHardwareSuppressList (hInf)) {
|
|
goto c0;
|
|
}
|
|
}
|
|
|
|
if (!pSpecialConversion (hInf, User, RenameTable)) {
|
|
goto c0;
|
|
}
|
|
|
|
//
|
|
// Perform merge
|
|
//
|
|
|
|
if (User) {
|
|
// User merge
|
|
if (!pMergeWin95WithUser (RenameTable)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pSpecialConversionNT (hInf, User, TRUE)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!LogonAccount && !DefaultUserAccount) {
|
|
// Non-default user, not logon prompt account
|
|
if (!pMergeNTDefaultsWithUser (hInf)) {
|
|
goto c0;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Workstation merge
|
|
if (!pCopyWin95ToSystem()) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pForceNTDefaultsHack (hInf, S_MERGE_FORCE_NT_DEFAULTS)) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!pMergeWin95WithSystem()) {
|
|
goto c0;
|
|
}
|
|
|
|
if (!CopyHardwareProfiles (hInf)) {
|
|
goto c0;
|
|
}
|
|
TickProgressBar ();
|
|
|
|
if (!pSpecialConversionNT (hInf, NULL, FALSE)) {
|
|
goto c0;
|
|
}
|
|
TickProgressBar ();
|
|
}
|
|
|
|
g_ProcessRenameTable = TRUE;
|
|
|
|
b = pProcessRenameTable (RenameTable);
|
|
TickProgressBar ();
|
|
|
|
g_ProcessRenameTable = FALSE;
|
|
|
|
//
|
|
// Once we are done with the complete registry merge, process the special section
|
|
// [Delete After Migration]
|
|
//
|
|
|
|
if (!pDeleteAfterMigration (hInf)) {
|
|
LOG((LOG_ERROR,"Registry Merge: Delete After Migration failed."));
|
|
goto c0;
|
|
}
|
|
|
|
c0:
|
|
if (RenameTable) {
|
|
pSetupStringTableDestroy (RenameTable);
|
|
}
|
|
|
|
if (User) {
|
|
SetCurrentUserW (NULL);
|
|
}
|
|
|
|
if (g_TempPool) {
|
|
PoolMemDestroyPool (g_TempPool);
|
|
}
|
|
if (g_RenamePool) {
|
|
PoolMemDestroyPool (g_RenamePool);
|
|
}
|
|
|
|
if (g_DuHandle) {
|
|
CloseRegKey (g_DuHandle);
|
|
g_DuHandle = NULL;
|
|
}
|
|
|
|
InfCloseInfFile (hInf);
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
PTSTR
|
|
pGetStringFromObjectData (
|
|
IN CPDATAOBJECT ObPtr
|
|
)
|
|
{
|
|
PTSTR p;
|
|
PTSTR end;
|
|
|
|
//
|
|
// Value type has to be a registry object
|
|
//
|
|
|
|
if (!DoesObjectHaveValue (ObPtr) ||
|
|
!IsRegistryTypeSpecified (ObPtr)
|
|
) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ObPtr->Type == REG_DWORD) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ObPtr->Value.Size & 1) {
|
|
return NULL;
|
|
}
|
|
|
|
p = (PTSTR) ObPtr->Value.Buffer;
|
|
end = (PTSTR) ((PBYTE) p + ObPtr->Value.Size);
|
|
|
|
if ((end - p) >= MAX_PATH) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ObPtr->Type == REG_SZ || ObPtr->Type == REG_EXPAND_SZ) {
|
|
return p;
|
|
}
|
|
|
|
//
|
|
// For REG_NONE and REG_BINARY, give it a try by looking for a terminated string
|
|
//
|
|
|
|
if (*(end - 1)) {
|
|
return NULL;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetObjectStringFlag (
|
|
IN PCTSTR ObjectStr,
|
|
IN DWORD Flag,
|
|
IN DWORD RemoveFlag
|
|
)
|
|
{
|
|
DWORD Val;
|
|
|
|
if (!MemDbGetValue (ObjectStr, &Val)) {
|
|
Val = 0;
|
|
}
|
|
|
|
if (Val & RemoveFlag) {
|
|
if (Val & RemoveFlag & (~Flag)) {
|
|
DEBUGMSG ((DBG_WARNING, "SetObjectStringFlag: Removing flag %x from val %x in %s",
|
|
Val & RemoveFlag, Val, ObjectStr));
|
|
Val = Val & (~RemoveFlag);
|
|
}
|
|
}
|
|
|
|
Val |= Flag;
|
|
return MemDbSetValue (ObjectStr, Val);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetObjectStructFlag (
|
|
IN CPDATAOBJECT ObPtr,
|
|
DWORD Flag,
|
|
DWORD RemoveFlag
|
|
)
|
|
{
|
|
TCHAR EncodedObject[MAX_ENCODED_RULE];
|
|
|
|
CreateObjectString (ObPtr, EncodedObject);
|
|
return SetObjectStringFlag (EncodedObject, Flag, RemoveFlag);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateRenamedObjectStruct (
|
|
IN PVOID RenameTable,
|
|
IN PDATAOBJECT InObPtr,
|
|
OUT PDATAOBJECT OutObPtr
|
|
)
|
|
|
|
// returns TRUE when OutObPtr is different than InObPtr
|
|
|
|
{
|
|
LONG rc;
|
|
PCTSTR NewPtr;
|
|
PTSTR p;
|
|
PCTSTR Tail;
|
|
PCTSTR RealValueName;
|
|
TCHAR EncodedObject[MAX_ENCODED_RULE];
|
|
TCHAR CopyOfEncodedObject[MAX_ENCODED_RULE];
|
|
PTSTR NewEncodedObject;
|
|
BOOL b = FALSE;
|
|
|
|
ZeroMemory (OutObPtr, sizeof (DATAOBJECT));
|
|
|
|
if (InObPtr->KeyPtr) {
|
|
// Look for HKR\sub\key
|
|
InObPtr->ObjectType &= ~(OT_TREE);
|
|
RealValueName = InObPtr->ValueName;
|
|
InObPtr->ValueName = NULL;
|
|
|
|
CreateObjectString (InObPtr, EncodedObject);
|
|
StringCopy (CopyOfEncodedObject, EncodedObject);
|
|
|
|
InObPtr->ValueName = RealValueName;
|
|
|
|
rc = pSetupStringTableLookUpStringEx (RenameTable,
|
|
EncodedObject,
|
|
STRTAB_CASE_INSENSITIVE,
|
|
(PBYTE) &NewPtr,
|
|
sizeof (NewPtr)
|
|
);
|
|
if (rc != -1) {
|
|
CreateObjectStruct (NewPtr, OutObPtr, WINNTOBJECT);
|
|
b = TRUE;
|
|
} else if (*EncodedObject) {
|
|
// Look for HKR\sub\key\*, HKR\sub\* and HKR\*
|
|
p = GetEndOfString (EncodedObject);
|
|
do {
|
|
StringCopy (p, TEXT("\\*"));
|
|
|
|
rc = pSetupStringTableLookUpStringEx (RenameTable,
|
|
EncodedObject,
|
|
STRTAB_CASE_INSENSITIVE,
|
|
(PBYTE) &NewPtr,
|
|
sizeof (NewPtr)
|
|
);
|
|
if (rc != -1) {
|
|
Tail = CopyOfEncodedObject + (p - EncodedObject);
|
|
NewEncodedObject = JoinPaths (NewPtr, Tail);
|
|
CreateObjectStruct (NewEncodedObject, OutObPtr, WINNTOBJECT);
|
|
FreePathString (NewEncodedObject);
|
|
b = TRUE;
|
|
break;
|
|
}
|
|
|
|
do {
|
|
// _tcsdec is fixed in strings.h
|
|
p = _tcsdec2 (EncodedObject, p);
|
|
} while (p && _tcsnextc (p) != TEXT('\\'));
|
|
} while (p);
|
|
}
|
|
}
|
|
|
|
if (InObPtr->ValueName) {
|
|
if (InObPtr->KeyPtr) {
|
|
// Look for HKR\sub\key\[value]
|
|
CreateObjectString (InObPtr, EncodedObject);
|
|
|
|
rc = pSetupStringTableLookUpStringEx (RenameTable,
|
|
EncodedObject,
|
|
STRTAB_CASE_INSENSITIVE,
|
|
(PBYTE) &NewPtr,
|
|
sizeof (NewPtr)
|
|
);
|
|
if (rc != -1) {
|
|
CreateObjectStruct (NewPtr, OutObPtr, WINNTOBJECT);
|
|
b = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!b) {
|
|
// If rename not found, copy in object to out object
|
|
CopyMemory (OutObPtr, InObPtr, sizeof (DATAOBJECT));
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CreateRenamedObjectString (
|
|
IN PVOID RenameTable,
|
|
IN PCTSTR InObStr,
|
|
OUT PTSTR OutObStr
|
|
)
|
|
{
|
|
DATAOBJECT InObject, OutObject;
|
|
BOOL b;
|
|
|
|
if (!CreateObjectStruct (InObStr, &InObject, WIN95OBJECT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = CreateRenamedObjectStruct (RenameTable, &InObject, &OutObject);
|
|
|
|
CreateObjectString (&OutObject, OutObStr);
|
|
|
|
FreeObjectStruct (&InObject);
|
|
if (b) {
|
|
FreeObjectStruct (&OutObject);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pForceCopy (
|
|
HINF InfFile
|
|
)
|
|
{
|
|
INFCONTEXT ic;
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
TCHAR DestObjectStr[MAX_ENCODED_RULE];
|
|
DATAOBJECT SrcObject, DestObject, DupObject;
|
|
BOOL b = TRUE;
|
|
FILTERRETURN fr;
|
|
|
|
//
|
|
// Look in INF for [ForceCopy] section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, S_MERGE_FORCECOPY, NULL, &ic)) {
|
|
//
|
|
// For each line in this section, get the encoded object in
|
|
// field 0 (the source) and copy it to the encoded object in
|
|
// field 1 (the destination).
|
|
//
|
|
do {
|
|
*DestObjectStr = 0;
|
|
if (SetupGetStringField (&ic, 0, SrcObjectStr, MAX_ENCODED_RULE, NULL) &&
|
|
SetupGetStringField (&ic, 1, DestObjectStr, MAX_ENCODED_RULE, NULL)
|
|
) {
|
|
if (!(*DestObjectStr)) {
|
|
StringCopy (DestObjectStr, SrcObjectStr);
|
|
}
|
|
|
|
if (!CreateObjectStruct (SrcObjectStr, &SrcObject, WIN95OBJECT)) {
|
|
DEBUGMSG ((DBG_WARNING, "pForceCopy: Source object invalid (Section line %u of %s)",
|
|
ic.Line, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
if (!CreateObjectStruct (DestObjectStr, &DestObject, WINNTOBJECT)) {
|
|
DEBUGMSG ((DBG_WARNING, "pForceCopy: Destination object invalid (Section line %u of %s)",
|
|
ic.Line, g_InfFileName));
|
|
FreeObjectStruct (&SrcObject);
|
|
continue;
|
|
}
|
|
|
|
if (b = DuplicateObjectStruct (&DupObject, &SrcObject)) {
|
|
if (b = CombineObjectStructs (&DupObject, &DestObject)) {
|
|
//
|
|
// Copy source to dest
|
|
//
|
|
|
|
fr = CopyObject (&SrcObject, &DupObject, NULL, NULL);
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Force Copy: CopyObject failed for %s=%s in %s", SrcObjectStr, DestObjectStr, g_InfFileName));
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
FreeObjectStruct (&DupObject);
|
|
}
|
|
|
|
FreeObjectStruct (&SrcObject);
|
|
FreeObjectStruct (&DestObject);
|
|
} else {
|
|
LOG ((LOG_ERROR, "Force Copy: syntax error in line %u of section %s in %s",
|
|
ic.Line, S_MERGE_FORCECOPY, g_InfFileName));
|
|
}
|
|
|
|
TickProgressBar ();
|
|
|
|
} while (b && SetupFindNextLine (&ic, &ic));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pForceCopyFromMemDb (
|
|
VOID
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
TCHAR key [MEMDB_MAX];
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
TCHAR DestObjectStr[MAX_ENCODED_RULE];
|
|
DATAOBJECT SrcObject, DestObject, DupObject;
|
|
BOOL b = TRUE;
|
|
FILTERRETURN fr;
|
|
|
|
//
|
|
// Look in MemDb for ForceCopy tree
|
|
//
|
|
MemDbBuildKey (key, MEMDB_CATEGORY_FORCECOPY, TEXT("*"), NULL, NULL);
|
|
if (MemDbEnumFirstValue (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
|
|
//
|
|
// For each key here the offset points to the destination
|
|
//
|
|
do {
|
|
if (e.dwValue != 0) {
|
|
StringCopy (SrcObjectStr, e.szName);
|
|
|
|
if (MemDbBuildKeyFromOffset (e.dwValue, DestObjectStr, 1, NULL)) {
|
|
|
|
if (!(*DestObjectStr)) {
|
|
StringCopy (DestObjectStr, SrcObjectStr);
|
|
}
|
|
|
|
if (!CreateObjectStruct (SrcObjectStr, &SrcObject, WIN95OBJECT)) {
|
|
DEBUGMSG ((DBG_WARNING, "pForceCopyFromMemDb: Source object invalid %s",
|
|
SrcObjectStr));
|
|
continue;
|
|
}
|
|
|
|
if (!CreateObjectStruct (DestObjectStr, &DestObject, WINNTOBJECT)) {
|
|
DEBUGMSG ((DBG_WARNING, "pForceCopyFromMemDb: Destination object invalid %s",
|
|
DestObjectStr));
|
|
FreeObjectStruct (&SrcObject);
|
|
continue;
|
|
}
|
|
|
|
if (b = DuplicateObjectStruct (&DupObject, &SrcObject)) {
|
|
if (b = CombineObjectStructs (&DupObject, &DestObject)) {
|
|
//
|
|
// Copy source to dest
|
|
//
|
|
|
|
fr = CopyObject (&SrcObject, &DupObject, NULL, NULL);
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Force Copy from MemDb: CopyObject failed for %s=%s", SrcObjectStr, DestObjectStr));
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
FreeObjectStruct (&DupObject);
|
|
}
|
|
|
|
FreeObjectStruct (&SrcObject);
|
|
FreeObjectStruct (&DestObject);
|
|
}
|
|
}
|
|
TickProgressBar ();
|
|
|
|
} while (b && MemDbEnumNextValue (&e));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define S_MERGE_DELETEAFTERMIGRATION TEXT("Delete After Migration")
|
|
|
|
BOOL
|
|
pDeleteAfterMigration (
|
|
IN HINF InfFile
|
|
)
|
|
{
|
|
BOOL rSuccess = TRUE;
|
|
TCHAR objectString[MAX_ENCODED_RULE];
|
|
DATAOBJECT object;
|
|
INFCONTEXT ic;
|
|
HKEY key;
|
|
|
|
//
|
|
// Look in INF for [DeleteAfterMigration] section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, S_MERGE_DELETEAFTERMIGRATION, NULL, &ic)) {
|
|
|
|
//
|
|
// For each line in this section, get the encoded object in
|
|
// field 0 and delete it from the registry.
|
|
//
|
|
|
|
do {
|
|
|
|
if (SetupGetStringField(&ic,0,objectString,MAX_ENCODED_RULE,NULL)) {
|
|
|
|
FixUpUserSpecifiedObject(objectString);
|
|
|
|
if (!CreateObjectStruct(objectString,&object,WINNTOBJECT)) {
|
|
LOG((
|
|
LOG_ERROR,
|
|
"Delete After Migration: ObjectString invalid. (Section line %u of %s)",
|
|
ic.Line,
|
|
g_InfFileName
|
|
));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We have a good object. Delete it!
|
|
//
|
|
|
|
if (object.ValueName) {
|
|
|
|
//
|
|
// Value is specified. Delete it.
|
|
//
|
|
if (!RegDeleteValue(object.KeyPtr->OpenKey,object.ValueName)) {
|
|
DEBUGMSG((DBG_WARNING,"pDeleteAfterMigration: RegDeleteValue failed for %s [%s]",
|
|
object.KeyPtr->KeyString,
|
|
object.ValueName ? object.ValueName : TEXT("<DEFAULT>")
|
|
));
|
|
}
|
|
}
|
|
else {
|
|
|
|
key = GetRootKeyFromOffset (object.RootItem);
|
|
pSetupRegistryDelnode (key == HKEY_ROOT ? g_hKeyRootNT : key, object.KeyPtr->KeyString);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Free our resources.
|
|
//
|
|
FreeObjectStruct(&object);
|
|
}
|
|
|
|
} while (SetupFindNextLine(&ic,&ic));
|
|
}
|
|
|
|
return rSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCreateRenameTable (
|
|
IN HINF InfFile,
|
|
OUT PVOID *RenameTablePtr
|
|
)
|
|
{
|
|
INFCONTEXT ic;
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
TCHAR DestObjectStr[MAX_ENCODED_RULE];
|
|
LONG rc;
|
|
DATAOBJECT OrgOb;
|
|
DATAOBJECT NewOb;
|
|
PCTSTR DestStr;
|
|
|
|
//
|
|
// Look in INF for [Rename] section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, S_MERGE_RENAME, NULL, &ic)) {
|
|
//
|
|
// Create string table
|
|
//
|
|
*RenameTablePtr = pSetupStringTableInitializeEx (sizeof (PCTSTR), 0);
|
|
if (!(*RenameTablePtr)) {
|
|
LOG ((LOG_ERROR, "Create Rename Table: Cannot allocate a string table"));
|
|
return FALSE;
|
|
}
|
|
|
|
do {
|
|
if (SetupGetStringField (&ic, 0, SrcObjectStr, MAX_ENCODED_RULE, NULL) &&
|
|
SetupGetStringField (&ic, 1, DestObjectStr, MAX_ENCODED_RULE, NULL)
|
|
) {
|
|
// Ignore bad lines
|
|
|
|
FixUpUserSpecifiedObject (SrcObjectStr);
|
|
FixUpUserSpecifiedObject (DestObjectStr);
|
|
|
|
if (!CreateObjectStruct (SrcObjectStr, &OrgOb, WIN95OBJECT)) {
|
|
DEBUGMSG ((DBG_WARNING, "pCreateRenameTable: Source object invalid (Section line %u of %s)",
|
|
ic.Line, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
if (!CreateObjectStruct (DestObjectStr, &NewOb, WINNTOBJECT)) {
|
|
FreeObjectStruct (&OrgOb);
|
|
DEBUGMSG ((DBG_WARNING, "pCreateRenameTable: Dest object invalid (Section line %u of %s)",
|
|
ic.Line, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Convert DestObjectStr into complete object string
|
|
//
|
|
|
|
if (!CombineObjectStructs (&OrgOb, &NewOb)) {
|
|
FreeObjectStruct (&NewOb);
|
|
FreeObjectStruct (&OrgOb);
|
|
|
|
DEBUGMSG ((DBG_WARNING, "pCreateRenameTable: Can't perform the rename (Section line %u in %s)",
|
|
ic.Line, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
// Disable tree for destination object
|
|
OrgOb.ObjectType &= ~OT_TREE;
|
|
|
|
CreateObjectString (&OrgOb, DestObjectStr);
|
|
FreeObjectStruct (&NewOb);
|
|
FreeObjectStruct (&OrgOb);
|
|
|
|
DestStr = PoolMemDuplicateString (g_RenamePool, DestObjectStr);
|
|
if (!DestStr) {
|
|
break;
|
|
}
|
|
|
|
rc = pSetupStringTableAddStringEx (
|
|
*RenameTablePtr,
|
|
(PTSTR) SrcObjectStr,
|
|
STRTAB_CASE_INSENSITIVE,
|
|
(PBYTE) &DestStr,
|
|
sizeof (PCTSTR)
|
|
);
|
|
|
|
if (rc == -1) {
|
|
SetLastError (rc);
|
|
LOG ((LOG_ERROR, "Create Rename Table: Cannot add string to string table"));
|
|
break;
|
|
}
|
|
|
|
SetObjectStringFlag (SrcObjectStr, REGMERGE_95_RENAME, REGMERGE_95_RENAME);
|
|
SetObjectStringFlag (DestStr, REGMERGE_NT_SUPPRESS, REGMERGE_NT_MASK);
|
|
} else {
|
|
LOG ((LOG_ERROR, "Create Rename Table: syntax error in line %u of section %s in %s",
|
|
ic.Line, S_MERGE_RENAME, g_InfFileName));
|
|
}
|
|
|
|
TickProgressBar ();
|
|
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CopyRenameTableEntry (
|
|
PVOID StringTable,
|
|
LONG StringID,
|
|
PCTSTR SrcObjectStr,
|
|
PVOID ExtraData,
|
|
UINT ExtraDataSize,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PCTSTR DestObjectStr = *((PCTSTR *) ExtraData);
|
|
DATAOBJECT SrcOb, DestOb;
|
|
FILTERRETURN fr = FILTER_RETURN_FAIL;
|
|
DWORD Val;
|
|
|
|
// See if src has been processed
|
|
if (MemDbGetValue (SrcObjectStr, &Val) && (Val & REGMERGE_95_RENAME_SUPPRESS)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// If not, copy Win95 src to WinNT dest
|
|
if (CreateObjectStruct (SrcObjectStr, &SrcOb, WIN95OBJECT)) {
|
|
if (CreateObjectStruct (DestObjectStr, &DestOb, WINNTOBJECT)) {
|
|
fr = CopyObject (&SrcOb, &DestOb, SuppressFilter95, NULL);
|
|
FreeObjectStruct (&DestOb);
|
|
}
|
|
FreeObjectStruct (&SrcOb);
|
|
}
|
|
|
|
return fr != FILTER_RETURN_FAIL;
|
|
}
|
|
|
|
BOOL
|
|
pProcessRenameTable (
|
|
IN PVOID RenameTable
|
|
)
|
|
{
|
|
PCTSTR DataBuf;
|
|
|
|
return pSetupStringTableEnum (RenameTable, (PVOID) &DataBuf, sizeof (DataBuf), CopyRenameTableEntry, 0);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pSpecialConversion (
|
|
IN HINF InfFile,
|
|
IN PCTSTR User,
|
|
IN PVOID RenameTable
|
|
)
|
|
{
|
|
INFCONTEXT ic;
|
|
TCHAR FunctionStr[MAX_ENCODED_RULE];
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
TCHAR RenamedObjectStr[MAX_ENCODED_RULE];
|
|
PROCESSINGFN Fn;
|
|
PVOID Arg;
|
|
|
|
//
|
|
// Look in INF for [SpecialConversion] section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, S_MERGE_WIN9X_CONVERSION, NULL, &ic)) {
|
|
//
|
|
// For each line, get the function and the source object, then call
|
|
// the function.
|
|
//
|
|
|
|
do {
|
|
if (SetupGetStringField (&ic, 0, FunctionStr, MAX_ENCODED_RULE, NULL) &&
|
|
SetupGetStringField (&ic, 1, SrcObjectStr, MAX_ENCODED_RULE, NULL)
|
|
) {
|
|
FixUpUserSpecifiedObject (SrcObjectStr);
|
|
|
|
Fn = RuleHlpr_GetFunctionAddr (FunctionStr, &Arg);
|
|
if (!Fn) {
|
|
LOG ((LOG_ERROR, "Special Conversion: Invalid function %s in %s", FunctionStr, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
CreateRenamedObjectString (RenameTable, SrcObjectStr, RenamedObjectStr);
|
|
|
|
if (!Fn (SrcObjectStr, RenamedObjectStr, User, Arg)) {
|
|
if (GetLastError () == ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
LOG ((LOG_ERROR, "Processing of Special Conversion was aborted because %s failed.", FunctionStr));
|
|
break;
|
|
}
|
|
|
|
SetObjectStringFlag (
|
|
SrcObjectStr,
|
|
REGMERGE_95_SUPPRESS|REGMERGE_95_RENAME_SUPPRESS,
|
|
REGMERGE_95_SUPPRESS|REGMERGE_95_RENAME_SUPPRESS
|
|
);
|
|
|
|
SetObjectStringFlag (RenamedObjectStr, REGMERGE_NT_SUPPRESS, REGMERGE_NT_MASK);
|
|
|
|
} else {
|
|
LOG ((LOG_ERROR, "Special Conversion: syntax error in line %u of section %s in %s",
|
|
ic.Line, S_MERGE_WIN9X_CONVERSION, g_InfFileName));
|
|
}
|
|
|
|
TickProgressBar ();
|
|
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetFlagsForObject (
|
|
IN HINF InfFile,
|
|
IN PCTSTR Section,
|
|
IN DWORD Flag,
|
|
IN DWORD RemoveFlag
|
|
)
|
|
{
|
|
INFCONTEXT ic;
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
|
|
//
|
|
// Look in INF for section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, Section, NULL, &ic)) {
|
|
//
|
|
// For each line, get the object and mark it as suppressed.
|
|
//
|
|
|
|
do {
|
|
if (SetupGetStringField (&ic, 1, SrcObjectStr, MAX_ENCODED_RULE, NULL)
|
|
) {
|
|
FixUpUserSpecifiedObject (SrcObjectStr);
|
|
SetObjectStringFlag (SrcObjectStr, Flag, RemoveFlag);
|
|
} else {
|
|
LOG ((LOG_ERROR, "Set Flags For Object: syntax error in line %u of section %s in %s",
|
|
ic.Line, Section, g_InfFileName));
|
|
}
|
|
TickProgressBar ();
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
} else {
|
|
DEBUGMSG ((DBG_VERBOSE, "SetFlagsForObject: Section %s can't be found", Section));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pProcessSuppressList (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
)
|
|
{
|
|
return SetFlagsForObject (
|
|
InfFile,
|
|
SectionName,
|
|
REGMERGE_95_SUPPRESS,
|
|
REGMERGE_95_SUPPRESS
|
|
);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pProcessHardwareSuppressList (
|
|
IN HINF InfFile
|
|
)
|
|
{
|
|
return SetFlagsForObject (InfFile, S_MERGE_WIN9X_SUPPRESS_HW, REGMERGE_95_SUPPRESS, REGMERGE_95_SUPPRESS);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pSuppressNTDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
)
|
|
{
|
|
//
|
|
// The objects listed in Suppress WinNT Settings are enumerated,
|
|
// and they are blocked from being transferred from the NT default
|
|
// user to the new user.
|
|
//
|
|
|
|
return SetFlagsForObject (
|
|
InfFile,
|
|
SectionName,
|
|
REGMERGE_NT_SUPPRESS,
|
|
REGMERGE_NT_SUPPRESS
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
pDontCombineWithDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
)
|
|
{
|
|
//
|
|
// The objects listed in Merge WinNT with Win9x are enumerated,
|
|
// and they are blocked from being transferred from the NT default
|
|
// user to the new user. In addition, they are put in a list
|
|
// to be processed at the end of user registry migration. This
|
|
// last step uses CombineFilter to make sure the NT values do
|
|
// not overwrite the 9x values.
|
|
//
|
|
|
|
return SetFlagsForObject (
|
|
InfFile,
|
|
SectionName,
|
|
REGMERGE_NT_IGNORE_DEFAULTS,
|
|
REGMERGE_NT_IGNORE_DEFAULTS
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
pForceNTDefaults (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
)
|
|
{
|
|
//
|
|
// The objects listed in Force WinNT Settings are enumerated,
|
|
// and they are blocked from being processed during the general
|
|
// 9x to NT copy. In addition, they are put in a list to be
|
|
// processed at the end of user registry migration. This last
|
|
// step forces the entire key to be copied from the default
|
|
// user to the new user, overwriting any previously migrated
|
|
// settings.
|
|
//
|
|
// It is important to note that the special conversion functions
|
|
// are not suppressed here, but the converted settings may be
|
|
// overwritten.
|
|
//
|
|
|
|
return SetFlagsForObject (
|
|
InfFile,
|
|
SectionName,
|
|
REGMERGE_NT_PRIORITY_NT|REGMERGE_95_SUPPRESS,
|
|
REGMERGE_NT_PRIORITY_NT|REGMERGE_95_SUPPRESS
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
pForceNTDefaultsHack (
|
|
IN HINF InfFile,
|
|
IN PCTSTR SectionName
|
|
)
|
|
{
|
|
//
|
|
// Take away the REGMERGE_95_SUPPRESS flag now, because the general
|
|
// 9x merge has completed, but we get confused between an actual
|
|
// suppress and a suppress done for the priority-nt case.
|
|
//
|
|
|
|
return SetFlagsForObject (
|
|
InfFile,
|
|
SectionName,
|
|
REGMERGE_NT_PRIORITY_NT,
|
|
REGMERGE_NT_PRIORITY_NT|REGMERGE_95_SUPPRESS
|
|
);
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
SuppressFilter95 (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
)
|
|
{
|
|
TCHAR ObStr[MAX_ENCODED_RULE];
|
|
DWORD Val;
|
|
PTSTR p, q, r;
|
|
TCHAR Node[MEMDB_MAX];
|
|
|
|
if (FilterType == FILTER_CREATE_KEY) {
|
|
//
|
|
// Check if this tree is suppressed
|
|
//
|
|
|
|
MYASSERT (SrcObjectPtr->ObjectType & OT_TREE);
|
|
MYASSERT (SrcObjectPtr->KeyPtr);
|
|
MYASSERT (!(SrcObjectPtr->ValueName));
|
|
|
|
// Query setting for HKR\Sub\Key\*
|
|
CreateObjectString (SrcObjectPtr, ObStr);
|
|
if (MemDbGetValue (ObStr, &Val)) {
|
|
if (Val & REGMERGE_95_SUPPRESS) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
|
|
if (!g_ProcessRenameTable && (Val & REGMERGE_95_RENAME)) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
}
|
|
|
|
// If key is a GUID and GUID is suppressed, suppress the tree
|
|
p = (PTSTR) SrcObjectPtr->ChildKey;
|
|
if (p && _tcsnextc (p) == TEXT('{')) {
|
|
// Look for matching curly brace
|
|
q = _tcschr (p, TEXT('}'));
|
|
if (q) {
|
|
q = _tcsinc (q);
|
|
|
|
// Create GUIDS\{a-b-c-d-e}
|
|
*Node = 0;
|
|
r = _tcsappend (Node, MEMDB_CATEGORY_GUIDS);
|
|
r = _tcsappend (r, TEXT("\\"));
|
|
StringCopyAB (r, p, q);
|
|
|
|
// Look for match
|
|
if (MemDbGetValue (Node, NULL)) {
|
|
DEBUGMSG ((DBG_VERBOSE, "Suppressed %s found in %s", Node, ObStr));
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (FilterType == FILTER_PROCESS_VALUES) {
|
|
//
|
|
// Check if this node is suppressed
|
|
//
|
|
|
|
MYASSERT (!(SrcObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (SrcObjectPtr->KeyPtr);
|
|
MYASSERT (!(SrcObjectPtr->ValueName));
|
|
CreateObjectString (SrcObjectPtr, ObStr);
|
|
|
|
// Query setting for HKR\Sub\Key
|
|
if (!MemDbGetValue (ObStr, &Val)) {
|
|
Val = 0;
|
|
}
|
|
|
|
if (Val & REGMERGE_95_SUPPRESS) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
if (!g_ProcessRenameTable && (Val & REGMERGE_95_RENAME)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
}
|
|
|
|
else if (FilterType == FILTER_VALUENAME_ENUM) {
|
|
//
|
|
// Check if this value is suppressed
|
|
//
|
|
|
|
MYASSERT (!(SrcObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (SrcObjectPtr->KeyPtr);
|
|
MYASSERT (SrcObjectPtr->ValueName);
|
|
CreateObjectString (SrcObjectPtr, ObStr);
|
|
|
|
// If value name is a GUID and GUID is suppressed, suppress the value
|
|
p = (PTSTR) SrcObjectPtr->ValueName;
|
|
if (_tcsnextc (p) == TEXT('{')) {
|
|
MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, p);
|
|
if (MemDbGetValue (Node, NULL)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
|
|
if (!MemDbGetValue (ObStr, &Val)) {
|
|
Val = 0;
|
|
}
|
|
|
|
if (Val & REGMERGE_95_SUPPRESS) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
if (!g_ProcessRenameTable && (Val & REGMERGE_95_RENAME)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
}
|
|
|
|
else if (FilterType == FILTER_VALUE_COPY) {
|
|
//
|
|
// Don't copy if value has a suppressed GUID
|
|
//
|
|
|
|
p = pGetStringFromObjectData (SrcObjectPtr);
|
|
|
|
if (p && _tcsnextc (p) == TEXT('{')) {
|
|
MemDbBuildKey (Node, MEMDB_CATEGORY_GUIDS, NULL, NULL, p);
|
|
if (MemDbGetValue (Node, NULL)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
SuppressFilterNT (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
)
|
|
{
|
|
TCHAR ObStr[MAX_ENCODED_RULE];
|
|
DWORD Val;
|
|
PTSTR p;
|
|
|
|
if (FilterType == FILTER_CREATE_KEY) {
|
|
//
|
|
// Check if this tree is suppressed
|
|
//
|
|
|
|
MYASSERT (DestObjectPtr->ObjectType & OT_TREE);
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (!(DestObjectPtr->ValueName));
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_MASK)) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
}
|
|
|
|
|
|
else if (FilterType == FILTER_PROCESS_VALUES) {
|
|
DATAOBJECT CopyOfDestOb;
|
|
DWORD rc;
|
|
DWORD ValueCount;
|
|
|
|
//
|
|
// Does destination already exist?
|
|
//
|
|
|
|
CopyMemory (&CopyOfDestOb, DestObjectPtr, sizeof (DATAOBJECT));
|
|
if (OpenObject (&CopyOfDestOb)) {
|
|
//
|
|
// Does it have values?
|
|
//
|
|
|
|
MYASSERT (!IsWin95Object (&CopyOfDestOb));
|
|
|
|
rc = RegQueryInfoKey (
|
|
CopyOfDestOb.KeyPtr->OpenKey,
|
|
NULL, // class
|
|
NULL, // class size
|
|
NULL, // reserved
|
|
NULL, // subkey count
|
|
NULL, // max subkey length
|
|
NULL, // max class length
|
|
&ValueCount,
|
|
NULL, // max value name size
|
|
NULL, // max value size
|
|
NULL, // security
|
|
NULL // last changed time
|
|
);
|
|
|
|
if (rc == ERROR_SUCCESS && ValueCount > 0) {
|
|
CloseObject (&CopyOfDestOb);
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Check if this node is suppressed
|
|
//
|
|
|
|
MYASSERT (DestObjectPtr->ObjectType & OT_TREE);
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (!(DestObjectPtr->ValueName));
|
|
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
p = _tcsrchr (ObStr, TEXT('\\'));
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_MASK)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
|
|
else if (FilterType == FILTER_VALUENAME_ENUM) {
|
|
//
|
|
// Check if this value is suppressed
|
|
//
|
|
|
|
MYASSERT (!(DestObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (DestObjectPtr->ValueName);
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_MASK)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
|
|
return FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
CombineFilter (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
)
|
|
{
|
|
BOOL b;
|
|
|
|
if (FilterType == FILTER_VALUE_COPY) {
|
|
//
|
|
// Check if destination already exists in the registry
|
|
//
|
|
|
|
MYASSERT (!(SrcObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (SrcObjectPtr->KeyPtr);
|
|
MYASSERT (SrcObjectPtr->ValueName);
|
|
MYASSERT (!(DestObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (DestObjectPtr->ValueName);
|
|
|
|
b = CheckIfNtKeyExists (DestObjectPtr);
|
|
|
|
if (b) {
|
|
return FILTER_RETURN_HANDLED;
|
|
} else if (GetLastError() != ERROR_SUCCESS) {
|
|
return FILTER_RETURN_FAIL;
|
|
}
|
|
}
|
|
|
|
return FILTER_RETURN_CONTINUE;
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
pSuppressDefaultUserFilter (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
)
|
|
{
|
|
TCHAR ObStr[MAX_ENCODED_RULE];
|
|
DWORD Val;
|
|
PTSTR p;
|
|
|
|
if (FilterType == FILTER_CREATE_KEY) {
|
|
//
|
|
// Check if this tree is suppressed
|
|
//
|
|
|
|
MYASSERT (DestObjectPtr->ObjectType & OT_TREE);
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (!(DestObjectPtr->ValueName));
|
|
|
|
|
|
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_IGNORE_DEFAULTS)) {
|
|
return FILTER_RETURN_DONE;
|
|
}
|
|
}
|
|
|
|
else if (FilterType == FILTER_PROCESS_VALUES) {
|
|
//
|
|
// Check if this node is suppressed
|
|
//
|
|
|
|
MYASSERT (DestObjectPtr->ObjectType & OT_TREE);
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (!(DestObjectPtr->ValueName));
|
|
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
p = _tcsrchr (ObStr, TEXT('\\'));
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_IGNORE_DEFAULTS)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
|
|
}
|
|
|
|
else if (FilterType == FILTER_VALUENAME_ENUM) {
|
|
//
|
|
// Check if this value is suppressed
|
|
//
|
|
|
|
MYASSERT (!(DestObjectPtr->ObjectType & OT_TREE));
|
|
MYASSERT (DestObjectPtr->KeyPtr);
|
|
MYASSERT (DestObjectPtr->ValueName);
|
|
|
|
|
|
|
|
CreateObjectString (DestObjectPtr, ObStr);
|
|
|
|
if (MemDbGetValue (ObStr, &Val) && (Val & REGMERGE_NT_IGNORE_DEFAULTS)) {
|
|
return FILTER_RETURN_HANDLED;
|
|
}
|
|
}
|
|
|
|
return CombineFilter (SrcObjectPtr, DestObjectPtr, FilterType, DontCare);
|
|
}
|
|
|
|
|
|
FILTERRETURN
|
|
CopyNoOverwriteFilter (
|
|
IN CPDATAOBJECT SrcObjectPtr,
|
|
IN CPDATAOBJECT DestObjectPtr, OPTIONAL
|
|
IN FILTERTYPE FilterType,
|
|
IN PVOID DontCare
|
|
)
|
|
{
|
|
FILTERRETURN fr;
|
|
|
|
fr = SuppressFilter95 (SrcObjectPtr, DestObjectPtr, FilterType, DontCare);
|
|
if (fr != FILTER_RETURN_CONTINUE) {
|
|
return fr;
|
|
}
|
|
|
|
return CombineFilter (SrcObjectPtr, DestObjectPtr, FilterType, DontCare);
|
|
}
|
|
|
|
|
|
BOOL
|
|
pMergeWin95WithUser (
|
|
IN PVOID RenameTable
|
|
)
|
|
{
|
|
DATAOBJECT SrcOb, DestOb;
|
|
BOOL b;
|
|
FILTERRETURN fr;
|
|
|
|
//
|
|
// Copy unsuppressed Win95 keys to NT user hive
|
|
//
|
|
|
|
b = CreateObjectStruct (TEXT("HKR\\*"), &SrcOb, WIN95OBJECT);
|
|
MYASSERT (b);
|
|
|
|
b = CreateObjectStruct (TEXT("HKR\\*"), &DestOb, WINNTOBJECT);
|
|
MYASSERT (b);
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, SuppressFilter95, NULL);
|
|
|
|
FreeObjectStruct (&SrcOb);
|
|
FreeObjectStruct (&DestOb);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Merge Win95 With User: CopyObject failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
RegistryCombineWorker (
|
|
DWORD Flag,
|
|
FILTERFUNCTION FilterFn,
|
|
PCTSTR MemDbRoot,
|
|
PCTSTR SrcRoot,
|
|
DWORD SrcObjectType
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
TCHAR SrcRegKey[MEMDB_MAX];
|
|
TCHAR DestRegKey[MEMDB_MAX];
|
|
PTSTR SrcPtr, DestPtr;
|
|
DATAOBJECT SrcOb, DestOb;
|
|
FILTERRETURN fr;
|
|
TCHAR Pattern[32];
|
|
|
|
wsprintf (Pattern, TEXT("%s\\*"), MemDbRoot);
|
|
|
|
//
|
|
// Enumerate all keys in memdb and call CopyObject for them
|
|
//
|
|
|
|
*SrcRegKey = 0;
|
|
*DestRegKey = 0;
|
|
|
|
SrcPtr = _tcsappend (SrcRegKey, SrcRoot);
|
|
SrcPtr = _tcsappend (SrcPtr, TEXT("\\"));
|
|
|
|
DestPtr = _tcsappend (DestRegKey, MemDbRoot);
|
|
DestPtr = _tcsappend (DestPtr, TEXT("\\"));
|
|
|
|
if (MemDbEnumFirstValue (
|
|
&e,
|
|
Pattern,
|
|
MEMDB_ALL_SUBLEVELS,
|
|
MEMDB_ENDPOINTS_ONLY
|
|
)) {
|
|
|
|
do {
|
|
if ((e.dwValue & REGMERGE_NT_MASK) & Flag) {
|
|
StringCopy (SrcPtr, e.szName);
|
|
StringCopy (DestPtr, e.szName);
|
|
|
|
if (!CreateObjectStruct (SrcRegKey, &SrcOb, SrcObjectType)) {
|
|
LOG ((LOG_ERROR, "Merge NT Defaults With User: Can't create object for %s", SrcRegKey));
|
|
continue;
|
|
}
|
|
|
|
if (!CreateObjectStruct (DestRegKey, &DestOb, WINNTOBJECT)) {
|
|
FreeObjectStruct (&SrcOb);
|
|
LOG ((LOG_ERROR, "Merge NT Defaults With User: Can't create object for %s", SrcRegKey));
|
|
continue;
|
|
}
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, FilterFn, NULL);
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Merge NT Defaults With User: Can't copy %s to %s", SrcRegKey, DestRegKey));
|
|
}
|
|
|
|
FreeObjectStruct (&SrcOb);
|
|
FreeObjectStruct (&DestOb);
|
|
}
|
|
|
|
TickProgressBar ();
|
|
|
|
} while (MemDbEnumNextValue (&e));
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pMergeNTDefaultsWithUser (
|
|
HINF hInf
|
|
)
|
|
{
|
|
DATAOBJECT SrcOb, DestOb;
|
|
FILTERRETURN fr;
|
|
BOOL b;
|
|
|
|
//
|
|
// Copy unsuppressed NT defaults to NT user hive
|
|
//
|
|
|
|
b = CreateObjectStruct (
|
|
TEXT("HKLM\\") S_MAPPED_DEFAULT_USER_KEY TEXT("\\*"),
|
|
&SrcOb,
|
|
WINNTOBJECT
|
|
);
|
|
|
|
MYASSERT (b);
|
|
|
|
b = CreateObjectStruct (TEXT("HKR\\*"), &DestOb, WINNTOBJECT);
|
|
MYASSERT (b);
|
|
|
|
__try {
|
|
b = FALSE;
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, SuppressFilterNT, NULL);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Merge NT Defaults With User: CopyObject failed"));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Copy forced NT defaults to NT user hive, then copy all NT defaults
|
|
// that need to be combined with Win95 settings.
|
|
//
|
|
|
|
RegistryCombineWorker (
|
|
REGMERGE_NT_PRIORITY_NT,
|
|
NULL,
|
|
TEXT("HKR"),
|
|
TEXT("HKLM\\") S_MAPPED_DEFAULT_USER_KEY,
|
|
WINNTOBJECT
|
|
);
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, pSuppressDefaultUserFilter, NULL);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Combine NT Defaults With User: CopyObject failed"));
|
|
__leave;
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
|
|
__finally {
|
|
FreeObjectStruct (&SrcOb);
|
|
FreeObjectStruct (&DestOb);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCopyWin9xValuesNotInNt (
|
|
HINF hInf
|
|
)
|
|
{
|
|
DATAOBJECT SrcOb, DestOb;
|
|
FILTERRETURN fr;
|
|
BOOL b;
|
|
|
|
//
|
|
// Copy Win9x values that NT does not have
|
|
//
|
|
|
|
b = CreateObjectStruct (
|
|
TEXT("HKLM\\*"),
|
|
&SrcOb,
|
|
WIN95OBJECT
|
|
);
|
|
|
|
MYASSERT (b);
|
|
|
|
b = CreateObjectStruct (TEXT("HKR\\*"), &DestOb, WINNTOBJECT);
|
|
MYASSERT (b);
|
|
|
|
__try {
|
|
b = FALSE;
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, SuppressFilterNT, NULL);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Merge NT Defaults With User: CopyObject failed"));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Copy forced NT defaults to NT user hive, then copy all NT defaults
|
|
// that need to be combined with Win95 settings.
|
|
//
|
|
|
|
RegistryCombineWorker (
|
|
REGMERGE_NT_PRIORITY_NT,
|
|
NULL,
|
|
TEXT("HKR"),
|
|
TEXT("HKLM\\") S_MAPPED_DEFAULT_USER_KEY,
|
|
WINNTOBJECT
|
|
);
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, pSuppressDefaultUserFilter, NULL);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Combine NT Defaults With User: CopyObject failed"));
|
|
__leave;
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
|
|
__finally {
|
|
FreeObjectStruct (&SrcOb);
|
|
FreeObjectStruct (&DestOb);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pMergeWin95WithSystem (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pMergeWin95WithSystem copies the Win95 registry to NT, skipping values
|
|
that already exist on NT.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE if failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
RegistryCombineWorker (
|
|
REGMERGE_NT_PRIORITY_NT,
|
|
CopyNoOverwriteFilter,
|
|
TEXT("HKLM"), // memdb root and dest root
|
|
TEXT("HKLM"), // source root
|
|
WIN95OBJECT
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCopyWin95ToSystem (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pCopyWin95ToSystem copies all Win95 settings to NT, unless the setting
|
|
is supressed. This achieves a copy with overwrite capability.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
TRUE if success, FALSE if failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DATAOBJECT SrcOb, DestOb;
|
|
BOOL b;
|
|
FILTERRETURN fr;
|
|
|
|
b = CreateObjectStruct (TEXT("HKLM\\*"), &SrcOb, WIN95OBJECT);
|
|
MYASSERT (b);
|
|
|
|
b = CreateObjectStruct (TEXT("HKLM\\*"), &DestOb, WINNTOBJECT);
|
|
MYASSERT (b);
|
|
|
|
fr = CopyObject (&SrcOb, &DestOb, SuppressFilter95, NULL);
|
|
|
|
FreeObjectStruct (&SrcOb);
|
|
FreeObjectStruct (&DestOb);
|
|
|
|
if (fr == FILTER_RETURN_FAIL) {
|
|
LOG ((LOG_ERROR, "Copy Win95 To System: CopyObject failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pSpecialConversionNT (
|
|
IN HINF InfFile,
|
|
IN PCTSTR User,
|
|
IN BOOL PerUser
|
|
)
|
|
{
|
|
INFCONTEXT ic;
|
|
DATAOBJECT SrcOb, DestOb;
|
|
TCHAR FunctionStr[MAX_ENCODED_RULE];
|
|
TCHAR SrcObjectStr[MAX_ENCODED_RULE];
|
|
TCHAR DestObjectStr[MAX_ENCODED_RULE];
|
|
PROCESSINGFN Fn;
|
|
PVOID Arg;
|
|
|
|
//
|
|
// Look in INF for [SpecialConversionNT] section
|
|
//
|
|
|
|
if (SetupFindFirstLine (InfFile, S_MERGE_WINNT_CONVERSION, NULL, &ic)) {
|
|
//
|
|
// For each line, get the function and the source object, then call
|
|
// the function.
|
|
//
|
|
|
|
do {
|
|
if (SetupGetStringField (&ic, 0, FunctionStr, MAX_ENCODED_RULE, NULL) &&
|
|
SetupGetStringField (&ic, 1, DestObjectStr, MAX_ENCODED_RULE, NULL)
|
|
) {
|
|
FixUpUserSpecifiedObject (DestObjectStr);
|
|
|
|
Fn = RuleHlpr_GetFunctionAddr (FunctionStr, &Arg);
|
|
|
|
if (!Fn) {
|
|
LOG ((LOG_ERROR, "Special Conversion: Invalid function %s in %s", FunctionStr, g_InfFileName));
|
|
continue;
|
|
}
|
|
|
|
if (PerUser) {
|
|
//
|
|
// Make source off of HKLM\MappedDefaultUser
|
|
//
|
|
|
|
if (!CreateObjectStruct (DestObjectStr, &SrcOb, WINNTOBJECT)) {
|
|
continue;
|
|
}
|
|
|
|
if (!(SrcOb.RootItem)) {
|
|
LOG ((LOG_ERROR, "Special Conversion NT: Invalid function object %s", DestObjectStr));
|
|
FreeObjectStruct (&SrcOb);
|
|
continue;
|
|
}
|
|
|
|
CreateObjectStruct (TEXT("HKLM"), &DestOb, WINNTOBJECT);
|
|
CombineObjectStructs (&SrcOb, &DestOb);
|
|
|
|
StringCopy (SrcObjectStr, S_MAPPED_DEFAULT_USER_KEY TEXT("\\"));
|
|
CreateObjectString (&SrcOb, GetEndOfString (SrcObjectStr));
|
|
|
|
FreeObjectStruct (&DestOb);
|
|
FreeObjectStruct (&SrcOb);
|
|
|
|
} else {
|
|
|
|
if (!CreateObjectStruct (DestObjectStr, &SrcOb, WINNTOBJECT)) {
|
|
continue;
|
|
}
|
|
|
|
if (!(SrcOb.RootItem)) {
|
|
LOG ((LOG_ERROR, "Special Conversion NT: Invalid function object %s", DestObjectStr));
|
|
FreeObjectStruct (&SrcOb);
|
|
continue;
|
|
}
|
|
|
|
|
|
CreateObjectString (&SrcOb, SrcObjectStr);
|
|
FreeObjectStruct (&SrcOb);
|
|
|
|
}
|
|
|
|
if (!Fn (SrcObjectStr, PerUser ? DestObjectStr : SrcObjectStr, User, Arg)) {
|
|
if (GetLastError () == ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
LOG ((LOG_ERROR, "Processing of Special Conversion was aborted because %s failed.", FunctionStr));
|
|
break;
|
|
}
|
|
|
|
SetObjectStringFlag (SrcObjectStr, REGMERGE_NT_SUPPRESS, REGMERGE_NT_MASK);
|
|
} else {
|
|
LOG ((LOG_ERROR, "Special Conversion NT: syntax error in line %u of section %s in %s",
|
|
ic.Line, S_MERGE_WINNT_CONVERSION, g_InfFileName));
|
|
}
|
|
|
|
TickProgressBar ();
|
|
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SuppressWin95Object (
|
|
IN PCTSTR ObjectStr
|
|
)
|
|
{
|
|
return SetObjectStringFlag (ObjectStr, REGMERGE_95_SUPPRESS, REGMERGE_95_SUPPRESS);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CheckIfNtKeyExists (
|
|
IN CPDATAOBJECT SrcObjectPtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
CheckIfNtKeyExists takes a 9x object and tests to see if the same NT
|
|
setting exists. The 9x object must have a key and value name.
|
|
|
|
Arguments:
|
|
|
|
SrcObjectPtr - Specifies the 9x object to test.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the object exists in NT, FALSE if it doesn't or if an error occurs.
|
|
GetLastError indicates the error (if any).
|
|
|
|
--*/
|
|
|
|
{
|
|
DATAOBJECT NtObject;
|
|
BOOL b;
|
|
PCSTR value1;
|
|
PCSTR value2;
|
|
PCWSTR value3;
|
|
PCWSTR oldValueName;
|
|
HKEY oldRoot;
|
|
|
|
if (!DuplicateObjectStruct (&NtObject, SrcObjectPtr)) {
|
|
LOG ((LOG_ERROR, "Combine Filter: destination is invalid"));
|
|
return FALSE;
|
|
}
|
|
|
|
SetPlatformType (&NtObject, FALSE);
|
|
|
|
b = OpenObject (&NtObject);
|
|
|
|
if (!b && g_DuHandle) {
|
|
|
|
oldRoot = GetRegRoot();
|
|
SetRegRoot (g_DuHandle);
|
|
|
|
b = OpenObject (&NtObject);
|
|
|
|
SetRegRoot (oldRoot);
|
|
}
|
|
|
|
if (b) {
|
|
b = ReadObject (&NtObject);
|
|
|
|
if (!b) {
|
|
if (OurGetACP() == 932) {
|
|
//
|
|
// Katakana special case
|
|
//
|
|
oldValueName = NtObject.ValueName;
|
|
value1 = ConvertWtoA (NtObject.ValueName);
|
|
value2 = ConvertSBtoDB (NULL, value1, NULL);
|
|
value3 = ConvertAtoW (value2);
|
|
NtObject.ValueName = value3;
|
|
FreeObjectVal (&NtObject);
|
|
b = ReadObject (&NtObject);
|
|
FreeConvertedStr (value3);
|
|
FreePathStringA (value2);
|
|
FreeConvertedStr (value1);
|
|
NtObject.ValueName = oldValueName;
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeObjectStruct (&NtObject);
|
|
SetLastError (ERROR_SUCCESS);
|
|
|
|
return b;
|
|
}
|
|
|
|
|