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
13 DBG_DEFAULT_CHANNEL(UserWinsta
);
15 /* GLOBALS *******************************************************************/
17 /* Currently active window station */
18 PWINSTATION_OBJECT InputWindowStation
= NULL
;
20 /* Winlogon SAS window */
23 /* Full path to WindowStations directory */
24 UNICODE_STRING gustrWindowStationsDir
;
26 /* INITIALIZATION FUNCTIONS ****************************************************/
31 InitWindowStationImpl(VOID
)
33 GENERIC_MAPPING IntWindowStationMapping
= { WINSTA_READ
,
38 /* Set Winsta Object Attributes */
39 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
40 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
41 ExWindowStationObjectType
->TypeInfo
.ValidAccessMask
= WINSTA_ACCESS_ALL
;
43 return STATUS_SUCCESS
;
48 UserCreateWinstaDirectory(VOID
)
52 WCHAR wstrWindowStationsDir
[MAX_PATH
];
53 OBJECT_ATTRIBUTES ObjectAttributes
;
56 /* Create the WindowStations directory and cache its path for later use */
58 if(Peb
->SessionId
== 0)
60 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, WINSTA_OBJ_DIR
))
62 return STATUS_INSUFFICIENT_RESOURCES
;
67 swprintf(wstrWindowStationsDir
,
73 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, wstrWindowStationsDir
))
75 return STATUS_INSUFFICIENT_RESOURCES
;
79 InitializeObjectAttributes(&ObjectAttributes
,
80 &gustrWindowStationsDir
,
84 Status
= ZwCreateDirectoryObject(&hWinstaDir
, 0, &ObjectAttributes
);
85 if (!NT_SUCCESS(Status
))
87 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir
, Status
);
91 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir
, Peb
->SessionId
);
96 /* OBJECT CALLBACKS **********************************************************/
100 IntWinStaObjectDelete(
101 _In_ PVOID Parameters
)
103 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
104 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeleteParameters
->Object
;
106 TRACE("Deleting window station (0x%p)\n", WinSta
);
108 WinSta
->Flags
|= WSS_DYING
;
110 UserEmptyClipboardData(WinSta
);
112 RtlDestroyAtomTable(WinSta
->AtomTable
);
114 RtlFreeUnicodeString(&WinSta
->Name
);
116 return STATUS_SUCCESS
;
121 IntWinStaObjectParse(
122 _In_ PVOID Parameters
)
124 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters
= Parameters
;
125 PUNICODE_STRING RemainingName
= ParseParameters
->RemainingName
;
127 /* Assume we don't find anything */
128 *ParseParameters
->Object
= NULL
;
130 /* Check for an empty name */
131 if (!RemainingName
->Length
)
133 /* Make sure this is a window station, can't parse a desktop now */
134 if (ParseParameters
->ObjectType
!= ExWindowStationObjectType
)
137 return STATUS_OBJECT_TYPE_MISMATCH
;
140 /* Reference the window station and return */
141 ObReferenceObject(ParseParameters
->ParseObject
);
142 *ParseParameters
->Object
= ParseParameters
->ParseObject
;
143 return STATUS_SUCCESS
;
146 /* Check for leading slash */
147 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
150 RemainingName
->Buffer
++;
151 RemainingName
->Length
-= sizeof(WCHAR
);
152 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
155 /* Check if there is still a slash */
156 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
158 /* In this case, fail */
159 return STATUS_OBJECT_PATH_INVALID
;
163 * Check if we are parsing a desktop.
165 if (ParseParameters
->ObjectType
== ExDesktopObjectType
)
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
,
175 ParseParameters
->Context
,
176 ParseParameters
->SecurityQos
,
177 ParseParameters
->Object
);
180 /* Should hopefully never get here */
181 return STATUS_OBJECT_TYPE_MISMATCH
;
187 _In_ PVOID Parameters
)
189 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
192 ppi
= PsGetCurrentProcessWin32Process();
194 if(ppi
&& (OkToCloseParameters
->Handle
== ppi
->hwinsta
))
196 return STATUS_ACCESS_DENIED
;
199 return STATUS_SUCCESS
;
202 /* PRIVATE FUNCTIONS **********************************************************/
205 * IntValidateWindowStationHandle
207 * Validates the window station handle.
210 * If the function succeeds, the handle remains referenced. If the
211 * fucntion fails, last error is set.
215 IntValidateWindowStationHandle(
216 HWINSTA WindowStation
,
217 KPROCESSOR_MODE AccessMode
,
218 ACCESS_MASK DesiredAccess
,
219 PWINSTATION_OBJECT
*Object
,
220 POBJECT_HANDLE_INFORMATION pObjectHandleInfo
)
224 if (WindowStation
== NULL
)
226 ERR("Invalid window station handle\n");
227 EngSetLastError(ERROR_INVALID_HANDLE
);
228 return STATUS_INVALID_HANDLE
;
231 Status
= ObReferenceObjectByHandle(WindowStation
,
233 ExWindowStationObjectType
,
238 if (!NT_SUCCESS(Status
))
239 SetLastNtError(Status
);
245 co_IntInitializeDesktopGraphics(VOID
)
248 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
251 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
252 if (NULL
== ScreenDeviceContext
)
254 IntDestroyPrimarySurface();
257 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
259 if (! IntCreatePrimarySurface())
264 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
266 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
267 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
269 /* Update the SERVERINFO */
270 gpsi
->aiSysMet
[SM_CXSCREEN
] = gppdevPrimary
->gdiinfo
.ulHorzRes
;
271 gpsi
->aiSysMet
[SM_CYSCREEN
] = gppdevPrimary
->gdiinfo
.ulVertRes
;
272 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
273 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
274 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
275 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
276 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
278 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
281 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
282 // Font is realized and this dc was previously set to internal DC_ATTR.
283 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
284 gpsi
->tmSysFont
= tmw
;
286 /* Put the pointer in the center of the screen */
287 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
288 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
291 UserAttachMonitor((HDEV
)gppdevPrimary
);
293 /* Setup the cursor */
294 co_IntLoadDefaultCursors();
296 /* Setup the icons */
302 /* Show the desktop */
303 pdesk
= IntGetActiveDesktop();
305 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
311 IntEndDesktopGraphics(VOID
)
313 if (NULL
!= ScreenDeviceContext
)
314 { // No need to allocate a new dcattr.
315 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
316 GreDeleteObject(ScreenDeviceContext
);
317 ScreenDeviceContext
= NULL
;
319 IntHideDesktop(IntGetActiveDesktop());
320 IntDestroyPrimarySurface();
326 return ScreenDeviceContext
;
330 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess
)
332 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
333 if ( gpidLogon
!= PsGetCurrentProcessId() )
335 if (!(ppi
->W32PF_flags
& W32PF_IOWINSTA
))
337 ERR("Requires Interactive Window Station\n");
338 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
);
341 if (!RtlAreAllAccessesGranted(ppi
->amwinsta
, DesiredAccess
))
343 ERR("Access Denied\n");
344 EngSetLastError(ERROR_ACCESS_DENIED
);
352 /* PUBLIC FUNCTIONS ***********************************************************/
355 * NtUserCreateWindowStation
357 * Creates a new window station.
360 * lpszWindowStationName
361 * Pointer to a null-terminated string specifying the name of the
362 * window station to be created. Window station names are
363 * case-insensitive and cannot contain backslash characters (\).
364 * Only members of the Administrators group are allowed to specify a
368 * Requested type of access
371 * Security descriptor
373 * Unknown3, Unknown4, Unknown5, Unknown6
377 * If the function succeeds, the return value is a handle to the newly
378 * created window station. If the specified window station already
379 * exists, the function succeeds and returns a handle to the existing
380 * window station. If the function fails, the return value is NULL.
387 NtUserCreateWindowStation(
388 POBJECT_ATTRIBUTES ObjectAttributes
,
389 ACCESS_MASK dwDesiredAccess
,
396 UNICODE_STRING WindowStationName
;
397 PWINSTATION_OBJECT WindowStationObject
;
398 HWINSTA WindowStation
;
401 TRACE("NtUserCreateWindowStation called\n");
403 Status
= ObOpenObjectByName(ObjectAttributes
,
404 ExWindowStationObjectType
,
409 (PVOID
*)&WindowStation
);
411 if (NT_SUCCESS(Status
))
413 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes
->ObjectName
);
414 return (HWINSTA
)WindowStation
;
418 * No existing window station found, try to create new one
421 /* Capture window station name */
424 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
425 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
, ObjectAttributes
->ObjectName
);
427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
429 Status
=_SEH2_GetExceptionCode();
433 if (! NT_SUCCESS(Status
))
435 ERR("Failed reading capturing window station name\n");
436 SetLastNtError(Status
);
440 /* Create the window station object */
441 Status
= ObCreateObject(UserMode
,
442 ExWindowStationObjectType
,
446 sizeof(WINSTATION_OBJECT
),
449 (PVOID
*)&WindowStationObject
);
451 if (!NT_SUCCESS(Status
))
453 ERR("ObCreateObject failed with %lx for window station %wZ\n", Status
, &WindowStationName
);
454 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
455 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
459 /* Initialize the window station */
460 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
462 InitializeListHead(&WindowStationObject
->DesktopListHead
);
463 WindowStationObject
->Name
= WindowStationName
;
464 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
465 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
466 if (!NT_SUCCESS(Status
))
468 ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status
, &WindowStationName
);
469 ObDereferenceObject(WindowStationObject
);
470 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
474 Status
= ObInsertObject((PVOID
)WindowStationObject
,
479 (PVOID
*)&WindowStation
);
481 if (!NT_SUCCESS(Status
))
483 ERR("ObInsertObject failed with %lx for window station\n", Status
);
484 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
488 if (InputWindowStation
== NULL
)
490 ERR("Initializing input window station\n");
491 InputWindowStation
= WindowStationObject
;
493 WindowStationObject
->Flags
&= ~WSS_NOIO
;
499 WindowStationObject
->Flags
|= WSS_NOIO
;
502 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
503 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
504 return WindowStation
;
508 * NtUserOpenWindowStation
510 * Opens an existing window station.
513 * lpszWindowStationName
514 * Name of the existing window station.
517 * Requested type of access.
520 * If the function succeeds, the return value is the handle to the
521 * specified window station. If the function fails, the return value
525 * The returned handle can be closed with NtUserCloseWindowStation.
532 NtUserOpenWindowStation(
533 POBJECT_ATTRIBUTES ObjectAttributes
,
534 ACCESS_MASK dwDesiredAccess
)
539 Status
= ObOpenObjectByName(ObjectAttributes
,
540 ExWindowStationObjectType
,
547 if (!NT_SUCCESS(Status
))
549 ERR("NtUserOpenWindowStation failed\n");
550 SetLastNtError(Status
);
554 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes
->ObjectName
, hwinsta
);
560 * NtUserCloseWindowStation
562 * Closes a window station handle.
566 * Handle to the window station.
572 * The window station handle can be created with NtUserCreateWindowStation
573 * or NtUserOpenWindowStation. Attemps to close a handle to the window
574 * station assigned to the calling process will fail.
582 NtUserCloseWindowStation(
585 PWINSTATION_OBJECT Object
;
588 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
590 if (hWinSta
== UserGetProcessWindowStation())
592 ERR("Attempted to close process window station\n");
596 Status
= IntValidateWindowStationHandle(hWinSta
,
602 if (!NT_SUCCESS(Status
))
604 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
608 ObDereferenceObject(Object
);
610 TRACE("Closing window station handle (%p)\n", hWinSta
);
612 Status
= ObCloseHandle(hWinSta
, UserMode
);
613 if (!NT_SUCCESS(Status
))
615 SetLastNtError(Status
);
623 * NtUserGetObjectInformation
625 * The NtUserGetObjectInformation function retrieves information about a
626 * window station or desktop object.
630 * Handle to the window station or desktop object for which to
631 * return information. This can be a handle of type HDESK or HWINSTA
632 * (for example, a handle returned by NtUserCreateWindowStation,
633 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
636 * Specifies the object information to be retrieved.
639 * Pointer to a buffer to receive the object information.
642 * Specifies the size, in bytes, of the buffer pointed to by the
646 * Pointer to a variable receiving the number of bytes required to
647 * store the requested information. If this variable's value is
648 * greater than the value of the nLength parameter when the function
649 * returns, the function returns FALSE, and none of the information
650 * is copied to the pvInfo buffer. If the value of the variable pointed
651 * to by lpnLengthNeeded is less than or equal to the value of nLength,
652 * the entire information block is copied.
655 * If the function succeeds, the return value is nonzero. If the function
656 * fails, the return value is zero.
663 NtUserGetObjectInformation(
668 PDWORD nLengthNeeded
)
671 PWINSTATION_OBJECT WinStaObject
= NULL
;
672 PDESKTOP DesktopObject
= NULL
;
673 USEROBJECTFLAGS ObjectFlags
;
675 SIZE_T nDataSize
= 0;
680 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
681 ProbeForWrite(pvInformation
, nLength
, 1);
683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
685 SetLastNtError(_SEH2_GetExceptionCode());
690 /* Try window station */
691 TRACE("Trying to open window station %p\n", hObject
);
692 Status
= ObReferenceObjectByHandle(hObject
,
694 ExWindowStationObjectType
,
696 (PVOID
*)&WinStaObject
,
699 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
702 TRACE("Trying to open desktop %p\n", hObject
);
704 Status
= IntValidateDesktopHandle(hObject
,
710 if (!NT_SUCCESS(Status
))
712 ERR("Failed: 0x%x\n", Status
);
716 TRACE("WinSta or Desktop opened!\n");
723 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo
;
726 ObjectFlags
.fReserved
= FALSE
;
728 /* Check whether this handle is inheritable */
729 Status
= ZwQueryObject(hObject
,
730 ObjectHandleFlagInformation
,
732 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
734 if (!NT_SUCCESS(Status
))
736 ERR("ZwQueryObject failed, Status 0x%08lx\n", Status
);
739 ObjectFlags
.fInherit
= HandleInfo
.Inherit
;
741 ObjectFlags
.dwFlags
= 0;
742 if (WinStaObject
!= NULL
)
744 if (!(WinStaObject
->Flags
& WSS_NOIO
))
745 ObjectFlags
.dwFlags
|= WSF_VISIBLE
;
747 else if (DesktopObject
!= NULL
)
749 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
753 ERR("No associated WinStaObject nor DesktopObject!\n");
756 pvData
= &ObjectFlags
;
757 nDataSize
= sizeof(ObjectFlags
);
758 Status
= STATUS_SUCCESS
;
764 if (WinStaObject
!= NULL
)
766 pvData
= WinStaObject
->Name
.Buffer
;
767 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
768 Status
= STATUS_SUCCESS
;
770 else if (DesktopObject
!= NULL
)
772 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
773 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
774 Status
= STATUS_SUCCESS
;
778 Status
= STATUS_INVALID_PARAMETER
;
785 if (WinStaObject
!= NULL
)
787 pvData
= L
"WindowStation";
788 nDataSize
= sizeof(L
"WindowStation");
789 Status
= STATUS_SUCCESS
;
791 else if (DesktopObject
!= NULL
)
794 nDataSize
= sizeof(L
"Desktop");
795 Status
= STATUS_SUCCESS
;
799 Status
= STATUS_INVALID_PARAMETER
;
805 Status
= STATUS_NOT_IMPLEMENTED
;
806 ERR("UOI_USER_SID unimplemented!\n");
810 Status
= STATUS_INVALID_PARAMETER
;
815 if ((Status
== STATUS_SUCCESS
) && (nLength
< nDataSize
))
816 Status
= STATUS_BUFFER_TOO_SMALL
;
821 *nLengthNeeded
= nDataSize
;
823 /* Try to copy data to caller */
824 if (Status
== STATUS_SUCCESS
)
826 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
827 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
830 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
832 Status
= _SEH2_GetExceptionCode();
836 /* Release objects */
837 if (DesktopObject
!= NULL
)
838 ObDereferenceObject(DesktopObject
);
839 if (WinStaObject
!= NULL
)
840 ObDereferenceObject(WinStaObject
);
842 if (!NT_SUCCESS(Status
))
844 SetLastNtError(Status
);
852 * NtUserSetObjectInformation
854 * The NtUserSetObjectInformation function sets information about a
855 * window station or desktop object.
859 * Handle to the window station or desktop object for which to set
860 * object information. This value can be a handle of type HDESK or
864 * Specifies the object information to be set.
867 * Pointer to a buffer containing the object information.
870 * Specifies the size, in bytes, of the information contained in the
871 * buffer pointed to by pvInfo.
874 * If the function succeeds, the return value is nonzero. If the function
875 * fails the return value is zero.
883 NtUserSetObjectInformation(
889 /* FIXME: ZwQueryObject */
890 /* FIXME: ZwSetInformationObject */
891 SetLastNtError(STATUS_UNSUCCESSFUL
);
899 UserGetProcessWindowStation(VOID
)
901 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
908 * NtUserGetProcessWindowStation
910 * Returns a handle to the current process window station.
913 * If the function succeeds, the return value is handle to the window
914 * station assigned to the current process. If the function fails, the
915 * return value is NULL.
922 NtUserGetProcessWindowStation(VOID
)
924 return UserGetProcessWindowStation();
928 UserSetProcessWindowStation(HWINSTA hWindowStation
)
933 OBJECT_HANDLE_INFORMATION ObjectHandleInfo
;
934 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
936 ppi
= PsGetCurrentProcessWin32Process();
938 /* Reference the new window station */
939 if (hWindowStation
!= NULL
)
941 Status
= IntValidateWindowStationHandle(hWindowStation
,
946 if (!NT_SUCCESS(Status
))
948 TRACE("Validation of window station handle (%p) failed\n",
950 SetLastNtError(Status
);
955 OldWinSta
= ppi
->prpwinsta
;
956 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
958 /* Dereference the previous window station */
959 if (OldWinSta
!= NULL
)
961 ObDereferenceObject(OldWinSta
);
964 /* Check if we have a stale handle (it should happen for console apps) */
965 if (hwinstaOld
!= ppi
->hwinsta
)
967 ObCloseHandle(hwinstaOld
, UserMode
);
971 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
974 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
976 ppi
->prpwinsta
= NewWinSta
;
977 ppi
->hwinsta
= hWindowStation
;
978 ppi
->amwinsta
= hWindowStation
!= NULL
? ObjectHandleInfo
.GrantedAccess
: 0;
979 TRACE("WS : Granted Access 0x%08lx\n",ppi
->amwinsta
);
981 if (RtlAreAllAccessesGranted(ppi
->amwinsta
, WINSTA_READSCREEN
))
983 ppi
->W32PF_flags
|= W32PF_READSCREENACCESSGRANTED
;
987 ppi
->W32PF_flags
&= ~W32PF_READSCREENACCESSGRANTED
;
990 if (NewWinSta
&& !(NewWinSta
->Flags
& WSS_NOIO
))
992 ppi
->W32PF_flags
|= W32PF_IOWINSTA
;
994 else // Might be closed if the handle is null.
996 ppi
->W32PF_flags
&= ~W32PF_IOWINSTA
;
1002 * NtUserSetProcessWindowStation
1004 * Assigns a window station to the current process.
1008 * Handle to the window station.
1018 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1022 UserEnterExclusive();
1024 ret
= UserSetProcessWindowStation(hWindowStation
);
1032 * NtUserLockWindowStation
1034 * Locks switching desktops. Only the logon application is allowed to call this function.
1041 NtUserLockWindowStation(HWINSTA hWindowStation
)
1043 PWINSTATION_OBJECT Object
;
1046 TRACE("About to set process window station with handle (%p)\n",
1049 if (gpidLogon
!= PsGetCurrentProcessId())
1051 ERR("Unauthorized process attempted to lock the window station!\n");
1052 EngSetLastError(ERROR_ACCESS_DENIED
);
1056 Status
= IntValidateWindowStationHandle(hWindowStation
,
1061 if (!NT_SUCCESS(Status
))
1063 TRACE("Validation of window station handle (%p) failed\n",
1065 SetLastNtError(Status
);
1069 Object
->Flags
|= WSS_LOCKED
;
1071 ObDereferenceObject(Object
);
1076 * NtUserUnlockWindowStation
1078 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1085 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1087 PWINSTATION_OBJECT Object
;
1091 TRACE("About to set process window station with handle (%p)\n",
1094 if (gpidLogon
!= PsGetCurrentProcessId())
1096 ERR("Unauthorized process attempted to unlock the window station!\n");
1097 EngSetLastError(ERROR_ACCESS_DENIED
);
1101 Status
= IntValidateWindowStationHandle(hWindowStation
,
1106 if (!NT_SUCCESS(Status
))
1108 TRACE("Validation of window station handle (%p) failed\n",
1110 SetLastNtError(Status
);
1114 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1115 Object
->Flags
&= ~WSS_LOCKED
;
1117 ObDereferenceObject(Object
);
1121 static NTSTATUS FASTCALL
1122 BuildWindowStationNameList(
1125 PULONG pRequiredSize
)
1127 OBJECT_ATTRIBUTES ObjectAttributes
;
1129 HANDLE DirectoryHandle
;
1130 char InitialBuffer
[256], *Buffer
;
1131 ULONG Context
, ReturnLength
, BufferSize
;
1133 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1137 * Try to open the directory.
1139 InitializeObjectAttributes(&ObjectAttributes
,
1140 &gustrWindowStationsDir
,
1141 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1145 Status
= ZwOpenDirectoryObject(&DirectoryHandle
,
1149 if (!NT_SUCCESS(Status
))
1154 /* First try to query the directory using a fixed-size buffer */
1157 Status
= ZwQueryDirectoryObject(DirectoryHandle
,
1159 sizeof(InitialBuffer
),
1164 if (NT_SUCCESS(Status
))
1166 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1167 FALSE
, &Context
, NULL
))
1169 /* Our fixed-size buffer is large enough */
1170 Buffer
= InitialBuffer
;
1176 /* Need a larger buffer, check how large exactly */
1177 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1179 if (!NT_SUCCESS(Status
))
1181 ERR("ZwQueryDirectoryObject failed\n");
1182 ZwClose(DirectoryHandle
);
1186 BufferSize
= ReturnLength
;
1187 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1190 ZwClose(DirectoryHandle
);
1191 return STATUS_NO_MEMORY
;
1194 /* We should have a sufficiently large buffer now */
1196 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1197 FALSE
, TRUE
, &Context
, &ReturnLength
);
1198 if (! NT_SUCCESS(Status
) ||
1199 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1200 FALSE
, &Context
, NULL
))
1202 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1203 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1204 ZwClose(DirectoryHandle
);
1205 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1209 ZwClose(DirectoryHandle
);
1212 * Count the required size of buffer.
1214 ReturnLength
= sizeof(DWORD
);
1216 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1217 0 != DirEntry
->Name
.Length
;
1220 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1223 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1224 if (NULL
!= pRequiredSize
)
1226 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1227 if (! NT_SUCCESS(Status
))
1229 if (Buffer
!= InitialBuffer
)
1231 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1233 return STATUS_BUFFER_TOO_SMALL
;
1238 * Check if the supplied buffer is large enough.
1240 if (dwSize
< ReturnLength
)
1242 if (Buffer
!= InitialBuffer
)
1244 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1246 return STATUS_BUFFER_TOO_SMALL
;
1250 * Generate the resulting buffer contents.
1252 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1253 if (! NT_SUCCESS(Status
))
1255 if (Buffer
!= InitialBuffer
)
1257 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1261 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1264 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1265 0 != DirEntry
->Name
.Length
;
1268 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1269 if (! NT_SUCCESS(Status
))
1271 if (Buffer
!= InitialBuffer
)
1273 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1277 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1278 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1279 if (! NT_SUCCESS(Status
))
1281 if (Buffer
!= InitialBuffer
)
1283 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1287 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1293 if (Buffer
!= InitialBuffer
)
1295 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1298 return STATUS_SUCCESS
;
1301 static NTSTATUS FASTCALL
1302 BuildDesktopNameList(
1303 HWINSTA hWindowStation
,
1306 PULONG pRequiredSize
)
1309 PWINSTATION_OBJECT WindowStation
;
1310 PLIST_ENTRY DesktopEntry
;
1311 PDESKTOP DesktopObject
;
1315 UNICODE_STRING DesktopName
;
1317 Status
= IntValidateWindowStationHandle(hWindowStation
,
1322 if (! NT_SUCCESS(Status
))
1328 * Count the required size of buffer.
1330 ReturnLength
= sizeof(DWORD
);
1332 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1333 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1334 DesktopEntry
= DesktopEntry
->Flink
)
1336 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1337 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1338 ReturnLength
+= DesktopName
.Length
+ sizeof(WCHAR
);
1341 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1342 if (NULL
!= pRequiredSize
)
1344 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1345 if (! NT_SUCCESS(Status
))
1347 ObDereferenceObject(WindowStation
);
1348 return STATUS_BUFFER_TOO_SMALL
;
1353 * Check if the supplied buffer is large enough.
1355 if (dwSize
< ReturnLength
)
1357 ObDereferenceObject(WindowStation
);
1358 return STATUS_BUFFER_TOO_SMALL
;
1362 * Generate the resulting buffer contents.
1364 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1365 if (! NT_SUCCESS(Status
))
1367 ObDereferenceObject(WindowStation
);
1370 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1373 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1374 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1375 DesktopEntry
= DesktopEntry
->Flink
)
1377 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1378 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1379 Status
= MmCopyToCaller(lpBuffer
, DesktopName
.Buffer
, DesktopName
.Length
);
1380 if (! NT_SUCCESS(Status
))
1382 ObDereferenceObject(WindowStation
);
1385 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
.Length
);
1386 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1387 if (! NT_SUCCESS(Status
))
1389 ObDereferenceObject(WindowStation
);
1392 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1396 * Clean up and return
1398 ObDereferenceObject(WindowStation
);
1399 return STATUS_SUCCESS
;
1403 * NtUserBuildNameList
1405 * Function used for enumeration of desktops or window stations.
1409 * For enumeration of window stations this parameter must be set to
1410 * zero. Otherwise it's handle for window station.
1413 * Size of buffer passed by caller.
1416 * Buffer passed by caller. If the function succeeds, the buffer is
1417 * filled with window station/desktop count (in first DWORD) and
1418 * NULL-terminated window station/desktop names.
1421 * If the function succeeds, this is the number of bytes copied.
1422 * Otherwise it's size of buffer needed for function to succeed.
1429 NtUserBuildNameList(
1430 HWINSTA hWindowStation
,
1433 PULONG pRequiredSize
)
1435 /* The WindowStation name list and desktop name list are build in completely
1436 different ways. Call the appropriate function */
1437 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1438 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1445 NtUserSetLogonNotifyWindow(HWND hWnd
)
1447 if (gpidLogon
!= PsGetCurrentProcessId())
1452 if (!IntIsWindow(hWnd
))
1464 NtUserLockWorkStation(VOID
)
1467 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1469 UserEnterExclusive();
1471 if (pti
->rpdesk
== IntGetActiveDesktop())
1473 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);
1487 NtUserSetWindowStationUser(
1488 IN HWINSTA hWindowStation
,
1490 IN PSID psid OPTIONAL
,
1495 PWINSTATION_OBJECT WindowStation
= NULL
;
1498 UserEnterExclusive();
1500 if (gpidLogon
!= PsGetCurrentProcessId())
1502 EngSetLastError(ERROR_ACCESS_DENIED
);
1506 /* Validate the window station */
1507 Status
= IntValidateWindowStationHandle(hWindowStation
,
1512 if (!NT_SUCCESS(Status
))
1517 /* Capture the user LUID */
1520 ProbeForRead(pluid
, sizeof(LUID
), 1);
1523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1525 Status
= _SEH2_GetExceptionCode();
1526 _SEH2_YIELD(goto Leave
);
1530 /* Reset the window station user LUID */
1531 RtlZeroMemory(&WindowStation
->luidUser
, sizeof(LUID
));
1533 /* Reset the window station user SID */
1534 if (WindowStation
->psidUser
)
1536 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
1537 WindowStation
->psidUser
= NULL
;
1540 /* Copy the new user SID if one has been provided */
1543 WindowStation
->psidUser
= ExAllocatePoolWithTag(PagedPool
, size
, USERTAG_SECURITY
);
1544 if (WindowStation
->psidUser
== NULL
)
1546 EngSetLastError(ERROR_OUTOFMEMORY
);
1550 Status
= STATUS_SUCCESS
;
1553 ProbeForRead(psid
, size
, 1);
1554 RtlCopyMemory(WindowStation
->psidUser
, psid
, size
);
1556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1558 Status
= _SEH2_GetExceptionCode();
1562 if (!NT_SUCCESS(Status
))
1564 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
1565 WindowStation
->psidUser
= NULL
;
1570 /* Copy the new user LUID */
1571 WindowStation
->luidUser
= luidUser
;
1577 ObDereferenceObject(WindowStation
);