[WIN32K:NTUSER]
[reactos.git] / reactos / win32ss / user / ntuser / winsta.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window stations
5 * FILE: win32ss/user/ntuser/winsta.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * TODO: The process window station is created on
8 * the first USER32/GDI32 call not related
9 * to window station/desktop handling
10 */
11
12 #include <win32k.h>
13 DBG_DEFAULT_CHANNEL(UserWinsta);
14
15 /* GLOBALS *******************************************************************/
16
17 /* Currently active window station */
18 PWINSTATION_OBJECT InputWindowStation = NULL;
19
20 /* Winlogon SAS window */
21 HWND hwndSAS = NULL;
22
23 /* Full path to WindowStations directory */
24 UNICODE_STRING gustrWindowStationsDir;
25
26 /* INITIALIZATION FUNCTIONS ****************************************************/
27
28 INIT_FUNCTION
29 NTSTATUS
30 NTAPI
31 InitWindowStationImpl(VOID)
32 {
33 GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
34 WINSTA_WRITE,
35 WINSTA_EXECUTE,
36 WINSTA_ACCESS_ALL};
37
38 /* Set Winsta Object Attributes */
39 ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
40 ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
41 ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
42
43 return STATUS_SUCCESS;
44 }
45
46 NTSTATUS
47 NTAPI
48 UserCreateWinstaDirectory(VOID)
49 {
50 PPEB Peb;
51 NTSTATUS Status;
52 WCHAR wstrWindowStationsDir[MAX_PATH];
53 OBJECT_ATTRIBUTES ObjectAttributes;
54 HANDLE hWinstaDir;
55
56 /* Create the WindowStations directory and cache its path for later use */
57 Peb = NtCurrentPeb();
58 if(Peb->SessionId == 0)
59 {
60 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR))
61 {
62 return STATUS_INSUFFICIENT_RESOURCES;
63 }
64 }
65 else
66 {
67 swprintf(wstrWindowStationsDir,
68 L"%ws\\%lu%ws",
69 SESSION_DIR,
70 Peb->SessionId,
71 WINSTA_OBJ_DIR);
72
73 if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
74 {
75 return STATUS_INSUFFICIENT_RESOURCES;
76 }
77 }
78
79 InitializeObjectAttributes(&ObjectAttributes,
80 &gustrWindowStationsDir,
81 0,
82 NULL,
83 NULL);
84 Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes);
85 if (!NT_SUCCESS(Status))
86 {
87 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status);
88 return Status;
89 }
90
91 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir, Peb->SessionId);
92
93 return Status;
94 }
95
96 /* OBJECT CALLBACKS **********************************************************/
97
98 NTSTATUS
99 APIENTRY
100 IntWinStaObjectDelete(
101 _In_ PVOID Parameters)
102 {
103 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
104 PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
105
106 TRACE("Deleting window station (0x%p)\n", WinSta);
107
108 WinSta->Flags |= WSS_DYING;
109
110 UserEmptyClipboardData(WinSta);
111
112 RtlDestroyAtomTable(WinSta->AtomTable);
113
114 RtlFreeUnicodeString(&WinSta->Name);
115
116 return STATUS_SUCCESS;
117 }
118
119 NTSTATUS
120 APIENTRY
121 IntWinStaObjectParse(
122 _In_ PVOID Parameters)
123 {
124 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters = Parameters;
125 PUNICODE_STRING RemainingName = ParseParameters->RemainingName;
126
127 /* Assume we don't find anything */
128 *ParseParameters->Object = NULL;
129
130 /* Check for an empty name */
131 if (!RemainingName->Length)
132 {
133 /* Make sure this is a window station, can't parse a desktop now */
134 if (ParseParameters->ObjectType != ExWindowStationObjectType)
135 {
136 /* Fail */
137 return STATUS_OBJECT_TYPE_MISMATCH;
138 }
139
140 /* Reference the window station and return */
141 ObReferenceObject(ParseParameters->ParseObject);
142 *ParseParameters->Object = ParseParameters->ParseObject;
143 return STATUS_SUCCESS;
144 }
145
146 /* Check for leading slash */
147 if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
148 {
149 /* Skip it */
150 RemainingName->Buffer++;
151 RemainingName->Length -= sizeof(WCHAR);
152 RemainingName->MaximumLength -= sizeof(WCHAR);
153 }
154
155 /* Check if there is still a slash */
156 if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
157 {
158 /* In this case, fail */
159 return STATUS_OBJECT_PATH_INVALID;
160 }
161
162 /*
163 * Check if we are parsing a desktop.
164 */
165 if (ParseParameters->ObjectType == ExDesktopObjectType)
166 {
167 /* Then call the desktop parse routine */
168 return IntDesktopObjectParse(ParseParameters->ParseObject,
169 ParseParameters->ObjectType,
170 ParseParameters->AccessState,
171 ParseParameters->AccessMode,
172 ParseParameters->Attributes,
173 ParseParameters->CompleteName,
174 RemainingName,
175 ParseParameters->Context,
176 ParseParameters->SecurityQos,
177 ParseParameters->Object);
178 }
179
180 /* Should hopefully never get here */
181 return STATUS_OBJECT_TYPE_MISMATCH;
182 }
183
184 NTSTATUS
185 NTAPI
186 IntWinstaOkToClose(
187 _In_ PVOID Parameters)
188 {
189 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
190 PPROCESSINFO ppi;
191
192 ppi = PsGetCurrentProcessWin32Process();
193
194 if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
195 {
196 return STATUS_ACCESS_DENIED;
197 }
198
199 return STATUS_SUCCESS;
200 }
201
202 /* PRIVATE FUNCTIONS **********************************************************/
203
204 /*
205 * IntValidateWindowStationHandle
206 *
207 * Validates the window station handle.
208 *
209 * Remarks
210 * If the function succeeds, the handle remains referenced. If the
211 * fucntion fails, last error is set.
212 */
213
214 NTSTATUS FASTCALL
215 IntValidateWindowStationHandle(
216 HWINSTA WindowStation,
217 KPROCESSOR_MODE AccessMode,
218 ACCESS_MASK DesiredAccess,
219 PWINSTATION_OBJECT *Object,
220 POBJECT_HANDLE_INFORMATION pObjectHandleInfo)
221 {
222 NTSTATUS Status;
223
224 if (WindowStation == NULL)
225 {
226 ERR("Invalid window station handle\n");
227 EngSetLastError(ERROR_INVALID_HANDLE);
228 return STATUS_INVALID_HANDLE;
229 }
230
231 Status = ObReferenceObjectByHandle(
232 WindowStation,
233 DesiredAccess,
234 ExWindowStationObjectType,
235 AccessMode,
236 (PVOID*)Object,
237 pObjectHandleInfo);
238
239 if (!NT_SUCCESS(Status))
240 SetLastNtError(Status);
241
242 return Status;
243 }
244
245 BOOL FASTCALL
246 co_IntInitializeDesktopGraphics(VOID)
247 {
248 TEXTMETRICW tmw;
249 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
250 PDESKTOP pdesk;
251
252 ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
253 if (NULL == ScreenDeviceContext)
254 {
255 IntDestroyPrimarySurface();
256 return FALSE;
257 }
258 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
259
260 if (! IntCreatePrimarySurface())
261 {
262 return FALSE;
263 }
264
265 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
266
267 NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
268 GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
269
270 /* Update the SERVERINFO */
271 gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
272 gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
273 gpsi->Planes = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
274 gpsi->BitsPixel = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
275 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
276 gpsi->dmLogPixels = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
277 if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
278 {
279 gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
280 }
281 else
282 gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
283 // Font is realized and this dc was previously set to internal DC_ATTR.
284 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
285 gpsi->tmSysFont = tmw;
286
287 /* Put the pointer in the center of the screen */
288 gpsi->ptCursor.x = gpsi->aiSysMet[SM_CXSCREEN] / 2;
289 gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
290
291 /* Attach monitor */
292 UserAttachMonitor((HDEV)gppdevPrimary);
293
294 /* Setup the cursor */
295 co_IntLoadDefaultCursors();
296
297 /* Setup the icons */
298 co_IntSetWndIcons();
299
300 /* Setup Menu */
301 MenuInit();
302
303 /* Show the desktop */
304 pdesk = IntGetActiveDesktop();
305 ASSERT(pdesk);
306 co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
307
308 return TRUE;
309 }
310
311 VOID FASTCALL
312 IntEndDesktopGraphics(VOID)
313 {
314 if (NULL != ScreenDeviceContext)
315 { // No need to allocate a new dcattr.
316 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
317 GreDeleteObject(ScreenDeviceContext);
318 ScreenDeviceContext = NULL;
319 }
320 IntHideDesktop(IntGetActiveDesktop());
321 IntDestroyPrimarySurface();
322 }
323
324 HDC FASTCALL
325 IntGetScreenDC(VOID)
326 {
327 return ScreenDeviceContext;
328 }
329
330 BOOL FASTCALL
331 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
332 {
333 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
334 if ( gpidLogon != PsGetCurrentProcessId() )
335 {
336 if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
337 {
338 ERR("Requires Interactive Window Station\n");
339 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
340 return FALSE;
341 }
342 if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
343 {
344 ERR("Access Denied\n");
345 EngSetLastError(ERROR_ACCESS_DENIED);
346 return FALSE;
347 }
348 }
349 return TRUE;
350 }
351
352
353 /* PUBLIC FUNCTIONS ***********************************************************/
354
355 /*
356 * NtUserCreateWindowStation
357 *
358 * Creates a new window station.
359 *
360 * Parameters
361 * lpszWindowStationName
362 * Pointer to a null-terminated string specifying the name of the
363 * window station to be created. Window station names are
364 * case-insensitive and cannot contain backslash characters (\).
365 * Only members of the Administrators group are allowed to specify a
366 * name.
367 *
368 * dwDesiredAccess
369 * Requested type of access
370 *
371 * lpSecurity
372 * Security descriptor
373 *
374 * Unknown3, Unknown4, Unknown5
375 * Unused
376 *
377 * Return Value
378 * If the function succeeds, the return value is a handle to the newly
379 * created window station. If the specified window station already
380 * exists, the function succeeds and returns a handle to the existing
381 * window station. If the function fails, the return value is NULL.
382 *
383 * Todo
384 * Correct the prototype to match the Windows one (with 7 parameters
385 * on Windows XP).
386 *
387 * Status
388 * @implemented
389 */
390
391 HWINSTA APIENTRY
392 NtUserCreateWindowStation(
393 POBJECT_ATTRIBUTES ObjectAttributes,
394 ACCESS_MASK dwDesiredAccess,
395 DWORD Unknown2,
396 DWORD Unknown3,
397 DWORD Unknown4,
398 DWORD Unknown5,
399 DWORD Unknown6)
400 {
401 UNICODE_STRING WindowStationName;
402 PWINSTATION_OBJECT WindowStationObject;
403 HWINSTA WindowStation;
404 NTSTATUS Status;
405
406 TRACE("NtUserCreateWindowStation called\n");
407
408 Status = ObOpenObjectByName(
409 ObjectAttributes,
410 ExWindowStationObjectType,
411 UserMode,
412 NULL,
413 dwDesiredAccess,
414 NULL,
415 (PVOID*)&WindowStation);
416
417 if (NT_SUCCESS(Status))
418 {
419 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName);
420 return (HWINSTA)WindowStation;
421 }
422
423 /*
424 * No existing window station found, try to create new one
425 */
426
427 /* Capture window station name */
428 _SEH2_TRY
429 {
430 ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
431 Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName);
432 }
433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
434 {
435 Status =_SEH2_GetExceptionCode();
436 }
437 _SEH2_END
438
439 if (! NT_SUCCESS(Status))
440 {
441 ERR("Failed reading capturing window station name\n");
442 SetLastNtError(Status);
443 return NULL;
444 }
445
446 /* Create the window station object */
447 Status = ObCreateObject(
448 UserMode,
449 ExWindowStationObjectType,
450 ObjectAttributes,
451 UserMode,
452 NULL,
453 sizeof(WINSTATION_OBJECT),
454 0,
455 0,
456 (PVOID*)&WindowStationObject);
457
458 if (!NT_SUCCESS(Status))
459 {
460 ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName);
461 ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
462 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
463 return 0;
464 }
465
466 Status = ObInsertObject(
467 (PVOID)WindowStationObject,
468 NULL,
469 dwDesiredAccess,
470 0,
471 NULL,
472 (PVOID*)&WindowStation);
473
474 if (!NT_SUCCESS(Status))
475 {
476 ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName);
477 ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
478 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
479 ObDereferenceObject(WindowStationObject);
480 return 0;
481 }
482
483 /* Initialize the window station */
484 RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
485
486 InitializeListHead(&WindowStationObject->DesktopListHead);
487 Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
488 WindowStationObject->Name = WindowStationName;
489 WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
490
491 if (InputWindowStation == NULL)
492 {
493 ERR("Initializing input window station\n");
494 InputWindowStation = WindowStationObject;
495
496 WindowStationObject->Flags &= ~WSS_NOIO;
497
498 InitCursorImpl();
499 }
500 else
501 {
502 WindowStationObject->Flags |= WSS_NOIO;
503 }
504
505 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
506 WindowStation, &WindowStationObject->Name, WindowStation);
507 return WindowStation;
508 }
509
510 /*
511 * NtUserOpenWindowStation
512 *
513 * Opens an existing window station.
514 *
515 * Parameters
516 * lpszWindowStationName
517 * Name of the existing window station.
518 *
519 * dwDesiredAccess
520 * Requested type of access.
521 *
522 * Return Value
523 * If the function succeeds, the return value is the handle to the
524 * specified window station. If the function fails, the return value
525 * is NULL.
526 *
527 * Remarks
528 * The returned handle can be closed with NtUserCloseWindowStation.
529 *
530 * Status
531 * @implemented
532 */
533
534 HWINSTA APIENTRY
535 NtUserOpenWindowStation(
536 POBJECT_ATTRIBUTES ObjectAttributes,
537 ACCESS_MASK dwDesiredAccess)
538 {
539 HWINSTA hwinsta;
540 NTSTATUS Status;
541
542 Status = ObOpenObjectByName(
543 ObjectAttributes,
544 ExWindowStationObjectType,
545 UserMode,
546 NULL,
547 dwDesiredAccess,
548 NULL,
549 (PVOID*)&hwinsta);
550
551 if (!NT_SUCCESS(Status))
552 {
553 ERR("NtUserOpenWindowStation failed\n");
554 SetLastNtError(Status);
555 return 0;
556 }
557
558 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
559
560 return hwinsta;
561 }
562
563 /*
564 * NtUserCloseWindowStation
565 *
566 * Closes a window station handle.
567 *
568 * Parameters
569 * hWinSta
570 * Handle to the window station.
571 *
572 * Return Value
573 * Status
574 *
575 * Remarks
576 * The window station handle can be created with NtUserCreateWindowStation
577 * or NtUserOpenWindowStation. Attemps to close a handle to the window
578 * station assigned to the calling process will fail.
579 *
580 * Status
581 * @implemented
582 */
583
584 BOOL
585 APIENTRY
586 NtUserCloseWindowStation(
587 HWINSTA hWinSta)
588 {
589 PWINSTATION_OBJECT Object;
590 NTSTATUS Status;
591
592 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
593
594 if (hWinSta == UserGetProcessWindowStation())
595 {
596 ERR("Attempted to close process window station\n");
597 return FALSE;
598 }
599
600 Status = IntValidateWindowStationHandle(
601 hWinSta,
602 KernelMode,
603 0,
604 &Object,
605 0);
606
607 if (!NT_SUCCESS(Status))
608 {
609 ERR("Validation of window station handle (%p) failed\n", hWinSta);
610 return FALSE;
611 }
612
613 ObDereferenceObject(Object);
614
615 TRACE("Closing window station handle (%p)\n", hWinSta);
616
617 Status = ObCloseHandle(hWinSta, UserMode);
618 if (!NT_SUCCESS(Status))
619 {
620 SetLastNtError(Status);
621 return FALSE;
622 }
623
624 return TRUE;
625 }
626
627 /*
628 * NtUserGetObjectInformation
629 *
630 * The NtUserGetObjectInformation function retrieves information about a
631 * window station or desktop object.
632 *
633 * Parameters
634 * hObj
635 * Handle to the window station or desktop object for which to
636 * return information. This can be a handle of type HDESK or HWINSTA
637 * (for example, a handle returned by NtUserCreateWindowStation,
638 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
639 *
640 * nIndex
641 * Specifies the object information to be retrieved.
642 *
643 * pvInfo
644 * Pointer to a buffer to receive the object information.
645 *
646 * nLength
647 * Specifies the size, in bytes, of the buffer pointed to by the
648 * pvInfo parameter.
649 *
650 * lpnLengthNeeded
651 * Pointer to a variable receiving the number of bytes required to
652 * store the requested information. If this variable's value is
653 * greater than the value of the nLength parameter when the function
654 * returns, the function returns FALSE, and none of the information
655 * is copied to the pvInfo buffer. If the value of the variable pointed
656 * to by lpnLengthNeeded is less than or equal to the value of nLength,
657 * the entire information block is copied.
658 *
659 * Return Value
660 * If the function succeeds, the return value is nonzero. If the function
661 * fails, the return value is zero.
662 *
663 * Status
664 * @unimplemented
665 */
666
667 BOOL APIENTRY
668 NtUserGetObjectInformation(
669 HANDLE hObject,
670 DWORD nIndex,
671 PVOID pvInformation,
672 DWORD nLength,
673 PDWORD nLengthNeeded)
674 {
675 PWINSTATION_OBJECT WinStaObject;
676 PDESKTOP DesktopObject = NULL;
677 NTSTATUS Status;
678 PVOID pvData = NULL;
679 DWORD nDataSize = 0;
680
681 _SEH2_TRY
682 {
683 if (nLengthNeeded)
684 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
685 ProbeForWrite(pvInformation, nLength, 1);
686 }
687 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
688 {
689 SetLastNtError(_SEH2_GetExceptionCode());
690 return FALSE;
691 }
692 _SEH2_END;
693
694 /* try windowstation */
695 TRACE("Trying to open window station %p\n", hObject);
696 Status = ObReferenceObjectByHandle(
697 hObject,
698 0,
699 ExWindowStationObjectType,
700 UserMode,
701 (PVOID*)&WinStaObject,
702 NULL);
703
704 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
705 {
706 /* try desktop */
707 TRACE("Trying to open desktop %p\n", hObject);
708 WinStaObject = NULL;
709 Status = IntValidateDesktopHandle(
710 hObject,
711 UserMode,
712 0,
713 &DesktopObject);
714 }
715
716 if (!NT_SUCCESS(Status))
717 {
718 ERR("Failed: 0x%x\n", Status);
719 goto Exit;
720 }
721
722 TRACE("WinSta or Desktop opened!!\n");
723
724 /* get data */
725 switch (nIndex)
726 {
727 case UOI_FLAGS:
728 Status = STATUS_NOT_IMPLEMENTED;
729 ERR("UOI_FLAGS unimplemented!\n");
730 break;
731
732 case UOI_NAME:
733 if (WinStaObject != NULL)
734 {
735 pvData = WinStaObject->Name.Buffer;
736 nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
737 Status = STATUS_SUCCESS;
738 }
739 else if (DesktopObject != NULL)
740 {
741 pvData = DesktopObject->pDeskInfo->szDesktopName;
742 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
743 Status = STATUS_SUCCESS;
744 }
745 else
746 Status = STATUS_INVALID_PARAMETER;
747 break;
748
749 case UOI_TYPE:
750 if (WinStaObject != NULL)
751 {
752 pvData = L"WindowStation";
753 nDataSize = sizeof(L"WindowStation");
754 Status = STATUS_SUCCESS;
755 }
756 else if (DesktopObject != NULL)
757 {
758 pvData = L"Desktop";
759 nDataSize = sizeof(L"Desktop");
760 Status = STATUS_SUCCESS;
761 }
762 else
763 Status = STATUS_INVALID_PARAMETER;
764 break;
765
766 case UOI_USER_SID:
767 Status = STATUS_NOT_IMPLEMENTED;
768 ERR("UOI_USER_SID unimplemented!\n");
769 break;
770
771 default:
772 Status = STATUS_INVALID_PARAMETER;
773 break;
774 }
775
776 Exit:
777 if (Status == STATUS_SUCCESS && nLength < nDataSize)
778 Status = STATUS_BUFFER_TOO_SMALL;
779
780 _SEH2_TRY
781 {
782 if (nLengthNeeded)
783 *nLengthNeeded = nDataSize;
784
785 /* try to copy data to caller */
786 if (Status == STATUS_SUCCESS)
787 {
788 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
789 RtlCopyMemory(pvInformation, pvData, nDataSize);
790 }
791 }
792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
793 {
794 Status = _SEH2_GetExceptionCode();
795 }
796 _SEH2_END;
797
798 /* release objects */
799 if (WinStaObject != NULL)
800 ObDereferenceObject(WinStaObject);
801 if (DesktopObject != NULL)
802 ObDereferenceObject(DesktopObject);
803
804 if (!NT_SUCCESS(Status))
805 {
806 SetLastNtError(Status);
807 return FALSE;
808 }
809
810 return TRUE;
811 }
812
813 /*
814 * NtUserSetObjectInformation
815 *
816 * The NtUserSetObjectInformation function sets information about a
817 * window station or desktop object.
818 *
819 * Parameters
820 * hObj
821 * Handle to the window station or desktop object for which to set
822 * object information. This value can be a handle of type HDESK or
823 * HWINSTA.
824 *
825 * nIndex
826 * Specifies the object information to be set.
827 *
828 * pvInfo
829 * Pointer to a buffer containing the object information.
830 *
831 * nLength
832 * Specifies the size, in bytes, of the information contained in the
833 * buffer pointed to by pvInfo.
834 *
835 * Return Value
836 * If the function succeeds, the return value is nonzero. If the function
837 * fails the return value is zero.
838 *
839 * Status
840 * @unimplemented
841 */
842
843 BOOL
844 APIENTRY
845 NtUserSetObjectInformation(
846 HANDLE hObject,
847 DWORD nIndex,
848 PVOID pvInformation,
849 DWORD nLength)
850 {
851 /* FIXME: ZwQueryObject */
852 /* FIXME: ZwSetInformationObject */
853 SetLastNtError(STATUS_UNSUCCESSFUL);
854 return FALSE;
855 }
856
857
858
859
860 HWINSTA FASTCALL
861 UserGetProcessWindowStation(VOID)
862 {
863 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
864
865 return ppi->hwinsta;
866 }
867
868
869 /*
870 * NtUserGetProcessWindowStation
871 *
872 * Returns a handle to the current process window station.
873 *
874 * Return Value
875 * If the function succeeds, the return value is handle to the window
876 * station assigned to the current process. If the function fails, the
877 * return value is NULL.
878 *
879 * Status
880 * @implemented
881 */
882
883 HWINSTA APIENTRY
884 NtUserGetProcessWindowStation(VOID)
885 {
886 return UserGetProcessWindowStation();
887 }
888
889 BOOL FASTCALL
890 UserSetProcessWindowStation(HWINSTA hWindowStation)
891 {
892 PPROCESSINFO ppi;
893 NTSTATUS Status;
894 HWINSTA hwinstaOld;
895 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
896 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
897
898 ppi = PsGetCurrentProcessWin32Process();
899
900 /* Reference the new window station */
901 if(hWindowStation !=NULL)
902 {
903 Status = IntValidateWindowStationHandle( hWindowStation,
904 KernelMode,
905 0,
906 &NewWinSta,
907 &ObjectHandleInfo);
908 if (!NT_SUCCESS(Status))
909 {
910 TRACE("Validation of window station handle (%p) failed\n",
911 hWindowStation);
912 SetLastNtError(Status);
913 return FALSE;
914 }
915 }
916
917 OldWinSta = ppi->prpwinsta;
918 hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
919
920 /* Dereference the previous window station */
921 if(OldWinSta != NULL)
922 {
923 ObDereferenceObject(OldWinSta);
924 }
925
926 /* Check if we have a stale handle (it should happen for console apps) */
927 if(hwinstaOld != ppi->hwinsta)
928 {
929 ObCloseHandle(hwinstaOld, UserMode);
930 }
931
932 /*
933 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
934 */
935
936 PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
937
938 ppi->prpwinsta = NewWinSta;
939 ppi->hwinsta = hWindowStation;
940 ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
941 TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
942
943 if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
944 {
945 ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
946 }
947 else
948 {
949 ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
950 }
951
952 if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
953 {
954 ppi->W32PF_flags |= W32PF_IOWINSTA;
955 }
956 else // Might be closed if the handle is null.
957 {
958 ppi->W32PF_flags &= ~W32PF_IOWINSTA;
959 }
960 return TRUE;
961 }
962
963 /*
964 * NtUserSetProcessWindowStation
965 *
966 * Assigns a window station to the current process.
967 *
968 * Parameters
969 * hWinSta
970 * Handle to the window station.
971 *
972 * Return Value
973 * Status
974 *
975 * Status
976 * @implemented
977 */
978
979 BOOL APIENTRY
980 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
981 {
982 BOOL ret;
983
984 UserEnterExclusive();
985
986 ret = UserSetProcessWindowStation(hWindowStation);
987
988 UserLeave();
989
990 return ret;
991 }
992
993 /*
994 * NtUserLockWindowStation
995 *
996 * Locks switching desktops. Only the logon application is allowed to call this function.
997 *
998 * Status
999 * @implemented
1000 */
1001
1002 BOOL APIENTRY
1003 NtUserLockWindowStation(HWINSTA hWindowStation)
1004 {
1005 PWINSTATION_OBJECT Object;
1006 NTSTATUS Status;
1007
1008 TRACE("About to set process window station with handle (%p)\n",
1009 hWindowStation);
1010
1011 if (gpidLogon != PsGetCurrentProcessId())
1012 {
1013 ERR("Unauthorized process attempted to lock the window station!\n");
1014 EngSetLastError(ERROR_ACCESS_DENIED);
1015 return FALSE;
1016 }
1017
1018 Status = IntValidateWindowStationHandle(
1019 hWindowStation,
1020 KernelMode,
1021 0,
1022 &Object,
1023 0);
1024 if (!NT_SUCCESS(Status))
1025 {
1026 TRACE("Validation of window station handle (%p) failed\n",
1027 hWindowStation);
1028 SetLastNtError(Status);
1029 return FALSE;
1030 }
1031
1032 Object->Flags |= WSS_LOCKED;
1033
1034 ObDereferenceObject(Object);
1035 return TRUE;
1036 }
1037
1038 /*
1039 * NtUserUnlockWindowStation
1040 *
1041 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1042 *
1043 * Status
1044 * @implemented
1045 */
1046
1047 BOOL APIENTRY
1048 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1049 {
1050 PWINSTATION_OBJECT Object;
1051 NTSTATUS Status;
1052 BOOL Ret;
1053
1054 TRACE("About to set process window station with handle (%p)\n",
1055 hWindowStation);
1056
1057 if (gpidLogon != PsGetCurrentProcessId())
1058 {
1059 ERR("Unauthorized process attempted to unlock the window station!\n");
1060 EngSetLastError(ERROR_ACCESS_DENIED);
1061 return FALSE;
1062 }
1063
1064 Status = IntValidateWindowStationHandle(
1065 hWindowStation,
1066 KernelMode,
1067 0,
1068 &Object,
1069 0);
1070 if (!NT_SUCCESS(Status))
1071 {
1072 TRACE("Validation of window station handle (%p) failed\n",
1073 hWindowStation);
1074 SetLastNtError(Status);
1075 return FALSE;
1076 }
1077
1078 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1079 Object->Flags &= ~WSS_LOCKED;
1080
1081 ObDereferenceObject(Object);
1082 return Ret;
1083 }
1084
1085 static NTSTATUS FASTCALL
1086 BuildWindowStationNameList(
1087 ULONG dwSize,
1088 PVOID lpBuffer,
1089 PULONG pRequiredSize)
1090 {
1091 OBJECT_ATTRIBUTES ObjectAttributes;
1092 NTSTATUS Status;
1093 HANDLE DirectoryHandle;
1094 char InitialBuffer[256], *Buffer;
1095 ULONG Context, ReturnLength, BufferSize;
1096 DWORD EntryCount;
1097 POBJECT_DIRECTORY_INFORMATION DirEntry;
1098 WCHAR NullWchar;
1099
1100 /*
1101 * Try to open the directory.
1102 */
1103 InitializeObjectAttributes(
1104 &ObjectAttributes,
1105 &gustrWindowStationsDir,
1106 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1107 NULL,
1108 NULL);
1109
1110 Status = ZwOpenDirectoryObject(
1111 &DirectoryHandle,
1112 DIRECTORY_QUERY,
1113 &ObjectAttributes);
1114
1115 if (!NT_SUCCESS(Status))
1116 {
1117 return Status;
1118 }
1119
1120 /* First try to query the directory using a fixed-size buffer */
1121 Context = 0;
1122 Buffer = NULL;
1123 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1124 FALSE, TRUE, &Context, &ReturnLength);
1125 if (NT_SUCCESS(Status))
1126 {
1127 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1128 FALSE, &Context, NULL))
1129 {
1130 /* Our fixed-size buffer is large enough */
1131 Buffer = InitialBuffer;
1132 }
1133 }
1134
1135 if (NULL == Buffer)
1136 {
1137 /* Need a larger buffer, check how large exactly */
1138 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1139 &ReturnLength);
1140 if (!NT_SUCCESS(Status))
1141 {
1142 ERR("ZwQueryDirectoryObject failed\n");
1143 ZwClose(DirectoryHandle);
1144 return Status;
1145 }
1146
1147 BufferSize = ReturnLength;
1148 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1149 if (NULL == Buffer)
1150 {
1151 ZwClose(DirectoryHandle);
1152 return STATUS_NO_MEMORY;
1153 }
1154
1155 /* We should have a sufficiently large buffer now */
1156 Context = 0;
1157 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1158 FALSE, TRUE, &Context, &ReturnLength);
1159 if (! NT_SUCCESS(Status) ||
1160 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1161 FALSE, &Context, NULL))
1162 {
1163 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1164 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1165 ZwClose(DirectoryHandle);
1166 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1167 }
1168 }
1169
1170 ZwClose(DirectoryHandle);
1171
1172 /*
1173 * Count the required size of buffer.
1174 */
1175 ReturnLength = sizeof(DWORD);
1176 EntryCount = 0;
1177 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1178 DirEntry++)
1179 {
1180 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1181 EntryCount++;
1182 }
1183 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1184 if (NULL != pRequiredSize)
1185 {
1186 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1187 if (! NT_SUCCESS(Status))
1188 {
1189 if (Buffer != InitialBuffer)
1190 {
1191 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1192 }
1193 return STATUS_BUFFER_TOO_SMALL;
1194 }
1195 }
1196
1197 /*
1198 * Check if the supplied buffer is large enough.
1199 */
1200 if (dwSize < ReturnLength)
1201 {
1202 if (Buffer != InitialBuffer)
1203 {
1204 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1205 }
1206 return STATUS_BUFFER_TOO_SMALL;
1207 }
1208
1209 /*
1210 * Generate the resulting buffer contents.
1211 */
1212 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1213 if (! NT_SUCCESS(Status))
1214 {
1215 if (Buffer != InitialBuffer)
1216 {
1217 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1218 }
1219 return Status;
1220 }
1221 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1222
1223 NullWchar = L'\0';
1224 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1225 DirEntry++)
1226 {
1227 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1228 if (! NT_SUCCESS(Status))
1229 {
1230 if (Buffer != InitialBuffer)
1231 {
1232 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1233 }
1234 return Status;
1235 }
1236 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1237 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1238 if (! NT_SUCCESS(Status))
1239 {
1240 if (Buffer != InitialBuffer)
1241 {
1242 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1243 }
1244 return Status;
1245 }
1246 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1247 }
1248
1249 /*
1250 * Clean up
1251 */
1252 if (Buffer != InitialBuffer)
1253 {
1254 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1255 }
1256
1257 return STATUS_SUCCESS;
1258 }
1259
1260 static NTSTATUS FASTCALL
1261 BuildDesktopNameList(
1262 HWINSTA hWindowStation,
1263 ULONG dwSize,
1264 PVOID lpBuffer,
1265 PULONG pRequiredSize)
1266 {
1267 NTSTATUS Status;
1268 PWINSTATION_OBJECT WindowStation;
1269 PLIST_ENTRY DesktopEntry;
1270 PDESKTOP DesktopObject;
1271 DWORD EntryCount;
1272 ULONG ReturnLength;
1273 WCHAR NullWchar;
1274 UNICODE_STRING DesktopName;
1275
1276 Status = IntValidateWindowStationHandle(hWindowStation,
1277 KernelMode,
1278 0,
1279 &WindowStation,
1280 0);
1281 if (! NT_SUCCESS(Status))
1282 {
1283 return Status;
1284 }
1285
1286 /*
1287 * Count the required size of buffer.
1288 */
1289 ReturnLength = sizeof(DWORD);
1290 EntryCount = 0;
1291 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1292 DesktopEntry != &WindowStation->DesktopListHead;
1293 DesktopEntry = DesktopEntry->Flink)
1294 {
1295 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1296 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1297 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1298 EntryCount++;
1299 }
1300 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1301 if (NULL != pRequiredSize)
1302 {
1303 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1304 if (! NT_SUCCESS(Status))
1305 {
1306 ObDereferenceObject(WindowStation);
1307 return STATUS_BUFFER_TOO_SMALL;
1308 }
1309 }
1310
1311 /*
1312 * Check if the supplied buffer is large enough.
1313 */
1314 if (dwSize < ReturnLength)
1315 {
1316 ObDereferenceObject(WindowStation);
1317 return STATUS_BUFFER_TOO_SMALL;
1318 }
1319
1320 /*
1321 * Generate the resulting buffer contents.
1322 */
1323 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1324 if (! NT_SUCCESS(Status))
1325 {
1326 ObDereferenceObject(WindowStation);
1327 return Status;
1328 }
1329 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1330
1331 NullWchar = L'\0';
1332 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1333 DesktopEntry != &WindowStation->DesktopListHead;
1334 DesktopEntry = DesktopEntry->Flink)
1335 {
1336 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1337 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1338 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1339 if (! NT_SUCCESS(Status))
1340 {
1341 ObDereferenceObject(WindowStation);
1342 return Status;
1343 }
1344 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1345 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1346 if (! NT_SUCCESS(Status))
1347 {
1348 ObDereferenceObject(WindowStation);
1349 return Status;
1350 }
1351 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1352 }
1353
1354 /*
1355 * Clean up and return
1356 */
1357 ObDereferenceObject(WindowStation);
1358 return STATUS_SUCCESS;
1359 }
1360
1361 /*
1362 * NtUserBuildNameList
1363 *
1364 * Function used for enumeration of desktops or window stations.
1365 *
1366 * Parameters
1367 * hWinSta
1368 * For enumeration of window stations this parameter must be set to
1369 * zero. Otherwise it's handle for window station.
1370 *
1371 * dwSize
1372 * Size of buffer passed by caller.
1373 *
1374 * lpBuffer
1375 * Buffer passed by caller. If the function succeeds, the buffer is
1376 * filled with window station/desktop count (in first DWORD) and
1377 * NULL-terminated window station/desktop names.
1378 *
1379 * pRequiredSize
1380 * If the function succeeds, this is the number of bytes copied.
1381 * Otherwise it's size of buffer needed for function to succeed.
1382 *
1383 * Status
1384 * @implemented
1385 */
1386
1387 NTSTATUS APIENTRY
1388 NtUserBuildNameList(
1389 HWINSTA hWindowStation,
1390 ULONG dwSize,
1391 PVOID lpBuffer,
1392 PULONG pRequiredSize)
1393 {
1394 /* The WindowStation name list and desktop name list are build in completely
1395 different ways. Call the appropriate function */
1396 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1397 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1398 }
1399
1400 /*
1401 * @implemented
1402 */
1403 BOOL APIENTRY
1404 NtUserSetLogonNotifyWindow(HWND hWnd)
1405 {
1406 if (gpidLogon != PsGetCurrentProcessId())
1407 {
1408 return FALSE;
1409 }
1410
1411 if (!IntIsWindow(hWnd))
1412 {
1413 return FALSE;
1414 }
1415
1416 hwndSAS = hWnd;
1417
1418 return TRUE;
1419 }
1420
1421 BOOL
1422 APIENTRY
1423 NtUserLockWorkStation(VOID)
1424 {
1425 BOOL ret;
1426 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1427
1428 UserEnterExclusive();
1429
1430 if (pti->rpdesk == IntGetActiveDesktop())
1431 {
1432 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1433 }
1434 else
1435 {
1436 ret = FALSE;
1437 }
1438
1439 UserLeave();
1440
1441 return ret;
1442 }
1443
1444 BOOL APIENTRY
1445 NtUserSetWindowStationUser(
1446 HWINSTA hWindowStation,
1447 PLUID pluid,
1448 PSID psid,
1449 DWORD size)
1450 {
1451 NTSTATUS Status;
1452 PWINSTATION_OBJECT WindowStation = NULL;
1453 BOOL Ret = FALSE;
1454
1455 UserEnterExclusive();
1456
1457 if (gpidLogon != PsGetCurrentProcessId())
1458 {
1459 EngSetLastError(ERROR_ACCESS_DENIED);
1460 goto Leave;
1461 }
1462
1463 Status = IntValidateWindowStationHandle(hWindowStation,
1464 KernelMode,
1465 0,
1466 &WindowStation,
1467 0);
1468 if (!NT_SUCCESS(Status))
1469 {
1470 goto Leave;
1471 }
1472
1473 if (WindowStation->psidUser)
1474 {
1475 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1476 }
1477
1478 WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
1479 if (WindowStation->psidUser == NULL)
1480 {
1481 EngSetLastError(ERROR_OUTOFMEMORY);
1482 goto Leave;
1483 }
1484
1485 _SEH2_TRY
1486 {
1487 ProbeForRead( psid, size, 1);
1488 ProbeForRead( pluid, sizeof(LUID), 1);
1489
1490 RtlCopyMemory(WindowStation->psidUser, psid, size);
1491 WindowStation->luidUser = *pluid;
1492 }
1493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1494 {
1495 Status = _SEH2_GetExceptionCode();
1496 }
1497 _SEH2_END;
1498
1499 if (!NT_SUCCESS(Status))
1500 {
1501 ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
1502 WindowStation->psidUser = 0;
1503 goto Leave;
1504 }
1505
1506 Ret = TRUE;
1507
1508 Leave:
1509 if (WindowStation) ObDereferenceObject(WindowStation);
1510 UserLeave();
1511 return Ret;
1512 }
1513
1514
1515 /* EOF */