2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * PURPOSE: Window stations
22 * FILE: subsys/win32k/ntuser/winsta.c
23 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * 06-06-2001 CSH Created
26 * NOTES: Exported functions set the Win32 last error value
27 * on errors. The value can be retrieved with the Win32
28 * function GetLastError().
29 * TODO: The process window station is created on
30 * the first USER32/GDI32 call not related
31 * to window station/desktop handling
34 /* INCLUDES ******************************************************************/
41 /* GLOBALS *******************************************************************/
43 /* Currently active window station */
44 PWINSTATION_OBJECT InputWindowStation
= NULL
;
46 /* INITALIZATION FUNCTIONS ****************************************************/
48 static GENERIC_MAPPING IntWindowStationMapping
=
50 STANDARD_RIGHTS_READ
| WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
,
51 STANDARD_RIGHTS_WRITE
| WINSTA_ACCESSCLIPBOARD
| WINSTA_CREATEDESKTOP
| WINSTA_WRITEATTRIBUTES
,
52 STANDARD_RIGHTS_EXECUTE
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_EXITWINDOWS
,
53 STANDARD_RIGHTS_REQUIRED
| WINSTA_ACCESSCLIPBOARD
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_CREATEDESKTOP
|
54 WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_EXITWINDOWS
|
55 WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
| WINSTA_WRITEATTRIBUTES
59 InitWindowStationImpl(VOID
)
61 OBJECT_ATTRIBUTES ObjectAttributes
;
62 HANDLE WindowStationsDirectory
;
63 UNICODE_STRING UnicodeString
;
67 * Create the '\Windows\WindowStations' directory
70 RtlInitUnicodeString(&UnicodeString
, WINSTA_ROOT_NAME
);
71 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeString
,
73 Status
= ZwCreateDirectoryObject(&WindowStationsDirectory
, 0,
75 if (!NT_SUCCESS(Status
))
77 DPRINT("Could not create \\Windows\\WindowStations directory "
78 "(Status 0x%X)\n", Status
);
82 /* Set Winsta Object Attributes */
83 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
84 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
86 return STATUS_SUCCESS
;
90 CleanupWindowStationImpl(VOID
)
92 return STATUS_SUCCESS
;
95 /* OBJECT CALLBACKS **********************************************************/
99 IntWinStaObjectOpen(OB_OPEN_REASON Reason
,
102 ACCESS_MASK GrantedAccess
,
105 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)ObjectBody
;
108 DPRINT1("IntWinStaObjectOpen\n");
110 if (Reason
== ObCreateHandle
)
112 DPRINT("Creating window station (0x%X)\n", WinSta
);
114 KeInitializeSpinLock(&WinSta
->Lock
);
116 InitializeListHead(&WinSta
->DesktopListHead
);
118 DPRINT1("Create winsta atomtable\n");
119 WinSta
->AtomTable
= NULL
;
120 Status
= RtlCreateAtomTable(37, &WinSta
->AtomTable
);
121 if (!NT_SUCCESS(Status
)) DPRINT1("Error creating atom table\n");
122 WinSta
->SystemMenuTemplate
= (HANDLE
)0;
124 DPRINT("Window station successfully created.\n");
127 return STATUS_SUCCESS
;
131 IntWinStaObjectDelete(PVOID DeletedObject
)
133 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeletedObject
;
135 DPRINT("Deleting window station (0x%X)\n", WinSta
);
137 RtlDestroyAtomTable(WinSta
->AtomTable
);
139 RtlFreeUnicodeString(&WinSta
->Name
);
143 IntWinStaObjectFind(PVOID Object
,
148 PDESKTOP_OBJECT CurrentObject
;
149 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)Object
;
151 DPRINT("WinStaObject (0x%X) Name (%wS)\n", WinStaObject
, Name
);
158 Current
= WinStaObject
->DesktopListHead
.Flink
;
159 while (Current
!= &WinStaObject
->DesktopListHead
)
161 CurrentObject
= CONTAINING_RECORD(Current
, DESKTOP_OBJECT
, ListEntry
);
162 DPRINT("Scanning %wZ for %wS\n", &CurrentObject
->Name
, Name
);
163 if (Attributes
& OBJ_CASE_INSENSITIVE
)
165 if (_wcsicmp(CurrentObject
->Name
.Buffer
, Name
) == 0)
167 DPRINT("Found desktop at (0x%X)\n", CurrentObject
);
168 return CurrentObject
;
173 if (wcscmp(CurrentObject
->Name
.Buffer
, Name
) == 0)
175 DPRINT("Found desktop at (0x%X)\n", CurrentObject
);
176 return CurrentObject
;
179 Current
= Current
->Flink
;
182 DPRINT("Returning NULL\n");
189 IntWinStaObjectParse(IN PVOID Object
,
191 IN OUT PACCESS_STATE AccessState
,
192 IN KPROCESSOR_MODE AccessMode
,
194 IN OUT PUNICODE_STRING FullPath
,
195 IN OUT PUNICODE_STRING RemainingName
,
196 IN OUT PVOID Context OPTIONAL
,
197 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
198 OUT PVOID
*NextObject
)
200 PWSTR
*Path
= &RemainingName
->Buffer
;
205 DPRINT("Object (0x%X) Path (0x%X) *Path (%wS)\n", Object
, Path
, *Path
);
209 if ((Path
== NULL
) || ((*Path
) == NULL
))
211 return STATUS_SUCCESS
;
214 End
= wcschr((*Path
) + 1, '\\');
217 DPRINT("Name contains illegal characters\n");
218 return STATUS_UNSUCCESSFUL
;
221 FoundObject
= IntWinStaObjectFind(Object
, (*Path
) + 1, Attributes
);
222 if (FoundObject
== NULL
)
224 DPRINT("Name was not found\n");
225 return STATUS_UNSUCCESSFUL
;
228 Status
= ObReferenceObjectByPointer(
230 STANDARD_RIGHTS_REQUIRED
,
234 *NextObject
= FoundObject
;
240 /* PRIVATE FUNCTIONS **********************************************************/
243 * IntGetFullWindowStationName
245 * Get a full window station object name from a name specified in
246 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
247 * or NtUserOpenDesktop.
250 * TRUE on success, FALSE on failure.
254 IntGetFullWindowStationName(
255 OUT PUNICODE_STRING FullName
,
256 IN PUNICODE_STRING WinStaName
,
257 IN OPTIONAL PUNICODE_STRING DesktopName
)
261 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
262 if (WinStaName
!= NULL
)
263 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
264 if (DesktopName
!= NULL
)
265 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
266 FullName
->MaximumLength
= FullName
->Length
;
267 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
268 if (FullName
->Buffer
== NULL
)
273 Buffer
= FullName
->Buffer
;
274 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
275 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
276 if (WinStaName
!= NULL
)
278 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
280 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
282 if (DesktopName
!= NULL
)
284 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
285 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
287 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
295 * IntValidateWindowStationHandle
297 * Validates the window station handle.
300 * If the function succeeds, the handle remains referenced. If the
301 * fucntion fails, last error is set.
305 IntValidateWindowStationHandle(
306 HWINSTA WindowStation
,
307 KPROCESSOR_MODE AccessMode
,
308 ACCESS_MASK DesiredAccess
,
309 PWINSTATION_OBJECT
*Object
)
313 if (WindowStation
== NULL
)
315 // DPRINT1("Invalid window station handle\n");
316 SetLastWin32Error(ERROR_INVALID_HANDLE
);
317 return STATUS_INVALID_HANDLE
;
320 Status
= ObReferenceObjectByHandle(
323 ExWindowStationObjectType
,
328 if (!NT_SUCCESS(Status
))
329 SetLastNtError(Status
);
335 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
339 Status
= ObReferenceObjectByPointer(
342 ExWindowStationObjectType
,
345 return NT_SUCCESS(Status
);
349 co_IntInitializeDesktopGraphics(VOID
)
351 UNICODE_STRING DriverName
;
352 if (! IntCreatePrimarySurface())
356 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
357 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
358 if (NULL
== ScreenDeviceContext
)
360 IntDestroyPrimarySurface();
363 DC_SetOwnership(ScreenDeviceContext
, NULL
);
365 UserAcquireOrReleaseInputOwnership(FALSE
);
367 /* Setup the cursor */
368 co_IntLoadDefaultCursors();
374 IntEndDesktopGraphics(VOID
)
376 UserAcquireOrReleaseInputOwnership(TRUE
);
377 if (NULL
!= ScreenDeviceContext
)
379 DC_SetOwnership(ScreenDeviceContext
, PsGetCurrentProcess());
380 NtGdiDeleteObjectApp(ScreenDeviceContext
);
381 ScreenDeviceContext
= NULL
;
383 IntHideDesktop(IntGetActiveDesktop());
384 IntDestroyPrimarySurface();
390 return ScreenDeviceContext
;
393 /* PUBLIC FUNCTIONS ***********************************************************/
396 * NtUserCreateWindowStation
398 * Creates a new window station.
401 * lpszWindowStationName
402 * Pointer to a null-terminated string specifying the name of the
403 * window station to be created. Window station names are
404 * case-insensitive and cannot contain backslash characters (\).
405 * Only members of the Administrators group are allowed to specify a
409 * Requested type of access
412 * Security descriptor
414 * Unknown3, Unknown4, Unknown5
418 * If the function succeeds, the return value is a handle to the newly
419 * created window station. If the specified window station already
420 * exists, the function succeeds and returns a handle to the existing
421 * window station. If the function fails, the return value is NULL.
424 * Correct the prototype to match the Windows one (with 7 parameters
432 NtUserCreateWindowStation(
433 PUNICODE_STRING lpszWindowStationName
,
434 ACCESS_MASK dwDesiredAccess
,
435 LPSECURITY_ATTRIBUTES lpSecurity
,
440 PSYSTEM_CURSORINFO CurInfo
;
441 UNICODE_STRING WindowStationName
;
442 UNICODE_STRING FullWindowStationName
;
443 PWINSTATION_OBJECT WindowStationObject
;
444 HWINSTA WindowStation
;
445 OBJECT_ATTRIBUTES ObjectAttributes
;
449 * Generate full window station name
451 Status
= ProbeAndCaptureUnicodeString(&WindowStationName
,
453 lpszWindowStationName
);
454 if (!NT_SUCCESS(Status
))
456 DPRINT1("Failed to capture window station name (status 0x%08x)\n",
458 SetLastNtError(Status
);
461 if (!IntGetFullWindowStationName(&FullWindowStationName
,
465 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
466 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
471 * Try to open already existing window station
474 DPRINT("Trying to open window station (%wZ)\n", &FullWindowStationName
);
476 /* Initialize ObjectAttributes for the window station object */
477 InitializeObjectAttributes(
479 &FullWindowStationName
,
484 Status
= ObOpenObjectByName(
486 ExWindowStationObjectType
,
491 (PVOID
*)&WindowStation
);
493 if (NT_SUCCESS(Status
))
495 DPRINT("Successfully opened window station (%wZ)\n",
496 FullWindowStationName
);
497 ExFreePool(FullWindowStationName
.Buffer
);
498 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
499 return (HWINSTA
)WindowStation
;
503 * No existing window station found, try to create new one
506 DPRINT("Creating window station (%wZ)\n", &FullWindowStationName
);
508 Status
= ObCreateObject(
510 ExWindowStationObjectType
,
514 sizeof(WINSTATION_OBJECT
),
517 (PVOID
*)&WindowStationObject
);
519 if (!NT_SUCCESS(Status
))
521 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName
);
522 ExFreePool(FullWindowStationName
.Buffer
);
523 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
524 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
528 WindowStationObject
->Name
= WindowStationName
;
530 Status
= ObInsertObject(
531 (PVOID
)WindowStationObject
,
533 STANDARD_RIGHTS_REQUIRED
,
536 (PVOID
*)&WindowStation
);
538 if (!NT_SUCCESS(Status
))
540 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName
);
541 ExFreePool(FullWindowStationName
.Buffer
);
542 ExFreePool(WindowStationName
.Buffer
);
543 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
544 ObDereferenceObject(WindowStationObject
);
549 * Initialize the new window station object
552 if(!(CurInfo
= ExAllocatePool(PagedPool
, sizeof(SYSTEM_CURSORINFO
))))
554 ExFreePool(FullWindowStationName
.Buffer
);
555 /* FIXME - Delete window station object */
556 ObDereferenceObject(WindowStationObject
);
557 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
561 CurInfo
->Enabled
= FALSE
;
562 CurInfo
->ButtonsDown
= 0;
563 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
564 CurInfo
->LastBtnDown
= 0;
565 CurInfo
->CurrentCursorObject
= NULL
;
566 CurInfo
->ShowingCursor
= 0;
568 /* FIXME: Obtain the following information from the registry */
569 CurInfo
->SwapButtons
= FALSE
;
570 CurInfo
->DblClickSpeed
= 500;
571 CurInfo
->DblClickWidth
= 4;
572 CurInfo
->DblClickHeight
= 4;
574 WindowStationObject
->SystemCursor
= CurInfo
;
576 if (!IntSetupCurIconHandles(WindowStationObject
))
578 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
579 /* FIXME: Complain more loudly? */
580 ExFreePool(FullWindowStationName
.Buffer
);
583 DPRINT("Window station successfully created (%wZ)\n", FullWindowStationName
);
584 ExFreePool(FullWindowStationName
.Buffer
);
585 return WindowStation
;
589 * NtUserOpenWindowStation
591 * Opens an existing window station.
594 * lpszWindowStationName
595 * Name of the existing window station.
598 * Requested type of access.
601 * If the function succeeds, the return value is the handle to the
602 * specified window station. If the function fails, the return value
606 * The returned handle can be closed with NtUserCloseWindowStation.
613 NtUserOpenWindowStation(
614 PUNICODE_STRING lpszWindowStationName
,
615 ACCESS_MASK dwDesiredAccess
)
617 UNICODE_STRING WindowStationName
;
618 HWINSTA WindowStation
;
619 OBJECT_ATTRIBUTES ObjectAttributes
;
623 * Generate full window station name
626 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
629 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
633 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
635 /* Initialize ObjectAttributes for the window station object */
636 InitializeObjectAttributes(
643 Status
= ObOpenObjectByName(
645 ExWindowStationObjectType
,
650 (PVOID
*)&WindowStation
);
652 if (!NT_SUCCESS(Status
))
654 SetLastNtError(Status
);
655 ExFreePool(WindowStationName
.Buffer
);
659 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName
);
660 ExFreePool(WindowStationName
.Buffer
);
662 return WindowStation
;
666 * NtUserCloseWindowStation
668 * Closes a window station handle.
672 * Handle to the window station.
678 * The window station handle can be created with NtUserCreateWindowStation
679 * or NtUserOpenWindowStation. Attemps to close a handle to the window
680 * station assigned to the calling process will fail.
688 NtUserCloseWindowStation(
691 PWINSTATION_OBJECT Object
;
694 DPRINT("About to close window station handle (0x%X)\n", hWinSta
);
696 Status
= IntValidateWindowStationHandle(
702 if (!NT_SUCCESS(Status
))
704 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta
);
709 /* FIXME - free the cursor information when actually deleting the object!! */
710 ASSERT(Object
->SystemCursor
);
711 ExFreePool(Object
->SystemCursor
);
714 ObDereferenceObject(Object
);
716 DPRINT("Closing window station handle (0x%X)\n", hWinSta
);
718 Status
= ZwClose(hWinSta
);
719 if (!NT_SUCCESS(Status
))
721 SetLastNtError(Status
);
729 * NtUserGetObjectInformation
731 * The NtUserGetObjectInformation function retrieves information about a
732 * window station or desktop object.
736 * Handle to the window station or desktop object for which to
737 * return information. This can be a handle of type HDESK or HWINSTA
738 * (for example, a handle returned by NtUserCreateWindowStation,
739 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
742 * Specifies the object information to be retrieved.
745 * Pointer to a buffer to receive the object information.
748 * Specifies the size, in bytes, of the buffer pointed to by the
752 * Pointer to a variable receiving the number of bytes required to
753 * store the requested information. If this variable's value is
754 * greater than the value of the nLength parameter when the function
755 * returns, the function returns FALSE, and none of the information
756 * is copied to the pvInfo buffer. If the value of the variable pointed
757 * to by lpnLengthNeeded is less than or equal to the value of nLength,
758 * the entire information block is copied.
761 * If the function succeeds, the return value is nonzero. If the function
762 * fails, the return value is zero.
769 NtUserGetObjectInformation(
774 PDWORD nLengthNeeded
)
776 PWINSTATION_OBJECT WinStaObject
= NULL
;
777 PDESKTOP_OBJECT DesktopObject
= NULL
;
782 /* try windowstation */
783 DPRINT("Trying to open window station 0x%x\n", hObject
);
784 Status
= IntValidateWindowStationHandle(
786 UserMode
,/*ExGetPreviousMode(),*/
787 GENERIC_READ
, /* FIXME: is this ok? */
791 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
793 DPRINT("Failed: 0x%x\n", Status
);
794 SetLastNtError(Status
);
798 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
801 DPRINT("Trying to open desktop 0x%x\n", hObject
);
802 Status
= IntValidateDesktopHandle(
804 UserMode
,/*ExGetPreviousMode(),*/
805 GENERIC_READ
, /* FIXME: is this ok? */
807 if (!NT_SUCCESS(Status
))
809 DPRINT("Failed: 0x%x\n", Status
);
810 SetLastNtError(Status
);
814 DPRINT("WinSta or Desktop opened!!\n");
820 Status
= STATUS_NOT_IMPLEMENTED
;
821 DPRINT1("UOI_FLAGS unimplemented!\n");
825 if (WinStaObject
!= NULL
)
827 pvData
= WinStaObject
->Name
.Buffer
;
828 nDataSize
= WinStaObject
->Name
.Length
+2;
829 Status
= STATUS_SUCCESS
;
831 else if (DesktopObject
!= NULL
)
833 pvData
= DesktopObject
->Name
.Buffer
;
834 nDataSize
= DesktopObject
->Name
.Length
+2;
835 Status
= STATUS_SUCCESS
;
838 Status
= STATUS_INVALID_PARAMETER
;
842 if (WinStaObject
!= NULL
)
844 pvData
= L
"WindowStation";
845 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
846 Status
= STATUS_SUCCESS
;
848 else if (DesktopObject
!= NULL
)
851 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
852 Status
= STATUS_SUCCESS
;
855 Status
= STATUS_INVALID_PARAMETER
;
859 Status
= STATUS_NOT_IMPLEMENTED
;
860 DPRINT1("UOI_USER_SID unimplemented!\n");
864 Status
= STATUS_INVALID_PARAMETER
;
868 /* try to copy data to caller */
869 if (Status
== STATUS_SUCCESS
)
871 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
872 *nLengthNeeded
= nDataSize
;
873 if (nLength
>= nDataSize
)
874 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
876 Status
= STATUS_BUFFER_TOO_SMALL
;
879 /* release objects */
880 if (WinStaObject
!= NULL
)
881 ObDereferenceObject(WinStaObject
);
882 if (DesktopObject
!= NULL
)
883 ObDereferenceObject(DesktopObject
);
885 SetLastNtError(Status
);
886 return NT_SUCCESS(Status
);
890 * NtUserSetObjectInformation
892 * The NtUserSetObjectInformation function sets information about a
893 * window station or desktop object.
897 * Handle to the window station or desktop object for which to set
898 * object information. This value can be a handle of type HDESK or
902 * Specifies the object information to be set.
905 * Pointer to a buffer containing the object information.
908 * Specifies the size, in bytes, of the information contained in the
909 * buffer pointed to by pvInfo.
912 * If the function succeeds, the return value is nonzero. If the function
913 * fails the return value is zero.
921 NtUserSetObjectInformation(
927 /* FIXME: ZwQueryObject */
928 /* FIXME: ZwSetInformationObject */
929 SetLastNtError(STATUS_UNSUCCESSFUL
);
937 UserGetProcessWindowStation(VOID
)
942 if(PsGetCurrentProcess() != CsrProcess
)
944 return PsGetCurrentProcess()->Win32WindowStation
;
948 DPRINT1("Should use ObFindHandleForObject\n");
949 Status
= ObOpenObjectByPointer(PsGetWin32Thread()->Desktop
->WindowStation
,
953 ExWindowStationObjectType
,
956 if (! NT_SUCCESS(Status
))
958 SetLastNtError(Status
);
959 DPRINT1("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
969 * NtUserGetProcessWindowStation
971 * Returns a handle to the current process window station.
974 * If the function succeeds, the return value is handle to the window
975 * station assigned to the current process. If the function fails, the
976 * return value is NULL.
983 NtUserGetProcessWindowStation(VOID
)
985 return UserGetProcessWindowStation();
988 PWINSTATION_OBJECT FASTCALL
989 IntGetWinStaObj(VOID
)
991 PWINSTATION_OBJECT WinStaObj
;
994 * just a temporary hack, this will be gone soon
997 if(PsGetWin32Thread() != NULL
&& PsGetWin32Thread()->Desktop
!= NULL
)
999 WinStaObj
= PsGetWin32Thread()->Desktop
->WindowStation
;
1000 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
1002 else if(PsGetCurrentProcess() != CsrProcess
)
1004 NTSTATUS Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
1008 if(!NT_SUCCESS(Status
))
1010 SetLastNtError(Status
);
1023 * NtUserSetProcessWindowStation
1025 * Assigns a window station to the current process.
1029 * Handle to the window station.
1039 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1042 PWINSTATION_OBJECT NewWinSta
;
1045 DPRINT("About to set process window station with handle (0x%X)\n",
1048 if(PsGetCurrentProcess() == CsrProcess
)
1050 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1051 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1055 Status
= IntValidateWindowStationHandle(
1061 if (!NT_SUCCESS(Status
))
1063 DPRINT("Validation of window station handle (0x%X) failed\n",
1065 SetLastNtError(Status
);
1070 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1073 /* FIXME - dereference the old window station, etc... */
1074 hOld
= InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation
, hWindowStation
);
1076 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1077 PsGetCurrentProcess()->Win32WindowStation
);
1083 * NtUserLockWindowStation
1085 * Locks switching desktops. Only the logon application is allowed to call this function.
1092 NtUserLockWindowStation(HWINSTA hWindowStation
)
1094 PWINSTATION_OBJECT Object
;
1097 DPRINT("About to set process window station with handle (0x%X)\n",
1100 if(PsGetWin32Process() != LogonProcess
)
1102 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1103 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1107 Status
= IntValidateWindowStationHandle(
1112 if (!NT_SUCCESS(Status
))
1114 DPRINT("Validation of window station handle (0x%X) failed\n",
1116 SetLastNtError(Status
);
1120 Object
->Flags
|= WSS_LOCKED
;
1122 ObDereferenceObject(Object
);
1127 * NtUserUnlockWindowStation
1129 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1136 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1138 PWINSTATION_OBJECT Object
;
1142 DPRINT("About to set process window station with handle (0x%X)\n",
1145 if(PsGetWin32Process() != LogonProcess
)
1147 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1148 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1152 Status
= IntValidateWindowStationHandle(
1157 if (!NT_SUCCESS(Status
))
1159 DPRINT("Validation of window station handle (0x%X) failed\n",
1161 SetLastNtError(Status
);
1165 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1166 Object
->Flags
&= ~WSS_LOCKED
;
1168 ObDereferenceObject(Object
);
1173 * NtUserSetWindowStationUser
1180 NtUserSetWindowStationUser(
1191 static NTSTATUS FASTCALL
1192 BuildWindowStationNameList(
1195 PULONG pRequiredSize
)
1197 OBJECT_ATTRIBUTES ObjectAttributes
;
1199 HANDLE DirectoryHandle
;
1200 UNICODE_STRING DirectoryName
;
1201 char InitialBuffer
[256], *Buffer
;
1202 ULONG Context
, ReturnLength
, BufferSize
;
1204 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1208 * Generate name of window station directory
1210 if (!IntGetFullWindowStationName(&DirectoryName
, NULL
, NULL
))
1212 return STATUS_INSUFFICIENT_RESOURCES
;
1216 * Try to open the directory.
1218 InitializeObjectAttributes(
1221 OBJ_CASE_INSENSITIVE
,
1225 Status
= ZwOpenDirectoryObject(
1230 ExFreePool(DirectoryName
.Buffer
);
1232 if (!NT_SUCCESS(Status
))
1237 /* First try to query the directory using a fixed-size buffer */
1240 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1241 FALSE
, TRUE
, &Context
, &ReturnLength
);
1242 if (NT_SUCCESS(Status
))
1244 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1245 FALSE
, &Context
, NULL
))
1247 /* Our fixed-size buffer is large enough */
1248 Buffer
= InitialBuffer
;
1254 /* Need a larger buffer, check how large exactly */
1255 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1257 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1259 BufferSize
= ReturnLength
;
1260 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1263 ObDereferenceObject(DirectoryHandle
);
1264 return STATUS_NO_MEMORY
;
1267 /* We should have a sufficiently large buffer now */
1269 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1270 FALSE
, TRUE
, &Context
, &ReturnLength
);
1271 if (! NT_SUCCESS(Status
) ||
1272 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1273 FALSE
, &Context
, NULL
))
1275 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1277 ObDereferenceObject(DirectoryHandle
);
1278 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1283 ZwClose(DirectoryHandle
);
1286 * Count the required size of buffer.
1288 ReturnLength
= sizeof(DWORD
);
1290 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1293 ReturnLength
+= DirEntry
->ObjectName
.Length
+ sizeof(WCHAR
);
1296 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1297 if (NULL
!= pRequiredSize
)
1299 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1300 if (! NT_SUCCESS(Status
))
1302 if (Buffer
!= InitialBuffer
)
1306 return STATUS_BUFFER_TOO_SMALL
;
1311 * Check if the supplied buffer is large enough.
1313 if (dwSize
< ReturnLength
)
1315 if (Buffer
!= InitialBuffer
)
1319 return STATUS_BUFFER_TOO_SMALL
;
1323 * Generate the resulting buffer contents.
1325 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1326 if (! NT_SUCCESS(Status
))
1328 if (Buffer
!= InitialBuffer
)
1334 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1337 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1340 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->ObjectName
.Buffer
, DirEntry
->ObjectName
.Length
);
1341 if (! NT_SUCCESS(Status
))
1343 if (Buffer
!= InitialBuffer
)
1349 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->ObjectName
.Length
);
1350 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1351 if (! NT_SUCCESS(Status
))
1353 if (Buffer
!= InitialBuffer
)
1359 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1365 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1370 return STATUS_SUCCESS
;
1373 static NTSTATUS FASTCALL
1374 BuildDesktopNameList(
1375 HWINSTA hWindowStation
,
1378 PULONG pRequiredSize
)
1381 PWINSTATION_OBJECT WindowStation
;
1383 PLIST_ENTRY DesktopEntry
;
1384 PDESKTOP_OBJECT DesktopObject
;
1389 Status
= IntValidateWindowStationHandle(hWindowStation
,
1393 if (! NT_SUCCESS(Status
))
1398 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1401 * Count the required size of buffer.
1403 ReturnLength
= sizeof(DWORD
);
1405 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1406 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1407 DesktopEntry
= DesktopEntry
->Flink
)
1409 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1410 ReturnLength
+= DesktopObject
->Name
.Length
+ sizeof(WCHAR
);
1413 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1414 if (NULL
!= pRequiredSize
)
1416 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1417 if (! NT_SUCCESS(Status
))
1419 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1420 ObDereferenceObject(WindowStation
);
1421 return STATUS_BUFFER_TOO_SMALL
;
1426 * Check if the supplied buffer is large enough.
1428 if (dwSize
< ReturnLength
)
1430 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1431 ObDereferenceObject(WindowStation
);
1432 return STATUS_BUFFER_TOO_SMALL
;
1436 * Generate the resulting buffer contents.
1438 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1439 if (! NT_SUCCESS(Status
))
1441 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1442 ObDereferenceObject(WindowStation
);
1445 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1448 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1449 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1450 DesktopEntry
= DesktopEntry
->Flink
)
1452 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1453 Status
= MmCopyToCaller(lpBuffer
, DesktopObject
->Name
.Buffer
, DesktopObject
->Name
.Length
);
1454 if (! NT_SUCCESS(Status
))
1456 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1457 ObDereferenceObject(WindowStation
);
1460 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DesktopObject
->Name
.Length
);
1461 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1462 if (! NT_SUCCESS(Status
))
1464 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1465 ObDereferenceObject(WindowStation
);
1468 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1474 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1475 ObDereferenceObject(WindowStation
);
1477 return STATUS_SUCCESS
;
1481 * NtUserBuildNameList
1483 * Function used for enumeration of desktops or window stations.
1487 * For enumeration of window stations this parameter must be set to
1488 * zero. Otherwise it's handle for window station.
1491 * Size of buffer passed by caller.
1494 * Buffer passed by caller. If the function succedes, the buffer is
1495 * filled with window station/desktop count (in first DWORD) and
1496 * NULL-terminated window station/desktop names.
1499 * If the function suceedes, this is the number of bytes copied.
1500 * Otherwise it's size of buffer needed for function to succeed.
1507 NtUserBuildNameList(
1508 HWINSTA hWindowStation
,
1511 PULONG pRequiredSize
)
1513 /* The WindowStation name list and desktop name list are build in completely
1514 different ways. Call the appropriate function */
1515 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1516 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);