- Implement ProcessQuotaLimits case for NtQueryInformationProcess. Based on Dmitry...
[reactos.git] / reactos / ntoskrnl / ps / query.c
index 48d5321..e00a0cd 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ps/query.c
- * PURPOSE:         Set/Query Process/Thread Information APIs
- *
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) - Created File
- *                  David Welch
+ * PURPOSE:         Process Manager: Thread/Process Query/Set Information
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Thomas Weidenmueller (w3seek@reactos.org)
  */
 
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
-/* GLOBALS ******************************************************************/
+/* Include Information Class Tables */
+#include "internal/ps_i.h"
 
-static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
+/* Debugging Level */
+ULONG PspTraceLevel = 0;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+NTSTATUS
+NTAPI
+PsReferenceProcessFilePointer(IN PEPROCESS Process,
+                              OUT PFILE_OBJECT *FileObject)
 {
-  ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION),     sizeof(ULONG), ICIF_QUERY ),                     /* ProcessBasicInformation */
-  ICI_SQ_SAME( sizeof(QUOTA_LIMITS),                  sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessQuotaLimits */
-  ICI_SQ_SAME( sizeof(IO_COUNTERS),                   sizeof(ULONG), ICIF_QUERY ),                     /* ProcessIoCounters */
-  ICI_SQ_SAME( sizeof(VM_COUNTERS),                   sizeof(ULONG), ICIF_QUERY ),                     /* ProcessVmCounters */
-  ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES),             sizeof(ULONG), ICIF_QUERY ),                     /* ProcessTimes */
-  ICI_SQ_SAME( sizeof(KPRIORITY),                     sizeof(ULONG), ICIF_SET ),                       /* ProcessBasePriority */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_SET ),                       /* ProcessRaisePriority */
-  ICI_SQ_SAME( sizeof(HANDLE),                        sizeof(ULONG), ICIF_QUERY ),                     /* ProcessDebugPort */
-  ICI_SQ_SAME( sizeof(HANDLE),                        sizeof(ULONG), ICIF_SET ),                       /* ProcessExceptionPort */
-  ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN),          sizeof(ULONG), ICIF_SET ),                       /* ProcessAccessToken */
-  ICI_SQ_SAME( 0 /* FIXME */,                         sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessLdtInformation */
-  ICI_SQ_SAME( 0 /* FIXME */,                         sizeof(ULONG), ICIF_SET ),                       /* ProcessLdtSize */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessDefaultHardErrorMode */
-  ICI_SQ_SAME( 0 /* FIXME */,                         sizeof(ULONG), ICIF_SET ),                       /* ProcessIoPortHandlers */
-  ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS),       sizeof(ULONG), ICIF_QUERY ),                     /* ProcessPooledUsageAndLimits */
-  ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION),  sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessWorkingSetWatch */
-  ICI_SQ_SAME( 0 /* FIXME */,                         sizeof(ULONG), ICIF_SET ),                       /* ProcessUserModeIOPL */
-  ICI_SQ_SAME( sizeof(BOOLEAN),                       sizeof(ULONG), ICIF_SET ),                       /* ProcessEnableAlignmentFaultFixup */
-  ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS),        sizeof(USHORT), ICIF_QUERY | ICIF_SET ),         /* ProcessPriorityClass */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY ),                     /* ProcessWx86Information */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY ),                     /* ProcessHandleCount */
-  ICI_SQ_SAME( sizeof(KAFFINITY),                     sizeof(ULONG), ICIF_SET ),                       /* ProcessAffinityMask */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessPriorityBoost */
-
-  ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query),                                   /* ProcessDeviceMap */
-         /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
-                                                /*Q*/ sizeof(ULONG),
-                                                /*S*/ sizeof(ULONG),
-                                                                     ICIF_QUERY | ICIF_SET ),
-
-  ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION),   sizeof(ULONG), ICIF_QUERY | ICIF_SET ),          /* ProcessSessionInformation */
-  ICI_SQ_SAME( sizeof(BOOLEAN),                       sizeof(ULONG), ICIF_SET ),                       /* ProcessForegroundInformation */
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY ),                     /* ProcessWow64Information */
-  ICI_SQ_SAME( sizeof(UNICODE_STRING),                sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */
-
-  /* FIXME */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessLUIDDeviceMapsEnabled */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessBreakOnTermination */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessDebugObjectHandle */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessDebugFlags */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessHandleTracing */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessUnknown33 */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessUnknown34 */
-  ICI_SQ_SAME( 0,                                     1,             0 ),                              /* ProcessUnknown35 */
-  
-  ICI_SQ_SAME( sizeof(ULONG),                         sizeof(ULONG), ICIF_QUERY),                      /* ProcessCookie */
-};
+    PSECTION Section;
+    PAGED_CODE();
+
+    /* Lock the process */
+    ExAcquireRundownProtection(&Process->RundownProtect);
+
+    /* Get the section */
+    Section = Process->SectionObject;
+    if (Section)
+    {
+        /* Get the file object and reference it */
+        *FileObject = MmGetFileObjectForSection((PVOID)Section);
+        ObReferenceObject(*FileObject);
+    }
+
+    /* Release the protection */
+    ExReleaseRundownProtection(&Process->RundownProtect);
+
+    /* Return status */
+    return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
 
 /*
- * FIXME:
- *   Remove the Implemented value if all functions are implemented.
+ * @implemented
  */
-
-static const struct
-{
-   BOOLEAN Implemented;
-   ULONG Size;
-} QueryInformationData[MaxThreadInfoClass + 1] = 
-{
-    {TRUE, sizeof(THREAD_BASIC_INFORMATION)},  // ThreadBasicInformation
-    {TRUE, sizeof(KERNEL_USER_TIMES)},         // ThreadTimes
-    {TRUE, 0},                                 // ThreadPriority
-    {TRUE, 0},                                 // ThreadBasePriority
-    {TRUE, 0},                                 // ThreadAffinityMask
-    {TRUE, 0},                                 // ThreadImpersonationToken
-    {FALSE, 0},                                        // ThreadDescriptorTableEntry
-    {TRUE, 0},                                 // ThreadEnableAlignmentFaultFixup
-    {TRUE, 0},                                 // ThreadEventPair
-    {TRUE, sizeof(PVOID)},                     // ThreadQuerySetWin32StartAddress
-    {TRUE, 0},                                 // ThreadZeroTlsCell
-    {TRUE, sizeof(LARGE_INTEGER)},             // ThreadPerformanceCount
-    {TRUE, sizeof(BOOLEAN)},                   // ThreadAmILastThread
-    {TRUE, 0},                                 // ThreadIdealProcessor
-    {FALSE, 0},                                        // ThreadPriorityBoost
-    {TRUE, 0},                                 // ThreadSetTlsArrayAddress
-    {FALSE, 0},                                        // ThreadIsIoPending
-    {TRUE, 0}                                  // ThreadHideFromDebugger
-};
-
-static const struct
+NTSTATUS
+NTAPI
+NtQueryInformationProcess(IN HANDLE ProcessHandle,
+                          IN PROCESSINFOCLASS ProcessInformationClass,
+                          OUT PVOID ProcessInformation,
+                          IN ULONG ProcessInformationLength,
+                          OUT PULONG ReturnLength OPTIONAL)
 {
-   BOOLEAN Implemented;
-   ULONG Size;
-} SetInformationData[MaxThreadInfoClass + 1] = 
+    PEPROCESS Process;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Length = 0;
+    PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
+        (PPROCESS_BASIC_INFORMATION)ProcessInformation;
+    PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
+    PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
+    ULONG HandleCount;
+    PPROCESS_SESSION_INFORMATION SessionInfo =
+        (PPROCESS_SESSION_INFORMATION)ProcessInformation;
+    PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
+    PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
+    PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
+    PROCESS_DEVICEMAP_INFORMATION DeviceMap;
+    PUNICODE_STRING ImageName;
+    ULONG Cookie;
+    PAGED_CODE();
+
+    /* Check validity of Information Class */
+#if 0
+    Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
+                                         PsProcessInfoClass,
+                                         RTL_NUMBER_OF(PsProcessInfoClass),
+                                         ProcessInformation,
+                                         ProcessInformationLength,
+                                         ReturnLength,
+                                         PreviousMode);
+    if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+    if((ProcessInformationClass == ProcessCookie) &&
+        (ProcessHandle != NtCurrentProcess()))
+    {
+        /*
+         * Retreiving the process cookie is only allowed for the calling process
+         * itself! XP only allowes NtCurrentProcess() as process handles even if
+         * a real handle actually represents the current process.
+         */
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Check the information class */
+    switch (ProcessInformationClass)
+    {
+        /* Basic process information */
+        case ProcessBasicInformation:
+
+            /* Set return length */
+            Length = sizeof(PROCESS_BASIC_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Protect writes with SEH */
+            _SEH2_TRY
+            {
+                /* Write all the information from the EPROCESS/KPROCESS */
+                ProcessBasicInfo->ExitStatus = Process->ExitStatus;
+                ProcessBasicInfo->PebBaseAddress = Process->Peb;
+                ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
+                ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
+                                                    UniqueProcessId;
+                ProcessBasicInfo->InheritedFromUniqueProcessId =
+                    (ULONG)Process->InheritedFromUniqueProcessId;
+                ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
+
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Process quota limits */
+        case ProcessQuotaLimits:
+
+            Length = sizeof(QUOTA_LIMITS);
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Indicate success */
+            Status = STATUS_SUCCESS;
+
+            _SEH2_TRY
+            {
+                /* Set max/min working set sizes */
+                QuotaLimits->MaximumWorkingSetSize =
+                        Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
+                QuotaLimits->MinimumWorkingSetSize =
+                        Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
+
+                /* Set default time limits */
+                QuotaLimits->TimeLimit.LowPart = (ULONG)-1;
+                QuotaLimits->TimeLimit.HighPart = (ULONG)-1;
+
+                /* Is quota block a default one? */
+                if (Process->QuotaBlock == &PspDefaultQuotaBlock)
+                {
+                    /* Set default pools and pagefile limits */
+                    QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
+                    QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
+                    QuotaLimits->PagefileLimit = (SIZE_T)-1;
+                }
+                else
+                {
+                    /* Get limits from non-default quota block */
+                    QuotaLimits->PagedPoolLimit =
+                        Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
+                    QuotaLimits->NonPagedPoolLimit =
+                        Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
+                    QuotaLimits->PagefileLimit =
+                        Process->QuotaBlock->QuotaEntry[2].Limit;
+                }
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        case ProcessIoCounters:
+
+            Length = sizeof(IO_COUNTERS);
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            _SEH2_TRY
+            {
+                IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
+                IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
+                IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
+                IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
+                IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
+                IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Ignore exception */
+            }
+            _SEH2_END;
+
+            /* Set status to success in any case */
+            Status = STATUS_SUCCESS;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Timing */
+        case ProcessTimes:
+
+            /* Set the return length */
+            Length = sizeof(KERNEL_USER_TIMES);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Protect writes with SEH */
+            _SEH2_TRY
+            {
+                /* Copy time information from EPROCESS/KPROCESS */
+                ProcessTime->CreateTime = Process->CreateTime;
+                ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
+                                                 100000LL;
+                ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
+                                                   100000LL;
+                ProcessTime->ExitTime = Process->ExitTime;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Process Debug Port */
+        case ProcessDebugPort:
+
+            /* Set return length */
+            Length = sizeof(HANDLE);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Return whether or not we have a debug port */
+                *(PHANDLE)ProcessInformation = (Process->DebugPort ?
+                                                (HANDLE)-1 : NULL);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* LDT, WS and VDM Information: not implemented */
+        case ProcessLdtInformation:
+        case ProcessWorkingSetWatch:
+        case ProcessWx86Information:
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case ProcessHandleCount:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Count the number of handles this process has */
+            HandleCount = ObGetProcessHandleCount(Process);
+
+            /* Protect write in SEH */
+            _SEH2_TRY
+            {
+                /* Return the count of handles */
+                *(PULONG)ProcessInformation = HandleCount;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Session ID for the process */
+        case ProcessSessionInformation:
+
+            /* Set the return length*/
+            Length = sizeof(PROCESS_SESSION_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Enter SEH for write safety */
+            _SEH2_TRY
+            {
+                /* Write back the Session ID */
+                SessionInfo->SessionId = Process->Session;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* WOW64: Not implemented */
+        case ProcessWow64Information:
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        /* Virtual Memory Statistics */
+        case ProcessVmCounters:
+
+            /* Set the return length */
+            Length = sizeof(VM_COUNTERS);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Enter SEH for write safety */
+            _SEH2_TRY
+            {
+                /* Return data from EPROCESS */
+                VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
+                VmCounters->VirtualSize = Process->VirtualSize;
+                VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
+                VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
+                VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
+                VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
+                VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
+                VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
+                VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
+                VmCounters->PagefileUsage = Process->QuotaUsage[2];
+                VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
+
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Hard Error Processing Mode */
+        case ProcessDefaultHardErrorMode:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Enter SEH for writing back data */
+            _SEH2_TRY
+            {
+                /* Write the current processing mode */
+                *(PULONG)ProcessInformation = Process->
+                                              DefaultHardErrorProcessing;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Priority Boosting status */
+        case ProcessPriorityBoost:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Enter SEH for writing back data */
+            _SEH2_TRY
+            {
+                /* Return boost status */
+                *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
+                                              TRUE : FALSE;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* DOS Device Map */
+        case ProcessDeviceMap:
+
+            /* Set the return length*/
+            Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Query the device map information */
+            ObQueryDeviceMapInformation(Process, &DeviceMap);
+
+            /* Enter SEH for writing back data */
+            _SEH2_TRY
+            {
+                *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Priority class */
+        case ProcessPriorityClass:
+
+            /* Set the return length*/
+            Length = sizeof(PROCESS_PRIORITY_CLASS);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Enter SEH for writing back data */
+            _SEH2_TRY
+            {
+                /* Return current priority class */
+                PsPriorityClass->PriorityClass = Process->PriorityClass;
+                PsPriorityClass->Foreground = FALSE;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        case ProcessImageFileName:
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Get the image path */
+            Status = SeLocateProcessImageName(Process, &ImageName);
+            if (NT_SUCCESS(Status))
+            {
+                /* Set return length */
+                Length = ImageName->MaximumLength +
+                         sizeof(OBJECT_NAME_INFORMATION);
+
+                /* Make sure it's large enough */
+                if (Length <= ProcessInformationLength)
+                {
+                    /* Enter SEH to protect write */
+                    _SEH2_TRY
+                    {
+                        /* Copy it */
+                        RtlCopyMemory(ProcessInformation,
+                                      ImageName,
+                                      Length);
+
+                        /* Update pointer */
+                        ((PUNICODE_STRING)ProcessInformation)->Buffer =
+                            (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
+                   }
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        /* Get the exception code */
+                        Status = _SEH2_GetExceptionCode();
+                    }
+                    _SEH2_END;
+                }
+                else
+                {
+                    /* Buffer too small */
+                    Status = STATUS_INFO_LENGTH_MISMATCH;
+                }
+
+                /* Free the image path */
+                ExFreePool(ImageName);
+            }
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
+        /* Per-process security cookie */
+        case ProcessCookie:
+
+            /* Get the current process and cookie */
+            Process = PsGetCurrentProcess();
+            Cookie = Process->Cookie;
+            if (!Cookie)
+            {
+                LARGE_INTEGER SystemTime;
+                ULONG NewCookie;
+                PKPRCB Prcb;
+
+                /* Generate a new cookie */
+                KeQuerySystemTime(&SystemTime);
+                Prcb = KeGetCurrentPrcb();
+                NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
+                            SystemTime.u.LowPart ^ SystemTime.u.HighPart;
+
+                /* Set the new cookie or return the current one */
+                Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
+                                                    NewCookie,
+                                                    Cookie);
+                if (!Cookie) Cookie = NewCookie;
+
+                /* Set return length */
+                Length = sizeof(ULONG);
+            }
+
+            /* Enter SEH to protect write */
+            _SEH2_TRY
+            {
+                /* Write back the cookie */
+                *(PULONG)ProcessInformation = Cookie;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
+
+        /* Not yet implemented, or unknown */
+        case ProcessBasePriority:
+        case ProcessRaisePriority:
+        case ProcessExceptionPort:
+        case ProcessAccessToken:
+        case ProcessLdtSize:
+        case ProcessIoPortHandlers:
+        case ProcessUserModeIOPL:
+        case ProcessEnableAlignmentFaultFixup:
+        case ProcessAffinityMask:
+        case ProcessForegroundInformation:
+        default:
+            DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
+            Status = STATUS_INVALID_INFO_CLASS;
+    }
+
+    /* Protect write with SEH */
+    _SEH2_TRY
+    {
+        /* Check if caller wanted return length */
+        if (ReturnLength) *ReturnLength = Length;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Get exception code */
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtSetInformationProcess(IN HANDLE ProcessHandle,
+                        IN PROCESSINFOCLASS ProcessInformationClass,
+                        IN PVOID ProcessInformation,
+                        IN ULONG ProcessInformationLength)
 {
-    {TRUE, 0},                 // ThreadBasicInformation
-    {TRUE, 0},                 // ThreadTimes
-    {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
-    {TRUE, sizeof(LONG)},      // ThreadBasePriority
-    {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
-    {TRUE, sizeof(HANDLE)},    // ThreadImpersonationToken
-    {TRUE, 0},                 // ThreadDescriptorTableEntry
-    {FALSE, 0},                        // ThreadEnableAlignmentFaultFixup
-    {FALSE, 0},                        // ThreadEventPair
-    {TRUE, sizeof(PVOID)},     // ThreadQuerySetWin32StartAddress
-    {FALSE, 0},                        // ThreadZeroTlsCell
-    {TRUE, 0},                 // ThreadPerformanceCount
-    {TRUE, 0},                 // ThreadAmILastThread
-    {FALSE, 0},                        // ThreadIdealProcessor
-    {FALSE, 0},                        // ThreadPriorityBoost
-    {FALSE, 0},                        // ThreadSetTlsArrayAddress
-    {TRUE, 0},                 // ThreadIsIoPending
-    {FALSE, 0}                 // ThreadHideFromDebugger
-};
-
-/* FUNCTIONS *****************************************************************/
+    PEPROCESS Process;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ACCESS_MASK Access;
+    NTSTATUS Status;
+    HANDLE PortHandle = NULL;
+    HANDLE TokenHandle = NULL;
+    PROCESS_SESSION_INFORMATION SessionInfo = {0};
+    PROCESS_PRIORITY_CLASS PriorityClass = {0};
+    PVOID ExceptionPort;
+    PAGED_CODE();
+
+    /* Verify Information Class validity */
+#if 0
+    Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
+                                       PsProcessInfoClass,
+                                       RTL_NUMBER_OF(PsProcessInfoClass),
+                                       ProcessInformation,
+                                       ProcessInformationLength,
+                                       PreviousMode);
+    if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+    /* Check what class this is */
+    Access = PROCESS_SET_INFORMATION;
+    if (ProcessInformationClass == ProcessSessionInformation)
+    {
+        /* Setting the Session ID needs a special mask */
+        Access |= PROCESS_SET_SESSIONID;
+    }
+    else if (ProcessInformationClass == ProcessExceptionPort)
+    {
+        /* Setting the exception port needs a special mask */
+        Access |= PROCESS_SUSPEND_RESUME;
+    }
+
+    /* Reference the process */
+    Status = ObReferenceObjectByHandle(ProcessHandle,
+                                       Access,
+                                       PsProcessType,
+                                       PreviousMode,
+                                       (PVOID*)&Process,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check what kind of information class this is */
+    switch (ProcessInformationClass)
+    {
+        /* Error/Exception Port */
+        case ProcessExceptionPort:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(HANDLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Capture the handle */
+                PortHandle = *(PHANDLE)ProcessInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Get the LPC Port */
+            Status = ObReferenceObjectByHandle(PortHandle,
+                                               0,
+                                               LpcPortObjectType,
+                                               PreviousMode,
+                                               (PVOID)&ExceptionPort,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Change the pointer */
+            if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
+                                                  ExceptionPort,
+                                                  NULL))
+            {
+                /* We already had one, fail */
+                ObDereferenceObject(ExceptionPort);
+                Status = STATUS_PORT_ALREADY_SET;
+            }
+            break;
+
+        /* Security Token */
+        case ProcessAccessToken:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Save the token handle */
+                TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
+                               Token;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Assign the actual token */
+            Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
+            break;
+
+        /* Hard error processing */
+        case ProcessDefaultHardErrorMode:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(ULONG))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Enter SEH for direct buffer read */
+            _SEH2_TRY
+            {
+                /* Update the current mode abd return the previous one */
+                InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
+                                    *(PLONG)ProcessInformation);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
+
+        /* Session ID */
+        case ProcessSessionInformation:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Enter SEH for capture */
+            _SEH2_TRY
+            {
+                /* Capture the caller's buffer */
+                SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Setting the session id requires the SeTcbPrivilege */
+            if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+            {
+                /* Can't set the session ID, bail out. */
+                Status = STATUS_PRIVILEGE_NOT_HELD;
+                break;
+            }
+
+            /* FIXME - update the session id for the process token */
+            //Status = PsLockProcess(Process, FALSE);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Write the session ID in the EPROCESS */
+            Process->Session = SessionInfo.SessionId;
+
+            /* Check if the process also has a PEB */
+            if (Process->Peb)
+            {
+                /*
+                 * Attach to the process to make sure we're in the right
+                 * context to access the PEB structure
+                 */
+                KeAttachProcess(&Process->Pcb);
+
+                /* Enter SEH for write to user-mode PEB */
+                _SEH2_TRY
+                {
+                    /* Write the session ID */
+                    Process->Peb->SessionId = SessionInfo.SessionId;
+                }
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                {
+                    /* Get exception code */
+                    Status = _SEH2_GetExceptionCode();
+                }
+                _SEH2_END;
+
+                /* Detach from the process */
+                KeDetachProcess();
+            }
+
+            /* Unlock the process */
+            //PsUnlockProcess(Process);
+            break;
+
+        case ProcessPriorityClass:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Enter SEH for capture */
+            _SEH2_TRY
+            {
+                /* Capture the caller's buffer */
+                PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Check for invalid PriorityClass value */
+            if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* TODO: Check privileges */
+
+            /* Check if we have a job */
+            if (Process->Job)
+            {
+                DPRINT1("Jobs not yet supported\n");
+            }
+
+            /* Set process priority class */
+            Process->PriorityClass = PriorityClass.PriorityClass;
+
+            /* Set process priority mode (foreground or background) */
+            PsSetProcessPriorityByClass(Process,
+                                        !PriorityClass.Foreground ? PsProcessPriorityBackground :
+                                        PsProcessPriorityForeground);
+
+            Status = STATUS_SUCCESS;
+            break;
+
+        /* We currently don't implement any of these */
+        case ProcessQuotaLimits:
+        case ProcessBasePriority:
+        case ProcessRaisePriority:
+        case ProcessLdtInformation:
+        case ProcessLdtSize:
+        case ProcessIoPortHandlers:
+        case ProcessWorkingSetWatch:
+        case ProcessUserModeIOPL:
+        case ProcessEnableAlignmentFaultFixup:
+        case ProcessAffinityMask:
+            DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        /* Supposedly these are invalid...!? verify! */
+        case ProcessBasicInformation:
+        case ProcessIoCounters:
+        case ProcessTimes:
+        case ProcessPooledUsageAndLimits:
+        case ProcessWx86Information:
+        case ProcessHandleCount:
+        case ProcessWow64Information:
+        case ProcessDebugPort:
+        default:
+            DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
+            Status = STATUS_INVALID_INFO_CLASS;
+    }
+
+    /* Dereference and return status */
+    ObDereferenceObject(Process);
+    return Status;
+}
 
 /*
- * @unimplemented
+ * @implemented
  */
-NTSTATUS STDCALL
-NtQueryInformationProcess(IN  HANDLE ProcessHandle,
-                         IN  PROCESSINFOCLASS ProcessInformationClass,
-                         OUT PVOID ProcessInformation,
-                         IN  ULONG ProcessInformationLength,
-                         OUT PULONG ReturnLength  OPTIONAL)
+NTSTATUS
+NTAPI
+NtSetInformationThread(IN HANDLE ThreadHandle,
+                       IN THREADINFOCLASS ThreadInformationClass,
+                       IN PVOID ThreadInformation,
+                       IN ULONG ThreadInformationLength)
 {
-   PEPROCESS Process;
-   KPROCESSOR_MODE PreviousMode;
-   NTSTATUS Status = STATUS_SUCCESS;
-   
-   PAGED_CODE();
-   
-   PreviousMode = ExGetPreviousMode();
-   
-   DefaultQueryInfoBufferCheck(ProcessInformationClass,
-                               PsProcessInfoClass,
-                               ProcessInformation,
-                               ProcessInformationLength,
-                               ReturnLength,
-                               PreviousMode,
-                               &Status);
-   if(!NT_SUCCESS(Status))
-   {
-     DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
-     return Status;
-   }
-   
-   if(ProcessInformationClass != ProcessCookie)
-   {
-     Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     PROCESS_QUERY_INFORMATION,
-                                     PsProcessType,
-                                     PreviousMode,
-                                     (PVOID*)&Process,
-                                     NULL);
-     if (!NT_SUCCESS(Status))
-       {
-       return(Status);
-       }
-   }
-   else if(ProcessHandle != NtCurrentProcess())
-   {
-     /* retreiving the process cookie is only allowed for the calling process
-        itself! XP only allowes NtCurrentProcess() as process handles even if a
-        real handle actually represents the current process. */
-     return STATUS_INVALID_PARAMETER;
-   }
-   
-   switch (ProcessInformationClass)
-     {
-      case ProcessBasicInformation:
-      {
-        PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
-         (PPROCESS_BASIC_INFORMATION)ProcessInformation;
-
-        _SEH_TRY
-        {
-         ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
-         ProcessBasicInformationP->PebBaseAddress = Process->Peb;
-         ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
-         ProcessBasicInformationP->UniqueProcessId =
-           Process->UniqueProcessId;
-         ProcessBasicInformationP->InheritedFromUniqueProcessId =
-           Process->InheritedFromUniqueProcessId;
-         ProcessBasicInformationP->BasePriority =
-           Process->Pcb.BasePriority;
-
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-       break;
-      }
-
-      case ProcessQuotaLimits:
-      case ProcessIoCounters:
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-
-      case ProcessTimes:
-      {
-         PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
-         _SEH_TRY
-         {
-           ProcessTimeP->CreateTime = Process->CreateTime;
-            ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
-            ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
-           ProcessTimeP->ExitTime = Process->ExitTime;
-
-          if (ReturnLength)
-          {
-            *ReturnLength = sizeof(KERNEL_USER_TIMES);
-          }
-         }
-         _SEH_HANDLE
-         {
-           Status = _SEH_GetExceptionCode();
-         }
-         _SEH_END;
-        break;
-      }
-
-      case ProcessDebugPort:
-      {
-        _SEH_TRY
-        {
-          *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(HANDLE);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        break;
-      }
-      
-      case ProcessLdtInformation:
-      case ProcessWorkingSetWatch:
-      case ProcessWx86Information:
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-
-      case ProcessHandleCount:
-      {
-       ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
-         
-       _SEH_TRY
-       {
-          *(PULONG)ProcessInformation = HandleCount;
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(ULONG);
-         }
-       }
-       _SEH_HANDLE
-       {
-          Status = _SEH_GetExceptionCode();
-       }
-       _SEH_END;
-       break;
-      }
-
-      case ProcessSessionInformation:
-      {
-        PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
-
-        _SEH_TRY
-        {
-          SessionInfo->SessionId = Process->Session;
-          if (ReturnLength)
-          {
-            *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
-          }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        break;
-      }
-      
-      case ProcessWow64Information:
-        DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-
-      case ProcessVmCounters:
-      {
-       PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
-         
-       _SEH_TRY
-       {
-         pOut->PeakVirtualSize            = Process->PeakVirtualSize;
-         /*
-          * Here we should probably use VirtualSize.LowPart, but due to
-          * incompatibilities in current headers (no unnamed union),
-          * I opted for cast.
-          */
-         pOut->VirtualSize                = (ULONG)Process->VirtualSize;
-         pOut->PageFaultCount             = Process->Vm.PageFaultCount;
-         pOut->PeakWorkingSetSize         = Process->Vm.PeakWorkingSetSize;
-         pOut->WorkingSetSize             = Process->Vm.WorkingSetSize;
-         pOut->QuotaPeakPagedPoolUsage    = Process->QuotaPeak[0]; // TODO: Verify!
-         pOut->QuotaPagedPoolUsage        = Process->QuotaUsage[0];     // TODO: Verify!
-         pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; // TODO: Verify!
-         pOut->QuotaNonPagedPoolUsage     = Process->QuotaUsage[1];     // TODO: Verify!
-         pOut->PagefileUsage              = Process->QuotaUsage[2];
-         pOut->PeakPagefileUsage          = Process->QuotaPeak[2];
-
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(VM_COUNTERS);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-       break;
-      }
-
-      case ProcessDefaultHardErrorMode:
-      {
-       PULONG HardErrMode = (PULONG)ProcessInformation;
-       _SEH_TRY
-       {
-         *HardErrMode = Process->DefaultHardErrorProcessing;
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(ULONG);
-         }
-       }
-       _SEH_HANDLE
-       {
-          Status = _SEH_GetExceptionCode();
-       }
-       _SEH_END;
-       break;
-      }
-
-      case ProcessPriorityBoost:
-      {
-       PULONG BoostEnabled = (PULONG)ProcessInformation;
-         
-       _SEH_TRY
-       {
-         *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
-
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(ULONG);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-       break;
-      }
+    PETHREAD Thread;
+    ULONG Access;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status;
+    HANDLE TokenHandle = NULL;
+    KPRIORITY Priority = 0;
+    KAFFINITY Affinity = 0, CombinedAffinity;
+    PVOID Address = NULL;
+    PEPROCESS Process;
+    ULONG DisableBoost = 0;
+    ULONG IdealProcessor = 0;
+    PTEB Teb;
+    ULONG TlsIndex = 0;
+    PVOID *ExpansionSlots;
+    PETHREAD ProcThread;
+    PAGED_CODE();
+
+    /* Verify Information Class validity */
+#if 0
+    Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
+                                       PsThreadInfoClass,
+                                       RTL_NUMBER_OF(PsThreadInfoClass),
+                                       ThreadInformation,
+                                       ThreadInformationLength,
+                                       PreviousMode);
+    if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+    /* Check what class this is */
+    Access = THREAD_SET_INFORMATION;
+    if (ThreadInformationClass == ThreadImpersonationToken)
+    {
+        /* Setting the impersonation token needs a special mask */
+        Access = THREAD_SET_THREAD_TOKEN;
+    }
+
+    /* Reference the process */
+    Status = ObReferenceObjectByHandle(ThreadHandle,
+                                       Access,
+                                       PsThreadType,
+                                       PreviousMode,
+                                       (PVOID*)&Thread,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check what kind of information class this is */
+    switch (ThreadInformationClass)
+    {
+        /* Thread priority */
+        case ThreadPriority:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(KPRIORITY))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
 
-      case ProcessDeviceMap:
-      {
-        PROCESS_DEVICEMAP_INFORMATION DeviceMap;
-          
-        ObQueryDeviceMapInformation(Process, &DeviceMap);
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Priority = *(PLONG)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
 
-        _SEH_TRY
-        {
-          *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
-         if (ReturnLength)
-          {
-           *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-       break;
-      }
-
-      case ProcessPriorityClass:
-      {
-       PUSHORT Priority = (PUSHORT)ProcessInformation;
-
-       _SEH_TRY
-       {
-         *Priority = Process->PriorityClass;
-
-         if (ReturnLength)
-         {
-           *ReturnLength = sizeof(USHORT);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-       break;
-      }
+            /* Validate it */
+            if ((Priority > HIGH_PRIORITY) ||
+                (Priority <= LOW_PRIORITY))
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
 
-      case ProcessImageFileName:
-      {
-        /*
-         * We DO NOT return the file name stored in the EPROCESS structure.
-         * Propably if we can't find a PEB or ProcessParameters structure for the
-         * process!
-         */
-        if(Process->Peb != NULL)
-        {
-          PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL;
-          UNICODE_STRING LocalDest;
-          BOOLEAN Attached;
-          ULONG ImagePathLen = 0;
-          PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
-
-          /* we need to attach to the process to make sure we're in the right context! */
-          Attached = Process != PsGetCurrentProcess();
-
-          if(Attached)
-            KeAttachProcess(&Process->Pcb);
-          
-          _SEH_TRY
-          {
-            ProcParams = Process->Peb->ProcessParameters;
-            ImagePathLen = ProcParams->ImagePathName.Length;
-          }
-          _SEH_HANDLE
-          {
-            Status = _SEH_GetExceptionCode();
-          }
-          _SEH_END;
-          
-          if(NT_SUCCESS(Status))
-          {
-            if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
-            {
-              Status = STATUS_INFO_LENGTH_MISMATCH;
+            /* Set the priority */
+            KeSetPriorityThread(&Thread->Tcb, Priority);
+            break;
+
+        case ThreadBasePriority:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(LONG))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
             }
-            else
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Priority = *(PLONG)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
-              PWSTR StrSource = NULL;
-              
-              RtlZeroMemory(&LocalDest, sizeof(LocalDest));
-
-              /* create a DstPath structure on the stack */
-              _SEH_TRY
-              {
-                LocalDest.Length = ImagePathLen;
-                LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR);
-                LocalDest.Buffer = (PWSTR)(DstPath + 1);
-
-                /* save a copy of the pointer to the source buffer */
-                StrSource = ProcParams->ImagePathName.Buffer;
-              }
-              _SEH_HANDLE
-              {
-                Status = _SEH_GetExceptionCode();
-              }
-              _SEH_END;
-
-              if(NT_SUCCESS(Status))
-              {
-                /* now, let's allocate some anonymous memory to copy the string to.
-                   we can't just copy it to the buffer the caller pointed as it might
-                   be user memory in another context */
-                PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR));
-                if(PathCopy != NULL)
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Validate it */
+            if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
+                (Priority < THREAD_BASE_PRIORITY_MIN))
+            {
+                /* These ones are OK */
+                if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
+                    (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
                 {
-                  /* make a copy of the buffer to the temporary buffer */
-                  _SEH_TRY
-                  {
-                    RtlCopyMemory(PathCopy, StrSource, LocalDest.Length);
-                    PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0';
-                  }
-                  _SEH_HANDLE
-                  {
-                    Status = _SEH_GetExceptionCode();
-                  }
-                  _SEH_END;
-
-                  /* detach from the process */
-                  if(Attached)
-                    KeDetachProcess();
-
-                  /* only copy the string back to the caller if we were able to
-                     copy it into the temporary buffer! */
-                  if(NT_SUCCESS(Status))
-                  {
-                    /* now let's copy the buffer back to the caller */
-                    _SEH_TRY
-                    {
-                      *DstPath = LocalDest;
-                      RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR));
-                      if (ReturnLength)
-                      {
-                        *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR);
-                      }
-                    }
-                    _SEH_HANDLE
+                    /* Check if the process is real time */
+                    if (PsGetCurrentProcess()->PriorityClass !=
+                        PROCESS_PRIORITY_CLASS_REALTIME)
                     {
-                      Status = _SEH_GetExceptionCode();
+                        /* It isn't, fail */
+                        Status = STATUS_INVALID_PARAMETER;
+                        break;
                     }
-                    _SEH_END;
-                  }
+                }
+            }
+
+            /* Set the base priority */
+            KeSetBasePriorityThread(&Thread->Tcb, Priority);
+            break;
+
+        case ThreadAffinityMask:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Affinity = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Validate it */
+            if (!Affinity)
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* Get the process */
+            Process = Thread->ThreadsProcess;
 
-                  /* we're done with the copy operation, free the temporary kernel buffer */
-                  ExFreePool(PathCopy);
+            /* Try to acquire rundown */
+            if (ExAcquireRundownProtection(&Process->RundownProtect))
+            {
+                /* Lock it */
+                KeEnterCriticalRegion();
+                ExAcquirePushLockShared(&Process->ProcessLock);
 
-                  /* we need to bail because we're already detached from the process */
-                  break;
+                /* Combine masks */
+                CombinedAffinity = Affinity & Process->Pcb.Affinity;
+                if (CombinedAffinity != Affinity)
+                {
+                    /* Fail */
+                    Status = STATUS_INVALID_PARAMETER;
                 }
                 else
                 {
-                  Status = STATUS_INSUFFICIENT_RESOURCES;
+                    /* Set the affinity */
+                    KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
                 }
-              }
+
+                /* Release the lock and rundown */
+                ExReleasePushLockShared(&Process->ProcessLock);
+                KeLeaveCriticalRegion();
+                ExReleaseRundownProtection(&Process->RundownProtect);
             }
-          }
-          
-          /* don't forget to detach from the process!!! */
-          if(Attached)
-            KeDetachProcess();
-        }
-        else
-        {
-          /* FIXME - what to do here? */
-          Status = STATUS_UNSUCCESSFUL;
-        }
-        break;
-      }
-      
-      case ProcessCookie:
-      {
-        ULONG Cookie;
-        
-        /* receive the process cookie, this is only allowed for the current
-           process! */
-
-        Process = PsGetCurrentProcess();
-
-        Cookie = Process->Cookie;
-        if(Cookie == 0)
-        {
-          LARGE_INTEGER SystemTime;
-          ULONG NewCookie;
-          PKPRCB Prcb;
-          
-          /* generate a new cookie */
-          
-          KeQuerySystemTime(&SystemTime);
-          
-          Prcb = KeGetCurrentPrcb();
-
-          NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
-                      SystemTime.u.LowPart ^ SystemTime.u.HighPart;
-          
-          /* try to set the new cookie, return the current one if another thread
-             set it in the meanwhile */
-          Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
-                                              NewCookie,
-                                              Cookie);
-          if(Cookie == 0)
-          {
-            /* successfully set the cookie */
-            Cookie = NewCookie;
-          }
-        }
-        
-        _SEH_TRY
-        {
-          *(PULONG)ProcessInformation = Cookie;
-         if (ReturnLength)
-          {
-           *ReturnLength = sizeof(ULONG);
-         }
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        
-        break;
-      }
-
-      /*
-       * Note: The following 10 information classes are verified to not be
-       * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
-       */
-      case ProcessBasePriority:
-      case ProcessRaisePriority:
-      case ProcessExceptionPort:
-      case ProcessAccessToken:
-      case ProcessLdtSize:
-      case ProcessIoPortHandlers:
-      case ProcessUserModeIOPL:
-      case ProcessEnableAlignmentFaultFixup:
-      case ProcessAffinityMask:
-      case ProcessForegroundInformation:
-      default:
-       Status = STATUS_INVALID_INFO_CLASS;
-     }
-
-   if(ProcessInformationClass != ProcessCookie)
-   {
-     ObDereferenceObject(Process);
-   }
-   
-   return Status;
+            else
+            {
+                /* Too late */
+                Status = STATUS_PROCESS_IS_TERMINATING;
+            }
+
+            /* Return status */
+            break;
+
+        case ThreadImpersonationToken:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(HANDLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Save the token handle */
+                TokenHandle = *(PHANDLE)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Assign the actual token */
+            Status = PsAssignImpersonationToken(Thread, TokenHandle);
+            break;
+
+        case ThreadQuerySetWin32StartAddress:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Address = *(PVOID*)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Set the address */
+            Thread->Win32StartAddress = Address;
+            break;
+
+        case ThreadIdealProcessor:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                IdealProcessor = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Validate it */
+            if (IdealProcessor > MAXIMUM_PROCESSORS)
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* Set the ideal */
+            Status = KeSetIdealProcessorThread(&Thread->Tcb,
+                                               (CCHAR)IdealProcessor);
+
+            /* Get the TEB and protect the thread */
+            Teb = Thread->Tcb.Teb;
+            if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
+            {
+                /* Save the ideal processor */
+                Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
+
+                /* Release rundown protection */
+                ExReleaseRundownProtection(&Thread->RundownProtect);
+            }
+
+            break;
+
+        case ThreadPriorityBoost:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                DisableBoost = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Call the kernel */
+            KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
+            break;
+
+        case ThreadZeroTlsCell:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                TlsIndex = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* This is only valid for the current thread */
+            if (Thread != PsGetCurrentThread())
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* Get the process */
+            Process = Thread->ThreadsProcess;
+
+            /* Loop the threads */
+            ProcThread = PsGetNextProcessThread(Process, NULL);
+            while (ProcThread)
+            {
+                /* Acquire rundown */
+                if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
+                {
+                    /* Get the TEB */
+                    Teb = ProcThread->Tcb.Teb;
+                    if (Teb)
+                    {
+                        /* Check if we're in the expansion range */
+                        if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
+                        {
+                            if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
+                                            TLS_EXPANSION_SLOTS) - 1)
+                            {
+                                /* Check if we have expansion slots */
+                                ExpansionSlots = Teb->TlsExpansionSlots;
+                                if (ExpansionSlots)
+                                {
+                                    /* Clear the index */
+                                    ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            /* Clear the index */
+                            Teb->TlsSlots[TlsIndex] = NULL;
+                        }
+                    }
+
+                    /* Release rundown */
+                    ExReleaseRundownProtection(&ProcThread->RundownProtect);
+                }
+
+                /* Go to the next thread */
+                ProcThread = PsGetNextProcessThread(Process, ProcThread);
+            }
+
+            /* All done */
+            break;
+
+        default:
+            /* We don't implement it yet */
+            DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+            Status = STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Dereference and return status */
+    ObDereferenceObject(Thread);
+    return Status;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
-NTSTATUS STDCALL
-NtSetInformationProcess(IN HANDLE ProcessHandle,
-                       IN PROCESSINFOCLASS ProcessInformationClass,
-                       IN PVOID ProcessInformation,
-                       IN ULONG ProcessInformationLength)
+NTSTATUS
+NTAPI
+NtQueryInformationThread(IN HANDLE ThreadHandle,
+                         IN THREADINFOCLASS ThreadInformationClass,
+                         OUT PVOID ThreadInformation,
+                         IN ULONG ThreadInformationLength,
+                         OUT PULONG ReturnLength OPTIONAL)
 {
-   PEPROCESS Process;
-   KPROCESSOR_MODE PreviousMode;
-   ACCESS_MASK Access;
-   NTSTATUS Status = STATUS_SUCCESS;
-   
-   PAGED_CODE();
-   
-   PreviousMode = ExGetPreviousMode();
-
-   DefaultSetInfoBufferCheck(ProcessInformationClass,
-                             PsProcessInfoClass,
-                             ProcessInformation,
-                             ProcessInformationLength,
-                             PreviousMode,
-                             &Status);
-   if(!NT_SUCCESS(Status))
-   {
-     DPRINT1("NtSetInformationProcess() %d %x  %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
-     DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
-     return Status;
-   }
-   
-   switch(ProcessInformationClass)
-   {
-     case ProcessSessionInformation:
-       Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
-       break;
-     case ProcessExceptionPort:
-       Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
-       break;
-
-     default:
-       Access = PROCESS_SET_INFORMATION;
-       break;
-   }
-   
-   Status = ObReferenceObjectByHandle(ProcessHandle,
-                                     Access,
-                                     PsProcessType,
-                                     PreviousMode,
-                                     (PVOID*)&Process,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-
-   switch (ProcessInformationClass)
-     {
-      case ProcessQuotaLimits:
-      case ProcessBasePriority:
-      case ProcessRaisePriority:
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-
-      case ProcessExceptionPort:
-      {
-        HANDLE PortHandle = NULL;
-
-        /* make a safe copy of the buffer on the stack */
-        _SEH_TRY
+    PETHREAD Thread;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Access;
+    ULONG Length = 0;
+    PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
+        (PTHREAD_BASIC_INFORMATION)ThreadInformation;
+    PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
+    KIRQL OldIrql;
+    PAGED_CODE();
+
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
         {
-          PortHandle = *(PHANDLE)ProcessInformation;
-          Status = STATUS_SUCCESS;
+            ProbeForWrite(ThreadInformation,
+                          ThreadInformationLength,
+                          sizeof(ULONG));
+
+            if (ReturnLength)
+            {
+                ProbeForWriteUlong(ReturnLength);
+            }
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-          Status = _SEH_GetExceptionCode();
+            Status = _SEH2_GetExceptionCode();
         }
-        _SEH_END;
-        
-        if(NT_SUCCESS(Status))
-        {
-          PEPORT ExceptionPort;
-          
-          /* in case we had success reading from the buffer, verify the provided
-           * LPC port handle
-           */
-          Status = ObReferenceObjectByHandle(PortHandle,
-                                             0,
-                                             LpcPortObjectType,
-                                             PreviousMode,
-                                             (PVOID)&ExceptionPort,
-                                             NULL);
-          if(NT_SUCCESS(Status))
-          {
-            /* lock the process to be thread-safe! */
-            
-            Status = PsLockProcess(Process, FALSE);
-            if(NT_SUCCESS(Status))
-            {
-              /*
-               * according to "NT Native API" documentation, setting the exception
-               * port is only permitted once!
-               */
-              if(Process->ExceptionPort == NULL)
-              {
-                /* keep the reference to the handle! */
-                Process->ExceptionPort = ExceptionPort;
-                Status = STATUS_SUCCESS;
-              }
-              else
-              {
-                ObDereferenceObject(ExceptionPort);
-                Status = STATUS_PORT_ALREADY_SET;
-              }
-              PsUnlockProcess(Process);
+        _SEH2_END;
+
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Check what class this is */
+    Access = THREAD_QUERY_INFORMATION;
+
+    /* Reference the process */
+    Status = ObReferenceObjectByHandle(ThreadHandle,
+                                       Access,
+                                       PsThreadType,
+                                       PreviousMode,
+                                       (PVOID*)&Thread,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check what kind of information class this is */
+    switch (ThreadInformationClass)
+    {
+        /* Basic thread information */
+        case ThreadBasicInformation:
+
+            /* Set return length */
+            Length = sizeof(THREAD_BASIC_INFORMATION);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
             }
-            else
+            /* Protect writes with SEH */
+            _SEH2_TRY
             {
-              ObDereferenceObject(ExceptionPort);
+                /* Write all the information from the ETHREAD/KTHREAD */
+                ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
+                ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
+                ThreadBasicInfo->ClientId = Thread->Cid;
+                ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
+                ThreadBasicInfo->Priority = Thread->Tcb.Priority;
+                ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
             }
-          }
-        }
-        break;
-      }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
 
-      case ProcessAccessToken:
-      {
-        HANDLE TokenHandle = NULL;
+        /* Thread time information */
+        case ThreadTimes:
 
-        /* make a safe copy of the buffer on the stack */
-        _SEH_TRY
-        {
-          TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
-          Status = STATUS_SUCCESS;
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
+            /* Set the return length */
+            Length = sizeof(KERNEL_USER_TIMES);
 
-        if(NT_SUCCESS(Status))
-        {
-          /* in case we had success reading from the buffer, perform the actual task */
-          Status = PspAssignPrimaryToken(Process, TokenHandle);
-        }
-       break;
-      }
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect writes with SEH */
+            _SEH2_TRY
+            {
+                /* Copy time information from ETHREAD/KTHREAD */
+                ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
+                                                   100000LL;
+                ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
+                                                 100000LL;
+                ThreadTime->CreateTime = Thread->CreateTime;
+                ThreadTime->ExitTime = Thread->ExitTime;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
 
-      case ProcessDefaultHardErrorMode:
-      {
-        _SEH_TRY
-        {
-          InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
-                              *(PLONG)ProcessInformation);
-          Status = STATUS_SUCCESS;
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        break;
-      }
-      
-      case ProcessSessionInformation:
-      {
-        PROCESS_SESSION_INFORMATION SessionInfo;
-        Status = STATUS_SUCCESS;
-        
-        RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
-        
-        _SEH_TRY
-        {
-          /* copy the structure to the stack */
-          SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        
-        if(NT_SUCCESS(Status))
-        {
-          /* we successfully copied the structure to the stack, continue processing */
-          
-          /*
-           * setting the session id requires the SeTcbPrivilege!
-           */
-          if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
-                                     PreviousMode))
-          {
-            DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
-            /* can't set the session id, bail! */
-            Status = STATUS_PRIVILEGE_NOT_HELD;
+        case ThreadQuerySetWin32StartAddress:
+
+            /* Set the return length*/
+            Length = sizeof(PVOID);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Return the Win32 Start Address */
+                *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
-          }
-          
-          /* FIXME - update the session id for the process token */
 
-          Status = PsLockProcess(Process, FALSE);
-          if(NT_SUCCESS(Status))
-          {
-            Process->Session = SessionInfo.SessionId;
+        case ThreadPerformanceCount:
+
+            /* Set the return length*/
+            Length = sizeof(LARGE_INTEGER);
 
-            /* Update the session id in the PEB structure */
-            if(Process->Peb != NULL)
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect write with SEH */
+            _SEH2_TRY
             {
-              /* we need to attach to the process to make sure we're in the right
-                 context to access the PEB structure */
-              KeAttachProcess(&Process->Pcb);
+                /* FIXME */
+                (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
 
-              _SEH_TRY
-              {
-                /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
+        case ThreadAmILastThread:
 
-                Status = STATUS_SUCCESS;
-              }
-              _SEH_HANDLE
-              {
-                Status = _SEH_GetExceptionCode();
-              }
-              _SEH_END;
+            /* Set the return length*/
+            Length = sizeof(ULONG);
 
-              KeDetachProcess();
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Return whether or not we are the last thread */
+                *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
+                                               ThreadListHead.Flink->Flink ==
+                                               &Thread->ThreadsProcess->
+                                               ThreadListHead) ?
+                                              TRUE : FALSE);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
             }
+            _SEH2_END;
+            break;
 
-            PsUnlockProcess(Process);
-          }
-        }
-        break;
-      }
-      
-      case ProcessPriorityClass:
-      {
-        PROCESS_PRIORITY_CLASS ppc;
-
-        _SEH_TRY
-        {
-          ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
-        }
-        _SEH_HANDLE
-        {
-          Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-        
-        if(NT_SUCCESS(Status))
-        {
-        }
-        
-        break;
-      }
-       
-      case ProcessLdtInformation:
-      case ProcessLdtSize:
-      case ProcessIoPortHandlers:
-      case ProcessWorkingSetWatch:
-      case ProcessUserModeIOPL:
-      case ProcessEnableAlignmentFaultFixup:
-      case ProcessAffinityMask:
-       Status = STATUS_NOT_IMPLEMENTED;
-       break;
-
-      case ProcessBasicInformation:
-      case ProcessIoCounters:
-      case ProcessTimes:
-      case ProcessPooledUsageAndLimits:
-      case ProcessWx86Information:
-      case ProcessHandleCount:
-      case ProcessWow64Information:
-      case ProcessDebugPort:
-      default:
-       Status = STATUS_INVALID_INFO_CLASS;
-     }
-   ObDereferenceObject(Process);
-   return(Status);
-}
+        case ThreadIsIoPending:
 
+            /* Set the return length*/
+            Length = sizeof(ULONG);
 
-/**********************************************************************
- * NAME                                                        INTERNAL
- *     PiQuerySystemProcessInformation
- *
- * DESCRIPTION
- *     Compute the size of a process+thread snapshot as 
- *     expected by NtQuerySystemInformation.
- *
- * RETURN VALUE
- *     0 on error; otherwise the size, in bytes of the buffer
- *     required to write a full snapshot.
- *
- * NOTE
- *     We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
- */
-NTSTATUS
-PiQuerySystemProcessInformation(PVOID Buffer,
-                               ULONG Size,
-                               PULONG ReqSize)
-{
-   return STATUS_NOT_IMPLEMENTED;
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Raise the IRQL to protect the IRP list */
+            KeRaiseIrql(APC_LEVEL, &OldIrql);
 
-#if 0
-       PLIST_ENTRY     CurrentEntryP;
-       PEPROCESS       CurrentP;
-       PLIST_ENTRY     CurrentEntryT;
-       PETHREAD        CurrentT;
-       
-       ULONG           RequiredSize = 0L;
-       BOOLEAN         SizeOnly = FALSE;
-
-       ULONG           SpiSize = 0L;
-       
-       PSYSTEM_PROCESS_INFORMATION     pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
-       PSYSTEM_PROCESS_INFORMATION     pInfoPLast = NULL;
-       PSYSTEM_THREAD_INFO             pInfoT = NULL;
-       
-
-   /* Lock the process list. */
-   ExAcquireFastMutex(&PspActiveProcessMutex);
-
-       /*
-        * Scan the process list. Since the
-        * list is circular, the guard is false
-        * after the last process.
-        */
-       for (   CurrentEntryP = PsActiveProcessHead.Flink;
-               (CurrentEntryP != & PsActiveProcessHead);
-               CurrentEntryP = CurrentEntryP->Flink
-               )
-       {
-               /*
-                * Compute how much space is
-                * occupied in the snapshot
-                * by adding this process info.
-                * (at least one thread).
-                */
-               SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
-               RequiredSize += SpiSizeCurrent;
-               /*
-                * Do not write process data in the
-                * buffer if it is too small.
-                */
-               if (TRUE == SizeOnly) continue;
-               /*
-                * Check if the buffer can contain
-                * the full snapshot.
-                */
-               if (Size < RequiredSize)
-               {
-                       SizeOnly = TRUE;
-                       continue;
-               }
-               /* 
-                * Get a reference to the 
-                * process descriptor we are
-                * handling.
-                */
-               CurrentP = CONTAINING_RECORD(
-                               CurrentEntryP,
-                               EPROCESS, 
-                               ProcessListEntry
-                               );
-               /*
-                * Write process data in the buffer.
-                */
-               RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
-               /* PROCESS */
-               pInfoP->ThreadCount = 0L;
-               pInfoP->ProcessId = CurrentP->UniqueProcessId;
-               RtlInitUnicodeString (
-                       & pInfoP->Name,
-                       CurrentP->ImageFileName
-                       );
-               /* THREAD */
-               for (   pInfoT = & CurrentP->ThreadSysInfo [0],
-                       CurrentEntryT = CurrentP->ThreadListHead.Flink;
-                       
-                       (CurrentEntryT != & CurrentP->ThreadListHead);
-                       
-                       pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
-                       CurrentEntryT = CurrentEntryT->Flink
-                       )
-               {
-                       /*
-                        * Recalculate the size of the
-                        * information block.
-                        */
-                       if (0 < pInfoP->ThreadCount)
-                       {
-                               RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
-                       }
-                       /*
-                        * Do not write thread data in the
-                        * buffer if it is too small.
-                        */
-                       if (TRUE == SizeOnly) continue;
-                       /*
-                        * Check if the buffer can contain
-                        * the full snapshot.
-                        */
-                       if (Size < RequiredSize)
-                       {
-                               SizeOnly = TRUE;
-                               continue;
-                       }
-                       /* 
-                        * Get a reference to the 
-                        * thread descriptor we are
-                        * handling.
-                        */
-                       CurrentT = CONTAINING_RECORD(
-                                       CurrentEntryT,
-                                       KTHREAD, 
-                                       ThreadListEntry
-                                       );
-                       /*
-                        * Write thread data.
-                        */
-                       RtlZeroMemory (
-                               pInfoT,
-                               sizeof (SYSTEM_THREAD_INFORMATION)
-                               );
-                       pInfoT->KernelTime      = CurrentT-> ;  /* TIME */
-                       pInfoT->UserTime        = CurrentT-> ;  /* TIME */
-                       pInfoT->CreateTime      = CurrentT-> ;  /* TIME */
-                       pInfoT->TickCount       = CurrentT-> ;  /* ULONG */
-                       pInfoT->StartEIP        = CurrentT-> ;  /* ULONG */
-                       pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
-                       pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
-                       pInfoT->DynamicPriority = CurrentT-> ;  /* ULONG */
-                       pInfoT->BasePriority    = CurrentT-> ;  /* ULONG */
-                       pInfoT->nSwitches       = CurrentT-> ;  /* ULONG */
-                       pInfoT->State           = CurrentT-> ;  /* DWORD */
-                       pInfoT->WaitReason      = CurrentT-> ;  /* KWAIT_REASON */
-                       /*
-                        * Count the number of threads 
-                        * this process has.
-                        */
-                       ++ pInfoP->ThreadCount;
-               }
-               /*
-                * Save the size of information
-                * stored in the buffer for the
-                * current process.
-                */
-               pInfoP->RelativeOffset = SpiSize;
-               /*
-                * Save a reference to the last
-                * valid information block.
-                */
-               pInfoPLast = pInfoP;
-               /*
-                * Compute the offset of the 
-                * SYSTEM_PROCESS_INFORMATION
-                * descriptor in the snapshot 
-                * buffer for the next process.
-                */
-               (ULONG) pInfoP += SpiSize;
-       }
-       /*
-        * Unlock the process list.
-        */
-       ExReleaseFastMutex (
-               & PspActiveProcessMutex
-               );
-       /*
-        * Return the proper error status code,
-        * if the buffer was too small.
-        */
-       if (TRUE == SizeOnly)
-       {
-               if (NULL != RequiredSize)
-               {
-                       *pRequiredSize = RequiredSize;
-               }
-               return STATUS_INFO_LENGTH_MISMATCH;
-       }
-       /*
-        * Mark the end of the snapshot.
-        */
-       pInfoP->RelativeOffset = 0L;
-       /* OK */        
-       return STATUS_SUCCESS;
-#endif
-}
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Check if the IRP list is empty or not */
+                *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
 
-/*
- * @unimplemented
- */
-NTSTATUS STDCALL
-NtSetInformationThread (IN HANDLE ThreadHandle,
-                       IN THREADINFOCLASS ThreadInformationClass,
-                       IN PVOID ThreadInformation,
-                       IN ULONG ThreadInformationLength)
-{
-  PETHREAD Thread;
-  NTSTATUS Status;
-  union
-  {
-     KPRIORITY Priority;
-     LONG Increment;
-     KAFFINITY Affinity;
-     HANDLE Handle;
-     PVOID Address;
-  }u;
-  
-  PAGED_CODE();
-
-  if (ThreadInformationClass <= MaxThreadInfoClass &&
-      !SetInformationData[ThreadInformationClass].Implemented)
-    {
-      return STATUS_NOT_IMPLEMENTED;
+            /* Lower IRQL back */
+            KeLowerIrql(OldIrql);
+            break;
+
+        case ThreadDescriptorTableEntry:
+            DPRINT1("NtQueryInformationThread(): case ThreadDescriptorTableEntry not implemented!\n");
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case ThreadPriorityBoost:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            _SEH2_TRY
+            {
+                *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
+
+        /* Anything else */
+        default:
+
+            /* Not yet implemented */
+            DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+            Status = STATUS_NOT_IMPLEMENTED;
     }
-  if (ThreadInformationClass > MaxThreadInfoClass ||
-      SetInformationData[ThreadInformationClass].Size == 0)
+
+    /* Protect write with SEH */
+    _SEH2_TRY
     {
-      return STATUS_INVALID_INFO_CLASS;
+        /* Check if caller wanted return length */
+        if (ReturnLength) *ReturnLength = Length;
     }
-  if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-      return STATUS_INFO_LENGTH_MISMATCH;
+        /* Get exception code */
+        Status = _SEH2_GetExceptionCode();
     }
+    _SEH2_END;
 
-  Status = ObReferenceObjectByHandle (ThreadHandle,
-                                     THREAD_SET_INFORMATION,
-                                     PsThreadType,
-                                     ExGetPreviousMode (),
-                                     (PVOID*)&Thread,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   Status = MmCopyFromCaller(&u.Priority,
-                            ThreadInformation,
-                            SetInformationData[ThreadInformationClass].Size);
-   if (NT_SUCCESS(Status))
-     {
-       switch (ThreadInformationClass)
-         {
-           case ThreadPriority:
-            if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
-              {
-                Status = STATUS_INVALID_PARAMETER;
-                break;
-              }
-            KeSetPriorityThread(&Thread->Tcb, u.Priority);
-            break;
-       
-           case ThreadBasePriority:
-            KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
-            break;
-       
-           case ThreadAffinityMask:
-            Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
-            break;
-       
-           case ThreadImpersonationToken:
-            Status = PsAssignImpersonationToken (Thread, u.Handle);
-            break;
-               
-           case ThreadQuerySetWin32StartAddress:
-            Thread->Win32StartAddress = u.Address;
-            break;
-
-           default:
-            /* Shoult never occure if the data table is correct */
-            KEBUGCHECK(0);
-        }
-     }
-  ObDereferenceObject (Thread);
-
-  return Status;
+    /* Dereference the thread, and return */
+    ObDereferenceObject(Thread);
+    return Status;
 }
 
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-NtQueryInformationThread (IN   HANDLE          ThreadHandle,
-                         IN    THREADINFOCLASS ThreadInformationClass,
-                         OUT   PVOID           ThreadInformation,
-                         IN    ULONG           ThreadInformationLength,
-                         OUT   PULONG          ReturnLength  OPTIONAL)
-{
-   PETHREAD Thread;
-   NTSTATUS Status;
-   union
-   {
-      THREAD_BASIC_INFORMATION TBI;
-      KERNEL_USER_TIMES TTI;
-      PVOID Address;
-      LARGE_INTEGER Count;
-      BOOLEAN Last;
-   }u;
-   
-   PAGED_CODE();
-
-   if (ThreadInformationClass <= MaxThreadInfoClass &&
-       !QueryInformationData[ThreadInformationClass].Implemented)
-     {
-       return STATUS_NOT_IMPLEMENTED;
-     }
-   if (ThreadInformationClass > MaxThreadInfoClass ||
-       QueryInformationData[ThreadInformationClass].Size == 0)
-     {
-       return STATUS_INVALID_INFO_CLASS;
-     }
-   if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
-     {
-       return STATUS_INFO_LENGTH_MISMATCH;
-     }
-
-   Status = ObReferenceObjectByHandle(ThreadHandle,
-                                     THREAD_QUERY_INFORMATION,
-                                     PsThreadType,
-                                     ExGetPreviousMode(),
-                                     (PVOID*)&Thread,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return Status;
-     }
-
-   switch (ThreadInformationClass)
-     {
-       case ThreadBasicInformation:
-         /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
-          * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is 
-          * 0. So do the conversion here:
-          * -Gunnar     */
-         u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
-        u.TBI.TebBaseAddress = Thread->Tcb.Teb;
-        u.TBI.ClientId = Thread->Cid;
-        u.TBI.AffinityMask = Thread->Tcb.Affinity;
-        u.TBI.Priority = Thread->Tcb.Priority;
-        u.TBI.BasePriority = Thread->Tcb.BasePriority;
-        break;
-       
-       case ThreadTimes:
-        u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
-         u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
-         u.TTI.CreateTime = Thread->CreateTime;
-         /*This works*/
-        u.TTI.ExitTime = Thread->ExitTime;
-         break;
-
-       case ThreadQuerySetWin32StartAddress:
-         u.Address = Thread->Win32StartAddress;
-         break;
-
-       case ThreadPerformanceCount:
-         /* Nebbett says this class is always zero */
-         u.Count.QuadPart = 0;
-         break;
-
-       case ThreadAmILastThread:
-         if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
-            &Thread->ThreadsProcess->ThreadListHead)
-          {
-            u.Last = TRUE;
-          }
-         else
-          {
-            u.Last = FALSE;
-          }
-         break;
-       default:
-        /* Shoult never occure if the data table is correct */
-        KEBUGCHECK(0);
-     }
-   if (QueryInformationData[ThreadInformationClass].Size)
-     {
-       Status = MmCopyToCaller(ThreadInformation,
-                               &u.TBI,
-                              QueryInformationData[ThreadInformationClass].Size);
-     }
-   if (ReturnLength)
-     {
-       NTSTATUS Status2;
-       static ULONG Null = 0;
-       Status2 = MmCopyToCaller(ReturnLength,
-                               NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null,
-                               sizeof(ULONG));
-       if (NT_SUCCESS(Status))
-         {
-          Status = Status2;
-        }
-     }
-
-   ObDereferenceObject(Thread);
-   return(Status);
-}
 /* EOF */