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 OBJECT_ATTRIBUTES ObjectAttributes
;
54 WCHAR wstrWindowStationsDir
[MAX_PATH
];
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 Status
= RtlStringCbPrintfW(wstrWindowStationsDir
,
68 sizeof(wstrWindowStationsDir
),
73 if (!NT_SUCCESS(Status
))
76 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, wstrWindowStationsDir
))
78 return STATUS_INSUFFICIENT_RESOURCES
;
82 InitializeObjectAttributes(&ObjectAttributes
,
83 &gustrWindowStationsDir
,
87 Status
= ZwCreateDirectoryObject(&hWinstaDir
, DIRECTORY_CREATE_OBJECT
, &ObjectAttributes
);
88 if (!NT_SUCCESS(Status
))
90 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir
, Status
);
94 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir
, Peb
->SessionId
);
99 /* OBJECT CALLBACKS **********************************************************/
103 IntWinStaObjectDelete(
104 _In_ PVOID Parameters
)
106 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
107 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeleteParameters
->Object
;
109 TRACE("Deleting window station (0x%p)\n", WinSta
);
111 WinSta
->Flags
|= WSS_DYING
;
113 UserEmptyClipboardData(WinSta
);
115 RtlDestroyAtomTable(WinSta
->AtomTable
);
117 RtlFreeUnicodeString(&WinSta
->Name
);
119 return STATUS_SUCCESS
;
124 IntWinStaObjectParse(
125 _In_ PVOID Parameters
)
127 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters
= Parameters
;
128 PUNICODE_STRING RemainingName
= ParseParameters
->RemainingName
;
130 /* Assume we don't find anything */
131 *ParseParameters
->Object
= NULL
;
133 /* Check for an empty name */
134 if (!RemainingName
->Length
)
136 /* Make sure this is a window station, can't parse a desktop now */
137 if (ParseParameters
->ObjectType
!= ExWindowStationObjectType
)
140 return STATUS_OBJECT_TYPE_MISMATCH
;
143 /* Reference the window station and return */
144 ObReferenceObject(ParseParameters
->ParseObject
);
145 *ParseParameters
->Object
= ParseParameters
->ParseObject
;
146 return STATUS_SUCCESS
;
149 /* Check for leading slash */
150 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
153 RemainingName
->Buffer
++;
154 RemainingName
->Length
-= sizeof(WCHAR
);
155 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
158 /* Check if there is still a slash */
159 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
161 /* In this case, fail */
162 return STATUS_OBJECT_PATH_INVALID
;
166 * Check if we are parsing a desktop.
168 if (ParseParameters
->ObjectType
== ExDesktopObjectType
)
170 /* Then call the desktop parse routine */
171 return IntDesktopObjectParse(ParseParameters
->ParseObject
,
172 ParseParameters
->ObjectType
,
173 ParseParameters
->AccessState
,
174 ParseParameters
->AccessMode
,
175 ParseParameters
->Attributes
,
176 ParseParameters
->CompleteName
,
178 ParseParameters
->Context
,
179 ParseParameters
->SecurityQos
,
180 ParseParameters
->Object
);
183 /* Should hopefully never get here */
184 return STATUS_OBJECT_TYPE_MISMATCH
;
190 _In_ PVOID Parameters
)
192 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
195 ppi
= PsGetCurrentProcessWin32Process();
197 if(ppi
&& (OkToCloseParameters
->Handle
== ppi
->hwinsta
))
199 return STATUS_ACCESS_DENIED
;
202 return STATUS_SUCCESS
;
205 /* PRIVATE FUNCTIONS **********************************************************/
208 * IntValidateWindowStationHandle
210 * Validates the window station handle.
213 * If the function succeeds, the handle remains referenced. If the
214 * fucntion fails, last error is set.
218 IntValidateWindowStationHandle(
219 HWINSTA WindowStation
,
220 KPROCESSOR_MODE AccessMode
,
221 ACCESS_MASK DesiredAccess
,
222 PWINSTATION_OBJECT
*Object
,
223 POBJECT_HANDLE_INFORMATION pObjectHandleInfo
)
227 if (WindowStation
== NULL
)
229 ERR("Invalid window station handle\n");
230 EngSetLastError(ERROR_INVALID_HANDLE
);
231 return STATUS_INVALID_HANDLE
;
234 Status
= ObReferenceObjectByHandle(WindowStation
,
236 ExWindowStationObjectType
,
241 if (!NT_SUCCESS(Status
))
242 SetLastNtError(Status
);
248 co_IntInitializeDesktopGraphics(VOID
)
251 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
254 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
255 if (NULL
== ScreenDeviceContext
)
257 IntDestroyPrimarySurface();
260 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
262 if (! IntCreatePrimarySurface())
267 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
269 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
270 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
272 /* Update the SERVERINFO */
273 gpsi
->aiSysMet
[SM_CXSCREEN
] = gppdevPrimary
->gdiinfo
.ulHorzRes
;
274 gpsi
->aiSysMet
[SM_CYSCREEN
] = gppdevPrimary
->gdiinfo
.ulVertRes
;
275 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
276 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
277 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
278 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
279 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
281 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
284 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
285 // Font is realized and this dc was previously set to internal DC_ATTR.
286 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
287 gpsi
->tmSysFont
= tmw
;
289 /* Put the pointer in the center of the screen */
290 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
291 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
294 UserAttachMonitor((HDEV
)gppdevPrimary
);
296 /* Setup the cursor */
297 co_IntLoadDefaultCursors();
299 /* Setup the icons */
305 /* Show the desktop */
306 pdesk
= IntGetActiveDesktop();
308 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
314 IntEndDesktopGraphics(VOID
)
316 if (NULL
!= ScreenDeviceContext
)
317 { // No need to allocate a new dcattr.
318 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
319 GreDeleteObject(ScreenDeviceContext
);
320 ScreenDeviceContext
= NULL
;
322 IntHideDesktop(IntGetActiveDesktop());
323 IntDestroyPrimarySurface();
329 return ScreenDeviceContext
;
333 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess
)
335 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
336 if ( gpidLogon
!= PsGetCurrentProcessId() )
338 if (!(ppi
->W32PF_flags
& W32PF_IOWINSTA
))
340 ERR("Requires Interactive Window Station\n");
341 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
);
344 if (!RtlAreAllAccessesGranted(ppi
->amwinsta
, DesiredAccess
))
346 ERR("Access Denied\n");
347 EngSetLastError(ERROR_ACCESS_DENIED
);
355 /* PUBLIC FUNCTIONS ***********************************************************/
358 * NtUserCreateWindowStation
360 * Creates a new window station.
363 * lpszWindowStationName
364 * Pointer to a null-terminated string specifying the name of the
365 * window station to be created. Window station names are
366 * case-insensitive and cannot contain backslash characters (\).
367 * Only members of the Administrators group are allowed to specify a
371 * Requested type of access
374 * Security descriptor
376 * Unknown3, Unknown4, Unknown5, Unknown6
380 * If the function succeeds, the return value is a handle to the newly
381 * created window station. If the specified window station already
382 * exists, the function succeeds and returns a handle to the existing
383 * window station. If the function fails, the return value is NULL.
391 IntCreateWindowStation(
392 OUT HWINSTA
* phWinSta
,
393 IN POBJECT_ATTRIBUTES ObjectAttributes
,
394 IN KPROCESSOR_MODE AccessMode
,
395 IN ACCESS_MASK dwDesiredAccess
,
403 HWINSTA WindowStation
;
404 PWINSTATION_OBJECT WindowStationObject
;
406 TRACE("IntCreateWindowStation called\n");
411 Status
= ObOpenObjectByName(ObjectAttributes
,
412 ExWindowStationObjectType
,
417 (PVOID
*)&WindowStation
);
418 if (NT_SUCCESS(Status
))
420 TRACE("IntCreateWindowStation opened window station %wZ\n",
421 ObjectAttributes
->ObjectName
);
422 *phWinSta
= WindowStation
;
427 * No existing window station found, try to create new one.
430 /* Create the window station object */
431 Status
= ObCreateObject(KernelMode
,
432 ExWindowStationObjectType
,
436 sizeof(WINSTATION_OBJECT
),
439 (PVOID
*)&WindowStationObject
);
440 if (!NT_SUCCESS(Status
))
442 ERR("ObCreateObject failed with %lx for window station %wZ\n",
443 Status
, ObjectAttributes
->ObjectName
);
444 SetLastNtError(Status
);
448 /* Initialize the window station */
449 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
451 InitializeListHead(&WindowStationObject
->DesktopListHead
);
452 WindowStationObject
->Name
= *ObjectAttributes
->ObjectName
;
453 ObjectAttributes
->ObjectName
= NULL
; // FIXME! (see NtUserCreateWindowStation())
454 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
455 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
456 if (!NT_SUCCESS(Status
))
458 ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status
, ObjectAttributes
->ObjectName
);
459 ObDereferenceObject(WindowStationObject
);
460 SetLastNtError(Status
);
464 Status
= ObInsertObject(WindowStationObject
,
469 (PVOID
*)&WindowStation
);
470 if (!NT_SUCCESS(Status
))
472 ERR("ObInsertObject failed with %lx for window station\n", Status
);
473 SetLastNtError(Status
);
477 // FIXME! TODO: Add this new window station to a linked list
479 if (InputWindowStation
== NULL
)
481 ERR("Initializing input window station\n");
482 InputWindowStation
= WindowStationObject
;
484 WindowStationObject
->Flags
&= ~WSS_NOIO
;
490 WindowStationObject
->Flags
|= WSS_NOIO
;
493 TRACE("IntCreateWindowStation created object 0x%p with name %wZ handle 0x%p\n",
494 WindowStationObject
, &WindowStationObject
->Name
, WindowStation
);
496 *phWinSta
= WindowStation
;
497 return STATUS_SUCCESS
;
502 NtUserCreateWindowStation(
503 IN POBJECT_ATTRIBUTES ObjectAttributes
,
504 IN ACCESS_MASK dwDesiredAccess
,
513 OBJECT_ATTRIBUTES LocalObjectAttributes
;
514 UNICODE_STRING WindowStationName
;
515 KPROCESSOR_MODE AccessMode
= UserMode
;
517 TRACE("NtUserCreateWindowStation called\n");
519 /* Capture window station name */
522 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
523 LocalObjectAttributes
= *ObjectAttributes
;
524 if (LocalObjectAttributes
.ObjectName
||
525 LocalObjectAttributes
.RootDirectory
527 LocalObjectAttributes.ObjectName->Buffer &&
528 LocalObjectAttributes.ObjectName->Length > 0 */)
530 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
,
531 LocalObjectAttributes
.ObjectName
);
532 LocalObjectAttributes
.ObjectName
= &WindowStationName
;
536 LocalObjectAttributes
.ObjectName
= NULL
;
537 Status
= STATUS_SUCCESS
;
540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
542 Status
=_SEH2_GetExceptionCode();
546 if (!NT_SUCCESS(Status
))
548 ERR("Failed reading or capturing window station name, Status 0x%08lx\n", Status
);
549 SetLastNtError(Status
);
554 * If the caller did not provide a window station name, build a new one
555 * based on the logon session identifier for the calling process.
557 if (!LocalObjectAttributes
.ObjectName
)
560 WCHAR ServiceWinStaName
[MAX_PATH
];
562 /* Retrieve the LUID of the current process */
563 Status
= GetProcessLuid(NULL
, NULL
, &CallerLuid
);
564 if (!NT_SUCCESS(Status
))
566 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status
);
567 SetLastNtError(Status
);
571 /* Build a valid window station name from the LUID */
572 Status
= RtlStringCbPrintfW(ServiceWinStaName
,
573 sizeof(ServiceWinStaName
),
574 L
"%wZ\\Service-0x%x-%x$",
575 &gustrWindowStationsDir
,
578 if (!NT_SUCCESS(Status
))
580 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status
);
581 SetLastNtError(Status
);
585 WindowStationName
.Length
= wcslen(ServiceWinStaName
) * sizeof(WCHAR
);
586 WindowStationName
.MaximumLength
=
587 WindowStationName
.Length
+ sizeof(UNICODE_NULL
);
588 WindowStationName
.Buffer
=
589 ExAllocatePoolWithTag(PagedPool
,
590 WindowStationName
.MaximumLength
,
592 if (!WindowStationName
.Buffer
)
594 Status
= STATUS_NO_MEMORY
;
595 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status
);
596 SetLastNtError(Status
);
599 RtlStringCbCopyW(WindowStationName
.Buffer
,
600 WindowStationName
.MaximumLength
,
602 LocalObjectAttributes
.ObjectName
= &WindowStationName
;
603 AccessMode
= KernelMode
;
606 // TODO: Capture and use the SecurityQualityOfService!
608 Status
= IntCreateWindowStation(&hWinSta
,
609 &LocalObjectAttributes
,
618 // FIXME! Because in some situations we store the allocated window station name
619 // inside the window station, we must not free it now! We know this fact when
620 // IntCreateWindowStation() sets LocalObjectAttributes.ObjectName to NULL.
621 // This hack must be removed once we just use the stored Ob name instead
622 // (in which case we will always free the allocated name here).
623 if (LocalObjectAttributes
.ObjectName
)
624 ExFreePoolWithTag(LocalObjectAttributes
.ObjectName
->Buffer
, TAG_STRING
);
626 if (NT_SUCCESS(Status
))
628 TRACE("NtUserCreateWindowStation created a window station with handle 0x%p\n", hWinSta
);
632 ASSERT(hWinSta
== NULL
);
633 TRACE("NtUserCreateWindowStation failed to create a window station!\n");
640 * NtUserOpenWindowStation
642 * Opens an existing window station.
645 * lpszWindowStationName
646 * Name of the existing window station.
649 * Requested type of access.
652 * If the function succeeds, the return value is the handle to the
653 * specified window station. If the function fails, the return value
657 * The returned handle can be closed with NtUserCloseWindowStation.
664 NtUserOpenWindowStation(
665 POBJECT_ATTRIBUTES ObjectAttributes
,
666 ACCESS_MASK dwDesiredAccess
)
671 Status
= ObOpenObjectByName(ObjectAttributes
,
672 ExWindowStationObjectType
,
679 if (!NT_SUCCESS(Status
))
681 ERR("NtUserOpenWindowStation failed\n");
682 SetLastNtError(Status
);
686 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes
->ObjectName
, hwinsta
);
692 * NtUserCloseWindowStation
694 * Closes a window station handle.
698 * Handle to the window station.
704 * The window station handle can be created with NtUserCreateWindowStation
705 * or NtUserOpenWindowStation. Attemps to close a handle to the window
706 * station assigned to the calling process will fail.
714 NtUserCloseWindowStation(
717 PWINSTATION_OBJECT Object
;
720 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
722 if (hWinSta
== UserGetProcessWindowStation())
724 ERR("Attempted to close process window station\n");
728 Status
= IntValidateWindowStationHandle(hWinSta
,
734 if (!NT_SUCCESS(Status
))
736 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
740 ObDereferenceObject(Object
);
742 TRACE("Closing window station handle (%p)\n", hWinSta
);
744 Status
= ObCloseHandle(hWinSta
, UserMode
);
745 if (!NT_SUCCESS(Status
))
747 SetLastNtError(Status
);
755 * NtUserGetObjectInformation
757 * The NtUserGetObjectInformation function retrieves information about a
758 * window station or desktop object.
762 * Handle to the window station or desktop object for which to
763 * return information. This can be a handle of type HDESK or HWINSTA
764 * (for example, a handle returned by NtUserCreateWindowStation,
765 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
768 * Specifies the object information to be retrieved.
771 * Pointer to a buffer to receive the object information.
774 * Specifies the size, in bytes, of the buffer pointed to by the
778 * Pointer to a variable receiving the number of bytes required to
779 * store the requested information. If this variable's value is
780 * greater than the value of the nLength parameter when the function
781 * returns, the function returns FALSE, and none of the information
782 * is copied to the pvInfo buffer. If the value of the variable pointed
783 * to by lpnLengthNeeded is less than or equal to the value of nLength,
784 * the entire information block is copied.
787 * If the function succeeds, the return value is nonzero. If the function
788 * fails, the return value is zero.
795 NtUserGetObjectInformation(
800 PDWORD nLengthNeeded
)
803 PWINSTATION_OBJECT WinStaObject
= NULL
;
804 PDESKTOP DesktopObject
= NULL
;
805 USEROBJECTFLAGS ObjectFlags
;
807 SIZE_T nDataSize
= 0;
812 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
813 ProbeForWrite(pvInformation
, nLength
, 1);
815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
817 SetLastNtError(_SEH2_GetExceptionCode());
822 /* Try window station */
823 TRACE("Trying to open window station %p\n", hObject
);
824 Status
= ObReferenceObjectByHandle(hObject
,
826 ExWindowStationObjectType
,
828 (PVOID
*)&WinStaObject
,
831 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
834 TRACE("Trying to open desktop %p\n", hObject
);
836 Status
= IntValidateDesktopHandle(hObject
,
842 if (!NT_SUCCESS(Status
))
844 ERR("Failed: 0x%x\n", Status
);
848 TRACE("WinSta or Desktop opened!\n");
855 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo
;
858 ObjectFlags
.fReserved
= FALSE
;
860 /* Check whether this handle is inheritable */
861 Status
= ZwQueryObject(hObject
,
862 ObjectHandleFlagInformation
,
864 sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION
),
866 if (!NT_SUCCESS(Status
))
868 ERR("ZwQueryObject failed, Status 0x%08lx\n", Status
);
871 ObjectFlags
.fInherit
= HandleInfo
.Inherit
;
873 ObjectFlags
.dwFlags
= 0;
874 if (WinStaObject
!= NULL
)
876 if (!(WinStaObject
->Flags
& WSS_NOIO
))
877 ObjectFlags
.dwFlags
|= WSF_VISIBLE
;
879 else if (DesktopObject
!= NULL
)
881 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
885 ERR("No associated WinStaObject nor DesktopObject!\n");
888 pvData
= &ObjectFlags
;
889 nDataSize
= sizeof(ObjectFlags
);
890 Status
= STATUS_SUCCESS
;
896 // FIXME: Use either ObQueryNameString() or read directly that name inside the Object section!
897 if (WinStaObject
!= NULL
)
899 pvData
= WinStaObject
->Name
.Buffer
;
900 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
901 Status
= STATUS_SUCCESS
;
903 else if (DesktopObject
!= NULL
)
905 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
906 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
907 Status
= STATUS_SUCCESS
;
911 Status
= STATUS_INVALID_PARAMETER
;
918 if (WinStaObject
!= NULL
)
920 pvData
= L
"WindowStation";
921 nDataSize
= sizeof(L
"WindowStation");
922 Status
= STATUS_SUCCESS
;
924 else if (DesktopObject
!= NULL
)
927 nDataSize
= sizeof(L
"Desktop");
928 Status
= STATUS_SUCCESS
;
932 Status
= STATUS_INVALID_PARAMETER
;
938 Status
= STATUS_NOT_IMPLEMENTED
;
939 ERR("UOI_USER_SID unimplemented!\n");
943 Status
= STATUS_INVALID_PARAMETER
;
948 if ((Status
== STATUS_SUCCESS
) && (nLength
< nDataSize
))
949 Status
= STATUS_BUFFER_TOO_SMALL
;
954 *nLengthNeeded
= nDataSize
;
956 /* Try to copy data to caller */
957 if (Status
== STATUS_SUCCESS
)
959 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
960 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
965 Status
= _SEH2_GetExceptionCode();
969 /* Release objects */
970 if (DesktopObject
!= NULL
)
971 ObDereferenceObject(DesktopObject
);
972 if (WinStaObject
!= NULL
)
973 ObDereferenceObject(WinStaObject
);
975 if (!NT_SUCCESS(Status
))
977 SetLastNtError(Status
);
985 * NtUserSetObjectInformation
987 * The NtUserSetObjectInformation function sets information about a
988 * window station or desktop object.
992 * Handle to the window station or desktop object for which to set
993 * object information. This value can be a handle of type HDESK or
997 * Specifies the object information to be set.
1000 * Pointer to a buffer containing the object information.
1003 * Specifies the size, in bytes, of the information contained in the
1004 * buffer pointed to by pvInfo.
1007 * If the function succeeds, the return value is nonzero. If the function
1008 * fails the return value is zero.
1016 NtUserSetObjectInformation(
1019 PVOID pvInformation
,
1022 /* FIXME: ZwQueryObject */
1023 /* FIXME: ZwSetInformationObject */
1024 SetLastNtError(STATUS_UNSUCCESSFUL
);
1032 UserGetProcessWindowStation(VOID
)
1034 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
1036 return ppi
->hwinsta
;
1041 * NtUserGetProcessWindowStation
1043 * Returns a handle to the current process window station.
1046 * If the function succeeds, the return value is handle to the window
1047 * station assigned to the current process. If the function fails, the
1048 * return value is NULL.
1055 NtUserGetProcessWindowStation(VOID
)
1057 return UserGetProcessWindowStation();
1061 UserSetProcessWindowStation(HWINSTA hWindowStation
)
1066 OBJECT_HANDLE_INFORMATION ObjectHandleInfo
;
1067 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
1069 ppi
= PsGetCurrentProcessWin32Process();
1071 /* Reference the new window station */
1072 if (hWindowStation
!= NULL
)
1074 Status
= IntValidateWindowStationHandle(hWindowStation
,
1079 if (!NT_SUCCESS(Status
))
1081 TRACE("Validation of window station handle (%p) failed\n",
1083 SetLastNtError(Status
);
1088 OldWinSta
= ppi
->prpwinsta
;
1089 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
1091 /* Dereference the previous window station */
1092 if (OldWinSta
!= NULL
)
1094 ObDereferenceObject(OldWinSta
);
1097 /* Check if we have a stale handle (it should happen for console apps) */
1098 if (hwinstaOld
!= ppi
->hwinsta
)
1100 ObCloseHandle(hwinstaOld
, UserMode
);
1104 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
1107 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
1109 ppi
->prpwinsta
= NewWinSta
;
1110 ppi
->hwinsta
= hWindowStation
;
1111 ppi
->amwinsta
= hWindowStation
!= NULL
? ObjectHandleInfo
.GrantedAccess
: 0;
1112 TRACE("WS : Granted Access 0x%08lx\n",ppi
->amwinsta
);
1114 if (RtlAreAllAccessesGranted(ppi
->amwinsta
, WINSTA_READSCREEN
))
1116 ppi
->W32PF_flags
|= W32PF_READSCREENACCESSGRANTED
;
1120 ppi
->W32PF_flags
&= ~W32PF_READSCREENACCESSGRANTED
;
1123 if (NewWinSta
&& !(NewWinSta
->Flags
& WSS_NOIO
))
1125 ppi
->W32PF_flags
|= W32PF_IOWINSTA
;
1127 else // Might be closed if the handle is null.
1129 ppi
->W32PF_flags
&= ~W32PF_IOWINSTA
;
1135 * NtUserSetProcessWindowStation
1137 * Assigns a window station to the current process.
1141 * Handle to the window station.
1151 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1155 UserEnterExclusive();
1157 ret
= UserSetProcessWindowStation(hWindowStation
);
1165 * NtUserLockWindowStation
1167 * Locks switching desktops. Only the logon application is allowed to call this function.
1174 NtUserLockWindowStation(HWINSTA hWindowStation
)
1176 PWINSTATION_OBJECT Object
;
1179 TRACE("About to set process window station with handle (%p)\n",
1182 if (gpidLogon
!= PsGetCurrentProcessId())
1184 ERR("Unauthorized process attempted to lock the window station!\n");
1185 EngSetLastError(ERROR_ACCESS_DENIED
);
1189 Status
= IntValidateWindowStationHandle(hWindowStation
,
1194 if (!NT_SUCCESS(Status
))
1196 TRACE("Validation of window station handle (%p) failed\n",
1198 SetLastNtError(Status
);
1202 Object
->Flags
|= WSS_LOCKED
;
1204 ObDereferenceObject(Object
);
1209 * NtUserUnlockWindowStation
1211 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1218 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1220 PWINSTATION_OBJECT Object
;
1224 TRACE("About to set process window station with handle (%p)\n",
1227 if (gpidLogon
!= PsGetCurrentProcessId())
1229 ERR("Unauthorized process attempted to unlock the window station!\n");
1230 EngSetLastError(ERROR_ACCESS_DENIED
);
1234 Status
= IntValidateWindowStationHandle(hWindowStation
,
1239 if (!NT_SUCCESS(Status
))
1241 TRACE("Validation of window station handle (%p) failed\n",
1243 SetLastNtError(Status
);
1247 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1248 Object
->Flags
&= ~WSS_LOCKED
;
1250 ObDereferenceObject(Object
);
1254 static NTSTATUS FASTCALL
1255 BuildWindowStationNameList(
1258 PULONG pRequiredSize
)
1260 OBJECT_ATTRIBUTES ObjectAttributes
;
1262 HANDLE DirectoryHandle
;
1263 char InitialBuffer
[256], *Buffer
;
1264 ULONG Context
, ReturnLength
, BufferSize
;
1266 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1270 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1271 // with judicious parameters one can create window stations elsewhere
1272 // than in Windows\WindowStations directory, Win32k definitely MUST
1273 // maintain a list of window stations it has created, and not rely
1274 // on the enumeration of Windows\WindowStations !!!
1278 * Try to open the directory.
1280 InitializeObjectAttributes(&ObjectAttributes
,
1281 &gustrWindowStationsDir
,
1282 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1286 Status
= ZwOpenDirectoryObject(&DirectoryHandle
,
1290 if (!NT_SUCCESS(Status
))
1295 /* First try to query the directory using a fixed-size buffer */
1298 Status
= ZwQueryDirectoryObject(DirectoryHandle
,
1300 sizeof(InitialBuffer
),
1305 if (NT_SUCCESS(Status
))
1307 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1308 FALSE
, &Context
, NULL
))
1310 /* Our fixed-size buffer is large enough */
1311 Buffer
= InitialBuffer
;
1317 /* Need a larger buffer, check how large exactly */
1318 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1320 if (!NT_SUCCESS(Status
))
1322 ERR("ZwQueryDirectoryObject failed\n");
1323 ZwClose(DirectoryHandle
);
1327 BufferSize
= ReturnLength
;
1328 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1331 ZwClose(DirectoryHandle
);
1332 return STATUS_NO_MEMORY
;
1335 /* We should have a sufficiently large buffer now */
1337 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1338 FALSE
, TRUE
, &Context
, &ReturnLength
);
1339 if (! NT_SUCCESS(Status
) ||
1340 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1341 FALSE
, &Context
, NULL
))
1343 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1344 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1345 ZwClose(DirectoryHandle
);
1346 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1350 ZwClose(DirectoryHandle
);
1353 * Count the required size of buffer.
1355 ReturnLength
= sizeof(DWORD
);
1357 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1358 0 != DirEntry
->Name
.Length
;
1361 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1364 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1365 if (NULL
!= pRequiredSize
)
1367 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1368 if (! NT_SUCCESS(Status
))
1370 if (Buffer
!= InitialBuffer
)
1372 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1374 return STATUS_BUFFER_TOO_SMALL
;
1379 * Check if the supplied buffer is large enough.
1381 if (dwSize
< ReturnLength
)
1383 if (Buffer
!= InitialBuffer
)
1385 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1387 return STATUS_BUFFER_TOO_SMALL
;
1391 * Generate the resulting buffer contents.
1393 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1394 if (! NT_SUCCESS(Status
))
1396 if (Buffer
!= InitialBuffer
)
1398 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1402 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1405 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1406 0 != DirEntry
->Name
.Length
;
1409 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1410 if (! NT_SUCCESS(Status
))
1412 if (Buffer
!= InitialBuffer
)
1414 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1418 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1419 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1420 if (! NT_SUCCESS(Status
))
1422 if (Buffer
!= InitialBuffer
)
1424 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1428 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1434 if (Buffer
!= InitialBuffer
)
1436 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1439 return STATUS_SUCCESS
;
1442 static NTSTATUS FASTCALL
1443 BuildDesktopNameList(
1444 HWINSTA hWindowStation
,
1447 PULONG pRequiredSize
)
1450 PWINSTATION_OBJECT WindowStation
;
1451 PLIST_ENTRY DesktopEntry
;
1452 PDESKTOP DesktopObject
;
1456 UNICODE_STRING DesktopName
;
1458 Status
= IntValidateWindowStationHandle(hWindowStation
,
1463 if (! NT_SUCCESS(Status
))
1469 * Count the required size of buffer.
1471 ReturnLength
= sizeof(DWORD
);
1473 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1474 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1475 DesktopEntry
= DesktopEntry
->Flink
)
1477 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1478 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1479 ReturnLength
+= DesktopName
.Length
+ sizeof(WCHAR
);
1482 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1483 if (NULL
!= pRequiredSize
)
1485 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1486 if (! NT_SUCCESS(Status
))
1488 ObDereferenceObject(WindowStation
);
1489 return STATUS_BUFFER_TOO_SMALL
;
1494 * Check if the supplied buffer is large enough.
1496 if (dwSize
< ReturnLength
)
1498 ObDereferenceObject(WindowStation
);
1499 return STATUS_BUFFER_TOO_SMALL
;
1503 * Generate the resulting buffer contents.
1505 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1506 if (! NT_SUCCESS(Status
))
1508 ObDereferenceObject(WindowStation
);
1511 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1514 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1515 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1516 DesktopEntry
= DesktopEntry
->Flink
)
1518 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1519 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1520 Status
= MmCopyToCaller(lpBuffer
, DesktopName
.Buffer
, DesktopName
.Length
);
1521 if (! NT_SUCCESS(Status
))
1523 ObDereferenceObject(WindowStation
);
1526 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
.Length
);
1527 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1528 if (! NT_SUCCESS(Status
))
1530 ObDereferenceObject(WindowStation
);
1533 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1537 * Clean up and return
1539 ObDereferenceObject(WindowStation
);
1540 return STATUS_SUCCESS
;
1544 * NtUserBuildNameList
1546 * Function used for enumeration of desktops or window stations.
1550 * For enumeration of window stations this parameter must be set to
1551 * zero. Otherwise it's handle for window station.
1554 * Size of buffer passed by caller.
1557 * Buffer passed by caller. If the function succeeds, the buffer is
1558 * filled with window station/desktop count (in first DWORD) and
1559 * NULL-terminated window station/desktop names.
1562 * If the function succeeds, this is the number of bytes copied.
1563 * Otherwise it's size of buffer needed for function to succeed.
1570 NtUserBuildNameList(
1571 HWINSTA hWindowStation
,
1574 PULONG pRequiredSize
)
1576 /* The WindowStation name list and desktop name list are build in completely
1577 different ways. Call the appropriate function */
1578 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1579 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1586 NtUserSetLogonNotifyWindow(HWND hWnd
)
1588 if (gpidLogon
!= PsGetCurrentProcessId())
1593 if (!IntIsWindow(hWnd
))
1605 NtUserLockWorkStation(VOID
)
1608 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1610 UserEnterExclusive();
1612 if (pti
->rpdesk
== IntGetActiveDesktop())
1614 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);
1628 NtUserSetWindowStationUser(
1629 IN HWINSTA hWindowStation
,
1631 IN PSID psid OPTIONAL
,
1636 PWINSTATION_OBJECT WindowStation
= NULL
;
1639 UserEnterExclusive();
1641 if (gpidLogon
!= PsGetCurrentProcessId())
1643 EngSetLastError(ERROR_ACCESS_DENIED
);
1647 /* Validate the window station */
1648 Status
= IntValidateWindowStationHandle(hWindowStation
,
1653 if (!NT_SUCCESS(Status
))
1658 /* Capture the user LUID */
1661 ProbeForRead(pluid
, sizeof(LUID
), 1);
1664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1666 Status
= _SEH2_GetExceptionCode();
1667 _SEH2_YIELD(goto Leave
);
1671 /* Reset the window station user LUID */
1672 RtlZeroMemory(&WindowStation
->luidUser
, sizeof(LUID
));
1674 /* Reset the window station user SID */
1675 if (WindowStation
->psidUser
)
1677 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
1678 WindowStation
->psidUser
= NULL
;
1681 /* Copy the new user SID if one has been provided */
1684 WindowStation
->psidUser
= ExAllocatePoolWithTag(PagedPool
, size
, USERTAG_SECURITY
);
1685 if (WindowStation
->psidUser
== NULL
)
1687 EngSetLastError(ERROR_OUTOFMEMORY
);
1691 Status
= STATUS_SUCCESS
;
1694 ProbeForRead(psid
, size
, 1);
1695 RtlCopyMemory(WindowStation
->psidUser
, psid
, size
);
1697 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1699 Status
= _SEH2_GetExceptionCode();
1703 if (!NT_SUCCESS(Status
))
1705 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
1706 WindowStation
->psidUser
= NULL
;
1711 /* Copy the new user LUID */
1712 WindowStation
->luidUser
= luidUser
;
1718 ObDereferenceObject(WindowStation
);