implemented CmUnRegisterCallback() and CmUnRegisterCallback()
Modified: trunk/reactos/ntoskrnl/cm/cm.h
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
Modified: trunk/reactos/ntoskrnl/cm/registry.c

Modified: trunk/reactos/ntoskrnl/cm/cm.h
--- trunk/reactos/ntoskrnl/cm/cm.h	2005-02-21 00:39:59 UTC (rev 13700)
+++ trunk/reactos/ntoskrnl/cm/cm.h	2005-02-21 02:41:16 UTC (rev 13701)
@@ -372,13 +372,71 @@
 
 extern ERESOURCE CmiRegistryLock;
 
+typedef enum _REG_NOTIFY_CLASS
+{
+  RegNtDeleteKey,
+  RegNtPreDeleteKey = RegNtDeleteKey,
+  RegNtSetValueKey,
+  RegNtPreSetValueKey = RegNtSetValueKey,
+  RegNtDeleteValueKey,
+  RegNtPreDeleteValueKey = RegNtDeleteValueKey,
+  RegNtSetInformationKey,
+  RegNtPreSetInformationKey = RegNtSetInformationKey,
+  RegNtRenameKey,
+  RegNtPreRenameKey = RegNtRenameKey,
+  RegNtEnumerateKey,
+  RegNtPreEnumerateKey = RegNtEnumerateKey,
+  RegNtEnumerateValueKey,
+  RegNtPreEnumerateValueKey = RegNtEnumerateValueKey,
+  RegNtQueryKey,
+  RegNtPreQueryKey = RegNtQueryKey,
+  RegNtQueryValueKey,
+  RegNtPreQueryValueKey = RegNtQueryValueKey,
+  RegNtQueryMultipleValueKey,
+  RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey,
+  RegNtPreCreateKey,
+  RegNtPostCreateKey,
+  RegNtPreOpenKey,
+  RegNtPostOpenKey,
+  RegNtKeyHandleClose,
+  RegNtPreKeyHandleClose = RegNtKeyHandleClose,
+  RegNtPostDeleteKey,
+  RegNtPostSetValueKey,
+  RegNtPostDeleteValueKey,
+  RegNtPostSetInformationKey,
+  RegNtPostRenameKey,
+  RegNtPostEnumerateKey,
+  RegNtPostEnumerateValueKey,
+  RegNtPostQueryKey,
+  RegNtPostQueryValueKey,
+  RegNtPostQueryMultipleValueKey,
+  RegNtPostKeyHandleClose,
+  RegNtPreCreateKeyEx,
+  RegNtPostCreateKeyEx,
+  RegNtPreOpenKeyEx,
+  RegNtPostOpenKeyEx
+} REG_NOTIFY_CLASS, *PREG_NOTIFY_CLASS;
+
 /* Registry Callback Function */
 typedef NTSTATUS (*PEX_CALLBACK_FUNCTION ) (
     IN PVOID CallbackContext,
-    IN PVOID Argument1,
+    IN REG_NOTIFY_CLASS Argument1,
     IN PVOID Argument2
     );
 
+typedef struct _REGISTRY_CALLBACK
+{
+    LIST_ENTRY ListEntry;
+    EX_RUNDOWN_REF RundownRef;
+    PEX_CALLBACK_FUNCTION Function;
+    PVOID Context;
+    LARGE_INTEGER Cookie;
+} REGISTRY_CALLBACK, *PREGISTRY_CALLBACK;
+
+NTSTATUS
+CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
+                           IN PVOID Argument2);
+
 VOID
 CmiVerifyBinHeader(PHBIN BinHeader);
 VOID

Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c
--- trunk/reactos/ntoskrnl/cm/ntfunc.c	2005-02-21 00:39:59 UTC (rev 13700)
+++ trunk/reactos/ntoskrnl/cm/ntfunc.c	2005-02-21 02:41:16 UTC (rev 13701)
@@ -24,33 +24,139 @@
 
 static BOOLEAN CmiRegistryInitialized = FALSE;
 
+LIST_ENTRY CmiCallbackHead;
+FAST_MUTEX CmiCallbackLock;
 
 /* FUNCTIONS ****************************************************************/
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS STDCALL
 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
                    IN PVOID Context,
                    IN OUT PLARGE_INTEGER Cookie)
 {
-  UNIMPLEMENTED;
-  return STATUS_NOT_IMPLEMENTED;
+  PREGISTRY_CALLBACK Callback;
+  
+  ASSERT(Function && Cookie);
+  
+  Callback = ExAllocatePoolWithTag(PagedPool,
+                                   sizeof(REGISTRY_CALLBACK),
+                                   TAG('C', 'M', 'c', 'b'));
+  if(Callback != NULL)
+  {
+    /* initialize the callback */
+    ExInitializeRundownProtection(&Callback->RundownRef);
+    Callback->Function = Function;
+    Callback->Context = Context;
+    
+    /* 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
+       callback object */
+    Callback->Cookie.QuadPart = (ULONG_PTR)Callback;
+    InsertTailList(&CmiCallbackHead, &Callback->ListEntry);
+
+    ExReleaseFastMutex(&CmiCallbackLock);
+    
+    *Cookie = Callback->Cookie;
+    return STATUS_SUCCESS;
+  }
+
+  return STATUS_INSUFFICIENT_RESOURCES;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS STDCALL
 CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
 {
-  UNIMPLEMENTED;
-  return STATUS_NOT_IMPLEMENTED;
+  PLIST_ENTRY CurrentEntry;
+
+  ExAcquireFastMutex(&CmiCallbackLock);
+
+  for(CurrentEntry = CmiCallbackHead.Flink;
+      CurrentEntry != &CmiCallbackHead;
+      CurrentEntry = CurrentEntry->Flink)
+  {
+    PREGISTRY_CALLBACK CurrentCallback;
+
+    CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
+    if(CurrentCallback->Cookie.QuadPart == Cookie.QuadPart)
+    {
+      /* found the callback, don't unlink it from the list yet so we don't screw
+         the calling loop */
+      ExReleaseFastMutex(&CmiCallbackLock);
+
+      /* if the callback is currently executing, wait until it finished */
+      ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef);
+
+      /* time to unlink it. It's now safe because every attempt to acquire a
+         runtime protection on this callback will fail */
+      ExAcquireFastMutex(&CmiCallbackLock);
+      RemoveEntryList(&CurrentCallback->ListEntry);
+      ExReleaseFastMutex(&CmiCallbackLock);
+
+      /* free the callback */
+      ExFreePool(CurrentCallback);
+      return STATUS_SUCCESS;
+    }
+  }
+  
+  ExReleaseFastMutex(&CmiCallbackLock);
+
+  return STATUS_UNSUCCESSFUL;
 }
 
 
+NTSTATUS
+CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
+                           IN PVOID Argument2)
+{
+  PLIST_ENTRY CurrentEntry;
+  
+  ExAcquireFastMutex(&CmiCallbackLock);
+
+  for(CurrentEntry = CmiCallbackHead.Flink;
+      CurrentEntry != &CmiCallbackHead;
+      CurrentEntry = CurrentEntry->Flink)
+  {
+    PREGISTRY_CALLBACK CurrentCallback;
+
+    CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
+    if(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);
+    }
+  }
+  
+  ExReleaseFastMutex(&CmiCallbackLock);
+  
+  return STATUS_SUCCESS;
+}
+
+
 NTSTATUS STDCALL
 NtCreateKey(OUT PHANDLE KeyHandle,
 	    IN ACCESS_MASK DesiredAccess,

Modified: trunk/reactos/ntoskrnl/cm/registry.c
--- trunk/reactos/ntoskrnl/cm/registry.c	2005-02-21 00:39:59 UTC (rev 13700)
+++ trunk/reactos/ntoskrnl/cm/registry.c	2005-02-21 02:41:16 UTC (rev 13701)
@@ -49,6 +49,9 @@
 		      PVOID SystemArgument1,
 		      PVOID SystemArgument2);
 
+extern LIST_ENTRY CmiCallbackHead;
+extern FAST_MUTEX CmiCallbackLock;
+
 /* FUNCTIONS ****************************************************************/
 
 VOID
@@ -286,6 +289,9 @@
   /*  Build volatile registry store  */
   Status = CmiCreateVolatileHive (&CmiVolatileHive);
   ASSERT(NT_SUCCESS(Status));
+  
+  InitializeListHead(&CmiCallbackHead);
+  ExInitializeFastMutex(&CmiCallbackLock);
 
   /* Create '\Registry' key. */
   RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);