- Optimized the dispatcher lock. It is now gone on non-SMP systems and IRQL is raised...
[reactos.git] / reactos / ntoskrnl / ps / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Set/Query Process/Thread Information APIs
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File
8 * David Welch
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
20 {
21 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */
22 ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */
23 ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */
24 ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */
25 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */
26 ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */
27 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */
28 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY ), /* ProcessDebugPort */
29 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */
30 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */
31 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */
32 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */
33 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */
34 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */
35 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */
36 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */
37 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */
38 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */
39 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */
40 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */
41 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */
42 ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */
43 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */
44
45 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */
46 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
47 /*Q*/ sizeof(ULONG),
48 /*S*/ sizeof(ULONG),
49 ICIF_QUERY | ICIF_SET ),
50
51 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */
52 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */
53 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */
54 ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */
55
56 /* FIXME */
57 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
58 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
59 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
60 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
61 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
62 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
63 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
64 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
65
66 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */
67 };
68
69 /*
70 * FIXME:
71 * Remove the Implemented value if all functions are implemented.
72 */
73
74 static const struct
75 {
76 BOOLEAN Implemented;
77 ULONG Size;
78 } QueryInformationData[MaxThreadInfoClass + 1] =
79 {
80 {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation
81 {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes
82 {TRUE, 0}, // ThreadPriority
83 {TRUE, 0}, // ThreadBasePriority
84 {TRUE, 0}, // ThreadAffinityMask
85 {TRUE, 0}, // ThreadImpersonationToken
86 {FALSE, 0}, // ThreadDescriptorTableEntry
87 {TRUE, 0}, // ThreadEnableAlignmentFaultFixup
88 {TRUE, 0}, // ThreadEventPair
89 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
90 {TRUE, 0}, // ThreadZeroTlsCell
91 {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount
92 {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread
93 {TRUE, 0}, // ThreadIdealProcessor
94 {FALSE, 0}, // ThreadPriorityBoost
95 {TRUE, 0}, // ThreadSetTlsArrayAddress
96 {FALSE, 0}, // ThreadIsIoPending
97 {TRUE, 0} // ThreadHideFromDebugger
98 };
99
100 static const struct
101 {
102 BOOLEAN Implemented;
103 ULONG Size;
104 } SetInformationData[MaxThreadInfoClass + 1] =
105 {
106 {TRUE, 0}, // ThreadBasicInformation
107 {TRUE, 0}, // ThreadTimes
108 {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
109 {TRUE, sizeof(LONG)}, // ThreadBasePriority
110 {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
111 {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken
112 {TRUE, 0}, // ThreadDescriptorTableEntry
113 {FALSE, 0}, // ThreadEnableAlignmentFaultFixup
114 {FALSE, 0}, // ThreadEventPair
115 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
116 {FALSE, 0}, // ThreadZeroTlsCell
117 {TRUE, 0}, // ThreadPerformanceCount
118 {TRUE, 0}, // ThreadAmILastThread
119 {FALSE, 0}, // ThreadIdealProcessor
120 {FALSE, 0}, // ThreadPriorityBoost
121 {FALSE, 0}, // ThreadSetTlsArrayAddress
122 {TRUE, 0}, // ThreadIsIoPending
123 {FALSE, 0} // ThreadHideFromDebugger
124 };
125
126 /* FUNCTIONS *****************************************************************/
127
128 /*
129 * @unimplemented
130 */
131 NTSTATUS STDCALL
132 NtQueryInformationProcess(IN HANDLE ProcessHandle,
133 IN PROCESSINFOCLASS ProcessInformationClass,
134 OUT PVOID ProcessInformation,
135 IN ULONG ProcessInformationLength,
136 OUT PULONG ReturnLength OPTIONAL)
137 {
138 PEPROCESS Process;
139 KPROCESSOR_MODE PreviousMode;
140 NTSTATUS Status = STATUS_SUCCESS;
141
142 PAGED_CODE();
143
144 PreviousMode = ExGetPreviousMode();
145
146 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
147 PsProcessInfoClass,
148 sizeof(PsProcessInfoClass) / sizeof(PsProcessInfoClass[0]),
149 ProcessInformation,
150 ProcessInformationLength,
151 ReturnLength,
152 PreviousMode);
153 if(!NT_SUCCESS(Status))
154 {
155 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
156 return Status;
157 }
158
159 if(ProcessInformationClass != ProcessCookie)
160 {
161 Status = ObReferenceObjectByHandle(ProcessHandle,
162 PROCESS_QUERY_INFORMATION,
163 PsProcessType,
164 PreviousMode,
165 (PVOID*)&Process,
166 NULL);
167 if (!NT_SUCCESS(Status))
168 {
169 return(Status);
170 }
171 }
172 else if(ProcessHandle != NtCurrentProcess())
173 {
174 /* retreiving the process cookie is only allowed for the calling process
175 itself! XP only allowes NtCurrentProcess() as process handles even if a
176 real handle actually represents the current process. */
177 return STATUS_INVALID_PARAMETER;
178 }
179
180 switch (ProcessInformationClass)
181 {
182 case ProcessBasicInformation:
183 {
184 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
185 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
186
187 _SEH_TRY
188 {
189 ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
190 ProcessBasicInformationP->PebBaseAddress = Process->Peb;
191 ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
192 ProcessBasicInformationP->UniqueProcessId =
193 (ULONG)Process->UniqueProcessId;
194 ProcessBasicInformationP->InheritedFromUniqueProcessId =
195 (ULONG)Process->InheritedFromUniqueProcessId;
196 ProcessBasicInformationP->BasePriority =
197 Process->Pcb.BasePriority;
198
199 if (ReturnLength)
200 {
201 *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
202 }
203 }
204 _SEH_HANDLE
205 {
206 Status = _SEH_GetExceptionCode();
207 }
208 _SEH_END;
209 break;
210 }
211
212 case ProcessQuotaLimits:
213 case ProcessIoCounters:
214 Status = STATUS_NOT_IMPLEMENTED;
215 break;
216
217 case ProcessTimes:
218 {
219 PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
220 _SEH_TRY
221 {
222 ProcessTimeP->CreateTime = Process->CreateTime;
223 ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
224 ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
225 ProcessTimeP->ExitTime = Process->ExitTime;
226
227 if (ReturnLength)
228 {
229 *ReturnLength = sizeof(KERNEL_USER_TIMES);
230 }
231 }
232 _SEH_HANDLE
233 {
234 Status = _SEH_GetExceptionCode();
235 }
236 _SEH_END;
237 break;
238 }
239
240 case ProcessDebugPort:
241 {
242 _SEH_TRY
243 {
244 *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
245 if (ReturnLength)
246 {
247 *ReturnLength = sizeof(HANDLE);
248 }
249 }
250 _SEH_HANDLE
251 {
252 Status = _SEH_GetExceptionCode();
253 }
254 _SEH_END;
255 break;
256 }
257
258 case ProcessLdtInformation:
259 case ProcessWorkingSetWatch:
260 case ProcessWx86Information:
261 Status = STATUS_NOT_IMPLEMENTED;
262 break;
263
264 case ProcessHandleCount:
265 {
266 ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
267
268 _SEH_TRY
269 {
270 *(PULONG)ProcessInformation = HandleCount;
271 if (ReturnLength)
272 {
273 *ReturnLength = sizeof(ULONG);
274 }
275 }
276 _SEH_HANDLE
277 {
278 Status = _SEH_GetExceptionCode();
279 }
280 _SEH_END;
281 break;
282 }
283
284 case ProcessSessionInformation:
285 {
286 PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
287
288 _SEH_TRY
289 {
290 SessionInfo->SessionId = Process->Session;
291 if (ReturnLength)
292 {
293 *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
294 }
295 }
296 _SEH_HANDLE
297 {
298 Status = _SEH_GetExceptionCode();
299 }
300 _SEH_END;
301 break;
302 }
303
304 case ProcessWow64Information:
305 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
306 Status = STATUS_NOT_IMPLEMENTED;
307 break;
308
309 case ProcessVmCounters:
310 {
311 PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
312
313 _SEH_TRY
314 {
315 pOut->PeakVirtualSize = Process->PeakVirtualSize;
316 /*
317 * Here we should probably use VirtualSize.LowPart, but due to
318 * incompatibilities in current headers (no unnamed union),
319 * I opted for cast.
320 */
321 pOut->VirtualSize = (ULONG)Process->VirtualSize;
322 pOut->PageFaultCount = Process->Vm.PageFaultCount;
323 pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
324 pOut->WorkingSetSize = Process->Vm.WorkingSetSize;
325 pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0]; // TODO: Verify!
326 pOut->QuotaPagedPoolUsage = Process->QuotaUsage[0]; // TODO: Verify!
327 pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; // TODO: Verify!
328 pOut->QuotaNonPagedPoolUsage = Process->QuotaUsage[1]; // TODO: Verify!
329 pOut->PagefileUsage = Process->QuotaUsage[2];
330 pOut->PeakPagefileUsage = Process->QuotaPeak[2];
331
332 if (ReturnLength)
333 {
334 *ReturnLength = sizeof(VM_COUNTERS);
335 }
336 }
337 _SEH_HANDLE
338 {
339 Status = _SEH_GetExceptionCode();
340 }
341 _SEH_END;
342 break;
343 }
344
345 case ProcessDefaultHardErrorMode:
346 {
347 PULONG HardErrMode = (PULONG)ProcessInformation;
348 _SEH_TRY
349 {
350 *HardErrMode = Process->DefaultHardErrorProcessing;
351 if (ReturnLength)
352 {
353 *ReturnLength = sizeof(ULONG);
354 }
355 }
356 _SEH_HANDLE
357 {
358 Status = _SEH_GetExceptionCode();
359 }
360 _SEH_END;
361 break;
362 }
363
364 case ProcessPriorityBoost:
365 {
366 PULONG BoostEnabled = (PULONG)ProcessInformation;
367
368 _SEH_TRY
369 {
370 *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
371
372 if (ReturnLength)
373 {
374 *ReturnLength = sizeof(ULONG);
375 }
376 }
377 _SEH_HANDLE
378 {
379 Status = _SEH_GetExceptionCode();
380 }
381 _SEH_END;
382 break;
383 }
384
385 case ProcessDeviceMap:
386 {
387 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
388
389 ObQueryDeviceMapInformation(Process, &DeviceMap);
390
391 _SEH_TRY
392 {
393 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
394 if (ReturnLength)
395 {
396 *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
397 }
398 }
399 _SEH_HANDLE
400 {
401 Status = _SEH_GetExceptionCode();
402 }
403 _SEH_END;
404 break;
405 }
406
407 case ProcessPriorityClass:
408 {
409 PUSHORT Priority = (PUSHORT)ProcessInformation;
410
411 _SEH_TRY
412 {
413 *Priority = Process->PriorityClass;
414
415 if (ReturnLength)
416 {
417 *ReturnLength = sizeof(USHORT);
418 }
419 }
420 _SEH_HANDLE
421 {
422 Status = _SEH_GetExceptionCode();
423 }
424 _SEH_END;
425 break;
426 }
427
428 case ProcessImageFileName:
429 {
430 /*
431 * We DO NOT return the file name stored in the EPROCESS structure.
432 * Propably if we can't find a PEB or ProcessParameters structure for the
433 * process!
434 */
435 if(Process->Peb != NULL)
436 {
437 PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL;
438 UNICODE_STRING LocalDest;
439 BOOLEAN Attached;
440 ULONG ImagePathLen = 0;
441 PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
442
443 /* we need to attach to the process to make sure we're in the right context! */
444 Attached = Process != PsGetCurrentProcess();
445
446 if(Attached)
447 KeAttachProcess(&Process->Pcb);
448
449 _SEH_TRY
450 {
451 ProcParams = Process->Peb->ProcessParameters;
452 ImagePathLen = ProcParams->ImagePathName.Length;
453 }
454 _SEH_HANDLE
455 {
456 Status = _SEH_GetExceptionCode();
457 }
458 _SEH_END;
459
460 if(NT_SUCCESS(Status))
461 {
462 if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
463 {
464 Status = STATUS_INFO_LENGTH_MISMATCH;
465 }
466 else
467 {
468 PWSTR StrSource = NULL;
469
470 RtlZeroMemory(&LocalDest, sizeof(LocalDest));
471
472 /* create a DstPath structure on the stack */
473 _SEH_TRY
474 {
475 LocalDest.Length = ImagePathLen;
476 LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR);
477 LocalDest.Buffer = (PWSTR)(DstPath + 1);
478
479 /* save a copy of the pointer to the source buffer */
480 StrSource = ProcParams->ImagePathName.Buffer;
481 }
482 _SEH_HANDLE
483 {
484 Status = _SEH_GetExceptionCode();
485 }
486 _SEH_END;
487
488 if(NT_SUCCESS(Status))
489 {
490 /* now, let's allocate some anonymous memory to copy the string to.
491 we can't just copy it to the buffer the caller pointed as it might
492 be user memory in another context */
493 PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR));
494 if(PathCopy != NULL)
495 {
496 /* make a copy of the buffer to the temporary buffer */
497 _SEH_TRY
498 {
499 RtlCopyMemory(PathCopy, StrSource, LocalDest.Length);
500 PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0';
501 }
502 _SEH_HANDLE
503 {
504 Status = _SEH_GetExceptionCode();
505 }
506 _SEH_END;
507
508 /* detach from the process */
509 if(Attached)
510 KeDetachProcess();
511
512 /* only copy the string back to the caller if we were able to
513 copy it into the temporary buffer! */
514 if(NT_SUCCESS(Status))
515 {
516 /* now let's copy the buffer back to the caller */
517 _SEH_TRY
518 {
519 *DstPath = LocalDest;
520 RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR));
521 if (ReturnLength)
522 {
523 *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR);
524 }
525 }
526 _SEH_HANDLE
527 {
528 Status = _SEH_GetExceptionCode();
529 }
530 _SEH_END;
531 }
532
533 /* we're done with the copy operation, free the temporary kernel buffer */
534 ExFreePool(PathCopy);
535
536 /* we need to bail because we're already detached from the process */
537 break;
538 }
539 else
540 {
541 Status = STATUS_INSUFFICIENT_RESOURCES;
542 }
543 }
544 }
545 }
546
547 /* don't forget to detach from the process!!! */
548 if(Attached)
549 KeDetachProcess();
550 }
551 else
552 {
553 /* FIXME - what to do here? */
554 Status = STATUS_UNSUCCESSFUL;
555 }
556 break;
557 }
558
559 case ProcessCookie:
560 {
561 ULONG Cookie;
562
563 /* receive the process cookie, this is only allowed for the current
564 process! */
565
566 Process = PsGetCurrentProcess();
567
568 Cookie = Process->Cookie;
569 if(Cookie == 0)
570 {
571 LARGE_INTEGER SystemTime;
572 ULONG NewCookie;
573 PKPRCB Prcb;
574
575 /* generate a new cookie */
576
577 KeQuerySystemTime(&SystemTime);
578
579 Prcb = KeGetCurrentPrcb();
580
581 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
582 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
583
584 /* try to set the new cookie, return the current one if another thread
585 set it in the meanwhile */
586 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
587 NewCookie,
588 Cookie);
589 if(Cookie == 0)
590 {
591 /* successfully set the cookie */
592 Cookie = NewCookie;
593 }
594 }
595
596 _SEH_TRY
597 {
598 *(PULONG)ProcessInformation = Cookie;
599 if (ReturnLength)
600 {
601 *ReturnLength = sizeof(ULONG);
602 }
603 }
604 _SEH_HANDLE
605 {
606 Status = _SEH_GetExceptionCode();
607 }
608 _SEH_END;
609
610 break;
611 }
612
613 /*
614 * Note: The following 10 information classes are verified to not be
615 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
616 */
617 case ProcessBasePriority:
618 case ProcessRaisePriority:
619 case ProcessExceptionPort:
620 case ProcessAccessToken:
621 case ProcessLdtSize:
622 case ProcessIoPortHandlers:
623 case ProcessUserModeIOPL:
624 case ProcessEnableAlignmentFaultFixup:
625 case ProcessAffinityMask:
626 case ProcessForegroundInformation:
627 default:
628 Status = STATUS_INVALID_INFO_CLASS;
629 }
630
631 if(ProcessInformationClass != ProcessCookie)
632 {
633 ObDereferenceObject(Process);
634 }
635
636 return Status;
637 }
638
639 /*
640 * @unimplemented
641 */
642 NTSTATUS STDCALL
643 NtSetInformationProcess(IN HANDLE ProcessHandle,
644 IN PROCESSINFOCLASS ProcessInformationClass,
645 IN PVOID ProcessInformation,
646 IN ULONG ProcessInformationLength)
647 {
648 PEPROCESS Process;
649 KPROCESSOR_MODE PreviousMode;
650 ACCESS_MASK Access;
651 NTSTATUS Status = STATUS_SUCCESS;
652
653 PAGED_CODE();
654
655 PreviousMode = ExGetPreviousMode();
656
657 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
658 PsProcessInfoClass,
659 sizeof(PsProcessInfoClass) / sizeof(PsProcessInfoClass[0]),
660 ProcessInformation,
661 ProcessInformationLength,
662 PreviousMode);
663 if(!NT_SUCCESS(Status))
664 {
665 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
666 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
667 return Status;
668 }
669
670 switch(ProcessInformationClass)
671 {
672 case ProcessSessionInformation:
673 Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
674 break;
675 case ProcessExceptionPort:
676 Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
677 break;
678
679 default:
680 Access = PROCESS_SET_INFORMATION;
681 break;
682 }
683
684 Status = ObReferenceObjectByHandle(ProcessHandle,
685 Access,
686 PsProcessType,
687 PreviousMode,
688 (PVOID*)&Process,
689 NULL);
690 if (!NT_SUCCESS(Status))
691 {
692 return(Status);
693 }
694
695 switch (ProcessInformationClass)
696 {
697 case ProcessQuotaLimits:
698 case ProcessBasePriority:
699 case ProcessRaisePriority:
700 Status = STATUS_NOT_IMPLEMENTED;
701 break;
702
703 case ProcessExceptionPort:
704 {
705 HANDLE PortHandle = NULL;
706
707 /* make a safe copy of the buffer on the stack */
708 _SEH_TRY
709 {
710 PortHandle = *(PHANDLE)ProcessInformation;
711 Status = STATUS_SUCCESS;
712 }
713 _SEH_HANDLE
714 {
715 Status = _SEH_GetExceptionCode();
716 }
717 _SEH_END;
718
719 if(NT_SUCCESS(Status))
720 {
721 PEPORT ExceptionPort;
722
723 /* in case we had success reading from the buffer, verify the provided
724 * LPC port handle
725 */
726 Status = ObReferenceObjectByHandle(PortHandle,
727 0,
728 LpcPortObjectType,
729 PreviousMode,
730 (PVOID)&ExceptionPort,
731 NULL);
732 if(NT_SUCCESS(Status))
733 {
734 /* lock the process to be thread-safe! */
735
736 Status = PsLockProcess(Process, FALSE);
737 if(NT_SUCCESS(Status))
738 {
739 /*
740 * according to "NT Native API" documentation, setting the exception
741 * port is only permitted once!
742 */
743 if(Process->ExceptionPort == NULL)
744 {
745 /* keep the reference to the handle! */
746 Process->ExceptionPort = ExceptionPort;
747 Status = STATUS_SUCCESS;
748 }
749 else
750 {
751 ObDereferenceObject(ExceptionPort);
752 Status = STATUS_PORT_ALREADY_SET;
753 }
754 PsUnlockProcess(Process);
755 }
756 else
757 {
758 ObDereferenceObject(ExceptionPort);
759 }
760 }
761 }
762 break;
763 }
764
765 case ProcessAccessToken:
766 {
767 HANDLE TokenHandle = NULL;
768
769 /* make a safe copy of the buffer on the stack */
770 _SEH_TRY
771 {
772 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
773 Status = STATUS_SUCCESS;
774 }
775 _SEH_HANDLE
776 {
777 Status = _SEH_GetExceptionCode();
778 }
779 _SEH_END;
780
781 if(NT_SUCCESS(Status))
782 {
783 /* in case we had success reading from the buffer, perform the actual task */
784 Status = PspAssignPrimaryToken(Process, TokenHandle);
785 }
786 break;
787 }
788
789 case ProcessDefaultHardErrorMode:
790 {
791 _SEH_TRY
792 {
793 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
794 *(PLONG)ProcessInformation);
795 Status = STATUS_SUCCESS;
796 }
797 _SEH_HANDLE
798 {
799 Status = _SEH_GetExceptionCode();
800 }
801 _SEH_END;
802 break;
803 }
804
805 case ProcessSessionInformation:
806 {
807 PROCESS_SESSION_INFORMATION SessionInfo;
808 Status = STATUS_SUCCESS;
809
810 RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
811
812 _SEH_TRY
813 {
814 /* copy the structure to the stack */
815 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
816 }
817 _SEH_HANDLE
818 {
819 Status = _SEH_GetExceptionCode();
820 }
821 _SEH_END;
822
823 if(NT_SUCCESS(Status))
824 {
825 /* we successfully copied the structure to the stack, continue processing */
826
827 /*
828 * setting the session id requires the SeTcbPrivilege!
829 */
830 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
831 PreviousMode))
832 {
833 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
834 /* can't set the session id, bail! */
835 Status = STATUS_PRIVILEGE_NOT_HELD;
836 break;
837 }
838
839 /* FIXME - update the session id for the process token */
840
841 Status = PsLockProcess(Process, FALSE);
842 if(NT_SUCCESS(Status))
843 {
844 Process->Session = SessionInfo.SessionId;
845
846 /* Update the session id in the PEB structure */
847 if(Process->Peb != NULL)
848 {
849 /* we need to attach to the process to make sure we're in the right
850 context to access the PEB structure */
851 KeAttachProcess(&Process->Pcb);
852
853 _SEH_TRY
854 {
855 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
856
857 Status = STATUS_SUCCESS;
858 }
859 _SEH_HANDLE
860 {
861 Status = _SEH_GetExceptionCode();
862 }
863 _SEH_END;
864
865 KeDetachProcess();
866 }
867
868 PsUnlockProcess(Process);
869 }
870 }
871 break;
872 }
873
874 case ProcessPriorityClass:
875 {
876 PROCESS_PRIORITY_CLASS ppc;
877
878 _SEH_TRY
879 {
880 ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
881 }
882 _SEH_HANDLE
883 {
884 Status = _SEH_GetExceptionCode();
885 }
886 _SEH_END;
887
888 if(NT_SUCCESS(Status))
889 {
890 }
891
892 break;
893 }
894
895 case ProcessLdtInformation:
896 case ProcessLdtSize:
897 case ProcessIoPortHandlers:
898 case ProcessWorkingSetWatch:
899 case ProcessUserModeIOPL:
900 case ProcessEnableAlignmentFaultFixup:
901 case ProcessAffinityMask:
902 Status = STATUS_NOT_IMPLEMENTED;
903 break;
904
905 case ProcessBasicInformation:
906 case ProcessIoCounters:
907 case ProcessTimes:
908 case ProcessPooledUsageAndLimits:
909 case ProcessWx86Information:
910 case ProcessHandleCount:
911 case ProcessWow64Information:
912 case ProcessDebugPort:
913 default:
914 Status = STATUS_INVALID_INFO_CLASS;
915 }
916 ObDereferenceObject(Process);
917 return(Status);
918 }
919
920
921 /**********************************************************************
922 * NAME INTERNAL
923 * PiQuerySystemProcessInformation
924 *
925 * DESCRIPTION
926 * Compute the size of a process+thread snapshot as
927 * expected by NtQuerySystemInformation.
928 *
929 * RETURN VALUE
930 * 0 on error; otherwise the size, in bytes of the buffer
931 * required to write a full snapshot.
932 *
933 * NOTE
934 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
935 */
936 NTSTATUS
937 PiQuerySystemProcessInformation(PVOID Buffer,
938 ULONG Size,
939 PULONG ReqSize)
940 {
941 return STATUS_NOT_IMPLEMENTED;
942
943 #if 0
944 PLIST_ENTRY CurrentEntryP;
945 PEPROCESS CurrentP;
946 PLIST_ENTRY CurrentEntryT;
947 PETHREAD CurrentT;
948
949 ULONG RequiredSize = 0L;
950 BOOLEAN SizeOnly = FALSE;
951
952 ULONG SpiSize = 0L;
953
954 PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
955 PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
956 PSYSTEM_THREAD_INFO pInfoT = NULL;
957
958
959 /* Lock the process list. */
960 ExAcquireFastMutex(&PspActiveProcessMutex);
961
962 /*
963 * Scan the process list. Since the
964 * list is circular, the guard is false
965 * after the last process.
966 */
967 for ( CurrentEntryP = PsActiveProcessHead.Flink;
968 (CurrentEntryP != & PsActiveProcessHead);
969 CurrentEntryP = CurrentEntryP->Flink
970 )
971 {
972 /*
973 * Compute how much space is
974 * occupied in the snapshot
975 * by adding this process info.
976 * (at least one thread).
977 */
978 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
979 RequiredSize += SpiSizeCurrent;
980 /*
981 * Do not write process data in the
982 * buffer if it is too small.
983 */
984 if (TRUE == SizeOnly) continue;
985 /*
986 * Check if the buffer can contain
987 * the full snapshot.
988 */
989 if (Size < RequiredSize)
990 {
991 SizeOnly = TRUE;
992 continue;
993 }
994 /*
995 * Get a reference to the
996 * process descriptor we are
997 * handling.
998 */
999 CurrentP = CONTAINING_RECORD(
1000 CurrentEntryP,
1001 EPROCESS,
1002 ProcessListEntry
1003 );
1004 /*
1005 * Write process data in the buffer.
1006 */
1007 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1008 /* PROCESS */
1009 pInfoP->ThreadCount = 0L;
1010 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1011 RtlInitUnicodeString (
1012 & pInfoP->Name,
1013 CurrentP->ImageFileName
1014 );
1015 /* THREAD */
1016 for ( pInfoT = & CurrentP->ThreadSysInfo [0],
1017 CurrentEntryT = CurrentP->ThreadListHead.Flink;
1018
1019 (CurrentEntryT != & CurrentP->ThreadListHead);
1020
1021 pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1022 CurrentEntryT = CurrentEntryT->Flink
1023 )
1024 {
1025 /*
1026 * Recalculate the size of the
1027 * information block.
1028 */
1029 if (0 < pInfoP->ThreadCount)
1030 {
1031 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1032 }
1033 /*
1034 * Do not write thread data in the
1035 * buffer if it is too small.
1036 */
1037 if (TRUE == SizeOnly) continue;
1038 /*
1039 * Check if the buffer can contain
1040 * the full snapshot.
1041 */
1042 if (Size < RequiredSize)
1043 {
1044 SizeOnly = TRUE;
1045 continue;
1046 }
1047 /*
1048 * Get a reference to the
1049 * thread descriptor we are
1050 * handling.
1051 */
1052 CurrentT = CONTAINING_RECORD(
1053 CurrentEntryT,
1054 KTHREAD,
1055 ThreadListEntry
1056 );
1057 /*
1058 * Write thread data.
1059 */
1060 RtlZeroMemory (
1061 pInfoT,
1062 sizeof (SYSTEM_THREAD_INFORMATION)
1063 );
1064 pInfoT->KernelTime = CurrentT-> ; /* TIME */
1065 pInfoT->UserTime = CurrentT-> ; /* TIME */
1066 pInfoT->CreateTime = CurrentT-> ; /* TIME */
1067 pInfoT->TickCount = CurrentT-> ; /* ULONG */
1068 pInfoT->StartEIP = CurrentT-> ; /* ULONG */
1069 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1070 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
1071 pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */
1072 pInfoT->BasePriority = CurrentT-> ; /* ULONG */
1073 pInfoT->nSwitches = CurrentT-> ; /* ULONG */
1074 pInfoT->State = CurrentT-> ; /* DWORD */
1075 pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */
1076 /*
1077 * Count the number of threads
1078 * this process has.
1079 */
1080 ++ pInfoP->ThreadCount;
1081 }
1082 /*
1083 * Save the size of information
1084 * stored in the buffer for the
1085 * current process.
1086 */
1087 pInfoP->RelativeOffset = SpiSize;
1088 /*
1089 * Save a reference to the last
1090 * valid information block.
1091 */
1092 pInfoPLast = pInfoP;
1093 /*
1094 * Compute the offset of the
1095 * SYSTEM_PROCESS_INFORMATION
1096 * descriptor in the snapshot
1097 * buffer for the next process.
1098 */
1099 (ULONG) pInfoP += SpiSize;
1100 }
1101 /*
1102 * Unlock the process list.
1103 */
1104 ExReleaseFastMutex (
1105 & PspActiveProcessMutex
1106 );
1107 /*
1108 * Return the proper error status code,
1109 * if the buffer was too small.
1110 */
1111 if (TRUE == SizeOnly)
1112 {
1113 if (NULL != RequiredSize)
1114 {
1115 *pRequiredSize = RequiredSize;
1116 }
1117 return STATUS_INFO_LENGTH_MISMATCH;
1118 }
1119 /*
1120 * Mark the end of the snapshot.
1121 */
1122 pInfoP->RelativeOffset = 0L;
1123 /* OK */
1124 return STATUS_SUCCESS;
1125 #endif
1126 }
1127
1128 /*
1129 * @unimplemented
1130 */
1131 NTSTATUS STDCALL
1132 NtSetInformationThread (IN HANDLE ThreadHandle,
1133 IN THREADINFOCLASS ThreadInformationClass,
1134 IN PVOID ThreadInformation,
1135 IN ULONG ThreadInformationLength)
1136 {
1137 PETHREAD Thread;
1138 union
1139 {
1140 KPRIORITY Priority;
1141 LONG Increment;
1142 KAFFINITY Affinity;
1143 HANDLE Handle;
1144 PVOID Address;
1145 }u;
1146 KPROCESSOR_MODE PreviousMode;
1147 NTSTATUS Status = STATUS_SUCCESS;
1148
1149 PAGED_CODE();
1150
1151 PreviousMode = ExGetPreviousMode();
1152
1153 if (ThreadInformationClass <= MaxThreadInfoClass &&
1154 !SetInformationData[ThreadInformationClass].Implemented)
1155 {
1156 return STATUS_NOT_IMPLEMENTED;
1157 }
1158 if (ThreadInformationClass > MaxThreadInfoClass ||
1159 SetInformationData[ThreadInformationClass].Size == 0)
1160 {
1161 return STATUS_INVALID_INFO_CLASS;
1162 }
1163 if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
1164 {
1165 return STATUS_INFO_LENGTH_MISMATCH;
1166 }
1167
1168 if (PreviousMode != KernelMode)
1169 {
1170 _SEH_TRY
1171 {
1172 ProbeForRead(ThreadInformation,
1173 SetInformationData[ThreadInformationClass].Size,
1174 1);
1175 RtlCopyMemory(&u.Priority,
1176 ThreadInformation,
1177 SetInformationData[ThreadInformationClass].Size);
1178 }
1179 _SEH_HANDLE
1180 {
1181 Status = _SEH_GetExceptionCode();
1182 }
1183 _SEH_END;
1184
1185 if (!NT_SUCCESS(Status))
1186 {
1187 return Status;
1188 }
1189 }
1190 else
1191 {
1192 RtlCopyMemory(&u.Priority,
1193 ThreadInformation,
1194 SetInformationData[ThreadInformationClass].Size);
1195 }
1196
1197 /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
1198 /* FIXME: We should also check for certain things before doing the reference */
1199 Status = ObReferenceObjectByHandle (ThreadHandle,
1200 THREAD_SET_INFORMATION,
1201 PsThreadType,
1202 ExGetPreviousMode (),
1203 (PVOID*)&Thread,
1204 NULL);
1205 if (NT_SUCCESS(Status))
1206 {
1207 switch (ThreadInformationClass)
1208 {
1209 case ThreadPriority:
1210 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
1211 {
1212 Status = STATUS_INVALID_PARAMETER;
1213 break;
1214 }
1215 KeSetPriorityThread(&Thread->Tcb, u.Priority);
1216 break;
1217
1218 case ThreadBasePriority:
1219 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
1220 break;
1221
1222 case ThreadAffinityMask:
1223
1224 /* Check if this is valid */
1225 DPRINT1("%lx, %lx\n", Thread->ThreadsProcess->Pcb.Affinity, u.Affinity);
1226 if ((Thread->ThreadsProcess->Pcb.Affinity & u.Affinity) !=
1227 u.Affinity)
1228 {
1229 DPRINT1("Wrong affinity given\n");
1230 Status = STATUS_INVALID_PARAMETER;
1231 }
1232 else
1233 {
1234 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
1235 }
1236 break;
1237
1238 case ThreadImpersonationToken:
1239 Status = PsAssignImpersonationToken (Thread, u.Handle);
1240 break;
1241
1242 case ThreadQuerySetWin32StartAddress:
1243 Thread->Win32StartAddress = u.Address;
1244 break;
1245
1246 default:
1247 /* Shoult never occure if the data table is correct */
1248 KEBUGCHECK(0);
1249 }
1250 ObDereferenceObject (Thread);
1251 }
1252
1253 return Status;
1254 }
1255
1256 /*
1257 * @implemented
1258 */
1259 NTSTATUS STDCALL
1260 NtQueryInformationThread (IN HANDLE ThreadHandle,
1261 IN THREADINFOCLASS ThreadInformationClass,
1262 OUT PVOID ThreadInformation,
1263 IN ULONG ThreadInformationLength,
1264 OUT PULONG ReturnLength OPTIONAL)
1265 {
1266 PETHREAD Thread;
1267 union
1268 {
1269 THREAD_BASIC_INFORMATION TBI;
1270 KERNEL_USER_TIMES TTI;
1271 PVOID Address;
1272 LARGE_INTEGER Count;
1273 BOOLEAN Last;
1274 }u;
1275 KPROCESSOR_MODE PreviousMode;
1276 NTSTATUS Status = STATUS_SUCCESS;
1277
1278 PAGED_CODE();
1279
1280 PreviousMode = ExGetPreviousMode();
1281
1282 if (ThreadInformationClass <= MaxThreadInfoClass &&
1283 !QueryInformationData[ThreadInformationClass].Implemented)
1284 {
1285 return STATUS_NOT_IMPLEMENTED;
1286 }
1287 if (ThreadInformationClass > MaxThreadInfoClass ||
1288 QueryInformationData[ThreadInformationClass].Size == 0)
1289 {
1290 return STATUS_INVALID_INFO_CLASS;
1291 }
1292 if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
1293 {
1294 return STATUS_INFO_LENGTH_MISMATCH;
1295 }
1296
1297 if (PreviousMode != KernelMode)
1298 {
1299 _SEH_TRY
1300 {
1301 ProbeForWrite(ThreadInformation,
1302 QueryInformationData[ThreadInformationClass].Size,
1303 1);
1304 if (ReturnLength != NULL)
1305 {
1306 ProbeForWriteUlong(ReturnLength);
1307 }
1308 }
1309 _SEH_HANDLE
1310 {
1311 Status = _SEH_GetExceptionCode();
1312 }
1313 _SEH_END;
1314
1315 if (!NT_SUCCESS(Status))
1316 {
1317 return Status;
1318 }
1319 }
1320
1321 Status = ObReferenceObjectByHandle(ThreadHandle,
1322 THREAD_QUERY_INFORMATION,
1323 PsThreadType,
1324 ExGetPreviousMode(),
1325 (PVOID*)&Thread,
1326 NULL);
1327 if (!NT_SUCCESS(Status))
1328 {
1329 return Status;
1330 }
1331
1332 switch (ThreadInformationClass)
1333 {
1334 case ThreadBasicInformation:
1335 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1336 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1337 * 0. So do the conversion here:
1338 * -Gunnar */
1339 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
1340 u.TBI.TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1341 u.TBI.ClientId = Thread->Cid;
1342 u.TBI.AffinityMask = Thread->Tcb.Affinity;
1343 u.TBI.Priority = Thread->Tcb.Priority;
1344 u.TBI.BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1345 break;
1346
1347 case ThreadTimes:
1348 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
1349 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
1350 u.TTI.CreateTime = Thread->CreateTime;
1351 /*This works*/
1352 u.TTI.ExitTime = Thread->ExitTime;
1353 break;
1354
1355 case ThreadQuerySetWin32StartAddress:
1356 u.Address = Thread->Win32StartAddress;
1357 break;
1358
1359 case ThreadPerformanceCount:
1360 /* Nebbett says this class is always zero */
1361 u.Count.QuadPart = 0;
1362 break;
1363
1364 case ThreadAmILastThread:
1365 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
1366 &Thread->ThreadsProcess->ThreadListHead)
1367 {
1368 u.Last = TRUE;
1369 }
1370 else
1371 {
1372 u.Last = FALSE;
1373 }
1374 break;
1375 default:
1376 /* Shoult never occure if the data table is correct */
1377 KEBUGCHECK(0);
1378 }
1379
1380 if (PreviousMode != KernelMode)
1381 {
1382 _SEH_TRY
1383 {
1384 if (QueryInformationData[ThreadInformationClass].Size)
1385 {
1386 RtlCopyMemory(ThreadInformation,
1387 &u.TBI,
1388 QueryInformationData[ThreadInformationClass].Size);
1389 }
1390 if (ReturnLength != NULL)
1391 {
1392 *ReturnLength = QueryInformationData[ThreadInformationClass].Size;
1393 }
1394 }
1395 _SEH_HANDLE
1396 {
1397 Status = _SEH_GetExceptionCode();
1398 }
1399 _SEH_END;
1400 }
1401 else
1402 {
1403 if (QueryInformationData[ThreadInformationClass].Size)
1404 {
1405 RtlCopyMemory(ThreadInformation,
1406 &u.TBI,
1407 QueryInformationData[ThreadInformationClass].Size);
1408 }
1409
1410 if (ReturnLength != NULL)
1411 {
1412 *ReturnLength = QueryInformationData[ThreadInformationClass].Size;
1413 }
1414 }
1415
1416 ObDereferenceObject(Thread);
1417 return(Status);
1418 }
1419 /* EOF */