mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 01:25:56 +00:00
Fixed reference counting in CmiConnectHive and CmiDisconnectHive.
No longer need hacks to check reference counts. Deleted a ton of wierd code. Fixed bug where we allocated uninitialized memory for child nodes we never populated. Now reference counting mirrors pointers exactly: - Hold one reference for the parent key pointer - Hold one reference for the list entry in the connected hive list svn path=/trunk/; revision=22684
This commit is contained in:
parent
c6661f1f9e
commit
61cb74d018
4 changed files with 143 additions and 171 deletions
|
@ -358,6 +358,9 @@ typedef struct _KEY_OBJECT
|
||||||
|
|
||||||
/* Time stamp for the last access by the parse routine */
|
/* Time stamp for the last access by the parse routine */
|
||||||
ULONG TimeStamp;
|
ULONG TimeStamp;
|
||||||
|
|
||||||
|
/* List entry for connected hives */
|
||||||
|
LIST_ENTRY HiveList;
|
||||||
} KEY_OBJECT, *PKEY_OBJECT;
|
} KEY_OBJECT, *PKEY_OBJECT;
|
||||||
|
|
||||||
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */
|
/* Bits 31-22 (top 10 bits) of the cell index is the directory index */
|
||||||
|
|
|
@ -143,6 +143,8 @@ CmImportBinaryHive (PCHAR ChunkBase,
|
||||||
KeEnterCriticalRegion();
|
KeEnterCriticalRegion();
|
||||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||||
|
|
||||||
|
DPRINT1("Adding new hive\n");
|
||||||
|
|
||||||
/* Add the new hive to the hive list */
|
/* Add the new hive to the hive list */
|
||||||
InsertTailList(&CmiHiveListHead, &Hive->HiveList);
|
InsertTailList(&CmiHiveListHead, &Hive->HiveList);
|
||||||
|
|
||||||
|
@ -195,7 +197,6 @@ CmImportSystemHive(PCHAR ChunkBase,
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1 ("CmiConnectHive(%wZ) failed (Status %lx)\n", &KeyName, Status);
|
DPRINT1 ("CmiConnectHive(%wZ) failed (Status %lx)\n", &KeyName, Status);
|
||||||
// CmiRemoveRegistryHive(RegistryHive);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ ERESOURCE CmiRegistryLock;
|
||||||
|
|
||||||
KTIMER CmiWorkerTimer;
|
KTIMER CmiWorkerTimer;
|
||||||
LIST_ENTRY CmiKeyObjectListHead;
|
LIST_ENTRY CmiKeyObjectListHead;
|
||||||
|
LIST_ENTRY CmiConnectedHiveList;
|
||||||
ULONG CmiTimer = 0;
|
ULONG CmiTimer = 0;
|
||||||
|
|
||||||
volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
|
volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
|
||||||
|
@ -385,6 +386,7 @@ CmInitializeRegistry(VOID)
|
||||||
|
|
||||||
/* Initialize the key object list */
|
/* Initialize the key object list */
|
||||||
InitializeListHead(&CmiKeyObjectListHead);
|
InitializeListHead(&CmiKeyObjectListHead);
|
||||||
|
InitializeListHead(&CmiConnectedHiveList);
|
||||||
|
|
||||||
/* Initialize the worker timer */
|
/* Initialize the worker timer */
|
||||||
KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
|
KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
|
||||||
|
@ -694,92 +696,94 @@ CmiCreateCurrentControlSetLink(VOID)
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
IN PREGISTRY_HIVE RegistryHive)
|
IN PREGISTRY_HIVE RegistryHive)
|
||||||
{
|
{
|
||||||
UNICODE_STRING RemainingPath;
|
UNICODE_STRING RemainingPath;
|
||||||
PKEY_OBJECT ParentKey;
|
PKEY_OBJECT ParentKey;
|
||||||
PKEY_OBJECT NewKey;
|
PKEY_OBJECT NewKey;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PWSTR SubName;
|
PWSTR SubName;
|
||||||
UNICODE_STRING ObjectName;
|
UNICODE_STRING ObjectName;
|
||||||
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
OBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||||||
|
|
||||||
DPRINT("CmiConnectHive(%p, %p) called.\n",
|
DPRINT("CmiConnectHive(%p, %p) called.\n",
|
||||||
KeyObjectAttributes, RegistryHive);
|
KeyObjectAttributes, RegistryHive);
|
||||||
|
|
||||||
/* Capture all the info */
|
/* Capture all the info */
|
||||||
DPRINT("Capturing Create Info\n");
|
DPRINT("Capturing Create Info\n");
|
||||||
Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
|
Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
|
||||||
KernelMode,
|
KernelMode,
|
||||||
FALSE,
|
FALSE,
|
||||||
&ObjectCreateInfo,
|
&ObjectCreateInfo,
|
||||||
&ObjectName);
|
&ObjectName);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
|
DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = CmFindObject(&ObjectCreateInfo,
|
Status = CmFindObject(&ObjectCreateInfo,
|
||||||
&ObjectName,
|
&ObjectName,
|
||||||
(PVOID*)&ParentKey,
|
(PVOID*)&ParentKey,
|
||||||
&RemainingPath,
|
&RemainingPath,
|
||||||
CmiKeyType,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
|
||||||
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT ("RemainingPath %wZ\n", &RemainingPath);
|
|
||||||
|
|
||||||
if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
|
|
||||||
{
|
|
||||||
ObDereferenceObject (ParentKey);
|
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
return STATUS_OBJECT_NAME_COLLISION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ignore leading backslash */
|
|
||||||
SubName = RemainingPath.Buffer;
|
|
||||||
if (*SubName == L'\\')
|
|
||||||
SubName++;
|
|
||||||
|
|
||||||
/* If RemainingPath contains \ we must return error
|
|
||||||
because CmiConnectHive() can not create trees */
|
|
||||||
if (wcschr (SubName, L'\\') != NULL)
|
|
||||||
{
|
|
||||||
ObDereferenceObject (ParentKey);
|
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT("RemainingPath %wZ ParentKey %p\n",
|
|
||||||
&RemainingPath, ParentKey);
|
|
||||||
|
|
||||||
Status = ObCreateObject(KernelMode,
|
|
||||||
CmiKeyType,
|
CmiKeyType,
|
||||||
NULL,
|
NULL,
|
||||||
KernelMode,
|
NULL);
|
||||||
NULL,
|
/* Yields a new reference */
|
||||||
sizeof(KEY_OBJECT),
|
ObpReleaseCapturedAttributes(&ObjectCreateInfo);
|
||||||
0,
|
|
||||||
0,
|
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
||||||
(PVOID*)&NewKey);
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
if (!NT_SUCCESS(Status))
|
return Status;
|
||||||
{
|
}
|
||||||
DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
|
|
||||||
ObDereferenceObject (ParentKey);
|
DPRINT ("RemainingPath %wZ\n", &RemainingPath);
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
return Status;
|
if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
|
||||||
}
|
{
|
||||||
|
ObDereferenceObject (ParentKey);
|
||||||
|
RtlFreeUnicodeString(&RemainingPath);
|
||||||
|
return STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore leading backslash */
|
||||||
|
SubName = RemainingPath.Buffer;
|
||||||
|
if (*SubName == L'\\')
|
||||||
|
SubName++;
|
||||||
|
|
||||||
|
/* If RemainingPath contains \ we must return error
|
||||||
|
because CmiConnectHive() can not create trees */
|
||||||
|
if (wcschr (SubName, L'\\') != NULL)
|
||||||
|
{
|
||||||
|
ObDereferenceObject (ParentKey);
|
||||||
|
RtlFreeUnicodeString(&RemainingPath);
|
||||||
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("RemainingPath %wZ ParentKey %p\n",
|
||||||
|
&RemainingPath, ParentKey);
|
||||||
|
|
||||||
|
Status = ObCreateObject(KernelMode,
|
||||||
|
CmiKeyType,
|
||||||
|
NULL,
|
||||||
|
KernelMode,
|
||||||
|
NULL,
|
||||||
|
sizeof(KEY_OBJECT),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(PVOID*)&NewKey);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
|
||||||
|
ObDereferenceObject (ParentKey);
|
||||||
|
RtlFreeUnicodeString(&RemainingPath);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
DPRINT("Inserting Key into Object Tree\n");
|
DPRINT("Inserting Key into Object Tree\n");
|
||||||
Status = ObInsertObject((PVOID)NewKey,
|
Status = ObInsertObject((PVOID)NewKey,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -787,56 +791,42 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
DPRINT("Status %x\n", Status);
|
DPRINT("Status %x\n", Status);
|
||||||
NewKey->RegistryHive = RegistryHive;
|
NewKey->RegistryHive = RegistryHive;
|
||||||
NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
|
NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
|
||||||
NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
|
NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
|
||||||
NewKey->Flags = 0;
|
NewKey->Flags = 0;
|
||||||
NewKey->NumberOfSubKeys = 0;
|
NewKey->NumberOfSubKeys = 0;
|
||||||
InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
|
NewKey->SubKeys = NULL;
|
||||||
if (NewKey->KeyCell->NumberOfSubKeys != 0)
|
InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
|
||||||
{
|
InsertTailList(&CmiConnectedHiveList, &NewKey->HiveList);
|
||||||
NewKey->SubKeys = ExAllocatePool(NonPagedPool,
|
|
||||||
NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
|
|
||||||
if (NewKey->SubKeys == NULL)
|
|
||||||
{
|
|
||||||
DPRINT("ExAllocatePool() failed\n");
|
|
||||||
ObDereferenceObject (NewKey);
|
|
||||||
ObDereferenceObject (ParentKey);
|
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NewKey->SubKeys = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT ("SubName %S\n", SubName);
|
DPRINT ("SubName %S\n", SubName);
|
||||||
|
|
||||||
Status = RtlpCreateUnicodeString(&NewKey->Name,
|
Status = RtlpCreateUnicodeString(&NewKey->Name,
|
||||||
SubName, NonPagedPool);
|
SubName, NonPagedPool);
|
||||||
RtlFreeUnicodeString(&RemainingPath);
|
RtlFreeUnicodeString(&RemainingPath);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
|
DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
|
||||||
if (NewKey->SubKeys != NULL)
|
if (NewKey->SubKeys != NULL)
|
||||||
{
|
{
|
||||||
ExFreePool (NewKey->SubKeys);
|
ExFreePool (NewKey->SubKeys);
|
||||||
}
|
}
|
||||||
ObDereferenceObject (NewKey);
|
ObDereferenceObject (NewKey);
|
||||||
ObDereferenceObject (ParentKey);
|
ObDereferenceObject (ParentKey);
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
CmiAddKeyToList (ParentKey, NewKey);
|
CmiAddKeyToList (ParentKey, NewKey);
|
||||||
ObDereferenceObject (ParentKey);
|
|
||||||
|
|
||||||
VERIFY_KEY_OBJECT(NewKey);
|
VERIFY_KEY_OBJECT(NewKey);
|
||||||
|
|
||||||
/* Note: Do not dereference NewKey here! */
|
/* We're holding a pointer to the parent key .. We must keep it
|
||||||
|
* referenced */
|
||||||
|
/* Note: Do not dereference NewKey here! */
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -845,9 +835,8 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
OUT PREGISTRY_HIVE *RegistryHive)
|
OUT PREGISTRY_HIVE *RegistryHive)
|
||||||
{
|
{
|
||||||
PKEY_OBJECT KeyObject;
|
PKEY_OBJECT KeyObject;
|
||||||
PREGISTRY_HIVE Hive;
|
|
||||||
HANDLE KeyHandle;
|
HANDLE KeyHandle;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
PLIST_ENTRY CurrentEntry;
|
PLIST_ENTRY CurrentEntry;
|
||||||
PKEY_OBJECT CurrentKey;
|
PKEY_OBJECT CurrentKey;
|
||||||
|
|
||||||
|
@ -875,6 +864,7 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
(PVOID*)&KeyObject,
|
(PVOID*)&KeyObject,
|
||||||
NULL);
|
NULL);
|
||||||
ZwClose (KeyHandle);
|
ZwClose (KeyHandle);
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
|
DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
|
||||||
|
@ -882,61 +872,39 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||||
}
|
}
|
||||||
DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
|
DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
|
||||||
|
|
||||||
if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
|
|
||||||
{
|
|
||||||
DPRINT1 ("Key is not the Hive-Root-Key\n");
|
|
||||||
ObDereferenceObject (KeyObject);
|
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquire registry lock exclusively */
|
/* Acquire registry lock exclusively */
|
||||||
KeEnterCriticalRegion();
|
KeEnterCriticalRegion();
|
||||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||||
|
|
||||||
CurrentEntry = CmiKeyObjectListHead.Flink;
|
/* Find out if we represent a connected hive. */
|
||||||
while (CurrentEntry != &CmiKeyObjectListHead)
|
for( CurrentEntry = CmiConnectedHiveList.Flink;
|
||||||
{
|
CurrentEntry != &CmiConnectedHiveList;
|
||||||
CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
|
CurrentEntry = CurrentEntry->Flink ) {
|
||||||
if (1 == ObGetObjectPointerCount(CurrentKey) &&
|
CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, HiveList);
|
||||||
!(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
|
if( CurrentKey == KeyObject ) {
|
||||||
{
|
/* Remove the connected hive from the connected hive list */
|
||||||
ObDereferenceObject(CurrentKey);
|
RemoveEntryList(CurrentEntry);
|
||||||
CurrentEntry = CmiKeyObjectListHead.Flink;
|
/* found ourselves in the connected hive list */
|
||||||
}
|
*RegistryHive = KeyObject->RegistryHive;
|
||||||
else
|
Status = STATUS_SUCCESS;
|
||||||
{
|
|
||||||
CurrentEntry = CurrentEntry->Flink;
|
/* Release references captured in CmiConnectHive */
|
||||||
}
|
ObDereferenceObject (KeyObject->ParentKey);
|
||||||
|
ObDereferenceObject (KeyObject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ObGetObjectHandleCount (KeyObject) != 0 ||
|
|
||||||
ObGetObjectPointerCount (KeyObject) != 2)
|
|
||||||
{
|
|
||||||
DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
|
|
||||||
ObDereferenceObject (KeyObject);
|
|
||||||
|
|
||||||
/* Release registry lock */
|
|
||||||
ExReleaseResourceLite (&CmiRegistryLock);
|
|
||||||
KeLeaveCriticalRegion();
|
|
||||||
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Hive = KeyObject->RegistryHive;
|
|
||||||
|
|
||||||
/* Dereference KeyObject twice to delete it */
|
|
||||||
ObDereferenceObject (KeyObject);
|
|
||||||
ObDereferenceObject (KeyObject);
|
|
||||||
|
|
||||||
*RegistryHive = Hive;
|
|
||||||
|
|
||||||
/* Release registry lock */
|
/* Release registry lock */
|
||||||
ExReleaseResourceLite (&CmiRegistryLock);
|
ExReleaseResourceLite (&CmiRegistryLock);
|
||||||
KeLeaveCriticalRegion();
|
KeLeaveCriticalRegion();
|
||||||
|
|
||||||
|
/* Release reference above */
|
||||||
|
ObDereferenceObject (KeyObject);
|
||||||
|
|
||||||
DPRINT ("CmiDisconnectHive() done\n");
|
DPRINT ("CmiDisconnectHive() done\n");
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -462,7 +462,7 @@ CmiObjectParse(IN PVOID ParsedObject,
|
||||||
ExReleaseResourceLite(&CmiRegistryLock);
|
ExReleaseResourceLite(&CmiRegistryLock);
|
||||||
KeLeaveCriticalRegion();
|
KeLeaveCriticalRegion();
|
||||||
|
|
||||||
DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
|
//DPRINT("CmiObjectParse: %s\n", FoundObject->Name);
|
||||||
|
|
||||||
*Path = EndPtr;
|
*Path = EndPtr;
|
||||||
|
|
||||||
|
@ -492,9 +492,9 @@ CmiObjectDelete(PVOID DeletedObject)
|
||||||
KeEnterCriticalRegion();
|
KeEnterCriticalRegion();
|
||||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||||
|
|
||||||
//if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
|
if (!NT_SUCCESS(CmiRemoveKeyFromList(KeyObject)))
|
||||||
{
|
{
|
||||||
// DPRINT1("Key not found in parent list ???\n");
|
DPRINT1("Key not found in parent list ???\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveEntryList(&KeyObject->ListEntry);
|
RemoveEntryList(&KeyObject->ListEntry);
|
||||||
|
@ -526,7 +526,7 @@ CmiObjectDelete(PVOID DeletedObject)
|
||||||
|
|
||||||
if (KeyObject->NumberOfSubKeys)
|
if (KeyObject->NumberOfSubKeys)
|
||||||
{
|
{
|
||||||
//KEBUGCHECK(REGISTRY_ERROR);
|
KEBUGCHECK(REGISTRY_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (KeyObject->SizeOfSubKeys)
|
if (KeyObject->SizeOfSubKeys)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue