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.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window stations
24 * FILE: subsys/win32k/ntuser/winsta.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
28 * NOTES: Exported functions set the Win32 last error value
29 * on errors. The value can be retrieved with the Win32
30 * function GetLastError().
31 * TODO: The process window station is created on
32 * the first USER32/GDI32 call not related
33 * to window station/desktop handling
36 /* INCLUDES ******************************************************************/
43 /* GLOBALS *******************************************************************/
45 /* Currently active window station */
46 PWINSTATION_OBJECT InputWindowStation
= NULL
;
48 /* INITALIZATION FUNCTIONS ****************************************************/
50 static GENERIC_MAPPING IntWindowStationMapping
=
52 STANDARD_RIGHTS_READ
| WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
,
53 STANDARD_RIGHTS_WRITE
| WINSTA_ACCESSCLIPBOARD
| WINSTA_CREATEDESKTOP
| WINSTA_WRITEATTRIBUTES
,
54 STANDARD_RIGHTS_EXECUTE
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_EXITWINDOWS
,
55 STANDARD_RIGHTS_REQUIRED
| WINSTA_ACCESSCLIPBOARD
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_CREATEDESKTOP
|
56 WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_EXITWINDOWS
|
57 WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
| WINSTA_WRITEATTRIBUTES
61 InitWindowStationImpl(VOID
)
63 OBJECT_ATTRIBUTES ObjectAttributes
;
64 HANDLE WindowStationsDirectory
;
65 UNICODE_STRING UnicodeString
;
69 * Create the '\Windows\WindowStations' directory
72 RtlInitUnicodeString(&UnicodeString
, WINSTA_ROOT_NAME
);
73 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeString
,
75 Status
= ZwCreateDirectoryObject(&WindowStationsDirectory
, 0,
77 if (!NT_SUCCESS(Status
))
79 DPRINT("Could not create \\Windows\\WindowStations directory "
80 "(Status 0x%X)\n", Status
);
84 /* Set Winsta Object Attributes */
85 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
86 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
88 return STATUS_SUCCESS
;
92 CleanupWindowStationImpl(VOID
)
94 return STATUS_SUCCESS
;
97 /* OBJECT CALLBACKS **********************************************************/
101 IntWinStaObjectOpen(OB_OPEN_REASON Reason
,
105 ACCESS_MASK GrantedAccess
)
107 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)ObjectBody
;
110 DPRINT1("IntWinStaObjectOpen\n");
112 if (Reason
== ObCreateHandle
)
114 DPRINT("Creating window station (0x%X)\n", WinSta
);
116 KeInitializeSpinLock(&WinSta
->Lock
);
118 InitializeListHead(&WinSta
->DesktopListHead
);
120 DPRINT1("Create winsta atomtable\n");
121 WinSta
->AtomTable
= NULL
;
122 Status
= RtlCreateAtomTable(37, &WinSta
->AtomTable
);
123 if (!NT_SUCCESS(Status
)) DPRINT1("Error creating atom table\n");
124 WinSta
->SystemMenuTemplate
= (HANDLE
)0;
126 DPRINT("Window station successfully created.\n");
129 return STATUS_SUCCESS
;
133 IntWinStaObjectDelete(PVOID DeletedObject
)
135 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeletedObject
;
137 DPRINT("Deleting window station (0x%X)\n", WinSta
);
139 RtlDestroyAtomTable(WinSta
->AtomTable
);
141 RtlFreeUnicodeString(&WinSta
->Name
);
145 IntWinStaObjectFind(PVOID Object
,
150 PDESKTOP_OBJECT CurrentObject
;
151 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)Object
;
153 DPRINT("WinStaObject (0x%X) Name (%wS)\n", WinStaObject
, Name
);
160 Current
= WinStaObject
->DesktopListHead
.Flink
;
161 while (Current
!= &WinStaObject
->DesktopListHead
)
163 CurrentObject
= CONTAINING_RECORD(Current
, DESKTOP_OBJECT
, ListEntry
);
164 DPRINT("Scanning %wZ for %wS\n", &CurrentObject
->Name
, Name
);
165 if (Attributes
& OBJ_CASE_INSENSITIVE
)
167 if (_wcsicmp(CurrentObject
->Name
.Buffer
, Name
) == 0)
169 DPRINT("Found desktop at (0x%X)\n", CurrentObject
);
170 return CurrentObject
;
175 if (wcscmp(CurrentObject
->Name
.Buffer
, Name
) == 0)
177 DPRINT("Found desktop at (0x%X)\n", CurrentObject
);
178 return CurrentObject
;
181 Current
= Current
->Flink
;
184 DPRINT("Returning NULL\n");
191 IntWinStaObjectParse(PVOID Object
,
193 PUNICODE_STRING FullPath
,
201 DPRINT("Object (0x%X) Path (0x%X) *Path (%wS)\n", Object
, Path
, *Path
);
205 if ((Path
== NULL
) || ((*Path
) == NULL
))
207 return STATUS_SUCCESS
;
210 End
= wcschr((*Path
) + 1, '\\');
213 DPRINT("Name contains illegal characters\n");
214 return STATUS_UNSUCCESSFUL
;
217 FoundObject
= IntWinStaObjectFind(Object
, (*Path
) + 1, Attributes
);
218 if (FoundObject
== NULL
)
220 DPRINT("Name was not found\n");
221 return STATUS_UNSUCCESSFUL
;
224 Status
= ObReferenceObjectByPointer(
226 STANDARD_RIGHTS_REQUIRED
,
230 *NextObject
= FoundObject
;
236 /* PRIVATE FUNCTIONS **********************************************************/
239 * IntGetFullWindowStationName
241 * Get a full window station object name from a name specified in
242 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
243 * or NtUserOpenDesktop.
246 * TRUE on success, FALSE on failure.
250 IntGetFullWindowStationName(
251 OUT PUNICODE_STRING FullName
,
252 IN PUNICODE_STRING WinStaName
,
253 IN OPTIONAL PUNICODE_STRING DesktopName
)
257 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
258 if (WinStaName
!= NULL
)
259 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
260 if (DesktopName
!= NULL
)
261 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
262 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
263 if (FullName
->Buffer
== NULL
)
268 Buffer
= FullName
->Buffer
;
269 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
270 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
271 if (WinStaName
!= NULL
)
273 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
275 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
277 if (DesktopName
!= NULL
)
279 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
280 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
282 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
290 * IntValidateWindowStationHandle
292 * Validates the window station handle.
295 * If the function succeeds, the handle remains referenced. If the
296 * fucntion fails, last error is set.
300 IntValidateWindowStationHandle(
301 HWINSTA WindowStation
,
302 KPROCESSOR_MODE AccessMode
,
303 ACCESS_MASK DesiredAccess
,
304 PWINSTATION_OBJECT
*Object
)
308 if (WindowStation
== NULL
)
310 // DPRINT1("Invalid window station handle\n");
311 SetLastWin32Error(ERROR_INVALID_HANDLE
);
312 return STATUS_INVALID_HANDLE
;
315 Status
= ObReferenceObjectByHandle(
318 ExWindowStationObjectType
,
323 if (!NT_SUCCESS(Status
))
324 SetLastNtError(Status
);
330 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
334 Status
= ObReferenceObjectByPointer(
337 ExWindowStationObjectType
,
340 return NT_SUCCESS(Status
);
344 co_IntInitializeDesktopGraphics(VOID
)
346 UNICODE_STRING DriverName
;
347 if (! IntCreatePrimarySurface())
351 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
352 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
353 if (NULL
== ScreenDeviceContext
)
355 IntDestroyPrimarySurface();
358 DC_SetOwnership(ScreenDeviceContext
, NULL
);
360 UserAcquireOrReleaseInputOwnership(FALSE
);
362 /* Setup the cursor */
363 co_IntLoadDefaultCursors();
369 IntEndDesktopGraphics(VOID
)
371 UserAcquireOrReleaseInputOwnership(TRUE
);
372 if (NULL
!= ScreenDeviceContext
)
374 DC_SetOwnership(ScreenDeviceContext
, PsGetCurrentProcess());
375 NtGdiDeleteDC(ScreenDeviceContext
);
376 ScreenDeviceContext
= NULL
;
378 IntHideDesktop(IntGetActiveDesktop());
379 IntDestroyPrimarySurface();
385 return ScreenDeviceContext
;
388 /* PUBLIC FUNCTIONS ***********************************************************/
391 * NtUserCreateWindowStation
393 * Creates a new window station.
396 * lpszWindowStationName
397 * Pointer to a null-terminated string specifying the name of the
398 * window station to be created. Window station names are
399 * case-insensitive and cannot contain backslash characters (\).
400 * Only members of the Administrators group are allowed to specify a
404 * Requested type of access
407 * Security descriptor
409 * Unknown3, Unknown4, Unknown5
413 * If the function succeeds, the return value is a handle to the newly
414 * created window station. If the specified window station already
415 * exists, the function succeeds and returns a handle to the existing
416 * window station. If the function fails, the return value is NULL.
419 * Correct the prototype to match the Windows one (with 7 parameters
427 NtUserCreateWindowStation(
428 PUNICODE_STRING lpszWindowStationName
,
429 ACCESS_MASK dwDesiredAccess
,
430 LPSECURITY_ATTRIBUTES lpSecurity
,
435 PSYSTEM_CURSORINFO CurInfo
;
436 UNICODE_STRING WindowStationName
;
437 PWINSTATION_OBJECT WindowStationObject
;
438 HWINSTA WindowStation
;
439 OBJECT_ATTRIBUTES ObjectAttributes
;
443 * Generate full window station name
446 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
449 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
454 * Try to open already existing window station
457 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
459 /* Initialize ObjectAttributes for the window station object */
460 InitializeObjectAttributes(
467 Status
= ObOpenObjectByName(
469 ExWindowStationObjectType
,
474 (PVOID
*)&WindowStation
);
476 if (NT_SUCCESS(Status
))
478 DPRINT("Successfully opened window station (%wZ)\n", WindowStationName
);
479 ExFreePool(WindowStationName
.Buffer
);
480 return (HWINSTA
)WindowStation
;
484 * No existing window station found, try to create new one
487 DPRINT("Creating window station (%wZ)\n", &WindowStationName
);
489 Status
= ObCreateObject(
491 ExWindowStationObjectType
,
495 sizeof(WINSTATION_OBJECT
),
498 (PVOID
*)&WindowStationObject
);
500 if (!NT_SUCCESS(Status
))
502 DPRINT1("Failed creating window station (%wZ)\n", &WindowStationName
);
503 ExFreePool(WindowStationName
.Buffer
);
504 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
508 WindowStationObject
->Name
= *lpszWindowStationName
;
510 Status
= ObInsertObject(
511 (PVOID
)WindowStationObject
,
513 STANDARD_RIGHTS_REQUIRED
,
516 (PVOID
*)&WindowStation
);
518 if (!NT_SUCCESS(Status
))
520 DPRINT1("Failed creating window station (%wZ)\n", &WindowStationName
);
521 ExFreePool(WindowStationName
.Buffer
);
522 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
523 ObDereferenceObject(WindowStationObject
);
528 * Initialize the new window station object
531 if(!(CurInfo
= ExAllocatePool(PagedPool
, sizeof(SYSTEM_CURSORINFO
))))
533 ExFreePool(WindowStationName
.Buffer
);
534 /* FIXME - Delete window station object */
535 ObDereferenceObject(WindowStationObject
);
536 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
540 CurInfo
->Enabled
= FALSE
;
541 CurInfo
->ButtonsDown
= 0;
542 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
543 CurInfo
->LastBtnDown
= 0;
544 CurInfo
->CurrentCursorObject
= NULL
;
545 CurInfo
->ShowingCursor
= 0;
547 /* FIXME: Obtain the following information from the registry */
548 CurInfo
->SwapButtons
= FALSE
;
549 CurInfo
->DblClickSpeed
= 500;
550 CurInfo
->DblClickWidth
= 4;
551 CurInfo
->DblClickHeight
= 4;
553 WindowStationObject
->SystemCursor
= CurInfo
;
555 if (!IntSetupCurIconHandles(WindowStationObject
))
557 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
558 /* FIXME: Complain more loudly? */
561 DPRINT("Window station successfully created (%wZ)\n", lpszWindowStationName
);
562 ExFreePool(WindowStationName
.Buffer
);
563 return WindowStation
;
567 * NtUserOpenWindowStation
569 * Opens an existing window station.
572 * lpszWindowStationName
573 * Name of the existing window station.
576 * Requested type of access.
579 * If the function succeeds, the return value is the handle to the
580 * specified window station. If the function fails, the return value
584 * The returned handle can be closed with NtUserCloseWindowStation.
591 NtUserOpenWindowStation(
592 PUNICODE_STRING lpszWindowStationName
,
593 ACCESS_MASK dwDesiredAccess
)
595 UNICODE_STRING WindowStationName
;
596 HWINSTA WindowStation
;
597 OBJECT_ATTRIBUTES ObjectAttributes
;
601 * Generate full window station name
604 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
607 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
611 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
613 /* Initialize ObjectAttributes for the window station object */
614 InitializeObjectAttributes(
621 Status
= ObOpenObjectByName(
623 ExWindowStationObjectType
,
628 (PVOID
*)&WindowStation
);
630 if (!NT_SUCCESS(Status
))
632 SetLastNtError(Status
);
633 ExFreePool(WindowStationName
.Buffer
);
637 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName
);
638 ExFreePool(WindowStationName
.Buffer
);
640 return WindowStation
;
644 * NtUserCloseWindowStation
646 * Closes a window station handle.
650 * Handle to the window station.
656 * The window station handle can be created with NtUserCreateWindowStation
657 * or NtUserOpenWindowStation. Attemps to close a handle to the window
658 * station assigned to the calling process will fail.
666 NtUserCloseWindowStation(
669 PWINSTATION_OBJECT Object
;
672 DPRINT("About to close window station handle (0x%X)\n", hWinSta
);
674 Status
= IntValidateWindowStationHandle(
680 if (!NT_SUCCESS(Status
))
682 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta
);
687 /* FIXME - free the cursor information when actually deleting the object!! */
688 ASSERT(Object
->SystemCursor
);
689 ExFreePool(Object
->SystemCursor
);
692 ObDereferenceObject(Object
);
694 DPRINT("Closing window station handle (0x%X)\n", hWinSta
);
696 Status
= ZwClose(hWinSta
);
697 if (!NT_SUCCESS(Status
))
699 SetLastNtError(Status
);
707 * NtUserGetObjectInformation
709 * The NtUserGetObjectInformation function retrieves information about a
710 * window station or desktop object.
714 * Handle to the window station or desktop object for which to
715 * return information. This can be a handle of type HDESK or HWINSTA
716 * (for example, a handle returned by NtUserCreateWindowStation,
717 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
720 * Specifies the object information to be retrieved.
723 * Pointer to a buffer to receive the object information.
726 * Specifies the size, in bytes, of the buffer pointed to by the
730 * Pointer to a variable receiving the number of bytes required to
731 * store the requested information. If this variable's value is
732 * greater than the value of the nLength parameter when the function
733 * returns, the function returns FALSE, and none of the information
734 * is copied to the pvInfo buffer. If the value of the variable pointed
735 * to by lpnLengthNeeded is less than or equal to the value of nLength,
736 * the entire information block is copied.
739 * If the function succeeds, the return value is nonzero. If the function
740 * fails, the return value is zero.
747 NtUserGetObjectInformation(
752 PDWORD nLengthNeeded
)
754 PWINSTATION_OBJECT WinStaObject
= NULL
;
755 PDESKTOP_OBJECT DesktopObject
= NULL
;
760 /* try windowstation */
761 DPRINT("Trying to open window station 0x%x\n", hObject
);
762 Status
= IntValidateWindowStationHandle(
764 UserMode
,/*ExGetPreviousMode(),*/
765 GENERIC_READ
, /* FIXME: is this ok? */
769 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
771 DPRINT("Failed: 0x%x\n", Status
);
772 SetLastNtError(Status
);
776 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
779 DPRINT("Trying to open desktop 0x%x\n", hObject
);
780 Status
= IntValidateDesktopHandle(
782 UserMode
,/*ExGetPreviousMode(),*/
783 GENERIC_READ
, /* FIXME: is this ok? */
785 if (!NT_SUCCESS(Status
))
787 DPRINT("Failed: 0x%x\n", Status
);
788 SetLastNtError(Status
);
792 DPRINT("WinSta or Desktop opened!!\n");
798 Status
= STATUS_NOT_IMPLEMENTED
;
799 DPRINT1("UOI_FLAGS unimplemented!\n");
803 if (WinStaObject
!= NULL
)
805 pvData
= WinStaObject
->Name
.Buffer
;
806 nDataSize
= WinStaObject
->Name
.Length
+2;
807 Status
= STATUS_SUCCESS
;
809 else if (DesktopObject
!= NULL
)
811 pvData
= DesktopObject
->Name
.Buffer
;
812 nDataSize
= DesktopObject
->Name
.Length
+2;
813 Status
= STATUS_SUCCESS
;
816 Status
= STATUS_INVALID_PARAMETER
;
820 if (WinStaObject
!= NULL
)
822 pvData
= L
"WindowStation";
823 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
824 Status
= STATUS_SUCCESS
;
826 else if (DesktopObject
!= NULL
)
829 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
830 Status
= STATUS_SUCCESS
;
833 Status
= STATUS_INVALID_PARAMETER
;
837 Status
= STATUS_NOT_IMPLEMENTED
;
838 DPRINT1("UOI_USER_SID unimplemented!\n");
842 Status
= STATUS_INVALID_PARAMETER
;
846 /* try to copy data to caller */
847 if (Status
== STATUS_SUCCESS
)
849 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
850 *nLengthNeeded
= nDataSize
;
851 if (nLength
>= nDataSize
)
852 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
854 Status
= STATUS_BUFFER_TOO_SMALL
;
857 /* release objects */
858 if (WinStaObject
!= NULL
)
859 ObDereferenceObject(WinStaObject
);
860 if (DesktopObject
!= NULL
)
861 ObDereferenceObject(DesktopObject
);
863 SetLastNtError(Status
);
864 return NT_SUCCESS(Status
);
868 * NtUserSetObjectInformation
870 * The NtUserSetObjectInformation function sets information about a
871 * window station or desktop object.
875 * Handle to the window station or desktop object for which to set
876 * object information. This value can be a handle of type HDESK or
880 * Specifies the object information to be set.
883 * Pointer to a buffer containing the object information.
886 * Specifies the size, in bytes, of the information contained in the
887 * buffer pointed to by pvInfo.
890 * If the function succeeds, the return value is nonzero. If the function
891 * fails the return value is zero.
899 NtUserSetObjectInformation(
905 /* FIXME: ZwQueryObject */
906 /* FIXME: ZwSetInformationObject */
907 SetLastNtError(STATUS_UNSUCCESSFUL
);
915 UserGetProcessWindowStation(VOID
)
917 if(PsGetCurrentProcess() != CsrProcess
)
919 return PsGetCurrentProcess()->Win32WindowStation
;
923 /* FIXME - get the pointer to the window station by querying the parent of
924 the desktop of the calling thread (which is a window station),
925 then use ObFindHandleForObject() to find a suitable handle */
926 DPRINT1("CSRSS called NtUserGetProcessWindowStation()!!! returned NULL!\n");
933 * NtUserGetProcessWindowStation
935 * Returns a handle to the current process window station.
938 * If the function succeeds, the return value is handle to the window
939 * station assigned to the current process. If the function fails, the
940 * return value is NULL.
947 NtUserGetProcessWindowStation(VOID
)
949 return UserGetProcessWindowStation();
952 PWINSTATION_OBJECT FASTCALL
953 IntGetWinStaObj(VOID
)
955 PWINSTATION_OBJECT WinStaObj
;
958 * just a temporary hack, this will be gone soon
961 if(PsGetWin32Thread() != NULL
&& PsGetWin32Thread()->Desktop
!= NULL
)
963 WinStaObj
= PsGetWin32Thread()->Desktop
->WindowStation
;
964 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
966 else if(PsGetCurrentProcess() != CsrProcess
)
968 NTSTATUS Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
972 if(!NT_SUCCESS(Status
))
974 SetLastNtError(Status
);
987 * NtUserSetProcessWindowStation
989 * Assigns a window station to the current process.
993 * Handle to the window station.
1003 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1006 PWINSTATION_OBJECT NewWinSta
;
1009 DPRINT("About to set process window station with handle (0x%X)\n",
1012 if(PsGetCurrentProcess() == CsrProcess
)
1014 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1015 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1019 Status
= IntValidateWindowStationHandle(
1025 if (!NT_SUCCESS(Status
))
1027 DPRINT("Validation of window station handle (0x%X) failed\n",
1029 SetLastNtError(Status
);
1034 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1037 /* FIXME - dereference the old window station, etc... */
1038 hOld
= InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation
, hWindowStation
);
1040 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1041 PsGetCurrentProcess()->Win32WindowStation
);
1047 * NtUserLockWindowStation
1049 * Locks switching desktops. Only the logon application is allowed to call this function.
1056 NtUserLockWindowStation(HWINSTA hWindowStation
)
1058 PWINSTATION_OBJECT Object
;
1061 DPRINT("About to set process window station with handle (0x%X)\n",
1064 if(PsGetWin32Process() != LogonProcess
)
1066 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1067 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1071 Status
= IntValidateWindowStationHandle(
1076 if (!NT_SUCCESS(Status
))
1078 DPRINT("Validation of window station handle (0x%X) failed\n",
1080 SetLastNtError(Status
);
1084 Object
->Flags
|= WSS_LOCKED
;
1086 ObDereferenceObject(Object
);
1091 * NtUserUnlockWindowStation
1093 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1100 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1102 PWINSTATION_OBJECT Object
;
1106 DPRINT("About to set process window station with handle (0x%X)\n",
1109 if(PsGetWin32Process() != LogonProcess
)
1111 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1112 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1116 Status
= IntValidateWindowStationHandle(
1121 if (!NT_SUCCESS(Status
))
1123 DPRINT("Validation of window station handle (0x%X) failed\n",
1125 SetLastNtError(Status
);
1129 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1130 Object
->Flags
&= ~WSS_LOCKED
;
1132 ObDereferenceObject(Object
);
1137 * NtUserSetWindowStationUser
1144 NtUserSetWindowStationUser(
1155 static NTSTATUS FASTCALL
1156 BuildWindowStationNameList(
1159 PULONG pRequiredSize
)
1161 OBJECT_ATTRIBUTES ObjectAttributes
;
1163 HANDLE DirectoryHandle
;
1164 UNICODE_STRING DirectoryName
;
1165 char InitialBuffer
[256], *Buffer
;
1166 ULONG Context
, ReturnLength
, BufferSize
;
1168 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1172 * Generate name of window station directory
1174 if (!IntGetFullWindowStationName(&DirectoryName
, NULL
, NULL
))
1176 return STATUS_INSUFFICIENT_RESOURCES
;
1180 * Try to open the directory.
1182 InitializeObjectAttributes(
1185 OBJ_CASE_INSENSITIVE
,
1189 Status
= ZwOpenDirectoryObject(
1194 ExFreePool(DirectoryName
.Buffer
);
1196 if (!NT_SUCCESS(Status
))
1201 /* First try to query the directory using a fixed-size buffer */
1204 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1205 FALSE
, TRUE
, &Context
, &ReturnLength
);
1206 if (NT_SUCCESS(Status
))
1208 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1209 FALSE
, &Context
, NULL
))
1211 /* Our fixed-size buffer is large enough */
1212 Buffer
= InitialBuffer
;
1218 /* Need a larger buffer, check how large exactly */
1219 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1221 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1223 BufferSize
= ReturnLength
;
1224 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1227 ObDereferenceObject(DirectoryHandle
);
1228 return STATUS_NO_MEMORY
;
1231 /* We should have a sufficiently large buffer now */
1233 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1234 FALSE
, TRUE
, &Context
, &ReturnLength
);
1235 if (! NT_SUCCESS(Status
) ||
1236 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1237 FALSE
, &Context
, NULL
))
1239 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1241 ObDereferenceObject(DirectoryHandle
);
1242 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1247 ZwClose(DirectoryHandle
);
1250 * Count the required size of buffer.
1252 ReturnLength
= sizeof(DWORD
);
1254 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1257 ReturnLength
+= DirEntry
->ObjectName
.Length
+ sizeof(WCHAR
);
1260 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1261 if (NULL
!= pRequiredSize
)
1263 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1264 if (! NT_SUCCESS(Status
))
1266 if (Buffer
!= InitialBuffer
)
1270 return STATUS_BUFFER_TOO_SMALL
;
1275 * Check if the supplied buffer is large enough.
1277 if (dwSize
< ReturnLength
)
1279 if (Buffer
!= InitialBuffer
)
1283 return STATUS_BUFFER_TOO_SMALL
;
1287 * Generate the resulting buffer contents.
1289 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1290 if (! NT_SUCCESS(Status
))
1292 if (Buffer
!= InitialBuffer
)
1298 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1301 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1304 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->ObjectName
.Buffer
, DirEntry
->ObjectName
.Length
);
1305 if (! NT_SUCCESS(Status
))
1307 if (Buffer
!= InitialBuffer
)
1313 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->ObjectName
.Length
);
1314 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1315 if (! NT_SUCCESS(Status
))
1317 if (Buffer
!= InitialBuffer
)
1323 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1329 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1334 return STATUS_SUCCESS
;
1337 static NTSTATUS FASTCALL
1338 BuildDesktopNameList(
1339 HWINSTA hWindowStation
,
1342 PULONG pRequiredSize
)
1345 PWINSTATION_OBJECT WindowStation
;
1347 PLIST_ENTRY DesktopEntry
;
1348 PDESKTOP_OBJECT DesktopObject
;
1353 Status
= IntValidateWindowStationHandle(hWindowStation
,
1357 if (! NT_SUCCESS(Status
))
1362 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1365 * Count the required size of buffer.
1367 ReturnLength
= sizeof(DWORD
);
1369 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1370 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1371 DesktopEntry
= DesktopEntry
->Flink
)
1373 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1374 ReturnLength
+= DesktopObject
->Name
.Length
+ sizeof(WCHAR
);
1377 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1378 if (NULL
!= pRequiredSize
)
1380 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1381 if (! NT_SUCCESS(Status
))
1383 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1384 ObDereferenceObject(WindowStation
);
1385 return STATUS_BUFFER_TOO_SMALL
;
1390 * Check if the supplied buffer is large enough.
1392 if (dwSize
< ReturnLength
)
1394 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1395 ObDereferenceObject(WindowStation
);
1396 return STATUS_BUFFER_TOO_SMALL
;
1400 * Generate the resulting buffer contents.
1402 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1403 if (! NT_SUCCESS(Status
))
1405 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1406 ObDereferenceObject(WindowStation
);
1409 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1412 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1413 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1414 DesktopEntry
= DesktopEntry
->Flink
)
1416 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1417 Status
= MmCopyToCaller(lpBuffer
, DesktopObject
->Name
.Buffer
, DesktopObject
->Name
.Length
);
1418 if (! NT_SUCCESS(Status
))
1420 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1421 ObDereferenceObject(WindowStation
);
1424 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DesktopObject
->Name
.Length
);
1425 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1426 if (! NT_SUCCESS(Status
))
1428 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1429 ObDereferenceObject(WindowStation
);
1432 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1438 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1439 ObDereferenceObject(WindowStation
);
1441 return STATUS_SUCCESS
;
1445 * NtUserBuildNameList
1447 * Function used for enumeration of desktops or window stations.
1451 * For enumeration of window stations this parameter must be set to
1452 * zero. Otherwise it's handle for window station.
1455 * Size of buffer passed by caller.
1458 * Buffer passed by caller. If the function succedes, the buffer is
1459 * filled with window station/desktop count (in first DWORD) and
1460 * NULL-terminated window station/desktop names.
1463 * If the function suceedes, this is the number of bytes copied.
1464 * Otherwise it's size of buffer needed for function to succeed.
1471 NtUserBuildNameList(
1472 HWINSTA hWindowStation
,
1475 PULONG pRequiredSize
)
1477 /* The WindowStation name list and desktop name list are build in completely
1478 different ways. Call the appropriate function */
1479 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1480 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);