Sync trunk r40500
[reactos.git] / reactos / ntoskrnl / ps / query.c
1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
18
19 /* Debugging Level */
20 ULONG PspTraceLevel = 0;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 PsReferenceProcessFilePointer(IN PEPROCESS Process,
27 OUT PFILE_OBJECT *FileObject)
28 {
29 PSECTION Section;
30 PAGED_CODE();
31
32 /* Lock the process */
33 ExAcquireRundownProtection(&Process->RundownProtect);
34
35 /* Get the section */
36 Section = Process->SectionObject;
37 if (Section)
38 {
39 /* Get the file object and reference it */
40 *FileObject = MmGetFileObjectForSection((PVOID)Section);
41 ObReferenceObject(*FileObject);
42 }
43
44 /* Release the protection */
45 ExReleaseRundownProtection(&Process->RundownProtect);
46
47 /* Return status */
48 return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
49 }
50
51 /* PUBLIC FUNCTIONS **********************************************************/
52
53 /*
54 * @implemented
55 */
56 NTSTATUS
57 NTAPI
58 NtQueryInformationProcess(IN HANDLE ProcessHandle,
59 IN PROCESSINFOCLASS ProcessInformationClass,
60 OUT PVOID ProcessInformation,
61 IN ULONG ProcessInformationLength,
62 OUT PULONG ReturnLength OPTIONAL)
63 {
64 PEPROCESS Process;
65 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
66 NTSTATUS Status = STATUS_SUCCESS;
67 ULONG Length = 0;
68 PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
69 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
70 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
71 ULONG HandleCount;
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;
77 ULONG Cookie;
78 PAGED_CODE();
79
80 /* Check validity of Information Class */
81 #if 0
82 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
83 PsProcessInfoClass,
84 RTL_NUMBER_OF(PsProcessInfoClass),
85 ProcessInformation,
86 ProcessInformationLength,
87 ReturnLength,
88 PreviousMode);
89 if (!NT_SUCCESS(Status)) return Status;
90 #endif
91
92 if((ProcessInformationClass == ProcessCookie) &&
93 (ProcessHandle != NtCurrentProcess()))
94 {
95 /*
96 * Retreiving the process cookie is only allowed for the calling process
97 * itself! XP only allowes NtCurrentProcess() as process handles even if
98 * a real handle actually represents the current process.
99 */
100 return STATUS_INVALID_PARAMETER;
101 }
102
103 /* Check the information class */
104 switch (ProcessInformationClass)
105 {
106 /* Basic process information */
107 case ProcessBasicInformation:
108
109 /* Set return length */
110 Length = sizeof(PROCESS_BASIC_INFORMATION);
111
112 if (ProcessInformationLength != Length)
113 {
114 Status = STATUS_INFO_LENGTH_MISMATCH;
115 break;
116 }
117
118 /* Reference the process */
119 Status = ObReferenceObjectByHandle(ProcessHandle,
120 PROCESS_QUERY_INFORMATION,
121 PsProcessType,
122 PreviousMode,
123 (PVOID*)&Process,
124 NULL);
125 if (!NT_SUCCESS(Status)) break;
126
127 /* Protect writes with SEH */
128 _SEH2_TRY
129 {
130 /* Write all the information from the EPROCESS/KPROCESS */
131 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
132 ProcessBasicInfo->PebBaseAddress = Process->Peb;
133 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
134 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
135 UniqueProcessId;
136 ProcessBasicInfo->InheritedFromUniqueProcessId =
137 (ULONG_PTR)Process->InheritedFromUniqueProcessId;
138 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
139
140 }
141 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
142 {
143 /* Get exception code */
144 Status = _SEH2_GetExceptionCode();
145 }
146 _SEH2_END;
147
148 /* Dereference the process */
149 ObDereferenceObject(Process);
150 break;
151
152 /* Quote limits and I/O Counters: not implemented */
153 case ProcessQuotaLimits:
154 case ProcessIoCounters:
155
156 Length = sizeof(IO_COUNTERS);
157 if (ProcessInformationLength != Length)
158 {
159 Status = STATUS_INFO_LENGTH_MISMATCH;
160 break;
161 }
162
163 /* Reference the process */
164 Status = ObReferenceObjectByHandle(ProcessHandle,
165 PROCESS_QUERY_INFORMATION,
166 PsProcessType,
167 PreviousMode,
168 (PVOID*)&Process,
169 NULL);
170 if (!NT_SUCCESS(Status)) break;
171
172 Status = STATUS_NOT_IMPLEMENTED;
173 /* Dereference the process */
174 ObDereferenceObject(Process);
175 break;
176
177 /* Timing */
178 case ProcessTimes:
179
180 /* Set the return length */
181 Length = sizeof(KERNEL_USER_TIMES);
182
183 if (ProcessInformationLength != Length)
184 {
185 Status = STATUS_INFO_LENGTH_MISMATCH;
186 break;
187 }
188
189 /* Reference the process */
190 Status = ObReferenceObjectByHandle(ProcessHandle,
191 PROCESS_QUERY_INFORMATION,
192 PsProcessType,
193 PreviousMode,
194 (PVOID*)&Process,
195 NULL);
196 if (!NT_SUCCESS(Status)) break;
197
198 /* Protect writes with SEH */
199 _SEH2_TRY
200 {
201 /* Copy time information from EPROCESS/KPROCESS */
202 ProcessTime->CreateTime = Process->CreateTime;
203 ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
204 100000LL;
205 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
206 100000LL;
207 ProcessTime->ExitTime = Process->ExitTime;
208 }
209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
210 {
211 /* Get exception code */
212 Status = _SEH2_GetExceptionCode();
213 }
214 _SEH2_END;
215
216 /* Dereference the process */
217 ObDereferenceObject(Process);
218 break;
219
220 /* Process Debug Port */
221 case ProcessDebugPort:
222
223 /* Set return length */
224 Length = sizeof(HANDLE);
225
226 if (ProcessInformationLength != Length)
227 {
228 Status = STATUS_INFO_LENGTH_MISMATCH;
229 break;
230 }
231
232 /* Reference the process */
233 Status = ObReferenceObjectByHandle(ProcessHandle,
234 PROCESS_QUERY_INFORMATION,
235 PsProcessType,
236 PreviousMode,
237 (PVOID*)&Process,
238 NULL);
239 if (!NT_SUCCESS(Status)) break;
240
241 /* Protect write with SEH */
242 _SEH2_TRY
243 {
244 /* Return whether or not we have a debug port */
245 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
246 (HANDLE)-1 : NULL);
247 }
248 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
249 {
250 /* Get exception code */
251 Status = _SEH2_GetExceptionCode();
252 }
253 _SEH2_END;
254
255 /* Dereference the process */
256 ObDereferenceObject(Process);
257 break;
258
259 /* LDT, WS and VDM Information: not implemented */
260 case ProcessLdtInformation:
261 case ProcessWorkingSetWatch:
262 case ProcessWx86Information:
263 Status = STATUS_NOT_IMPLEMENTED;
264 break;
265
266 case ProcessHandleCount:
267
268 /* Set the return length*/
269 Length = sizeof(ULONG);
270
271 if (ProcessInformationLength != Length)
272 {
273 Status = STATUS_INFO_LENGTH_MISMATCH;
274 break;
275 }
276
277 /* Reference the process */
278 Status = ObReferenceObjectByHandle(ProcessHandle,
279 PROCESS_QUERY_INFORMATION,
280 PsProcessType,
281 PreviousMode,
282 (PVOID*)&Process,
283 NULL);
284 if (!NT_SUCCESS(Status)) break;
285
286 /* Count the number of handles this process has */
287 HandleCount = ObGetProcessHandleCount(Process);
288
289 /* Protect write in SEH */
290 _SEH2_TRY
291 {
292 /* Return the count of handles */
293 *(PULONG)ProcessInformation = HandleCount;
294 }
295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
296 {
297 /* Get the exception code */
298 Status = _SEH2_GetExceptionCode();
299 }
300 _SEH2_END;
301
302 /* Dereference the process */
303 ObDereferenceObject(Process);
304 break;
305
306 /* Session ID for the process */
307 case ProcessSessionInformation:
308
309 /* Set the return length*/
310 Length = sizeof(PROCESS_SESSION_INFORMATION);
311
312 if (ProcessInformationLength != Length)
313 {
314 Status = STATUS_INFO_LENGTH_MISMATCH;
315 break;
316 }
317
318 /* Reference the process */
319 Status = ObReferenceObjectByHandle(ProcessHandle,
320 PROCESS_QUERY_INFORMATION,
321 PsProcessType,
322 PreviousMode,
323 (PVOID*)&Process,
324 NULL);
325 if (!NT_SUCCESS(Status)) break;
326
327 /* Enter SEH for write safety */
328 _SEH2_TRY
329 {
330 /* Write back the Session ID */
331 SessionInfo->SessionId = PtrToUlong(Process->Session);
332 }
333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
334 {
335 /* Get the exception code */
336 Status = _SEH2_GetExceptionCode();
337 }
338 _SEH2_END;
339
340 /* Dereference the process */
341 ObDereferenceObject(Process);
342 break;
343
344 /* WOW64: Not implemented */
345 case ProcessWow64Information:
346 Status = STATUS_NOT_IMPLEMENTED;
347 break;
348
349 /* Virtual Memory Statistics */
350 case ProcessVmCounters:
351
352 /* Set the return length */
353 Length = sizeof(VM_COUNTERS);
354
355 if (ProcessInformationLength != Length)
356 {
357 Status = STATUS_INFO_LENGTH_MISMATCH;
358 break;
359 }
360
361 /* Reference the process */
362 Status = ObReferenceObjectByHandle(ProcessHandle,
363 PROCESS_QUERY_INFORMATION,
364 PsProcessType,
365 PreviousMode,
366 (PVOID*)&Process,
367 NULL);
368 if (!NT_SUCCESS(Status)) break;
369
370 /* Enter SEH for write safety */
371 _SEH2_TRY
372 {
373 /* Return data from EPROCESS */
374 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
375 VmCounters->VirtualSize = Process->VirtualSize;
376 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
377 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
378 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
379 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
380 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
381 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
382 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
383 VmCounters->PagefileUsage = Process->QuotaUsage[2];
384 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
385
386 }
387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
388 {
389 /* Get the exception code */
390 Status = _SEH2_GetExceptionCode();
391 }
392 _SEH2_END;
393
394 /* Dereference the process */
395 ObDereferenceObject(Process);
396 break;
397
398 /* Hard Error Processing Mode */
399 case ProcessDefaultHardErrorMode:
400
401 /* Set the return length*/
402 Length = sizeof(ULONG);
403
404 if (ProcessInformationLength != Length)
405 {
406 Status = STATUS_INFO_LENGTH_MISMATCH;
407 break;
408 }
409
410 /* Reference the process */
411 Status = ObReferenceObjectByHandle(ProcessHandle,
412 PROCESS_QUERY_INFORMATION,
413 PsProcessType,
414 PreviousMode,
415 (PVOID*)&Process,
416 NULL);
417 if (!NT_SUCCESS(Status)) break;
418
419 /* Enter SEH for writing back data */
420 _SEH2_TRY
421 {
422 /* Write the current processing mode */
423 *(PULONG)ProcessInformation = Process->
424 DefaultHardErrorProcessing;
425 }
426 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
427 {
428 /* Get the exception code */
429 Status = _SEH2_GetExceptionCode();
430 }
431 _SEH2_END;
432
433 /* Dereference the process */
434 ObDereferenceObject(Process);
435 break;
436
437 /* Priority Boosting status */
438 case ProcessPriorityBoost:
439
440 /* Set the return length*/
441 Length = sizeof(ULONG);
442
443 if (ProcessInformationLength != Length)
444 {
445 Status = STATUS_INFO_LENGTH_MISMATCH;
446 break;
447 }
448
449 /* Reference the process */
450 Status = ObReferenceObjectByHandle(ProcessHandle,
451 PROCESS_QUERY_INFORMATION,
452 PsProcessType,
453 PreviousMode,
454 (PVOID*)&Process,
455 NULL);
456 if (!NT_SUCCESS(Status)) break;
457
458 /* Enter SEH for writing back data */
459 _SEH2_TRY
460 {
461 /* Return boost status */
462 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
463 TRUE : FALSE;
464 }
465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
466 {
467 /* Get the exception code */
468 Status = _SEH2_GetExceptionCode();
469 }
470 _SEH2_END;
471
472 /* Dereference the process */
473 ObDereferenceObject(Process);
474 break;
475
476 /* DOS Device Map */
477 case ProcessDeviceMap:
478
479 /* Set the return length*/
480 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
481
482 if (ProcessInformationLength != Length)
483 {
484 Status = STATUS_INFO_LENGTH_MISMATCH;
485 break;
486 }
487
488 /* Reference the process */
489 Status = ObReferenceObjectByHandle(ProcessHandle,
490 PROCESS_QUERY_INFORMATION,
491 PsProcessType,
492 PreviousMode,
493 (PVOID*)&Process,
494 NULL);
495 if (!NT_SUCCESS(Status)) break;
496
497 /* Query the device map information */
498 ObQueryDeviceMapInformation(Process, &DeviceMap);
499
500 /* Enter SEH for writing back data */
501 _SEH2_TRY
502 {
503 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
504 }
505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
506 {
507 /* Get the exception code */
508 Status = _SEH2_GetExceptionCode();
509 }
510 _SEH2_END;
511
512 /* Dereference the process */
513 ObDereferenceObject(Process);
514 break;
515
516 /* Priority class */
517 case ProcessPriorityClass:
518
519 /* Set the return length*/
520 Length = sizeof(USHORT);
521
522 if (ProcessInformationLength != Length)
523 {
524 Status = STATUS_INFO_LENGTH_MISMATCH;
525 break;
526 }
527
528 /* Reference the process */
529 Status = ObReferenceObjectByHandle(ProcessHandle,
530 PROCESS_QUERY_INFORMATION,
531 PsProcessType,
532 PreviousMode,
533 (PVOID*)&Process,
534 NULL);
535 if (!NT_SUCCESS(Status)) break;
536
537 /* Enter SEH for writing back data */
538 _SEH2_TRY
539 {
540 /* Return current priority class */
541 *(PUSHORT)ProcessInformation = Process->PriorityClass;
542 }
543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
544 {
545 /* Get the exception code */
546 Status = _SEH2_GetExceptionCode();
547 }
548 _SEH2_END;
549
550 /* Dereference the process */
551 ObDereferenceObject(Process);
552 break;
553
554 case ProcessImageFileName:
555
556 /* Reference the process */
557 Status = ObReferenceObjectByHandle(ProcessHandle,
558 PROCESS_QUERY_INFORMATION,
559 PsProcessType,
560 PreviousMode,
561 (PVOID*)&Process,
562 NULL);
563 if (!NT_SUCCESS(Status)) break;
564
565 /* Get the image path */
566 Status = SeLocateProcessImageName(Process, &ImageName);
567 if (NT_SUCCESS(Status))
568 {
569 /* Set return length */
570 Length = ImageName->MaximumLength +
571 sizeof(OBJECT_NAME_INFORMATION);
572
573 /* Make sure it's large enough */
574 if (Length <= ProcessInformationLength)
575 {
576 /* Enter SEH to protect write */
577 _SEH2_TRY
578 {
579 /* Copy it */
580 RtlCopyMemory(ProcessInformation,
581 ImageName,
582 Length);
583
584 /* Update pointer */
585 ((PUNICODE_STRING)ProcessInformation)->Buffer =
586 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
587 }
588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
589 {
590 /* Get the exception code */
591 Status = _SEH2_GetExceptionCode();
592 }
593 _SEH2_END;
594 }
595 else
596 {
597 /* Buffer too small */
598 Status = STATUS_INFO_LENGTH_MISMATCH;
599 }
600
601 /* Free the image path */
602 ExFreePool(ImageName);
603 }
604 /* Dereference the process */
605 ObDereferenceObject(Process);
606 break;
607
608 /* Per-process security cookie */
609 case ProcessCookie:
610
611 /* Get the current process and cookie */
612 Process = PsGetCurrentProcess();
613 Cookie = Process->Cookie;
614 if (!Cookie)
615 {
616 LARGE_INTEGER SystemTime;
617 ULONG NewCookie;
618 PKPRCB Prcb;
619
620 /* Generate a new cookie */
621 KeQuerySystemTime(&SystemTime);
622 Prcb = KeGetCurrentPrcb();
623 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
624 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
625
626 /* Set the new cookie or return the current one */
627 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
628 NewCookie,
629 Cookie);
630 if (!Cookie) Cookie = NewCookie;
631
632 /* Set return length */
633 Length = sizeof(ULONG);
634 }
635
636 /* Enter SEH to protect write */
637 _SEH2_TRY
638 {
639 /* Write back the cookie */
640 *(PULONG)ProcessInformation = Cookie;
641 }
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
643 {
644 /* Get the exception code */
645 Status = _SEH2_GetExceptionCode();
646 }
647 _SEH2_END;
648 break;
649
650 /* Not yet implemented, or unknown */
651 case ProcessBasePriority:
652 case ProcessRaisePriority:
653 case ProcessExceptionPort:
654 case ProcessAccessToken:
655 case ProcessLdtSize:
656 case ProcessIoPortHandlers:
657 case ProcessUserModeIOPL:
658 case ProcessEnableAlignmentFaultFixup:
659 case ProcessAffinityMask:
660 case ProcessForegroundInformation:
661 default:
662 Status = STATUS_INVALID_INFO_CLASS;
663 }
664
665 /* Protect write with SEH */
666 _SEH2_TRY
667 {
668 /* Check if caller wanted return length */
669 if (ReturnLength) *ReturnLength = Length;
670 }
671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
672 {
673 /* Get exception code */
674 Status = _SEH2_GetExceptionCode();
675 }
676 _SEH2_END;
677
678 return Status;
679 }
680
681 /*
682 * @implemented
683 */
684 NTSTATUS
685 NTAPI
686 NtSetInformationProcess(IN HANDLE ProcessHandle,
687 IN PROCESSINFOCLASS ProcessInformationClass,
688 IN PVOID ProcessInformation,
689 IN ULONG ProcessInformationLength)
690 {
691 PEPROCESS Process;
692 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
693 ACCESS_MASK Access;
694 NTSTATUS Status;
695 HANDLE PortHandle = NULL;
696 HANDLE TokenHandle = NULL;
697 PROCESS_SESSION_INFORMATION SessionInfo = {0};
698 PVOID ExceptionPort;
699 PAGED_CODE();
700
701 /* Verify Information Class validity */
702 #if 0
703 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
704 PsProcessInfoClass,
705 RTL_NUMBER_OF(PsProcessInfoClass),
706 ProcessInformation,
707 ProcessInformationLength,
708 PreviousMode);
709 if (!NT_SUCCESS(Status)) return Status;
710 #endif
711
712 /* Check what class this is */
713 Access = PROCESS_SET_INFORMATION;
714 if (ProcessInformationClass == ProcessSessionInformation)
715 {
716 /* Setting the Session ID needs a special mask */
717 Access |= PROCESS_SET_SESSIONID;
718 }
719 else if (ProcessInformationClass == ProcessExceptionPort)
720 {
721 /* Setting the exception port needs a special mask */
722 Access |= PROCESS_SUSPEND_RESUME;
723 }
724
725 /* Reference the process */
726 Status = ObReferenceObjectByHandle(ProcessHandle,
727 Access,
728 PsProcessType,
729 PreviousMode,
730 (PVOID*)&Process,
731 NULL);
732 if (!NT_SUCCESS(Status)) return Status;
733
734 /* Check what kind of information class this is */
735 switch (ProcessInformationClass)
736 {
737 /* Quotas and priorities: not implemented */
738 case ProcessQuotaLimits:
739 case ProcessBasePriority:
740 case ProcessRaisePriority:
741 Status = STATUS_NOT_IMPLEMENTED;
742 break;
743
744 /* Error/Exception Port */
745 case ProcessExceptionPort:
746
747 /* Use SEH for capture */
748 _SEH2_TRY
749 {
750 /* Capture the handle */
751 PortHandle = *(PHANDLE)ProcessInformation;
752 }
753 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
754 {
755 /* Get the exception code */
756 Status = _SEH2_GetExceptionCode();
757 }
758 _SEH2_END;
759 if (!NT_SUCCESS(Status)) break;
760
761 /* Get the LPC Port */
762 Status = ObReferenceObjectByHandle(PortHandle,
763 0,
764 LpcPortObjectType,
765 PreviousMode,
766 (PVOID)&ExceptionPort,
767 NULL);
768 if (!NT_SUCCESS(Status)) break;
769
770 /* Change the pointer */
771 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
772 ExceptionPort,
773 NULL))
774 {
775 /* We already had one, fail */
776 ObDereferenceObject(ExceptionPort);
777 Status = STATUS_PORT_ALREADY_SET;
778 }
779 break;
780
781 /* Security Token */
782 case ProcessAccessToken:
783
784 /* Use SEH for capture */
785 _SEH2_TRY
786 {
787 /* Save the token handle */
788 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
789 Token;
790 }
791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
792 {
793 /* Get the exception code */
794 Status = _SEH2_GetExceptionCode();
795 }
796 _SEH2_END;
797 if (!NT_SUCCESS(Status)) break;
798
799 /* Assign the actual token */
800 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
801 break;
802
803 /* Hard error processing */
804 case ProcessDefaultHardErrorMode:
805
806 /* Enter SEH for direct buffer read */
807 _SEH2_TRY
808 {
809 /* Update the current mode abd return the previous one */
810 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
811 *(PLONG)ProcessInformation);
812 }
813 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
814 {
815 /* Get exception code */
816 Status = _SEH2_GetExceptionCode();
817 }
818 _SEH2_END;
819 break;
820
821 /* Session ID */
822 case ProcessSessionInformation:
823
824 /* Enter SEH for capture */
825 _SEH2_TRY
826 {
827 /* Capture the caller's buffer */
828 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
829 }
830 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
831 {
832 /* Get the exception code */
833 Status = _SEH2_GetExceptionCode();
834 }
835 _SEH2_END;
836 if (!NT_SUCCESS(Status)) break;
837
838 /* Setting the session id requires the SeTcbPrivilege */
839 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
840 {
841 /* Can't set the session ID, bail out. */
842 Status = STATUS_PRIVILEGE_NOT_HELD;
843 break;
844 }
845
846 /* FIXME - update the session id for the process token */
847 //Status = PsLockProcess(Process, FALSE);
848 if (!NT_SUCCESS(Status)) break;
849
850 /* Write the session ID in the EPROCESS */
851 Process->Session = SessionInfo.SessionId;
852
853 /* Check if the process also has a PEB */
854 if (Process->Peb)
855 {
856 /*
857 * Attach to the process to make sure we're in the right
858 * context to access the PEB structure
859 */
860 KeAttachProcess(&Process->Pcb);
861
862 /* Enter SEH for write to user-mode PEB */
863 _SEH2_TRY
864 {
865 /* Write the session ID */
866 Process->Peb->SessionId = SessionInfo.SessionId;
867 }
868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
869 {
870 /* Get exception code */
871 Status = _SEH2_GetExceptionCode();
872 }
873 _SEH2_END;
874
875 /* Detach from the process */
876 KeDetachProcess();
877 }
878
879 /* Unlock the process */
880 //PsUnlockProcess(Process);
881 break;
882
883 /* Priority class: HACK! */
884 case ProcessPriorityClass:
885 break;
886
887 /* We currently don't implement any of these */
888 case ProcessLdtInformation:
889 case ProcessLdtSize:
890 case ProcessIoPortHandlers:
891 case ProcessWorkingSetWatch:
892 case ProcessUserModeIOPL:
893 case ProcessEnableAlignmentFaultFixup:
894 case ProcessAffinityMask:
895 Status = STATUS_NOT_IMPLEMENTED;
896 break;
897
898 /* Supposedly these are invalid...!? verify! */
899 case ProcessBasicInformation:
900 case ProcessIoCounters:
901 case ProcessTimes:
902 case ProcessPooledUsageAndLimits:
903 case ProcessWx86Information:
904 case ProcessHandleCount:
905 case ProcessWow64Information:
906 case ProcessDebugPort:
907 default:
908 Status = STATUS_INVALID_INFO_CLASS;
909 }
910
911 /* Dereference and return status */
912 ObDereferenceObject(Process);
913 return Status;
914 }
915
916 /*
917 * @implemented
918 */
919 NTSTATUS
920 NTAPI
921 NtSetInformationThread(IN HANDLE ThreadHandle,
922 IN THREADINFOCLASS ThreadInformationClass,
923 IN PVOID ThreadInformation,
924 IN ULONG ThreadInformationLength)
925 {
926 PETHREAD Thread;
927 ULONG Access;
928 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
929 NTSTATUS Status;
930 HANDLE TokenHandle = NULL;
931 KPRIORITY Priority = 0;
932 KAFFINITY Affinity = 0, CombinedAffinity;
933 PVOID Address = NULL;
934 PEPROCESS Process;
935 ULONG DisableBoost = 0;
936 ULONG IdealProcessor = 0;
937 PTEB Teb;
938 ULONG TlsIndex = 0;
939 PVOID *ExpansionSlots;
940 PETHREAD ProcThread;
941 PAGED_CODE();
942
943 /* Verify Information Class validity */
944 #if 0
945 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
946 PsThreadInfoClass,
947 RTL_NUMBER_OF(PsThreadInfoClass),
948 ThreadInformation,
949 ThreadInformationLength,
950 PreviousMode);
951 if (!NT_SUCCESS(Status)) return Status;
952 #endif
953
954 /* Check what class this is */
955 Access = THREAD_SET_INFORMATION;
956 if (ThreadInformationClass == ThreadImpersonationToken)
957 {
958 /* Setting the impersonation token needs a special mask */
959 Access = THREAD_SET_THREAD_TOKEN;
960 }
961
962 /* Reference the process */
963 Status = ObReferenceObjectByHandle(ThreadHandle,
964 Access,
965 PsThreadType,
966 PreviousMode,
967 (PVOID*)&Thread,
968 NULL);
969 if (!NT_SUCCESS(Status)) return Status;
970
971 /* Check what kind of information class this is */
972 switch (ThreadInformationClass)
973 {
974 /* Thread priority */
975 case ThreadPriority:
976
977 /* Use SEH for capture */
978 _SEH2_TRY
979 {
980 /* Get the priority */
981 Priority = *(PLONG)ThreadInformation;
982 }
983 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
984 {
985 /* Get the exception code */
986 Status = _SEH2_GetExceptionCode();
987 }
988 _SEH2_END;
989 if (!NT_SUCCESS(Status)) break;
990
991 /* Validate it */
992 if ((Priority > HIGH_PRIORITY) ||
993 (Priority <= LOW_PRIORITY))
994 {
995 /* Fail */
996 Status = STATUS_INVALID_PARAMETER;
997 break;
998 }
999
1000 /* Set the priority */
1001 KeSetPriorityThread(&Thread->Tcb, Priority);
1002 break;
1003
1004 case ThreadBasePriority:
1005
1006 /* Use SEH for capture */
1007 _SEH2_TRY
1008 {
1009 /* Get the priority */
1010 Priority = *(PLONG)ThreadInformation;
1011 }
1012 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1013 {
1014 /* Get the exception code */
1015 Status = _SEH2_GetExceptionCode();
1016 }
1017 _SEH2_END;
1018 if (!NT_SUCCESS(Status)) break;
1019
1020 /* Validate it */
1021 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
1022 (Priority < THREAD_BASE_PRIORITY_MIN))
1023 {
1024 /* These ones are OK */
1025 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
1026 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
1027 {
1028 /* Check if the process is real time */
1029 if (PsGetCurrentProcess()->PriorityClass !=
1030 PROCESS_PRIORITY_CLASS_REALTIME)
1031 {
1032 /* It isn't, fail */
1033 Status = STATUS_INVALID_PARAMETER;
1034 break;
1035 }
1036 }
1037 }
1038
1039 /* Set the base priority */
1040 KeSetBasePriorityThread(&Thread->Tcb, Priority);
1041 break;
1042
1043 case ThreadAffinityMask:
1044
1045 /* Use SEH for capture */
1046 _SEH2_TRY
1047 {
1048 /* Get the priority */
1049 Affinity = *(PULONG_PTR)ThreadInformation;
1050 }
1051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1052 {
1053 /* Get the exception code */
1054 Status = _SEH2_GetExceptionCode();
1055 }
1056 _SEH2_END;
1057 if (!NT_SUCCESS(Status)) break;
1058
1059 /* Validate it */
1060 if (!Affinity)
1061 {
1062 /* Fail */
1063 Status = STATUS_INVALID_PARAMETER;
1064 break;
1065 }
1066
1067 /* Get the process */
1068 Process = Thread->ThreadsProcess;
1069
1070 /* Try to acquire rundown */
1071 if (ExAcquireRundownProtection(&Process->RundownProtect))
1072 {
1073 /* Lock it */
1074 KeEnterCriticalRegion();
1075 ExAcquirePushLockShared(&Process->ProcessLock);
1076
1077 /* Combine masks */
1078 CombinedAffinity = Affinity & Process->Pcb.Affinity;
1079 if (CombinedAffinity != Affinity)
1080 {
1081 /* Fail */
1082 Status = STATUS_INVALID_PARAMETER;
1083 }
1084 else
1085 {
1086 /* Set the affinity */
1087 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
1088 }
1089
1090 /* Release the lock and rundown */
1091 ExReleasePushLockShared(&Process->ProcessLock);
1092 KeLeaveCriticalRegion();
1093 ExReleaseRundownProtection(&Process->RundownProtect);
1094 }
1095 else
1096 {
1097 /* Too late */
1098 Status = STATUS_PROCESS_IS_TERMINATING;
1099 }
1100
1101 /* Return status */
1102 break;
1103
1104 case ThreadImpersonationToken:
1105
1106 /* Use SEH for capture */
1107 _SEH2_TRY
1108 {
1109 /* Save the token handle */
1110 TokenHandle = *(PHANDLE)ThreadInformation;
1111 }
1112 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1113 {
1114 /* Get the exception code */
1115 Status = _SEH2_GetExceptionCode();
1116 }
1117 _SEH2_END;
1118 if (!NT_SUCCESS(Status)) break;
1119
1120 /* Assign the actual token */
1121 Status = PsAssignImpersonationToken(Thread, TokenHandle);
1122 break;
1123
1124 case ThreadQuerySetWin32StartAddress:
1125
1126 /* Use SEH for capture */
1127 _SEH2_TRY
1128 {
1129 /* Get the priority */
1130 Address = *(PVOID*)ThreadInformation;
1131 }
1132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1133 {
1134 /* Get the exception code */
1135 Status = _SEH2_GetExceptionCode();
1136 }
1137 _SEH2_END;
1138 if (!NT_SUCCESS(Status)) break;
1139
1140 /* Set the address */
1141 Thread->Win32StartAddress = Address;
1142 break;
1143
1144 case ThreadIdealProcessor:
1145
1146 /* Use SEH for capture */
1147 _SEH2_TRY
1148 {
1149 /* Get the priority */
1150 IdealProcessor = *(PULONG_PTR)ThreadInformation;
1151 }
1152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1153 {
1154 /* Get the exception code */
1155 Status = _SEH2_GetExceptionCode();
1156 }
1157 _SEH2_END;
1158 if (!NT_SUCCESS(Status)) break;
1159
1160 /* Validate it */
1161 if (IdealProcessor > MAXIMUM_PROCESSORS)
1162 {
1163 /* Fail */
1164 Status = STATUS_INVALID_PARAMETER;
1165 break;
1166 }
1167
1168 /* Set the ideal */
1169 Status = KeSetIdealProcessorThread(&Thread->Tcb,
1170 (CCHAR)IdealProcessor);
1171
1172 /* Get the TEB and protect the thread */
1173 Teb = Thread->Tcb.Teb;
1174 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
1175 {
1176 /* Save the ideal processor */
1177 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
1178
1179 /* Release rundown protection */
1180 ExReleaseRundownProtection(&Thread->RundownProtect);
1181 }
1182
1183 break;
1184
1185 case ThreadPriorityBoost:
1186
1187 /* Use SEH for capture */
1188 _SEH2_TRY
1189 {
1190 /* Get the priority */
1191 DisableBoost = *(PULONG_PTR)ThreadInformation;
1192 }
1193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1194 {
1195 /* Get the exception code */
1196 Status = _SEH2_GetExceptionCode();
1197 }
1198 _SEH2_END;
1199 if (!NT_SUCCESS(Status)) break;
1200
1201 /* Call the kernel */
1202 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
1203 break;
1204
1205 case ThreadZeroTlsCell:
1206
1207 /* Use SEH for capture */
1208 _SEH2_TRY
1209 {
1210 /* Get the priority */
1211 TlsIndex = *(PULONG_PTR)ThreadInformation;
1212 }
1213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1214 {
1215 /* Get the exception code */
1216 Status = _SEH2_GetExceptionCode();
1217 }
1218 _SEH2_END;
1219 if (!NT_SUCCESS(Status)) break;
1220
1221 /* This is only valid for the current thread */
1222 if (Thread != PsGetCurrentThread())
1223 {
1224 /* Fail */
1225 Status = STATUS_INVALID_PARAMETER;
1226 break;
1227 }
1228
1229 /* Get the process */
1230 Process = Thread->ThreadsProcess;
1231
1232 /* Loop the threads */
1233 ProcThread = PsGetNextProcessThread(Process, NULL);
1234 while (ProcThread)
1235 {
1236 /* Acquire rundown */
1237 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
1238 {
1239 /* Get the TEB */
1240 Teb = ProcThread->Tcb.Teb;
1241 if (Teb)
1242 {
1243 /* Check if we're in the expansion range */
1244 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
1245 {
1246 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
1247 TLS_EXPANSION_SLOTS) - 1)
1248 {
1249 /* Check if we have expansion slots */
1250 ExpansionSlots = Teb->TlsExpansionSlots;
1251 if (ExpansionSlots)
1252 {
1253 /* Clear the index */
1254 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
1255 }
1256 }
1257 }
1258 else
1259 {
1260 /* Clear the index */
1261 Teb->TlsSlots[TlsIndex] = NULL;
1262 }
1263 }
1264
1265 /* Release rundown */
1266 ExReleaseRundownProtection(&ProcThread->RundownProtect);
1267 }
1268
1269 /* Go to the next thread */
1270 ProcThread = PsGetNextProcessThread(Process, ProcThread);
1271 }
1272
1273 /* All done */
1274 break;
1275
1276 default:
1277 /* We don't implement it yet */
1278 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1279 Status = STATUS_NOT_IMPLEMENTED;
1280 }
1281
1282 /* Dereference and return status */
1283 ObDereferenceObject(Thread);
1284 return Status;
1285 }
1286
1287 /*
1288 * @implemented
1289 */
1290 NTSTATUS
1291 NTAPI
1292 NtQueryInformationThread(IN HANDLE ThreadHandle,
1293 IN THREADINFOCLASS ThreadInformationClass,
1294 OUT PVOID ThreadInformation,
1295 IN ULONG ThreadInformationLength,
1296 OUT PULONG ReturnLength OPTIONAL)
1297 {
1298 PETHREAD Thread;
1299 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1300 NTSTATUS Status = STATUS_SUCCESS;
1301 ULONG Access;
1302 ULONG Length = 0;
1303 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
1304 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
1305 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
1306 KIRQL OldIrql;
1307 PAGED_CODE();
1308
1309 /* Verify Information Class validity */
1310 #if 0
1311 Status = DefaultQueryInfoBufferCheck(ThreadInformationClass,
1312 PsThreadInfoClass,
1313 RTL_NUMBER_OF(PsThreadInfoClass),
1314 ThreadInformation,
1315 ThreadInformationLength,
1316 ReturnLength,
1317 PreviousMode);
1318 if (!NT_SUCCESS(Status)) return Status;
1319 #endif
1320
1321 /* Check what class this is */
1322 Access = THREAD_QUERY_INFORMATION;
1323
1324 /* Reference the process */
1325 Status = ObReferenceObjectByHandle(ThreadHandle,
1326 Access,
1327 PsThreadType,
1328 PreviousMode,
1329 (PVOID*)&Thread,
1330 NULL);
1331 if (!NT_SUCCESS(Status)) return Status;
1332
1333 /* Check what kind of information class this is */
1334 switch (ThreadInformationClass)
1335 {
1336 /* Basic thread information */
1337 case ThreadBasicInformation:
1338
1339 /* Set return length */
1340 Length = sizeof(THREAD_BASIC_INFORMATION);
1341
1342 if (ThreadInformationLength != Length)
1343 {
1344 Status = STATUS_INFO_LENGTH_MISMATCH;
1345 break;
1346 }
1347 /* Protect writes with SEH */
1348 _SEH2_TRY
1349 {
1350 /* Write all the information from the ETHREAD/KTHREAD */
1351 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
1352 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1353 ThreadBasicInfo->ClientId = Thread->Cid;
1354 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
1355 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
1356 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1357 }
1358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1359 {
1360 /* Get exception code */
1361 Status = _SEH2_GetExceptionCode();
1362 }
1363 _SEH2_END;
1364 break;
1365
1366 /* Thread time information */
1367 case ThreadTimes:
1368
1369 /* Set the return length */
1370 Length = sizeof(KERNEL_USER_TIMES);
1371
1372 if (ThreadInformationLength != Length)
1373 {
1374 Status = STATUS_INFO_LENGTH_MISMATCH;
1375 break;
1376 }
1377 /* Protect writes with SEH */
1378 _SEH2_TRY
1379 {
1380 /* Copy time information from ETHREAD/KTHREAD */
1381 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
1382 100000LL;
1383 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
1384 100000LL;
1385 ThreadTime->CreateTime = Thread->CreateTime;
1386 ThreadTime->ExitTime = Thread->ExitTime;
1387 }
1388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1389 {
1390 /* Get exception code */
1391 Status = _SEH2_GetExceptionCode();
1392 }
1393 _SEH2_END;
1394 break;
1395
1396 case ThreadQuerySetWin32StartAddress:
1397
1398 /* Set the return length*/
1399 Length = sizeof(PVOID);
1400
1401 if (ThreadInformationLength != Length)
1402 {
1403 Status = STATUS_INFO_LENGTH_MISMATCH;
1404 break;
1405 }
1406 /* Protect write with SEH */
1407 _SEH2_TRY
1408 {
1409 /* Return the Win32 Start Address */
1410 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
1411 }
1412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1413 {
1414 /* Get exception code */
1415 Status = _SEH2_GetExceptionCode();
1416 }
1417 _SEH2_END;
1418 break;
1419
1420 case ThreadPerformanceCount:
1421
1422 /* Set the return length*/
1423 Length = sizeof(LARGE_INTEGER);
1424
1425 if (ThreadInformationLength != Length)
1426 {
1427 Status = STATUS_INFO_LENGTH_MISMATCH;
1428 break;
1429 }
1430 /* Protect write with SEH */
1431 _SEH2_TRY
1432 {
1433 /* FIXME */
1434 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
1435 }
1436 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1437 {
1438 /* Get exception code */
1439 Status = _SEH2_GetExceptionCode();
1440 }
1441 _SEH2_END;
1442 break;
1443
1444 case ThreadAmILastThread:
1445
1446 /* Set the return length*/
1447 Length = sizeof(ULONG);
1448
1449 if (ThreadInformationLength != Length)
1450 {
1451 Status = STATUS_INFO_LENGTH_MISMATCH;
1452 break;
1453 }
1454 /* Protect write with SEH */
1455 _SEH2_TRY
1456 {
1457 /* Return whether or not we are the last thread */
1458 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1459 ThreadListHead.Flink->Flink ==
1460 &Thread->ThreadsProcess->
1461 ThreadListHead) ?
1462 TRUE : FALSE);
1463 }
1464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1465 {
1466 /* Get exception code */
1467 Status = _SEH2_GetExceptionCode();
1468 }
1469 _SEH2_END;
1470 break;
1471
1472 case ThreadIsIoPending:
1473
1474 /* Set the return length*/
1475 Length = sizeof(ULONG);
1476
1477 if (ThreadInformationLength != Length)
1478 {
1479 Status = STATUS_INFO_LENGTH_MISMATCH;
1480 break;
1481 }
1482 /* Raise the IRQL to protect the IRP list */
1483 KeRaiseIrql(APC_LEVEL, &OldIrql);
1484
1485 /* Protect write with SEH */
1486 _SEH2_TRY
1487 {
1488 /* Check if the IRP list is empty or not */
1489 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1490 }
1491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1492 {
1493 /* Get exception code */
1494 Status = _SEH2_GetExceptionCode();
1495 }
1496 _SEH2_END;
1497
1498 /* Lower IRQL back */
1499 KeLowerIrql(OldIrql);
1500 break;
1501
1502 /* Anything else */
1503 default:
1504
1505 /* Not yet implemented */
1506 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1507 Status = STATUS_NOT_IMPLEMENTED;
1508 }
1509
1510 /* Protect write with SEH */
1511 _SEH2_TRY
1512 {
1513 /* Check if caller wanted return length */
1514 if (ReturnLength) *ReturnLength = Length;
1515 }
1516 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1517 {
1518 /* Get exception code */
1519 Status = _SEH2_GetExceptionCode();
1520 }
1521 _SEH2_END;
1522
1523 /* Dereference the thread, and return */
1524 ObDereferenceObject(Thread);
1525 return Status;
1526 }
1527
1528 /* EOF */