Set the value/data cell to dirty, if an existing value is overwritten.
[reactos.git] / reactos / ntoskrnl / cm / ntfunc.c
index 9b1f635..e506b34 100644 (file)
@@ -1,5 +1,5 @@
 /* $Id$
- * 
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/cm/ntfunc.c
@@ -39,11 +39,11 @@ CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
                    IN OUT PLARGE_INTEGER Cookie)
 {
   PREGISTRY_CALLBACK Callback;
-  
+
   PAGED_CODE();
-  
+
   ASSERT(Function && Cookie);
-  
+
   Callback = ExAllocatePoolWithTag(PagedPool,
                                    sizeof(REGISTRY_CALLBACK),
                                    TAG('C', 'M', 'c', 'b'));
@@ -54,7 +54,7 @@ CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
     Callback->Function = Function;
     Callback->Context = Context;
     Callback->PendingDelete = FALSE;
-    
+
     /* add it to the callback list and receive a cookie for the callback */
     ExAcquireFastMutex(&CmiCallbackLock);
     /* FIXME - to receive a unique cookie we'll just return the pointer to the
@@ -63,7 +63,7 @@ CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
     InsertTailList(&CmiCallbackHead, &Callback->ListEntry);
 
     ExReleaseFastMutex(&CmiCallbackLock);
-    
+
     *Cookie = Callback->Cookie;
     return STATUS_SUCCESS;
   }
@@ -79,7 +79,7 @@ NTSTATUS STDCALL
 CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
 {
   PLIST_ENTRY CurrentEntry;
-  
+
   PAGED_CODE();
 
   ExAcquireFastMutex(&CmiCallbackLock);
@@ -121,7 +121,7 @@ CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
       }
     }
   }
-  
+
   ExReleaseFastMutex(&CmiCallbackLock);
 
   return STATUS_UNSUCCESSFUL;
@@ -133,9 +133,10 @@ CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
                            IN PVOID Argument2)
 {
   PLIST_ENTRY CurrentEntry;
-  
+  NTSTATUS Status = STATUS_SUCCESS;
+
   PAGED_CODE();
-  
+
   ExAcquireFastMutex(&CmiCallbackLock);
 
   for(CurrentEntry = CmiCallbackHead.Flink;
@@ -148,31 +149,29 @@ CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
     if(!CurrentCallback->PendingDelete &&
        ExAcquireRundownProtectionEx(&CurrentCallback->RundownRef, 1))
     {
-      NTSTATUS Status;
-      
       /* don't hold locks during the callbacks! */
       ExReleaseFastMutex(&CmiCallbackLock);
-      
+
       Status = CurrentCallback->Function(CurrentCallback->Context,
                                          Argument1,
                                          Argument2);
-      if(!NT_SUCCESS(Status))
-      {
-        /* one callback returned failure, don't call any more callbacks */
-        return Status;
-      }
 
       ExAcquireFastMutex(&CmiCallbackLock);
       /* don't release the rundown protection before holding the callback lock
          so the pointer to the next callback isn't cleared in case this callback
          get's deleted */
       ExReleaseRundownProtectionEx(&CurrentCallback->RundownRef, 1);
+      if(!NT_SUCCESS(Status))
+      {
+        /* one callback returned failure, don't call any more callbacks */
+        break;
+      }
     }
   }
-  
+
   ExReleaseFastMutex(&CmiCallbackLock);
-  
-  return STATUS_SUCCESS;
+
+  return Status;
 }
 
 
@@ -185,28 +184,95 @@ NtCreateKey(OUT PHANDLE KeyHandle,
            IN ULONG CreateOptions,
            OUT PULONG Disposition)
 {
-  UNICODE_STRING RemainingPath;
+  UNICODE_STRING RemainingPath = {0};
+  BOOLEAN FreeRemainingPath = TRUE;
+  ULONG LocalDisposition;
   PKEY_OBJECT KeyObject;
-  NTSTATUS Status;
-  PVOID Object;
+  NTSTATUS Status = STATUS_SUCCESS;
+  PVOID Object = NULL;
   PWSTR Start;
+  UNICODE_STRING ObjectName;
+  OBJECT_CREATE_INFORMATION ObjectCreateInfo;
   unsigned i;
-  
+  REG_PRE_CREATE_KEY_INFORMATION PreCreateKeyInfo;
+  REG_POST_CREATE_KEY_INFORMATION PostCreateKeyInfo;
+  KPROCESSOR_MODE PreviousMode;
+  UNICODE_STRING CapturedClass = {0};
+  HANDLE hKey;
+
   PAGED_CODE();
 
-  DPRINT("NtCreateKey (Name %wZ  KeyHandle %x  Root %x)\n",
-        ObjectAttributes->ObjectName,
-        KeyHandle,
-        ObjectAttributes->RootDirectory);
+  PreviousMode = KeGetPreviousMode();
 
-  Status = ObFindObject(ObjectAttributes,
-                       &Object,
-                       &RemainingPath,
-                       CmiKeyType);
+  if (PreviousMode != KernelMode)
+  {
+      _SEH_TRY
+      {
+          ProbeForWriteHandle(KeyHandle);
+          if (Disposition != NULL)
+          {
+              ProbeForWriteUlong(Disposition);
+          }
+      }
+      _SEH_HANDLE
+      {
+          Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+      
+      if (!NT_SUCCESS(Status))
+      {
+          return Status;
+      }
+  }
+  
+  if (Class != NULL)
+  {
+      Status = ProbeAndCaptureUnicodeString(&CapturedClass,
+                                            PreviousMode,
+                                            Class);
+      if (!NT_SUCCESS(Status))
+      {
+          return Status;
+      }
+  }
+
+  /* Capture all the info */
+  DPRINT("Capturing Create Info\n");
+  Status = ObpCaptureObjectAttributes(ObjectAttributes,
+                                      PreviousMode,
+                                      CmiKeyType,
+                                      &ObjectCreateInfo,
+                                      &ObjectName);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT("ObFindObject failed, Status: 0x%x\n", Status);
-      return(Status);
+      DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
+      goto Cleanup;
+    }
+
+  PostCreateKeyInfo.CompleteName = &ObjectName;
+  PreCreateKeyInfo.CompleteName = &ObjectName;
+  Status = CmiCallRegisteredCallbacks(RegNtPreCreateKey, &PreCreateKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObpReleaseCapturedAttributes(&ObjectCreateInfo);
+      goto Cleanup;
+    }
+    
+  Status = ObFindObject(&ObjectCreateInfo,
+                        &ObjectName,
+                        (PVOID*)&Object,
+                        &RemainingPath,
+                        CmiKeyType);
+  ObpReleaseCapturedAttributes(&ObjectCreateInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      PostCreateKeyInfo.Object = NULL;
+      PostCreateKeyInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+      DPRINT("CmpFindObject failed, Status: 0x%x\n", Status);
+      goto Cleanup;
     }
 
   DPRINT("RemainingPath %wZ\n", &RemainingPath);
@@ -216,25 +282,29 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       /* Fail if the key has been deleted */
       if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
        {
-         ObDereferenceObject(Object);
-         RtlFreeUnicodeString(&RemainingPath);
+          PostCreateKeyInfo.Object = NULL;
+          PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
+          CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
          DPRINT("Object marked for delete!\n");
-         return(STATUS_UNSUCCESSFUL);
+         Status = STATUS_UNSUCCESSFUL;
+         goto Cleanup;
        }
 
-      if (Disposition)
-       *Disposition = REG_OPENED_EXISTING_KEY;
-
-      Status = ObCreateHandle(PsGetCurrentProcess(),
+      Status = ObpCreateHandle(PsGetCurrentProcess(),
                              Object,
                              DesiredAccess,
                              TRUE,
-                             KeyHandle);
+                             &hKey);
 
-      DPRINT("ObCreateHandle failed Status 0x%x\n", Status);
-      ObDereferenceObject(Object);
-      RtlFreeUnicodeString(&RemainingPath);
-      return Status;
+      DPRINT("ObpCreateHandle failed Status 0x%x\n", Status);
+
+      PostCreateKeyInfo.Object = NULL;
+      PostCreateKeyInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+      LocalDisposition = REG_OPENED_EXISTING_KEY;
+      goto SuccessReturn;
     }
 
   /* If RemainingPath contains \ we must return error
@@ -247,19 +317,23 @@ NtCreateKey(OUT PHANDLE KeyHandle,
     {
       if (L'\\' == RemainingPath.Buffer[i])
         {
-          ObDereferenceObject(Object);
-          DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
-          RtlFreeUnicodeString(&RemainingPath);
-          return STATUS_OBJECT_NAME_NOT_FOUND;
+          DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
+
+          PostCreateKeyInfo.Object = NULL;
+          PostCreateKeyInfo.Status = STATUS_OBJECT_NAME_NOT_FOUND;
+          CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+          Status = STATUS_OBJECT_NAME_NOT_FOUND;
+          goto Cleanup;
         }
     }
 
-  DPRINT("RemainingPath %S  ParentObject %x\n", RemainingPath.Buffer, Object);
+  DPRINT("RemainingPath %S  ParentObject 0x%p\n", RemainingPath.Buffer, Object);
 
-  Status = ObCreateObject(ExGetPreviousMode(),
+  Status = ObCreateObject(PreviousMode,
                          CmiKeyType,
                          NULL,
-                         ExGetPreviousMode(),
+                         PreviousMode,
                          NULL,
                          sizeof(KEY_OBJECT),
                          0,
@@ -268,7 +342,11 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   if (!NT_SUCCESS(Status))
     {
       DPRINT1("ObCreateObject() failed!\n");
-      return(Status);
+      PostCreateKeyInfo.Object = NULL;
+      PostCreateKeyInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+      goto Cleanup;
     }
 
   Status = ObInsertObject((PVOID)KeyObject,
@@ -276,13 +354,17 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                          DesiredAccess,
                          0,
                          NULL,
-                         KeyHandle);
+                         &hKey);
   if (!NT_SUCCESS(Status))
     {
       ObDereferenceObject(KeyObject);
-      RtlFreeUnicodeString(&RemainingPath);
       DPRINT1("ObInsertObject() failed!\n");
-      return(Status);
+
+      PostCreateKeyInfo.Object = NULL;
+      PostCreateKeyInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+      goto Cleanup;
     }
 
   KeyObject->ParentKey = Object;
@@ -309,7 +391,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                        KeyObject,
                        &RemainingPath,
                        TitleIndex,
-                       Class,
+                       &CapturedClass,
                        CreateOptions);
   if (!NT_SUCCESS(Status))
     {
@@ -318,19 +400,23 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       ExReleaseResourceLite(&CmiRegistryLock);
       KeLeaveCriticalRegion();
       ObDereferenceObject(KeyObject);
-      ObDereferenceObject(Object);
-      RtlFreeUnicodeString(&RemainingPath);
-      return STATUS_UNSUCCESSFUL;
+
+      PostCreateKeyInfo.Object = NULL;
+      PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
+      CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+      Status = STATUS_UNSUCCESSFUL;
+      goto Cleanup;
     }
 
   if (Start == RemainingPath.Buffer)
     {
       KeyObject->Name = RemainingPath;
+      FreeRemainingPath = FALSE;
     }
   else
     {
       RtlpCreateUnicodeString(&KeyObject->Name, Start, NonPagedPool);
-      RtlFreeUnicodeString(&RemainingPath);
     }
 
   if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
@@ -344,10 +430,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       KeyObject->KeyCell->SecurityKeyOffset = -1;
       /* This key must remain in memory unless it is deleted
         or file is unloaded */
-      ObReferenceObjectByPointer(KeyObject,
-                                STANDARD_RIGHTS_REQUIRED,
-                                NULL,
-                                UserMode);
+      ObReferenceObject(KeyObject);
     }
 
   CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
@@ -358,13 +441,38 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
+  PostCreateKeyInfo.Object = KeyObject;
+  PostCreateKeyInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
+
+  CmiSyncHives();
   
-  ObDereferenceObject(Object);
+  LocalDisposition = REG_CREATED_NEW_KEY;
 
-  if (Disposition)
-    *Disposition = REG_CREATED_NEW_KEY;
+SuccessReturn:
+  _SEH_TRY
+  {
+      *KeyHandle = hKey;
+      if (Disposition != NULL)
+      {
+          *Disposition = LocalDisposition;
+      }
+  }
+  _SEH_HANDLE
+  {
+      Status = _SEH_GetExceptionCode();
+  }
+  _SEH_END;
 
-  CmiSyncHives();
+Cleanup:
+  if (Class != NULL)
+  {
+    ReleaseCapturedUnicodeString(&CapturedClass,
+                                 PreviousMode);
+  }
+  if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+  if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
+  if (Object != NULL) ObDereferenceObject(Object);
 
   return Status;
 }
@@ -376,11 +484,13 @@ NtDeleteKey(IN HANDLE KeyHandle)
   KPROCESSOR_MODE PreviousMode;
   PKEY_OBJECT KeyObject;
   NTSTATUS Status;
-  
+  REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
 
-  DPRINT1("NtDeleteKey(KeyHandle %x) called\n", KeyHandle);
-  
+  DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle);
+
   PreviousMode = ExGetPreviousMode();
 
   /* Verify that the handle is valid and is a registry key */
@@ -396,6 +506,17 @@ NtDeleteKey(IN HANDLE KeyHandle)
       return Status;
     }
 
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  DeleteKeyInfo.Object = (PVOID)KeyObject;
+  Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &DeleteKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      PostOperationInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtDeleteKey, &PostOperationInfo);
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock */
   KeEnterCriticalRegion();
   ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
@@ -418,16 +539,20 @@ NtDeleteKey(IN HANDLE KeyHandle)
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
-  DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
+  DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
 
-  /* Dereference the object */
-  ObDereferenceObject(KeyObject);
   /* Remove the keep-alive reference */
   ObDereferenceObject(KeyObject);
 
   if (KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
     ObDereferenceObject(KeyObject);
 
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
+
+  /* Dereference the object */
+  ObDereferenceObject(KeyObject);
+
   DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
   DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID)KeyObject));
 
@@ -462,12 +587,14 @@ NtEnumerateKey(IN HANDLE KeyHandle,
   ULONG NameSize, ClassSize;
   KPROCESSOR_MODE PreviousMode;
   NTSTATUS Status;
-  
+  REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
-  
+
   PreviousMode = ExGetPreviousMode();
 
-  DPRINT("KH %x  I %d  KIC %x KI %x  L %d  RL %x\n",
+  DPRINT("KH 0x%p  I %d  KIC %x KI 0x%p  L %d  RL 0x%p\n",
         KeyHandle,
         Index,
         KeyInformationClass,
@@ -488,6 +615,20 @@ NtEnumerateKey(IN HANDLE KeyHandle,
       return(Status);
     }
 
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  EnumerateKeyInfo.Object = (PVOID)KeyObject;
+  EnumerateKeyInfo.Index = Index;
+  EnumerateKeyInfo.KeyInformationClass = KeyInformationClass;
+  EnumerateKeyInfo.Length = Length;
+  EnumerateKeyInfo.ResultLength = ResultLength;
+
+  Status = CmiCallRegisteredCallbacks(RegNtEnumerateKey, &EnumerateKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock */
   KeEnterCriticalRegion();
   ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
@@ -505,6 +646,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
     {
       ExReleaseResourceLite(&CmiRegistryLock);
       KeLeaveCriticalRegion();
+      PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
+      CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
       ObDereferenceObject(KeyObject);
       DPRINT("No more volatile entries\n");
       return STATUS_NO_MORE_ENTRIES;
@@ -534,6 +677,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
        {
          ExReleaseResourceLite(&CmiRegistryLock);
          KeLeaveCriticalRegion();
+          PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
+          CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
          ObDereferenceObject(KeyObject);
          DPRINT("No more non-volatile entries\n");
          return STATUS_NO_MORE_ENTRIES;
@@ -548,6 +693,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
        {
          ExReleaseResourceLite(&CmiRegistryLock);
          KeLeaveCriticalRegion();
+          PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
+          CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
          ObDereferenceObject(KeyObject);
          return STATUS_NO_MORE_ENTRIES;
        }
@@ -558,6 +705,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
          DPRINT("CmiGetBlock() failed\n");
          ExReleaseResourceLite(&CmiRegistryLock);
          KeLeaveCriticalRegion();
+          PostOperationInfo.Status = STATUS_UNSUCCESSFUL;
+          CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
          ObDereferenceObject(KeyObject);
          return STATUS_UNSUCCESSFUL;
        }
@@ -571,6 +720,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
     {
       ExReleaseResourceLite(&CmiRegistryLock);
       KeLeaveCriticalRegion();
+      PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
+      CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
       ObDereferenceObject(KeyObject);
       DPRINT("No more entries\n");
       return STATUS_NO_MORE_ENTRIES;
@@ -687,10 +838,10 @@ NtEnumerateKey(IN HANDLE KeyHandle,
                Status = STATUS_BUFFER_OVERFLOW;
                CHECKPOINT;
              }
-           else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - 
+           else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
                     NameSize < ClassSize)
              {
-               ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - 
+               ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
                            NameSize;
                Status = STATUS_BUFFER_OVERFLOW;
                CHECKPOINT;
@@ -786,6 +937,10 @@ NtEnumerateKey(IN HANDLE KeyHandle,
 
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
+
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
+
   ObDereferenceObject(KeyObject);
 
   DPRINT("Returning status %x\n", Status);
@@ -812,10 +967,10 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
   PKEY_VALUE_BASIC_INFORMATION  ValueBasicInformation;
   PKEY_VALUE_PARTIAL_INFORMATION  ValuePartialInformation;
   PKEY_VALUE_FULL_INFORMATION  ValueFullInformation;
-  
+
   PAGED_CODE();
 
-  DPRINT("KH %x  I %d  KVIC %x  KVI %x  L %d  RL %x\n",
+  DPRINT("KH 0x%p  I %d  KVIC %x  KVI 0x%p  L %d  RL 0x%p\n",
         KeyHandle,
         Index,
         KeyValueInformationClass,
@@ -879,7 +1034,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
             }
           else
             {
-              ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION) 
+              ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
                 KeyValueInformation;
               ValueBasicInformation->TitleIndex = 0;
               ValueBasicInformation->Type = ValueCell->DataType;
@@ -911,7 +1066,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
         case KeyValuePartialInformation:
           DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
 
-          *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + 
+          *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
             DataSize;
 
           if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
@@ -933,18 +1088,18 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                   Status = STATUS_BUFFER_OVERFLOW;
                   CHECKPOINT;
                 }
-              
+
               if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
               {
                 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
-                RtlCopyMemory(ValuePartialInformation->Data, 
+                RtlCopyMemory(ValuePartialInformation->Data,
                   DataCell->Data,
                   DataSize);
               }
               else
               {
-                RtlCopyMemory(ValuePartialInformation->Data, 
-                  &ValueCell->DataOffset, 
+                RtlCopyMemory(ValuePartialInformation->Data,
+                  &ValueCell->DataOffset,
                   DataSize);
               }
             }
@@ -967,31 +1122,29 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
             }
           else
             {
-              ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION) 
+              ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
                 KeyValueInformation;
               ValueFullInformation->TitleIndex = 0;
               ValueFullInformation->Type = ValueCell->DataType;
               ValueFullInformation->NameLength = NameSize;
-              ValueFullInformation->DataOffset = 
+              ValueFullInformation->DataOffset =
                 (ULONG_PTR)ValueFullInformation->Name -
                 (ULONG_PTR)ValueFullInformation +
                 ValueFullInformation->NameLength;
               ValueFullInformation->DataOffset =
                   ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
               ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
-              
-             if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
-                 NameSize)
+
+              if (Length < ValueFullInformation->DataOffset)
                {
                  NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
                  DataSize = 0;
                  Status = STATUS_BUFFER_OVERFLOW;
                  CHECKPOINT;
                }
-              else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
-                       Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
+              else if (Length - ValueFullInformation->DataOffset < DataSize) 
                {
-                 DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) - NameSize, sizeof(PVOID));
+                 DataSize = Length - ValueFullInformation->DataOffset;
                  Status = STATUS_BUFFER_OVERFLOW;
                  CHECKPOINT;
                }
@@ -1050,11 +1203,11 @@ NtFlushKey(IN HANDLE KeyHandle)
   PKEY_OBJECT  KeyObject;
   PREGISTRY_HIVE  RegistryHive;
   KPROCESSOR_MODE  PreviousMode;
-  
+
   PAGED_CODE();
 
   DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
-  
+
   PreviousMode = ExGetPreviousMode();
 
   /* Verify that the handle is valid and is a registry key */
@@ -1103,48 +1256,88 @@ NtOpenKey(OUT PHANDLE KeyHandle,
 {
   UNICODE_STRING RemainingPath;
   KPROCESSOR_MODE PreviousMode;
-  PVOID Object;
+  PVOID Object = NULL;
   HANDLE hKey;
   NTSTATUS Status = STATUS_SUCCESS;
-  
+  UNICODE_STRING ObjectName;
+  OBJECT_CREATE_INFORMATION ObjectCreateInfo;
+  REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo;
+  REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo;
+
   PAGED_CODE();
 
-  DPRINT("NtOpenKey(KH %x  DA %x  OA %x  OA->ON '%wZ'\n",
+  DPRINT("NtOpenKey(KH 0x%p  DA %x  OA 0x%p  OA->ON '%wZ'\n",
         KeyHandle,
         DesiredAccess,
         ObjectAttributes,
         ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
 
+  /* Check place for result handle, if it's null - return immediately */
+  if (KeyHandle == NULL)
+         return(STATUS_INVALID_PARAMETER);
+
   PreviousMode = ExGetPreviousMode();
 
   if(PreviousMode != KernelMode)
   {
     _SEH_TRY
     {
-      ProbeForWrite(KeyHandle,
-                    sizeof(HANDLE),
-                    sizeof(ULONG));
+      ProbeForWriteHandle(KeyHandle);
     }
     _SEH_HANDLE
     {
       Status = _SEH_GetExceptionCode();
     }
     _SEH_END;
-    
+
     if(!NT_SUCCESS(Status))
     {
       return Status;
     }
   }
 
+  /* WINE checks for the length also */
+  /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
+         return(STATUS_BUFFER_OVERFLOW);*/
+
+      /* Capture all the info */
+   DPRINT("Capturing Create Info\n");
+   Status = ObpCaptureObjectAttributes(ObjectAttributes,
+                                       PreviousMode,
+                                       CmiKeyType,
+                                       &ObjectCreateInfo,
+                                       &ObjectName);
+   if (!NT_SUCCESS(Status))
+     {
+       DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
+       return Status;
+     }
+
+  PostOpenKeyInfo.CompleteName = &ObjectName;
+  PreOpenKeyInfo.CompleteName = &ObjectName;
+  Status = CmiCallRegisteredCallbacks(RegNtPreOpenKey, &PreOpenKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObpReleaseCapturedAttributes(&ObjectCreateInfo);
+      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+      return Status;
+    }
+
+
   RemainingPath.Buffer = NULL;
-  Status = ObFindObject(ObjectAttributes,
-                       &Object,
-                       &RemainingPath,
-                       CmiKeyType);
+
+  Status = ObFindObject(&ObjectCreateInfo,
+                        &ObjectName,
+                       (PVOID*)&Object,
+                        &RemainingPath,
+                        CmiKeyType);
+  ObpReleaseCapturedAttributes(&ObjectCreateInfo);
   if (!NT_SUCCESS(Status))
     {
-      return(Status);
+      DPRINT("CmpFindObject() returned 0x%08lx\n", Status);
+      Status = STATUS_INVALID_HANDLE; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
+      hKey = *KeyHandle; /* Preserve hkResult value */
+      goto openkey_cleanup;
     }
 
   VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
@@ -1153,9 +1346,10 @@ NtOpenKey(OUT PHANDLE KeyHandle,
 
   if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
     {
-      ObDereferenceObject(Object);
       RtlFreeUnicodeString(&RemainingPath);
-      return STATUS_OBJECT_NAME_NOT_FOUND;
+      Status = STATUS_OBJECT_NAME_NOT_FOUND;
+      hKey = NULL;
+      goto openkey_cleanup;
     }
 
   RtlFreeUnicodeString(&RemainingPath);
@@ -1163,20 +1357,30 @@ NtOpenKey(OUT PHANDLE KeyHandle,
   /* Fail if the key has been deleted */
   if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
     {
-      ObDereferenceObject(Object);
-      return(STATUS_UNSUCCESSFUL);
+      Status = STATUS_UNSUCCESSFUL;
+      hKey = NULL;
+      goto openkey_cleanup;
     }
 
-  Status = ObCreateHandle(PsGetCurrentProcess(),
+  Status = ObpCreateHandle(PsGetCurrentProcess(),
                          Object,
                          DesiredAccess,
                          TRUE,
                          &hKey);
-  ObDereferenceObject(Object);
 
   if (!NT_SUCCESS(Status))
+     hKey = NULL;
+
+openkey_cleanup:
+
+  PostOpenKeyInfo.Object = NT_SUCCESS(Status) ? (PVOID)Object : NULL;
+  PostOpenKeyInfo.Status = Status;
+  CmiCallRegisteredCallbacks (RegNtPostOpenKey, &PostOpenKeyInfo);
+  if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+
+  if (Object)
     {
-      return(Status);
+      ObDereferenceObject(Object);
     }
 
   _SEH_TRY
@@ -1209,10 +1413,12 @@ NtQueryKey(IN HANDLE KeyHandle,
   PKEY_CELL KeyCell;
   ULONG NameSize, ClassSize;
   NTSTATUS Status;
-  
+  REG_QUERY_KEY_INFORMATION QueryKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
 
-  DPRINT("NtQueryKey(KH %x  KIC %x  KI %x  L %d  RL %x)\n",
+  DPRINT("NtQueryKey(KH 0x%p  KIC %x  KI 0x%p  L %d  RL 0x%p)\n",
         KeyHandle,
         KeyInformationClass,
         KeyInformation,
@@ -1231,6 +1437,20 @@ NtQueryKey(IN HANDLE KeyHandle,
       return Status;
     }
 
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  QueryKeyInfo.Object = (PVOID)KeyObject;
+  QueryKeyInfo.KeyInformationClass = KeyInformationClass;
+  QueryKeyInfo.KeyInformation = KeyInformation;
+  QueryKeyInfo.Length = Length;
+  QueryKeyInfo.ResultLength = ResultLength;
+  
+  Status = CmiCallRegisteredCallbacks(RegNtQueryKey, &QueryKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock */
   KeEnterCriticalRegion();
   ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
@@ -1308,10 +1528,10 @@ NtQueryKey(IN HANDLE KeyHandle,
                Status = STATUS_BUFFER_OVERFLOW;
                CHECKPOINT;
              }
-           else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - 
+           else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
                     NameSize < ClassSize)
              {
-               ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) - 
+               ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
                            NameSize;
                Status = STATUS_BUFFER_OVERFLOW;
                CHECKPOINT;
@@ -1368,7 +1588,7 @@ NtQueryKey(IN HANDLE KeyHandle,
                Status = STATUS_BUFFER_OVERFLOW;
                CHECKPOINT;
              }
-             
+
            if (ClassSize)
              {
                ClassCell = CmiGetCell (KeyObject->RegistryHive,
@@ -1395,6 +1615,10 @@ NtQueryKey(IN HANDLE KeyHandle,
 
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
+
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
+
   ObDereferenceObject(KeyObject);
 
   return(Status);
@@ -1419,10 +1643,12 @@ NtQueryValueKey(IN HANDLE KeyHandle,
   PKEY_VALUE_BASIC_INFORMATION  ValueBasicInformation;
   PKEY_VALUE_PARTIAL_INFORMATION  ValuePartialInformation;
   PKEY_VALUE_FULL_INFORMATION  ValueFullInformation;
-  
+  REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
 
-  DPRINT("NtQueryValueKey(KeyHandle %x  ValueName %S  Length %x)\n",
+  DPRINT("NtQueryValueKey(KeyHandle 0x%p  ValueName %S  Length %x)\n",
     KeyHandle, ValueName->Buffer, Length);
 
   /* Verify that the handle is valid and is a registry key */
@@ -1435,7 +1661,21 @@ NtQueryValueKey(IN HANDLE KeyHandle,
 
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status);
+      DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
+      return Status;
+    }
+  
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  QueryValueKeyInfo.Object = (PVOID)KeyObject;
+  QueryValueKeyInfo.ValueName = ValueName;
+  QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
+  QueryValueKeyInfo.Length = Length;
+  QueryValueKeyInfo.ResultLength = ResultLength;
+
+  Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(KeyObject);
       return Status;
     }
 
@@ -1480,7 +1720,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
          }
        else
          {
-           ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION) 
+           ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
              KeyValueInformation;
            ValueBasicInformation->TitleIndex = 0;
            ValueBasicInformation->Type = ValueCell->DataType;
@@ -1573,7 +1813,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
            ValueFullInformation->TitleIndex = 0;
            ValueFullInformation->Type = ValueCell->DataType;
            ValueFullInformation->NameLength = NameSize;
-           ValueFullInformation->DataOffset = 
+           ValueFullInformation->DataOffset =
              (ULONG_PTR)ValueFullInformation->Name -
              (ULONG_PTR)ValueFullInformation +
              ValueFullInformation->NameLength;
@@ -1637,6 +1877,9 @@ NtQueryValueKey(IN HANDLE KeyHandle,
 ByeBye:;
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
+
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
   ObDereferenceObject(KeyObject);
 
   return Status;
@@ -1661,10 +1904,12 @@ NtSetValueKey(IN HANDLE KeyHandle,
   PDATA_CELL NewDataCell;
   PHBIN pBin;
   ULONG DesiredAccess;
-  
+  REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
 
-  DPRINT("NtSetValueKey(KeyHandle %x  ValueName '%wZ'  Type %d)\n",
+  DPRINT("NtSetValueKey(KeyHandle 0x%p  ValueName '%wZ'  Type %d)\n",
         KeyHandle, ValueName, Type);
 
   DesiredAccess = KEY_SET_VALUE;
@@ -1679,6 +1924,20 @@ NtSetValueKey(IN HANDLE KeyHandle,
   if (!NT_SUCCESS(Status))
     return(Status);
 
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  SetValueKeyInfo.Object = (PVOID)KeyObject;
+  SetValueKeyInfo.ValueName = ValueName;
+  SetValueKeyInfo.TitleIndex = TitleIndex;
+  SetValueKeyInfo.Type = Type;
+  SetValueKeyInfo.Data = Data;
+  SetValueKeyInfo.DataSize = DataSize;
+  Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock exclucively */
   KeEnterCriticalRegion();
   ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
@@ -1710,6 +1969,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
 
       ExReleaseResourceLite(&CmiRegistryLock);
       KeLeaveCriticalRegion();
+      PostOperationInfo.Status = Status;
+      CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
       ObDereferenceObject(KeyObject);
       return Status;
     }
@@ -1732,7 +1993,6 @@ NtSetValueKey(IN HANDLE KeyHandle,
       RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
       ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
       ValueCell->DataType = Type;
-      RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
       CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
     }
   else if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
@@ -1744,6 +2004,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
       RtlCopyMemory(DataCell->Data, Data, DataSize);
       ValueCell->DataSize = DataSize;
       ValueCell->DataType = Type;
+      CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
+      CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
     }
   else
     {
@@ -1775,6 +2037,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
 
          ExReleaseResourceLite(&CmiRegistryLock);
          KeLeaveCriticalRegion();
+          PostOperationInfo.Status = Status;
+          CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
          ObDereferenceObject(KeyObject);
 
          return Status;
@@ -1800,6 +2064,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
 
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
   ObDereferenceObject(KeyObject);
 
   CmiSyncHives();
@@ -1816,14 +2082,20 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
 {
   PKEY_OBJECT KeyObject;
   NTSTATUS Status;
-  
+  REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+  KPROCESSOR_MODE PreviousMode;
+  UNICODE_STRING CapturedValueName;
+
   PAGED_CODE();
+  
+  PreviousMode = KeGetPreviousMode();
 
   /* Verify that the handle is valid and is a registry key */
   Status = ObReferenceObjectByHandle(KeyHandle,
-               KEY_QUERY_VALUE,
+               KEY_SET_VALUE,
                CmiKeyType,
-               UserMode,
+               PreviousMode,
                (PVOID *)&KeyObject,
                NULL);
   if (!NT_SUCCESS(Status))
@@ -1831,6 +2103,27 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
       return Status;
     }
 
+  Status = ProbeAndCaptureUnicodeString(&CapturedValueName,
+                                        PreviousMode,
+                                        ValueName);
+  if (!NT_SUCCESS(Status))
+    {
+      goto Fail;
+    }
+  DeleteValueKeyInfo.Object = (PVOID)KeyObject;
+  DeleteValueKeyInfo.ValueName = &CapturedValueName;
+
+  /* FIXME - check if value exists before calling the callbacks? */
+  Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, &DeleteValueKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ReleaseCapturedUnicodeString(&CapturedValueName,
+                                   PreviousMode);
+Fail:
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock */
   KeEnterCriticalRegion();
   ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
@@ -1849,6 +2142,14 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
+  ReleaseCapturedUnicodeString(&CapturedValueName,
+                               PreviousMode);
+
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  PostOperationInfo.Status = Status;
+
+  CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, &PostOperationInfo);
+
   ObDereferenceObject (KeyObject);
 
   CmiSyncHives ();
@@ -1889,7 +2190,7 @@ NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   ULONG BufferSize;
   ULONG Length;
   NTSTATUS Status;
-  
+
   PAGED_CODE();
 
   DPRINT ("NtLoadKey2() called\n");
@@ -2024,7 +2325,7 @@ NtNotifyChangeKey (IN HANDLE KeyHandle,
                   IN ULONG Length,
                   IN BOOLEAN Asynchronous)
 {
-     return NtNotifyChangeMultipleKeys(KeyHandle,          
+     return NtNotifyChangeMultipleKeys(KeyHandle,
                                        0,
                                        NULL,
                                        Event,
@@ -2057,7 +2358,9 @@ NtQueryMultipleValueKey (IN HANDLE KeyHandle,
   NTSTATUS Status;
   PUCHAR DataPtr;
   ULONG i;
-  
+  REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
   PAGED_CODE();
 
   /* Verify that the handle is valid and is a registry key */
@@ -2073,6 +2376,21 @@ NtQueryMultipleValueKey (IN HANDLE KeyHandle,
       return(Status);
     }
 
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  QueryMultipleValueKeyInfo.Object = (PVOID)KeyObject;
+  QueryMultipleValueKeyInfo.ValueEntries = ValueList;
+  QueryMultipleValueKeyInfo.EntryCount = NumberOfValues;
+  QueryMultipleValueKeyInfo.ValueBuffer = Buffer;
+  QueryMultipleValueKeyInfo.BufferLength = Length;
+  QueryMultipleValueKeyInfo.RequiredBufferLength = ReturnLength;
+
+  Status = CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey, &QueryMultipleValueKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject(KeyObject);
+      return Status;
+    }
+
   /* Acquire hive lock */
   KeEnterCriticalRegion();
   ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
@@ -2152,6 +2470,9 @@ NtQueryMultipleValueKey (IN HANDLE KeyHandle,
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey, &PostOperationInfo);
+
   ObDereferenceObject(KeyObject);
 
   DPRINT("Return Status 0x%X\n", Status);
@@ -2187,7 +2508,7 @@ NtSaveKey (IN HANDLE KeyHandle,
   PREGISTRY_HIVE TempHive;
   PKEY_OBJECT KeyObject;
   NTSTATUS Status;
-  
+
   PAGED_CODE();
 
   DPRINT ("NtSaveKey() called\n");
@@ -2291,14 +2612,10 @@ NtSetInformationKey (IN HANDLE KeyHandle,
 {
   PKEY_OBJECT KeyObject;
   NTSTATUS Status;
-  
-  PAGED_CODE();
+  REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo;
+  REG_POST_OPERATION_INFORMATION PostOperationInfo;
 
-  if (KeyInformationClass != KeyWriteTimeInformation)
-    return STATUS_INVALID_INFO_CLASS;
-
-  if (KeyInformationLength != sizeof (KEY_WRITE_TIME_INFORMATION))
-    return STATUS_INFO_LENGTH_MISMATCH;
+  PAGED_CODE();
 
   /* Verify that the handle is valid and is a registry key */
   Status = ObReferenceObjectByHandle (KeyHandle,
@@ -2313,25 +2630,56 @@ NtSetInformationKey (IN HANDLE KeyHandle,
       return Status;
     }
 
-  /* Acquire hive lock */
-  KeEnterCriticalRegion();
-  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
+  PostOperationInfo.Object = (PVOID)KeyObject;
+  SetInformationKeyInfo.Object = (PVOID)KeyObject;
+  SetInformationKeyInfo.KeySetInformationClass = KeyInformationClass;
+  SetInformationKeyInfo.KeySetInformation = KeyInformation;
+  SetInformationKeyInfo.KeySetInformationLength = KeyInformationLength;
 
-  VERIFY_KEY_OBJECT(KeyObject);
+  Status = CmiCallRegisteredCallbacks(RegNtSetInformationKey, &SetInformationKeyInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject (KeyObject);
+      return Status;
+    }
 
-  KeyObject->KeyCell->LastWriteTime.QuadPart =
-    ((PKEY_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
+  if (KeyInformationClass != KeyWriteTimeInformation)
+    {
+      Status = STATUS_INVALID_INFO_CLASS;
+    }
 
-  CmiMarkBlockDirty (KeyObject->RegistryHive,
-                    KeyObject->KeyCellOffset);
+  else if (KeyInformationLength != sizeof (KEY_WRITE_TIME_INFORMATION))
+    {
+      Status = STATUS_INFO_LENGTH_MISMATCH;
+    }
+  else
+    {
+      /* Acquire hive lock */
+      KeEnterCriticalRegion();
+      ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
-  /* Release hive lock */
-  ExReleaseResourceLite(&CmiRegistryLock);
-  KeLeaveCriticalRegion();
+      VERIFY_KEY_OBJECT(KeyObject);
+
+      KeyObject->KeyCell->LastWriteTime.QuadPart =
+        ((PKEY_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
+
+      CmiMarkBlockDirty (KeyObject->RegistryHive,
+                        KeyObject->KeyCellOffset);
+
+      /* Release hive lock */
+      ExReleaseResourceLite(&CmiRegistryLock);
+      KeLeaveCriticalRegion();
+    }
+
+  PostOperationInfo.Status = Status;
+  CmiCallRegisteredCallbacks(RegNtPostSetInformationKey, &PostOperationInfo);
 
   ObDereferenceObject (KeyObject);
 
-  CmiSyncHives ();
+  if (NT_SUCCESS(Status))
+    {
+      CmiSyncHives ();
+    }
 
   DPRINT ("NtSaveKey() done\n");
 
@@ -2349,7 +2697,7 @@ NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes)
 {
   PREGISTRY_HIVE RegistryHive;
   NTSTATUS Status;
-  
+
   PAGED_CODE();
 
   DPRINT ("NtUnloadKey() called\n");
@@ -2397,7 +2745,7 @@ NTSTATUS STDCALL
 NtInitializeRegistry (IN BOOLEAN SetUpBoot)
 {
   NTSTATUS Status;
-  
+
   PAGED_CODE();
 
   if (CmiRegistryInitialized == TRUE)