- Acquire the temporary buffer from non paged pool in NtQueryDirectoryObject, because...
[reactos.git] / reactos / ntoskrnl / ob / dirobj.c
index 4b41d81..e2558f0 100644 (file)
@@ -1,12 +1,11 @@
-/* $Id: dirobj.c,v 1.24 2004/08/20 22:38:10 gvg Exp $
+/* $Id$
  *
  * COPYRIGHT:      See COPYING in the top level directory
  * PROJECT:        ReactOS kernel
  * FILE:           ntoskrnl/ob/dirobj.c
  * PURPOSE:        Interface functions to directory object
- * PROGRAMMER:     David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                 22/05/98: Created
+ *
+ * PROGRAMMERS:    David Welch (welch@mcmail.com)
  */
 
 /* INCLUDES ***************************************************************/
  *
  * DESCRIPTION
  *     Opens a namespace directory object.
- *     
+ *
  * ARGUMENTS
  *     DirectoryHandle (OUT)
  *             Variable which receives the directory handle.
- *             
+ *
  *     DesiredAccess
  *             Desired access to the directory.
- *             
+ *
  *     ObjectAttributes
  *             Structure describing the directory.
- *             
+ *
  * RETURN VALUE
  *     Status.
- *     
+ *
  * NOTES
  *     Undocumented.
  */
@@ -47,97 +46,89 @@ NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle,
                       IN ACCESS_MASK DesiredAccess,
                       IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
-   PVOID Object;
-   NTSTATUS Status;
-
-   *DirectoryHandle = 0;
-   
-   Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
-                                   ObjectAttributes->Attributes,
-                                   NULL,
-                                   DesiredAccess,
-                                   ObDirectoryType,
-                                   UserMode,
-                                   NULL,
-                                   &Object);
-   if (!NT_SUCCESS(Status))
+   HANDLE hDirectory;
+   KPROCESSOR_MODE PreviousMode;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   PAGED_CODE();
+
+   PreviousMode = ExGetPreviousMode();
+
+   if(PreviousMode != KernelMode)
+   {
+     _SEH_TRY
      {
-       return Status;
+       ProbeForWriteHandle(DirectoryHandle);
      }
-   
-   Status = ObCreateHandle(PsGetCurrentProcess(),
-                          Object,
-                          DesiredAccess,
-                          FALSE,
-                          DirectoryHandle);
-   return STATUS_SUCCESS;
-}
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
 
-static NTSTATUS
-CopyDirectoryString(PUNICODE_STRING UnsafeTarget, PUNICODE_STRING Source, PUCHAR *Buffer)
-{
-    UNICODE_STRING Target;
-    NTSTATUS Status;
-    WCHAR NullWchar;
-
-    Target.Length        = Source->Length;
-    Target.MaximumLength = (Source->Length + sizeof (WCHAR));
-    Target.Buffer        = (PWCHAR) *Buffer;
-    Status = MmCopyToCaller(UnsafeTarget, &Target, sizeof(UNICODE_STRING));
-    if (! NT_SUCCESS(Status))
-      {
-       return Status;
-      }
-    Status = MmCopyToCaller(*Buffer, Source->Buffer, Source->Length);
-    if (! NT_SUCCESS(Status))
-      {
-       return Status;
-      }
-    *Buffer += Source->Length;
-    NullWchar = L'\0';
-    Status = MmCopyToCaller(*Buffer, &NullWchar, sizeof(WCHAR));
-    if (! NT_SUCCESS(Status))
-      {
-       return Status;
-      }
-    *Buffer += sizeof(WCHAR);
+     if(!NT_SUCCESS(Status))
+     {
+       DPRINT1("NtOpenDirectoryObject failed, Status: 0x%x\n", Status);
+       return Status;
+     }
+   }
+
+   Status = ObOpenObjectByName(ObjectAttributes,
+                               ObDirectoryType,
+                               NULL,
+                               PreviousMode,
+                               DesiredAccess,
+                               NULL,
+                               &hDirectory);
+   if(NT_SUCCESS(Status))
+   {
+     _SEH_TRY
+     {
+       *DirectoryHandle = hDirectory;
+     }
+     _SEH_HANDLE
+     {
+       Status = _SEH_GetExceptionCode();
+     }
+     _SEH_END;
+   }
 
-    return STATUS_SUCCESS;
+   return Status;
 }
 
 
 /**********************************************************************
  * NAME                                                        EXPORTED
  *     NtQueryDirectoryObject
- * 
+ *
  * DESCRIPTION
  *     Reads information from a directory in the system namespace.
- *     
+ *
  * ARGUMENTS
  *     DirectoryHandle
  *             Handle, obtained with NtOpenDirectoryObject(), which
  *             must grant DIRECTORY_QUERY access to the directory
  *             object.
- *             
+ *
  *     Buffer (OUT)
  *             Buffer to hold the data read.
- *             
+ *
  *     BufferLength
  *             Size of the buffer in bytes.
- *             
+ *
  *     ReturnSingleEntry
  *             When TRUE, only 1 entry is written in DirObjInformation;
  *             otherwise as many as will fit in the buffer.
- *             
+ *
  *     RestartScan
  *             If TRUE start reading at index 0.
  *             If FALSE start reading at the index specified
  *             by object index *ObjectIndex.
- *             
+ *
  *     Context
  *             Zero based index into the directory, interpretation
  *             depends on RestartScan.
- *             
+ *
  *     ReturnLength (OUT)
  *             Caller supplied storage for the number of bytes
  *             written (or NULL).
@@ -169,224 +160,265 @@ NtQueryDirectoryObject (IN HANDLE DirectoryHandle,
                        IN ULONG BufferLength,
                        IN BOOLEAN ReturnSingleEntry,
                        IN BOOLEAN RestartScan,
-                       IN OUT PULONG UnsafeContext,
-                       OUT PULONG UnsafeReturnLength OPTIONAL)
+                       IN OUT PULONG Context,
+                       OUT PULONG ReturnLength OPTIONAL)
 {
-    PDIRECTORY_OBJECT   dir = NULL;
-    PLIST_ENTRY         current_entry = NULL;
-    PLIST_ENTRY         start_entry;
-    POBJECT_HEADER      current = NULL;
-    NTSTATUS            Status = STATUS_SUCCESS;
-    ULONG               DirectoryCount = 0;
-    ULONG               DirectoryIndex = 0;
-    PDIRECTORY_BASIC_INFORMATION current_odi = (PDIRECTORY_BASIC_INFORMATION) Buffer;
-    DIRECTORY_BASIC_INFORMATION ZeroOdi;
-    PUCHAR              FirstFree = (PUCHAR) Buffer;
-    ULONG               Context;
-    ULONG               RequiredSize;
-    ULONG               NewValue;
-    KIRQL               OldLevel;
-
-    DPRINT("NtQueryDirectoryObject(DirectoryHandle %x)\n", DirectoryHandle);
-
-    /* Check Context is not NULL */
-    if (NULL == UnsafeContext)
-      {
-        return STATUS_INVALID_PARAMETER;
-      }
-
-    /* Reference the DIRECTORY_OBJECT */
-    Status = ObReferenceObjectByHandle(DirectoryHandle,
-                                     DIRECTORY_QUERY,
-                                     ObDirectoryType,
-                                     UserMode,
-                                     (PVOID*)&dir,
-                                     NULL);
-    if (!NT_SUCCESS(Status))
-      {
-        return Status;
-      }
+  PDIRECTORY_OBJECT Directory;
+  KPROCESSOR_MODE PreviousMode;
+  ULONG SkipEntries = 0;
+  ULONG NextEntry = 0;
+  ULONG CopyBytes = 0;
+  NTSTATUS Status = STATUS_SUCCESS;
 
-    KeAcquireSpinLock(&dir->Lock, &OldLevel);
+  PAGED_CODE();
 
-    /*
-     * Optionally, skip over some entries at the start of the directory
-     * (use *ObjectIndex value)
-     */
-    start_entry = dir->head.Flink;
-    if (! RestartScan)
-      {
-        register ULONG EntriesToSkip;
-
-       Status = MmCopyFromCaller(&Context, UnsafeContext, sizeof(ULONG));
-       if (! NT_SUCCESS(Status))
-         {
-           KeReleaseSpinLock(&dir->Lock, OldLevel);
-            ObDereferenceObject(dir);
-           return Status;
-         }
-       EntriesToSkip = Context;
-
-       CHECKPOINT;
-       
-       for (; 0 != EntriesToSkip-- && start_entry != &dir->head;
-            start_entry = start_entry->Flink)
-         {
-           ;
-         }
-       if ((0 != EntriesToSkip) && (start_entry == &dir->head))
-         {
-           KeReleaseSpinLock(&dir->Lock, OldLevel);
-            ObDereferenceObject(dir);
-            return STATUS_NO_MORE_ENTRIES;
-         }
-      }
+  PreviousMode = ExGetPreviousMode();
 
-    /*
-     * Compute number of entries that we will copy into the buffer and
-     * the total size of all entries (even if larger than the buffer size)
-     */
-    DirectoryCount = 0;
-    /* For the end sentenil */
-    RequiredSize = sizeof(DIRECTORY_BASIC_INFORMATION);
-    for (current_entry = start_entry;
-         current_entry != &dir->head;
-         current_entry = current_entry->Flink)
+  if(PreviousMode != KernelMode)
+  {
+    _SEH_TRY
+    {
+      /* a test showed that the Buffer pointer just has to be 16 bit aligned,
+         propably due to the fact that most information that needs to be copied
+         is unicode strings */
+      ProbeForWrite(Buffer,
+                    BufferLength,
+                    sizeof(WCHAR));
+      ProbeForWriteUlong(Context);
+      if(!RestartScan)
       {
-       current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
-
-       RequiredSize += sizeof(DIRECTORY_BASIC_INFORMATION) +
-                       current->Name.Length + sizeof(WCHAR) +
-                       current->ObjectType->TypeName.Length + sizeof(WCHAR);
-       if (RequiredSize <= BufferLength &&
-           (! ReturnSingleEntry || DirectoryCount < 1))
-         {
-           DirectoryCount++;
-         }
+        SkipEntries = *Context;
       }
-
-    /*
-     * If there's no room to even copy a single entry, return error status
-     */
-    if (0 == DirectoryCount)
+      if(ReturnLength != NULL)
       {
-       KeReleaseSpinLock(&dir->Lock, OldLevel);
-       ObDereferenceObject(dir);
-       if (NULL != UnsafeReturnLength)
-         {
-           Status = MmCopyToCaller(UnsafeReturnLength, &RequiredSize, sizeof(ULONG));
-         }
-
-       return NT_SUCCESS(Status) ? STATUS_BUFFER_TOO_SMALL : Status;
+        ProbeForWriteUlong(ReturnLength);
       }
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
+    }
+    _SEH_END;
 
-    /*
-     * Move FirstFree to point to the Unicode strings area
-     */
-    FirstFree += (DirectoryCount + 1) * sizeof(DIRECTORY_BASIC_INFORMATION);
-
-    /* Scan the directory */
-    current_entry = start_entry;
-    for (DirectoryIndex = 0; DirectoryIndex < DirectoryCount; DirectoryIndex++) 
-      {
-       current = CONTAINING_RECORD(current_entry, OBJECT_HEADER, Entry);
-
-       /*
-        * Copy the current directory entry's data into the buffer
-        * and update the OBJDIR_INFORMATION entry in the array.
-        */
-       /* --- Object's name --- */
-       Status = CopyDirectoryString(&current_odi->ObjectName, &current->Name, &FirstFree);
-       if (! NT_SUCCESS(Status))
-         {
-           KeReleaseSpinLock(&dir->Lock, OldLevel);
-           ObDereferenceObject(dir);
-           return Status;
-         }
-       /* --- Object type's name --- */
-       Status = CopyDirectoryString(&current_odi->ObjectTypeName, &current->ObjectType->TypeName, &FirstFree);
-       if (! NT_SUCCESS(Status))
-         {
-           KeReleaseSpinLock(&dir->Lock, OldLevel);
-           ObDereferenceObject(dir);
-           return Status;
-         }
-
-       /* Next entry in the array */
-       current_odi++;
-       /* Next object in the directory */
-       current_entry = current_entry->Flink;
+    if(!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtQueryDirectoryObject failed, Status: 0x%x\n", Status);
+      return Status;
     }
+  }
+  else if(!RestartScan)
+  {
+    SkipEntries = *Context;
+  }
+
+  Status = ObReferenceObjectByHandle(DirectoryHandle,
+                                     DIRECTORY_QUERY,
+                                     ObDirectoryType,
+                                     PreviousMode,
+                                     (PVOID*)&Directory,
+                                     NULL);
+  if(NT_SUCCESS(Status))
+  {
+    PVOID TemporaryBuffer = ExAllocatePool(NonPagedPool,
+                                           BufferLength);
+    if(TemporaryBuffer != NULL)
+    {
+      POBJECT_HEADER EntryHeader;
+      PLIST_ENTRY ListEntry;
+      KIRQL OldLevel;
+      ULONG RequiredSize = sizeof(OBJECT_DIRECTORY_INFORMATION);
+      ULONG nDirectories = 0;
+      POBJECT_DIRECTORY_INFORMATION DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
 
-    /*
-     * Don't need dir object anymore
-     */
-    KeReleaseSpinLock(&dir->Lock, OldLevel);
-    ObDereferenceObject(dir);
+      Status = STATUS_NO_MORE_ENTRIES;
 
-    /* Terminate with all zero entry */
-    memset(&ZeroOdi, '\0', sizeof(DIRECTORY_BASIC_INFORMATION));
-    Status = MmCopyToCaller(current_odi, &ZeroOdi, sizeof(DIRECTORY_BASIC_INFORMATION));
-    if (! NT_SUCCESS(Status))
-      {
-        return Status;
-      }
+      KeAcquireSpinLock(&Directory->Lock, &OldLevel);
 
-    /*
-     * Store current index in Context
-     */
-    if (RestartScan)
+      for(ListEntry = Directory->head.Flink;
+          ListEntry != &Directory->head;
+          ListEntry = ListEntry->Flink)
       {
-       Context = DirectoryCount;
+        NextEntry++;
+        if(SkipEntries == 0)
+        {
+          PUNICODE_STRING Name, Type;
+          ULONG EntrySize;
+
+          EntryHeader = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, Entry);
+
+          /* calculate the size of the required buffer space for this entry */
+          Name = (HEADER_TO_OBJECT_NAME(EntryHeader)->Name.Length != 0 ? &HEADER_TO_OBJECT_NAME(EntryHeader)->Name : NULL);
+          Type = &EntryHeader->Type->Name;
+          EntrySize = sizeof(OBJECT_DIRECTORY_INFORMATION) +
+                      ((Name != NULL) ? ((ULONG)Name->Length + sizeof(WCHAR)) : 0) +
+                      (ULONG)EntryHeader->Type->Name.Length + sizeof(WCHAR);
+
+          if(RequiredSize + EntrySize <= BufferLength)
+          {
+            /* the buffer is large enough to receive this entry. It would've
+               been much easier if the strings were directly appended to the
+               OBJECT_DIRECTORY_INFORMATION structured written into the buffer */
+            if(Name != NULL)
+              DirInfo->ObjectName = *Name;
+            else
+            {
+              DirInfo->ObjectName.Length = DirInfo->ObjectName.MaximumLength = 0;
+              DirInfo->ObjectName.Buffer = NULL;
+            }
+            DirInfo->ObjectTypeName = *Type;
+
+            nDirectories++;
+            RequiredSize += EntrySize;
+
+            Status = STATUS_SUCCESS;
+
+            if(ReturnSingleEntry)
+            {
+              /* we're only supposed to query one entry, so bail and copy the
+                 strings to the buffer */
+              break;
+            }
+            DirInfo++;
+          }
+          else
+          {
+            if(ReturnSingleEntry)
+            {
+              /* the buffer is too small, so return the number of bytes that
+                 would've been required for this query */
+              RequiredSize += EntrySize;
+              Status = STATUS_BUFFER_TOO_SMALL;
+            }
+
+            /* we couldn't query this entry, so leave the index that will be stored
+               in Context to this entry so the caller can query it the next time
+               he queries (hopefully with a buffer that is large enough then...) */
+            NextEntry--;
+
+            /* just copy the entries that fit into the buffer */
+            break;
+          }
+        }
+        else
+        {
+          /* skip the entry */
+          SkipEntries--;
+        }
       }
-    else
+
+      if(!ReturnSingleEntry && ListEntry != &Directory->head)
       {
-       Context += DirectoryCount;
+        /* there are more entries to enumerate but the buffer is already full.
+           only tell this to the user if he queries multiple entries */
+        Status = STATUS_MORE_ENTRIES;
       }
-    Status = MmCopyToCaller(UnsafeContext, &Context, sizeof(ULONG));
-    if (! NT_SUCCESS(Status))
+
+      if(NT_SUCCESS(Status) && nDirectories > 0)
       {
-        return Status;
+        PWSTR strbuf = (PWSTR)((POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer + nDirectories + 1);
+        PWSTR deststrbuf = (PWSTR)((POBJECT_DIRECTORY_INFORMATION)Buffer + nDirectories + 1);
+        memset((POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer + nDirectories, 0, sizeof(OBJECT_DIRECTORY_INFORMATION));
+
+        CopyBytes = (nDirectories + 1) * sizeof(OBJECT_DIRECTORY_INFORMATION);
+
+        /* copy the names from the objects and append them to the list of the
+           objects. copy to the temporary buffer only because the directory
+           lock can't be released and the buffer might be pagable memory! */
+        for(DirInfo = (POBJECT_DIRECTORY_INFORMATION)TemporaryBuffer;
+            nDirectories > 0;
+            nDirectories--, DirInfo++)
+        {
+          ULONG NameLength;
+
+          if(DirInfo->ObjectName.Length > 0)
+          {
+            RtlCopyMemory(strbuf,
+                          DirInfo->ObjectName.Buffer,
+                          DirInfo->ObjectName.Length);
+            /* change the buffer pointer to the buffer */
+            DirInfo->ObjectName.Buffer = deststrbuf;
+            NameLength = DirInfo->ObjectName.Length / sizeof(WCHAR);
+            /* NULL-terminate the string */
+            strbuf[NameLength] = L'\0';
+            strbuf += NameLength + 1;
+            deststrbuf += NameLength + 1;
+
+            CopyBytes += (NameLength + 1) * sizeof(WCHAR);
+          }
+
+          RtlCopyMemory(strbuf,
+                        DirInfo->ObjectTypeName.Buffer,
+                        DirInfo->ObjectTypeName.Length);
+          /* change the buffer pointer to the buffer */
+          DirInfo->ObjectTypeName.Buffer = deststrbuf;
+          NameLength = DirInfo->ObjectTypeName.Length / sizeof(WCHAR);
+          /* NULL-terminate the string */
+          strbuf[NameLength] = L'\0';
+          strbuf += NameLength + 1;
+          deststrbuf += NameLength + 1;
+
+          CopyBytes += (NameLength + 1) * sizeof(WCHAR);
+        }
       }
 
-    /*
-     * Report to the caller how much bytes
-     * we wrote in the user buffer.
-     */
-    if (NULL != UnsafeReturnLength)
+      KeReleaseSpinLock(&Directory->Lock, OldLevel);
+      ObDereferenceObject(Directory);
+
+      if(NT_SUCCESS(Status) || ReturnSingleEntry)
       {
-       NewValue = FirstFree - (PUCHAR) Buffer;
-       Status = MmCopyToCaller(UnsafeReturnLength, &NewValue, sizeof(ULONG));
-       if (! NT_SUCCESS(Status))
-         {
-           return Status;
-         }
+        _SEH_TRY
+        {
+          if(CopyBytes != 0)
+          {
+            RtlCopyMemory(Buffer,
+                          TemporaryBuffer,
+                          CopyBytes);
+          }
+          *Context = NextEntry;
+          if(ReturnLength != NULL)
+          {
+            *ReturnLength = RequiredSize;
+          }
+        }
+        _SEH_HANDLE
+        {
+          Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
       }
 
-    return Status;
+      ExFreePool(TemporaryBuffer);
+    }
+    else
+    {
+      Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+  }
+
+  return Status;
 }
 
 
 /**********************************************************************
  * NAME                                                (EXPORTED as Zw)
  *     NtCreateDirectoryObject
- *     
+ *
  * DESCRIPTION
  *     Creates or opens a directory object (a container for other
  *     objects).
- *     
+ *
  * ARGUMENTS
  *     DirectoryHandle (OUT)
- *             Caller supplied storage for the handle of the 
+ *             Caller supplied storage for the handle of the
  *             directory.
- *             
+ *
  *     DesiredAccess
  *             Access desired to the directory.
- *             
+ *
  *     ObjectAttributes
  *             Object attributes initialized with
  *             InitializeObjectAttributes.
- *             
+ *
  * RETURN VALUE
  *     Status.
  */
@@ -395,37 +427,75 @@ NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle,
                         IN ACCESS_MASK DesiredAccess,
                         IN POBJECT_ATTRIBUTES ObjectAttributes)
 {
-  PDIRECTORY_OBJECT DirectoryObject;
-  NTSTATUS Status;
+  PDIRECTORY_OBJECT Directory;
+  HANDLE hDirectory;
+  KPROCESSOR_MODE PreviousMode;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  PAGED_CODE();
 
   DPRINT("NtCreateDirectoryObject(DirectoryHandle %x, "
-        "DesiredAccess %x, ObjectAttributes %x, "
-        "ObjectAttributes->ObjectName %wZ)\n",
-        DirectoryHandle, DesiredAccess, ObjectAttributes,
-        ObjectAttributes->ObjectName);
-
-  Status = ObCreateObject (ExGetPreviousMode(),
-                          ObDirectoryType,
-                          ObjectAttributes,
-                          ExGetPreviousMode(),
-                          NULL,
-                          sizeof(DIRECTORY_OBJECT),
-                          0,
-                          0,
-                          (PVOID*)&DirectoryObject);
-  if (!NT_SUCCESS(Status))
+         "DesiredAccess %x, ObjectAttributes %x\n",
+          DirectoryHandle, DesiredAccess, ObjectAttributes);
+
+  PreviousMode = ExGetPreviousMode();
+
+  if(PreviousMode != KernelMode)
+  {
+    _SEH_TRY
     {
-      return Status;
+      ProbeForWriteHandle(DirectoryHandle);
+    }
+    _SEH_HANDLE
+    {
+      Status = _SEH_GetExceptionCode();
     }
+    _SEH_END;
 
-  Status = ObInsertObject ((PVOID)DirectoryObject,
-                          NULL,
-                          DesiredAccess,
-                          0,
-                          NULL,
-                          DirectoryHandle);
+    if(!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtCreateDirectoryObject failed, Status: 0x%x\n", Status);
+      return Status;
+    }
+  }
+
+  Status = ObCreateObject(PreviousMode,
+                          ObDirectoryType,
+                          ObjectAttributes,
+                          PreviousMode,
+                          NULL,
+                          sizeof(DIRECTORY_OBJECT),
+                          0,
+                          0,
+                          (PVOID*)&Directory);
+
+  if(NT_SUCCESS(Status))
+  {
+    Status = ObInsertObject((PVOID)Directory,
+                            NULL,
+                            DesiredAccess,
+                            0,
+                            NULL,
+                            &hDirectory);
+    if (!NT_SUCCESS(Status))
+    {
+       ObMakeTemporaryObject(Directory);
+    }
+    ObDereferenceObject(Directory);
 
-  ObDereferenceObject(DirectoryObject);
+    if(NT_SUCCESS(Status))
+    {
+      _SEH_TRY
+      {
+        *DirectoryHandle = hDirectory;
+      }
+      _SEH_HANDLE
+      {
+        Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+    }
+  }
 
   return Status;
 }