convert DefaultSetInfoBufferCheck and DefaultQueryInfoBufferCheck to inlined functions
[reactos.git] / reactos / ntoskrnl / ex / event.c
index 2daf124..2eb0ac1 100644 (file)
@@ -1,28 +1,11 @@
 /*
- *  ReactOS kernel
- *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
+ * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/nt/event.c
  * PURPOSE:         Named event support
- * PROGRAMMER:      Philip Susi and David Welch
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ *
+ * PROGRAMMERS:     Alex Ionescu(alex@relsoft.net) - Fixed bugs/commented
+ *                  Philip Susi and David Welch
  */
 
 /* INCLUDES *****************************************************************/
 POBJECT_TYPE EXPORTED ExEventObjectType = NULL;
 
 static GENERIC_MAPPING ExpEventMapping = {
-       STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE,
-       STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE,
-       STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE,
-       EVENT_ALL_ACCESS};
+    STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE,
+    STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE,
+    STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE,
+    EVENT_ALL_ACCESS};
+
+static const INFORMATION_CLASS_INFO ExEventInfoClass[] = {
 
+    /* EventBasicInformation */
+    ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
+};
 
 /* FUNCTIONS *****************************************************************/
 
-NTSTATUS STDCALL
-NtpCreateEvent(PVOID ObjectBody,
-              PVOID Parent,
-              PWSTR RemainingPath,
-              POBJECT_ATTRIBUTES ObjectAttributes)
+VOID
+INIT_FUNCTION
+STDCALL
+ExpInitializeEventImplementation(VOID)
 {
-  DPRINT("NtpCreateEvent(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-        ObjectBody, Parent, RemainingPath);
+  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+  UNICODE_STRING Name;
+
+  DPRINT("Creating Event Object Type\n");
+  
+  /* Create the Event Object Type */
+  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+  RtlInitUnicodeString(&Name, L"Event");
+  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+  ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT);
+  ObjectTypeInitializer.GenericMapping = ExpEventMapping;
+  ObjectTypeInitializer.PoolType = NonPagedPool;
+  ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
+  ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType);
+}
 
-  if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
-    {
-      return(STATUS_UNSUCCESSFUL);
-    }
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
+NtClearEvent(IN HANDLE EventHandle)
+{
+    PKEVENT Event;
+    NTSTATUS Status;
 
-  return(STATUS_SUCCESS);
-}
+    PAGED_CODE();
 
+    /* Reference the Object */
+    Status = ObReferenceObjectByHandle(EventHandle,
+                                       EVENT_MODIFY_STATE,
+                                       ExEventObjectType,
+                                       ExGetPreviousMode(),
+                                       (PVOID*)&Event,
+                                       NULL);
 
-VOID INIT_FUNCTION
-ExpInitializeEventImplementation(VOID)
-{
-   ExEventObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
-   
-   RtlCreateUnicodeString(&ExEventObjectType->TypeName, L"Event");
-   
-   ExEventObjectType->Tag = TAG('E', 'V', 'T', 'T');
-   ExEventObjectType->PeakObjects = 0;
-   ExEventObjectType->PeakHandles = 0;
-   ExEventObjectType->TotalObjects = 0;
-   ExEventObjectType->TotalHandles = 0;
-   ExEventObjectType->PagedPoolCharge = 0;
-   ExEventObjectType->NonpagedPoolCharge = sizeof(KEVENT);
-   ExEventObjectType->Mapping = &ExpEventMapping;
-   ExEventObjectType->Dump = NULL;
-   ExEventObjectType->Open = NULL;
-   ExEventObjectType->Close = NULL;
-   ExEventObjectType->Delete = NULL;
-   ExEventObjectType->Parse = NULL;
-   ExEventObjectType->Security = NULL;
-   ExEventObjectType->QueryName = NULL;
-   ExEventObjectType->OkayToClose = NULL;
-   ExEventObjectType->Create = NtpCreateEvent;
-   ExEventObjectType->DuplicationNotify = NULL;
-
-   ObpCreateTypeObject(ExEventObjectType);
-}
+    /* Check for Success */
+    if(NT_SUCCESS(Status)) {
 
+        /* Clear the Event and Dereference */
+        KeClearEvent(Event);
+        ObDereferenceObject(Event);
+    }
 
-NTSTATUS STDCALL
-NtClearEvent(IN HANDLE EventHandle)
-{
-   PKEVENT Event;
-   NTSTATUS Status;
-   
-   Status = ObReferenceObjectByHandle(EventHandle,
-                                     EVENT_MODIFY_STATE,
-                                     ExEventObjectType,
-                                     UserMode,
-                                     (PVOID*)&Event,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   KeClearEvent(Event);
-   ObDereferenceObject(Event);
-   return(STATUS_SUCCESS);
+    /* Return Status */
+    return Status;
 }
 
 
 /*
  * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS
+STDCALL
 NtCreateEvent(OUT PHANDLE EventHandle,
-             IN ACCESS_MASK DesiredAccess,
-             IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
-             IN EVENT_TYPE EventType,
-             IN BOOLEAN InitialState)
+              IN ACCESS_MASK DesiredAccess,
+              IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
+              IN EVENT_TYPE EventType,
+              IN BOOLEAN InitialState)
 {
-   PKEVENT Event;
-   HANDLE hEvent;
-   NTSTATUS Status;
-   OBJECT_ATTRIBUTES SafeObjectAttributes;
-   
-   if (ObjectAttributes != NULL)
-     {
-       Status = MmCopyFromCaller(&SafeObjectAttributes, ObjectAttributes,
-                                sizeof(OBJECT_ATTRIBUTES));
-       if (!NT_SUCCESS(Status))
-        {
-          return(Status);
-        }
-       ObjectAttributes = &SafeObjectAttributes;
-     }
-
-   Status = ObCreateObject(ExGetPreviousMode(),
-                          ExEventObjectType,
-                          ObjectAttributes,
-                          ExGetPreviousMode(),
-                          NULL,
-                          sizeof(KEVENT),
-                          0,
-                          0,
-                          (PVOID*)&Event);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   KeInitializeEvent(Event,
-                    EventType,
-                    InitialState);
-
-   Status = ObInsertObject ((PVOID)Event,
-                           NULL,
-                           DesiredAccess,
-                           0,
-                           NULL,
-                           &hEvent);
-   ObDereferenceObject(Event);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   Status = MmCopyToCaller(EventHandle, &hEvent, sizeof(HANDLE));
-   if (!NT_SUCCESS(Status))
-     {
-       ZwClose(hEvent);
-       return(Status);
-     }
-   return(STATUS_SUCCESS);
-}
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PKEVENT Event;
+    HANDLE hEvent;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+    DPRINT("NtCreateEvent(0x%p, 0x%x, 0x%p)\n", EventHandle, DesiredAccess, ObjectAttributes);
+
+    /* Check Output Safety */
+    if(PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteHandle(EventHandle);
+        } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Create the Object */
+    Status = ObCreateObject(PreviousMode,
+                            ExEventObjectType,
+                            ObjectAttributes,
+                            PreviousMode,
+                            NULL,
+                            sizeof(KEVENT),
+                            0,
+                            0,
+                            (PVOID*)&Event);
+
+    /* Check for Success */
+    if(NT_SUCCESS(Status)) {
+
+        /* Initalize the Event */
+        KeInitializeEvent(Event,
+                          EventType,
+                          InitialState);
 
+        /* Insert it */
+        Status = ObInsertObject((PVOID)Event,
+                                 NULL,
+                                 DesiredAccess,
+                                 0,
+                                 NULL,
+                                 &hEvent);
+        ObDereferenceObject(Event);
 
-NTSTATUS STDCALL
+        /* Check for success and return handle */
+        if(NT_SUCCESS(Status)) {
+
+            _SEH_TRY {
+
+                *EventHandle = hEvent;
+
+            } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+                Status = _SEH_GetExceptionCode();
+
+            } _SEH_END;
+        }
+    }
+
+    /* Return Status */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
 NtOpenEvent(OUT PHANDLE EventHandle,
-           IN ACCESS_MASK DesiredAccess,
-           IN POBJECT_ATTRIBUTES ObjectAttributes)
+            IN ACCESS_MASK DesiredAccess,
+            IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
-   NTSTATUS Status;
-   HANDLE hEvent;
-
-   DPRINT("ObjectName '%wZ'\n", ObjectAttributes->ObjectName);
-
-   Status = ObOpenObjectByName(ObjectAttributes,
-                              ExEventObjectType,
-                              NULL,
-                              UserMode,
-                              DesiredAccess,
-                              NULL,
-                              &hEvent);
-             
-  if (!NT_SUCCESS(Status))
-  {
-    return(Status);
-  }
-
-   Status = MmCopyToCaller(EventHandle, &hEvent, sizeof(HANDLE));
-   if (!NT_SUCCESS(Status))
-     {
-       ZwClose(EventHandle);
-       return(Status);
-     }
-     
-   return(Status);
-}
+    HANDLE hEvent;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+    DPRINT("NtOpenEvent(0x%p, 0x%x, 0x%p)\n", EventHandle, DesiredAccess, ObjectAttributes);
+
+    /* Check Output Safety */
+    if(PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteHandle(EventHandle);
+        } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
 
+        } _SEH_END;
 
-NTSTATUS STDCALL
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Open the Object */
+    Status = ObOpenObjectByName(ObjectAttributes,
+                                ExEventObjectType,
+                                NULL,
+                                PreviousMode,
+                                DesiredAccess,
+                                NULL,
+                                &hEvent);
+
+    /* Check for success and return handle */
+    if(NT_SUCCESS(Status)) {
+
+        _SEH_TRY {
+
+            *EventHandle = hEvent;
+
+        } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+    }
+
+    /* Return status */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
 NtPulseEvent(IN HANDLE EventHandle,
-            OUT PLONG PreviousState  OPTIONAL)
+             OUT PLONG PreviousState OPTIONAL)
 {
-   PKEVENT Event;
-   NTSTATUS Status;
-
-   DPRINT("NtPulseEvent(EventHandle %x PreviousState %x)\n",
-         EventHandle, PreviousState);
-
-   Status = ObReferenceObjectByHandle(EventHandle,
-                                     EVENT_MODIFY_STATE,
-                                     ExEventObjectType,
-                                     UserMode,
-                                     (PVOID*)&Event,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-
-   KePulseEvent(Event, EVENT_INCREMENT, FALSE);
-
-   ObDereferenceObject(Event);
-   return(STATUS_SUCCESS);
+    PKEVENT Event;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+    DPRINT("NtPulseEvent(EventHandle 0%x PreviousState 0%x)\n",
+            EventHandle, PreviousState);
+
+    /* Check buffer validity */
+    if(PreviousState && PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteLong(PreviousState);
+         } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Open the Object */
+    Status = ObReferenceObjectByHandle(EventHandle,
+                                       EVENT_MODIFY_STATE,
+                                       ExEventObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Event,
+                                       NULL);
+
+    /* Check for success */
+    if(NT_SUCCESS(Status)) {
+
+        /* Pulse the Event */
+        LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE);
+        ObDereferenceObject(Event);
+
+        /* Return it */
+        if(PreviousState) {
+
+            _SEH_TRY {
+
+                *PreviousState = Prev;
+
+            } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+                Status = _SEH_GetExceptionCode();
+
+            } _SEH_END;
+        }
+   }
+
+   /* Return Status */
+   return Status;
 }
 
 
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
 NtQueryEvent(IN HANDLE EventHandle,
-            IN EVENT_INFORMATION_CLASS EventInformationClass,
-            OUT PVOID EventInformation,
-            IN ULONG EventInformationLength,
-            OUT PULONG ReturnLength  OPTIONAL)
+             IN EVENT_INFORMATION_CLASS EventInformationClass,
+             OUT PVOID EventInformation,
+             IN ULONG EventInformationLength,
+             OUT PULONG ReturnLength  OPTIONAL)
 {
-   EVENT_BASIC_INFORMATION Info;
-   PKEVENT Event;
-   NTSTATUS Status;
-   ULONG RetLen;
-
-   if (EventInformationClass > EventBasicInformation)
-     return STATUS_INVALID_INFO_CLASS;
-
-   if (EventInformationLength < sizeof(EVENT_BASIC_INFORMATION))
-     return STATUS_INFO_LENGTH_MISMATCH;
-
-   Status = ObReferenceObjectByHandle(EventHandle,
-                                     EVENT_QUERY_STATE,
-                                     ExEventObjectType,
-                                     UserMode,
-                                     (PVOID*)&Event,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     return Status;
-
-   if (Event->Header.Type == InternalNotificationEvent)
-     Info.EventType = NotificationEvent;
-   else
-     Info.EventType = SynchronizationEvent;
-   Info.EventState = KeReadStateEvent(Event);
-
-   Status = MmCopyToCaller(EventInformation, &Event,
-                          sizeof(EVENT_BASIC_INFORMATION));
-   if (!NT_SUCCESS(Status))
-     {
-       ObDereferenceObject(Event);
-       return(Status);
-     }
-
-   if (ReturnLength != NULL)
-     {
-       RetLen = sizeof(EVENT_BASIC_INFORMATION);
-       Status = MmCopyToCaller(ReturnLength, &RetLen, sizeof(ULONG));
-       if (!NT_SUCCESS(Status))
-         {
-           ObDereferenceObject(Event);
-           return(Status);
-         }
-     }
-
-   ObDereferenceObject(Event);
-   return(STATUS_SUCCESS);
-}
+    PKEVENT Event;
+    KPROCESSOR_MODE PreviousMode  = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    PEVENT_BASIC_INFORMATION BasicInfo = (PEVENT_BASIC_INFORMATION)EventInformation;
+
+    PAGED_CODE();
+    DPRINT("NtQueryEvent(0x%p, 0x%x)\n", EventHandle, EventInformationClass);
+
+    /* Check buffers and class validity */
+    Status = DefaultQueryInfoBufferCheck(EventInformationClass,
+                                         ExEventInfoClass,
+                                         sizeof(ExEventInfoClass) / sizeof(ExEventInfoClass[0]),
+                                         EventInformation,
+                                         EventInformationLength,
+                                         ReturnLength,
+                                         PreviousMode);
+    if(!NT_SUCCESS(Status)) {
+
+        /* Invalid buffers */
+        DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
+        return Status;
+    }
 
+    /* Get the Object */
+    Status = ObReferenceObjectByHandle(EventHandle,
+                                       EVENT_QUERY_STATE,
+                                       ExEventObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Event,
+                                       NULL);
 
-NTSTATUS STDCALL
-NtResetEvent(IN HANDLE EventHandle,
-            OUT PLONG PreviousState  OPTIONAL)
-{
-   PKEVENT Event;
-   NTSTATUS Status;
-   
-   DPRINT("NtResetEvent(EventHandle %x)\n", EventHandle);
-   
-   Status = ObReferenceObjectByHandle(EventHandle,
-                                     EVENT_MODIFY_STATE,
-                                     ExEventObjectType,
-                                     UserMode,
-                                     (PVOID*)&Event,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   KeResetEvent(Event);
-   ObDereferenceObject(Event);
-   return(STATUS_SUCCESS);
-}
+    /* Check for success */
+    if(NT_SUCCESS(Status)) {
+
+        _SEH_TRY {
+
+            /* Return Event Type and State */
+            BasicInfo->EventType = Event->Header.Type;
+            BasicInfo->EventState = KeReadStateEvent(Event);
+
+            /* Return length */
+            if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
+
+        } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
 
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+
+        /* Dereference the Object */
+        ObDereferenceObject(Event);
+   }
+
+   /* Return status */
+   return Status;
+}
 
 /*
  * @implemented
  */
-NTSTATUS STDCALL
-NtSetEvent(IN HANDLE EventHandle,
-          OUT PLONG PreviousState  OPTIONAL)
+NTSTATUS
+STDCALL
+NtResetEvent(IN HANDLE EventHandle,
+             OUT PLONG PreviousState OPTIONAL)
 {
-   PKEVENT Event;
-   NTSTATUS Status;
-   
-   DPRINT("NtSetEvent(EventHandle %x)\n", EventHandle);
-   
-   Status = ObReferenceObjectByHandle(EventHandle,
-                                     EVENT_MODIFY_STATE,
-                                     ExEventObjectType,
-                                     UserMode,
-                                     (PVOID*)&Event,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   KeSetEvent(Event,EVENT_INCREMENT,FALSE);
-   ObDereferenceObject(Event);
-   return(STATUS_SUCCESS);
+    PKEVENT Event;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+    DPRINT("NtResetEvent(EventHandle 0%x PreviousState 0%x)\n",
+            EventHandle, PreviousState);
+
+    /* Check buffer validity */
+    if(PreviousState && PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteLong(PreviousState);
+         } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Open the Object */
+    Status = ObReferenceObjectByHandle(EventHandle,
+                                       EVENT_MODIFY_STATE,
+                                       ExEventObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Event,
+                                       NULL);
+
+    /* Check for success */
+    if(NT_SUCCESS(Status)) {
+
+        /* Reset the Event */
+        LONG Prev = KeResetEvent(Event);
+        ObDereferenceObject(Event);
+
+        /* Return it */
+        if(PreviousState) {
+
+            _SEH_TRY {
+
+                *PreviousState = Prev;
+
+            } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+                Status = _SEH_GetExceptionCode();
+
+            } _SEH_END;
+        }
+   }
+
+   /* Return Status */
+   return Status;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 STDCALL
-NtTraceEvent(
-       IN ULONG TraceHandle,
-       IN ULONG Flags,
-       IN ULONG TraceHeaderLength,
-       IN struct _EVENT_TRACE_HEADER* TraceHeader
-       )
+NtSetEvent(IN HANDLE EventHandle,
+           OUT PLONG PreviousState  OPTIONAL)
 {
-       UNIMPLEMENTED;
-       return STATUS_NOT_IMPLEMENTED;
-}
+    PKEVENT Event;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    PAGED_CODE();
+    DPRINT("NtSetEvent(EventHandle 0%x PreviousState 0%x)\n",
+           EventHandle, PreviousState);
+
+    /* Check buffer validity */
+    if(PreviousState != NULL && PreviousMode != KernelMode) {
+
+        _SEH_TRY {
+
+            ProbeForWriteLong(PreviousState);
+         } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+            Status = _SEH_GetExceptionCode();
+
+        } _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Open the Object */
+    Status = ObReferenceObjectByHandle(EventHandle,
+                                       EVENT_MODIFY_STATE,
+                                       ExEventObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Event,
+                                       NULL);
 
+    /* Check for success */
+    if(NT_SUCCESS(Status)) {
+
+        /* Set the Event */
+        LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
+        ObDereferenceObject(Event);
+
+        /* Return it */
+        if(PreviousState) {
+
+            _SEH_TRY {
+
+                *PreviousState = Prev;
+
+            } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
+
+                Status = _SEH_GetExceptionCode();
+
+            } _SEH_END;
+        }
+   }
+
+   /* Return Status */
+   return Status;
+}
 
 /* EOF */