2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Process Manager: Thread/Process Query/Set Information
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
10 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
20 ULONG PspTraceLevel
= 0;//PS_KILL_DEBUG | PS_REF_DEBUG;
22 /* PRIVATE FUNCTIONS *********************************************************/
26 PsReferenceProcessFilePointer(IN PEPROCESS Process
,
27 OUT PFILE_OBJECT
*FileObject
)
29 PROS_SECTION_OBJECT Section
;
32 /* Lock the process */
33 ExAcquireRundownProtection(&Process
->RundownProtect
);
36 Section
= (PROS_SECTION_OBJECT
)Process
->SectionObject
;
39 /* Get the file object and reference it */
40 *FileObject
= MmGetFileObjectForSection(Section
);
41 ObReferenceObject(*FileObject
);
44 /* Release the protection */
45 ExReleaseRundownProtection(&Process
->RundownProtect
);
48 return Section
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
51 /* PUBLIC FUNCTIONS **********************************************************/
58 NtQueryInformationProcess(IN HANDLE ProcessHandle
,
59 IN PROCESSINFOCLASS ProcessInformationClass
,
60 OUT PVOID ProcessInformation
,
61 IN ULONG ProcessInformationLength
,
62 OUT PULONG ReturnLength OPTIONAL
)
65 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
68 PPROCESS_BASIC_INFORMATION ProcessBasicInfo
=
69 (PPROCESS_BASIC_INFORMATION
)ProcessInformation
;
70 PKERNEL_USER_TIMES ProcessTime
= (PKERNEL_USER_TIMES
)ProcessInformation
;
72 PPROCESS_SESSION_INFORMATION SessionInfo
=
73 (PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
74 PVM_COUNTERS VmCounters
= (PVM_COUNTERS
)ProcessInformation
;
75 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
76 PUNICODE_STRING ImageName
;
80 /* Check validity of Information Class */
81 Status
= DefaultQueryInfoBufferCheck(ProcessInformationClass
,
83 RTL_NUMBER_OF(PsProcessInfoClass
),
85 ProcessInformationLength
,
88 if (!NT_SUCCESS(Status
)) return Status
;
90 /* Check if this isn't the cookie class */
91 if(ProcessInformationClass
!= ProcessCookie
)
93 /* Reference the process */
94 Status
= ObReferenceObjectByHandle(ProcessHandle
,
95 PROCESS_QUERY_INFORMATION
,
100 if (!NT_SUCCESS(Status
)) return Status
;
102 else if(ProcessHandle
!= NtCurrentProcess())
105 * Retreiving the process cookie is only allowed for the calling process
106 * itself! XP only allowes NtCurrentProcess() as process handles even if
107 * a real handle actually represents the current process.
109 return STATUS_INVALID_PARAMETER
;
112 /* Check the information class */
113 switch (ProcessInformationClass
)
115 /* Basic process information */
116 case ProcessBasicInformation
:
118 /* Protect writes with SEH */
121 /* Write all the information from the EPROCESS/KPROCESS */
122 ProcessBasicInfo
->ExitStatus
= Process
->ExitStatus
;
123 ProcessBasicInfo
->PebBaseAddress
= Process
->Peb
;
124 ProcessBasicInfo
->AffinityMask
= Process
->Pcb
.Affinity
;
125 ProcessBasicInfo
->UniqueProcessId
= (ULONG
)Process
->
127 ProcessBasicInfo
->InheritedFromUniqueProcessId
=
128 (ULONG
)Process
->InheritedFromUniqueProcessId
;
129 ProcessBasicInfo
->BasePriority
= Process
->Pcb
.BasePriority
;
131 /* Set return length */
132 Length
= sizeof(PROCESS_BASIC_INFORMATION
);
136 /* Get exception code */
137 Status
= _SEH_GetExceptionCode();
142 /* Quote limits and I/O Counters: not implemented */
143 case ProcessQuotaLimits
:
144 case ProcessIoCounters
:
145 Status
= STATUS_NOT_IMPLEMENTED
;
151 /* Protect writes with SEH */
154 /* Copy time information from EPROCESS/KPROCESS */
155 ProcessTime
->CreateTime
= Process
->CreateTime
;
156 ProcessTime
->UserTime
.QuadPart
= Process
->Pcb
.UserTime
*
158 ProcessTime
->KernelTime
.QuadPart
= Process
->Pcb
.KernelTime
*
160 ProcessTime
->ExitTime
= Process
->ExitTime
;
162 /* Set the return length */
163 Length
= sizeof(KERNEL_USER_TIMES
);
167 /* Get exception code */
168 Status
= _SEH_GetExceptionCode();
173 /* Process Debug Port */
174 case ProcessDebugPort
:
176 /* Protect write with SEH */
179 /* Return whether or not we have a debug port */
180 *(PHANDLE
)ProcessInformation
= (Process
->DebugPort
?
183 /* Set the return length*/
184 Length
= sizeof(HANDLE
);
188 /* Get exception code */
189 Status
= _SEH_GetExceptionCode();
194 /* LDT, WS and VDM Information: not implemented */
195 case ProcessLdtInformation
:
196 case ProcessWorkingSetWatch
:
197 case ProcessWx86Information
:
198 Status
= STATUS_NOT_IMPLEMENTED
;
201 case ProcessHandleCount
:
203 /* Count the number of handles this process has */
204 HandleCount
= ObpGetHandleCountByHandleTable(Process
->ObjectTable
);
206 /* Protect write in SEH */
209 /* Return the count of handles */
210 *(PULONG
)ProcessInformation
= HandleCount
;
212 /* Set the return length*/
213 Length
= sizeof(ULONG
);
217 /* Get the exception code */
218 Status
= _SEH_GetExceptionCode();
223 /* Session ID for the process */
224 case ProcessSessionInformation
:
226 /* Enter SEH for write safety */
229 /* Write back the Session ID */
230 SessionInfo
->SessionId
= Process
->Session
;
232 /* Set the return length */
233 Length
= sizeof(PROCESS_SESSION_INFORMATION
);
237 /* Get the exception code */
238 Status
= _SEH_GetExceptionCode();
243 /* WOW64: Not implemented */
244 case ProcessWow64Information
:
245 Status
= STATUS_NOT_IMPLEMENTED
;
248 /* Virtual Memory Statistics */
249 case ProcessVmCounters
:
251 /* Enter SEH for write safety */
254 /* Return data from EPROCESS */
255 VmCounters
->PeakVirtualSize
= Process
->PeakVirtualSize
;
256 VmCounters
->VirtualSize
= Process
->VirtualSize
;
257 VmCounters
->PageFaultCount
= Process
->Vm
.PageFaultCount
;
258 VmCounters
->PeakWorkingSetSize
= Process
->Vm
.PeakWorkingSetSize
;
259 VmCounters
->WorkingSetSize
= Process
->Vm
.WorkingSetSize
;
260 VmCounters
->QuotaPeakPagedPoolUsage
= Process
->QuotaPeak
[0];
261 VmCounters
->QuotaPagedPoolUsage
= Process
->QuotaUsage
[0];
262 VmCounters
->QuotaPeakNonPagedPoolUsage
= Process
->QuotaPeak
[1];
263 VmCounters
->QuotaNonPagedPoolUsage
= Process
->QuotaUsage
[1];
264 VmCounters
->PagefileUsage
= Process
->QuotaUsage
[2];
265 VmCounters
->PeakPagefileUsage
= Process
->QuotaPeak
[2];
267 /* Set the return length */
268 *ReturnLength
= sizeof(VM_COUNTERS
);
272 /* Get the exception code */
273 Status
= _SEH_GetExceptionCode();
278 /* Hard Error Processing Mode */
279 case ProcessDefaultHardErrorMode
:
281 /* Enter SEH for writing back data */
284 /* Write the current processing mode */
285 *(PULONG
)ProcessInformation
= Process
->
286 DefaultHardErrorProcessing
;
288 /* Set the return length */
289 Length
= sizeof(ULONG
);
293 /* Get the exception code */
294 Status
= _SEH_GetExceptionCode();
299 /* Priority Boosting status */
300 case ProcessPriorityBoost
:
302 /* Enter SEH for writing back data */
305 /* Return boost status */
306 *(PULONG
)ProcessInformation
= Process
->Pcb
.DisableBoost
?
309 /* Set the return length */
310 Length
= sizeof(ULONG
);
314 /* Get the exception code */
315 Status
= _SEH_GetExceptionCode();
321 case ProcessDeviceMap
:
323 /* Query the device map information */
324 ObQueryDeviceMapInformation(Process
, &DeviceMap
);
326 /* Enter SEH for writing back data */
329 *(PPROCESS_DEVICEMAP_INFORMATION
)ProcessInformation
= DeviceMap
;
331 /* Set the return length */
332 Length
= sizeof(PROCESS_DEVICEMAP_INFORMATION
);
336 /* Get the exception code */
337 Status
= _SEH_GetExceptionCode();
343 case ProcessPriorityClass
:
345 /* Enter SEH for writing back data */
348 /* Return current priority class */
349 *(PUSHORT
)ProcessInformation
= Process
->PriorityClass
;
351 /* Set the return length */
352 Length
= sizeof(USHORT
);
356 /* Get the exception code */
357 Status
= _SEH_GetExceptionCode();
362 case ProcessImageFileName
:
364 /* Get the image path */
365 Status
= SeLocateProcessImageName(Process
, &ImageName
);
366 if (NT_SUCCESS(Status
))
368 /* Set return length */
369 Length
= ImageName
->MaximumLength
+
370 sizeof(OBJECT_NAME_INFORMATION
);
372 /* Make sure it's large enough */
373 if (Length
<= ProcessInformationLength
)
375 /* Enter SEH to protect write */
379 RtlCopyMemory(ProcessInformation
,
384 ((PUNICODE_STRING
)ProcessInformation
)->Buffer
=
385 (PWSTR
)((PUNICODE_STRING
)ProcessInformation
+ 1);
389 /* Get the exception code */
390 Status
= _SEH_GetExceptionCode();
397 /* Per-process security cookie */
400 /* Get the current process and cookie */
401 Process
= PsGetCurrentProcess();
402 Cookie
= Process
->Cookie
;
405 LARGE_INTEGER SystemTime
;
409 /* Generate a new cookie */
410 KeQuerySystemTime(&SystemTime
);
411 Prcb
= KeGetCurrentPrcb();
412 NewCookie
= Prcb
->KeSystemCalls
^ Prcb
->InterruptTime
^
413 SystemTime
.u
.LowPart
^ SystemTime
.u
.HighPart
;
415 /* Set the new cookie or return the current one */
416 Cookie
= InterlockedCompareExchange((LONG
*)&Process
->Cookie
,
419 if (!Cookie
) Cookie
= NewCookie
;
421 /* Set return length */
422 Length
= sizeof(ULONG
);
425 /* Enter SEH to protect write */
428 /* Write back the cookie */
429 *(PULONG
)ProcessInformation
= Cookie
;
433 /* Get the exception code */
434 Status
= _SEH_GetExceptionCode();
439 /* Not yet implemented, or unknown */
440 case ProcessBasePriority
:
441 case ProcessRaisePriority
:
442 case ProcessExceptionPort
:
443 case ProcessAccessToken
:
445 case ProcessIoPortHandlers
:
446 case ProcessUserModeIOPL
:
447 case ProcessEnableAlignmentFaultFixup
:
448 case ProcessAffinityMask
:
449 case ProcessForegroundInformation
:
451 Status
= STATUS_INVALID_INFO_CLASS
;
454 /* Protect write with SEH */
457 /* Check if caller wanted return length */
458 if (ReturnLength
) *ReturnLength
= Length
;
462 /* Get exception code */
463 Status
= _SEH_GetExceptionCode();
467 /* If we referenced the process, dereference it */
468 if(ProcessInformationClass
!= ProcessCookie
) ObDereferenceObject(Process
);
477 NtSetInformationProcess(IN HANDLE ProcessHandle
,
478 IN PROCESSINFOCLASS ProcessInformationClass
,
479 IN PVOID ProcessInformation
,
480 IN ULONG ProcessInformationLength
)
483 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
486 HANDLE PortHandle
= NULL
;
487 HANDLE TokenHandle
= NULL
;
488 PROCESS_SESSION_INFORMATION SessionInfo
= {0};
492 /* Verify Information Class validity */
493 Status
= DefaultSetInfoBufferCheck(ProcessInformationClass
,
495 RTL_NUMBER_OF(PsProcessInfoClass
),
497 ProcessInformationLength
,
499 if (!NT_SUCCESS(Status
)) return Status
;
501 /* Check what class this is */
502 Access
= PROCESS_SET_INFORMATION
;
503 if (ProcessInformationClass
== ProcessSessionInformation
)
505 /* Setting the Session ID needs a special mask */
506 Access
|= PROCESS_SET_SESSIONID
;
508 else if (ProcessInformationClass
== ProcessExceptionPort
)
510 /* Setting the exception port needs a special mask */
511 Access
|= PROCESS_SUSPEND_RESUME
;
514 /* Reference the process */
515 Status
= ObReferenceObjectByHandle(ProcessHandle
,
521 if (!NT_SUCCESS(Status
)) return Status
;
523 /* Check what kind of information class this is */
524 switch (ProcessInformationClass
)
526 /* Quotas and priorities: not implemented */
527 case ProcessQuotaLimits
:
528 case ProcessBasePriority
:
529 case ProcessRaisePriority
:
530 Status
= STATUS_NOT_IMPLEMENTED
;
533 /* Error/Exception Port */
534 case ProcessExceptionPort
:
536 /* Use SEH for capture */
539 /* Capture the handle */
540 PortHandle
= *(PHANDLE
)ProcessInformation
;
544 /* Get the exception code */
545 Status
= _SEH_GetExceptionCode();
548 if (!NT_SUCCESS(Status
)) break;
550 /* Get the LPC Port */
551 Status
= ObReferenceObjectByHandle(PortHandle
,
555 (PVOID
)&ExceptionPort
,
557 if (!NT_SUCCESS(Status
)) break;
559 /* Change the pointer */
560 if (InterlockedCompareExchangePointer(&Process
->ExceptionPort
,
564 /* We already had one, fail */
565 ObDereferenceObject(ExceptionPort
);
566 Status
= STATUS_PORT_ALREADY_SET
;
571 case ProcessAccessToken
:
573 /* Use SEH for capture */
576 /* Save the token handle */
577 TokenHandle
= ((PPROCESS_ACCESS_TOKEN
)ProcessInformation
)->
582 /* Get the exception code */
583 Status
= _SEH_GetExceptionCode();
586 if (!NT_SUCCESS(Status
)) break;
588 /* Assign the actual token */
589 Status
= PspSetPrimaryToken(Process
, TokenHandle
, NULL
);
592 /* Hard error processing */
593 case ProcessDefaultHardErrorMode
:
595 /* Enter SEH for direct buffer read */
598 /* Update the current mode abd return the previous one */
599 InterlockedExchange((LONG
*)&Process
->DefaultHardErrorProcessing
,
600 *(PLONG
)ProcessInformation
);
604 /* Get exception code */
605 Status
= _SEH_GetExceptionCode();
611 case ProcessSessionInformation
:
613 /* Enter SEH for capture */
616 /* Capture the caller's buffer */
617 SessionInfo
= *(PPROCESS_SESSION_INFORMATION
)ProcessInformation
;
621 /* Get the exception code */
622 Status
= _SEH_GetExceptionCode();
625 if (!NT_SUCCESS(Status
)) break;
627 /* Setting the session id requires the SeTcbPrivilege */
628 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
630 /* Can't set the session ID, bail out. */
631 Status
= STATUS_PRIVILEGE_NOT_HELD
;
635 /* FIXME - update the session id for the process token */
636 //Status = PsLockProcess(Process, FALSE);
637 if (!NT_SUCCESS(Status
)) break;
639 /* Write the session ID in the EPROCESS */
640 Process
->Session
= SessionInfo
.SessionId
;
642 /* Check if the process also has a PEB */
646 * Attach to the process to make sure we're in the right
647 * context to access the PEB structure
649 KeAttachProcess(&Process
->Pcb
);
651 /* Enter SEH for write to user-mode PEB */
654 /* Write the session ID */
655 Process
->Peb
->SessionId
= SessionInfo
.SessionId
;
659 /* Get exception code */
660 Status
= _SEH_GetExceptionCode();
664 /* Detach from the process */
668 /* Unlock the process */
669 //PsUnlockProcess(Process);
672 /* Priority class: HACK! */
673 case ProcessPriorityClass
:
676 /* We currently don't implement any of these */
677 case ProcessLdtInformation
:
679 case ProcessIoPortHandlers
:
680 case ProcessWorkingSetWatch
:
681 case ProcessUserModeIOPL
:
682 case ProcessEnableAlignmentFaultFixup
:
683 case ProcessAffinityMask
:
684 Status
= STATUS_NOT_IMPLEMENTED
;
687 /* Supposedly these are invalid...!? verify! */
688 case ProcessBasicInformation
:
689 case ProcessIoCounters
:
691 case ProcessPooledUsageAndLimits
:
692 case ProcessWx86Information
:
693 case ProcessHandleCount
:
694 case ProcessWow64Information
:
695 case ProcessDebugPort
:
697 Status
= STATUS_INVALID_INFO_CLASS
;
700 /* Dereference and return status */
701 ObDereferenceObject(Process
);
710 NtSetInformationThread(IN HANDLE ThreadHandle
,
711 IN THREADINFOCLASS ThreadInformationClass
,
712 IN PVOID ThreadInformation
,
713 IN ULONG ThreadInformationLength
)
717 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
719 HANDLE TokenHandle
= NULL
;
720 KPRIORITY Priority
= 0;
721 KAFFINITY Affinity
= 0;
722 PVOID Address
= NULL
;
726 /* Verify Information Class validity */
727 Status
= DefaultSetInfoBufferCheck(ThreadInformationClass
,
729 RTL_NUMBER_OF(PsThreadInfoClass
),
731 ThreadInformationLength
,
733 if (!NT_SUCCESS(Status
)) return Status
;
735 /* Check what class this is */
736 Access
= THREAD_SET_INFORMATION
;
737 if (ThreadInformationClass
== ThreadImpersonationToken
)
739 /* Setting the impersonation token needs a special mask */
740 Access
= THREAD_SET_THREAD_TOKEN
;
743 /* Reference the process */
744 Status
= ObReferenceObjectByHandle(ThreadHandle
,
750 if (!NT_SUCCESS(Status
)) return Status
;
752 /* Check what kind of information class this is */
753 switch (ThreadInformationClass
)
755 /* Thread priority */
758 /* Use SEH for capture */
761 /* Get the priority */
762 Priority
= *(PLONG
)ThreadInformation
;
766 /* Get the exception code */
767 Status
= _SEH_GetExceptionCode();
770 if (!NT_SUCCESS(Status
)) break;
772 /* Set the priority */
773 KeSetPriorityThread(&Thread
->Tcb
, Priority
);
776 case ThreadBasePriority
:
778 /* Use SEH for capture */
781 /* Get the priority */
782 Priority
= *(PLONG
)ThreadInformation
;
786 /* Get the exception code */
787 Status
= _SEH_GetExceptionCode();
790 if (!NT_SUCCESS(Status
)) break;
792 /* Set the base priority */
793 KeSetBasePriorityThread(&Thread
->Tcb
, Priority
);
796 case ThreadAffinityMask
:
798 /* Use SEH for capture */
801 /* Get the priority */
802 Affinity
= *(PULONG_PTR
)ThreadInformation
;
806 /* Get the exception code */
807 Status
= _SEH_GetExceptionCode();
810 if (!NT_SUCCESS(Status
)) break;
812 /* Get the process */
813 Process
= Thread
->ThreadsProcess
;
815 /* Set the affinity */
816 KeSetAffinityThread(&Thread
->Tcb
, Affinity
& Process
->Pcb
.Affinity
);
819 case ThreadImpersonationToken
:
821 /* Use SEH for capture */
824 /* Save the token handle */
825 TokenHandle
= *(PHANDLE
)ThreadInformation
;
829 /* Get the exception code */
830 Status
= _SEH_GetExceptionCode();
833 if (!NT_SUCCESS(Status
)) break;
835 /* Assign the actual token */
836 Status
= PsAssignImpersonationToken(Thread
, TokenHandle
);
839 case ThreadQuerySetWin32StartAddress
:
841 /* Use SEH for capture */
844 /* Get the priority */
845 Address
= *(PVOID
*)ThreadInformation
;
849 /* Get the exception code */
850 Status
= _SEH_GetExceptionCode();
853 if (!NT_SUCCESS(Status
)) break;
855 /* Set the address */
856 Thread
->Win32StartAddress
= Address
;
860 /* We don't implement it yet */
861 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
862 Status
= STATUS_NOT_IMPLEMENTED
;
865 /* Dereference and return status */
866 ObDereferenceObject(Thread
);
875 NtQueryInformationThread(IN HANDLE ThreadHandle
,
876 IN THREADINFOCLASS ThreadInformationClass
,
877 OUT PVOID ThreadInformation
,
878 IN ULONG ThreadInformationLength
,
879 OUT PULONG ReturnLength OPTIONAL
)
882 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
883 NTSTATUS Status
= STATUS_SUCCESS
;
886 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
=
887 (PTHREAD_BASIC_INFORMATION
)ThreadInformation
;
888 PKERNEL_USER_TIMES ThreadTime
= (PKERNEL_USER_TIMES
)ThreadInformation
;
892 /* Verify Information Class validity */
893 Status
= DefaultQueryInfoBufferCheck(ThreadInformationClass
,
895 RTL_NUMBER_OF(PsThreadInfoClass
),
897 ThreadInformationLength
,
900 if (!NT_SUCCESS(Status
)) return Status
;
902 /* Check what class this is */
903 Access
= THREAD_QUERY_INFORMATION
;
905 /* Reference the process */
906 Status
= ObReferenceObjectByHandle(ThreadHandle
,
912 if (!NT_SUCCESS(Status
)) return Status
;
914 /* Check what kind of information class this is */
915 switch (ThreadInformationClass
)
917 /* Basic thread information */
918 case ThreadBasicInformation
:
920 /* Protect writes with SEH */
923 /* Write all the information from the ETHREAD/KTHREAD */
924 ThreadBasicInfo
->ExitStatus
= Thread
->ExitStatus
;
925 ThreadBasicInfo
->TebBaseAddress
= (PVOID
)Thread
->Tcb
.Teb
;
926 ThreadBasicInfo
->ClientId
= Thread
->Cid
;
927 ThreadBasicInfo
->AffinityMask
= Thread
->Tcb
.Affinity
;
928 ThreadBasicInfo
->Priority
= Thread
->Tcb
.Priority
;
929 ThreadBasicInfo
->BasePriority
= KeQueryBasePriorityThread(&Thread
->Tcb
);
931 /* Set return length */
932 Length
= sizeof(THREAD_BASIC_INFORMATION
);
936 /* Get exception code */
937 Status
= _SEH_GetExceptionCode();
942 /* Thread time information */
945 /* Protect writes with SEH */
948 /* Copy time information from ETHREAD/KTHREAD */
949 ThreadTime
->KernelTime
.QuadPart
= Thread
->Tcb
.KernelTime
*
951 ThreadTime
->UserTime
.QuadPart
= Thread
->Tcb
.UserTime
*
953 ThreadTime
->CreateTime
= Thread
->CreateTime
;
954 ThreadTime
->ExitTime
= Thread
->ExitTime
;
956 /* Set the return length */
957 Length
= sizeof(KERNEL_USER_TIMES
);
961 /* Get exception code */
962 Status
= _SEH_GetExceptionCode();
967 case ThreadQuerySetWin32StartAddress
:
969 /* Protect write with SEH */
972 /* Return the Win32 Start Address */
973 *(PVOID
*)ThreadInformation
= Thread
->Win32StartAddress
;
975 /* Set the return length*/
976 Length
= sizeof(PVOID
);
980 /* Get exception code */
981 Status
= _SEH_GetExceptionCode();
986 case ThreadPerformanceCount
:
988 /* Protect write with SEH */
992 (*(PLARGE_INTEGER
)ThreadInformation
).QuadPart
= 0;
994 /* Set the return length*/
995 Length
= sizeof(LARGE_INTEGER
);
999 /* Get exception code */
1000 Status
= _SEH_GetExceptionCode();
1005 case ThreadAmILastThread
:
1007 /* Protect write with SEH */
1010 /* Return whether or not we are the last thread */
1011 *(PULONG
)ThreadInformation
= ((Thread
->ThreadsProcess
->
1012 ThreadListHead
.Flink
->Flink
==
1013 &Thread
->ThreadsProcess
->
1017 /* Set the return length*/
1018 Length
= sizeof(ULONG
);
1022 /* Get exception code */
1023 Status
= _SEH_GetExceptionCode();
1028 case ThreadIsIoPending
:
1030 /* Raise the IRQL to protect the IRP list */
1031 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1033 /* Protect write with SEH */
1036 /* Check if the IRP list is empty or not */
1037 *(PULONG
)ThreadInformation
= !IsListEmpty(&Thread
->IrpList
);
1039 /* Set the return length*/
1040 Length
= sizeof(ULONG
);
1044 /* Get exception code */
1045 Status
= _SEH_GetExceptionCode();
1049 /* Lower IRQL back */
1050 KeLowerIrql(OldIrql
);
1056 /* Not yet implemented */
1057 DPRINT1("Not implemented: %lx\n", ThreadInformationClass
);
1058 Status
= STATUS_NOT_IMPLEMENTED
;
1061 /* Protect write with SEH */
1064 /* Check if caller wanted return length */
1065 if (ReturnLength
) *ReturnLength
= Length
;
1069 /* Get exception code */
1070 Status
= _SEH_GetExceptionCode();
1074 /* Dereference the thread, and return */
1075 ObDereferenceObject(Thread
);