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 if (Reason
== ObCreateHandle
)
112 DPRINT("Creating window station (0x%X)\n", WinSta
);
114 KeInitializeSpinLock(&WinSta
->Lock
);
116 InitializeListHead(&WinSta
->DesktopListHead
);
118 WinSta
->AtomTable
= NULL
;
120 Status
= RtlCreateAtomTable(37, &WinSta
->AtomTable
);
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(PVOID Object
,
191 PUNICODE_STRING FullPath
,
199 DPRINT("Object (0x%X) Path (0x%X) *Path (%wS)\n", Object
, Path
, *Path
);
203 if ((Path
== NULL
) || ((*Path
) == NULL
))
205 return STATUS_SUCCESS
;
208 End
= wcschr((*Path
) + 1, '\\');
211 DPRINT("Name contains illegal characters\n");
212 return STATUS_UNSUCCESSFUL
;
215 FoundObject
= IntWinStaObjectFind(Object
, (*Path
) + 1, Attributes
);
216 if (FoundObject
== NULL
)
218 DPRINT("Name was not found\n");
219 return STATUS_UNSUCCESSFUL
;
222 Status
= ObReferenceObjectByPointer(
224 STANDARD_RIGHTS_REQUIRED
,
228 *NextObject
= FoundObject
;
234 /* PRIVATE FUNCTIONS **********************************************************/
237 * IntGetFullWindowStationName
239 * Get a full window station object name from a name specified in
240 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
241 * or NtUserOpenDesktop.
244 * TRUE on success, FALSE on failure.
248 IntGetFullWindowStationName(
249 OUT PUNICODE_STRING FullName
,
250 IN PUNICODE_STRING WinStaName
,
251 IN OPTIONAL PUNICODE_STRING DesktopName
)
255 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
256 if (WinStaName
!= NULL
)
257 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
258 if (DesktopName
!= NULL
)
259 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
260 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
261 if (FullName
->Buffer
== NULL
)
266 Buffer
= FullName
->Buffer
;
267 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
268 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
269 if (WinStaName
!= NULL
)
271 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
273 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
275 if (DesktopName
!= NULL
)
277 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
278 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
280 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
288 * IntValidateWindowStationHandle
290 * Validates the window station handle.
293 * If the function succeeds, the handle remains referenced. If the
294 * fucntion fails, last error is set.
298 IntValidateWindowStationHandle(
299 HWINSTA WindowStation
,
300 KPROCESSOR_MODE AccessMode
,
301 ACCESS_MASK DesiredAccess
,
302 PWINSTATION_OBJECT
*Object
)
306 if (WindowStation
== NULL
)
308 // DPRINT1("Invalid window station handle\n");
309 SetLastWin32Error(ERROR_INVALID_HANDLE
);
310 return STATUS_INVALID_HANDLE
;
313 Status
= ObReferenceObjectByHandle(
316 ExWindowStationObjectType
,
321 if (!NT_SUCCESS(Status
))
322 SetLastNtError(Status
);
328 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
332 Status
= ObReferenceObjectByPointer(
335 ExWindowStationObjectType
,
338 return NT_SUCCESS(Status
);
342 co_IntInitializeDesktopGraphics(VOID
)
344 UNICODE_STRING DriverName
;
345 if (! IntCreatePrimarySurface())
349 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
350 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
351 if (NULL
== ScreenDeviceContext
)
353 IntDestroyPrimarySurface();
356 DC_SetOwnership(ScreenDeviceContext
, NULL
);
358 UserAcquireOrReleaseInputOwnership(FALSE
);
360 /* Setup the cursor */
361 co_IntLoadDefaultCursors();
367 IntEndDesktopGraphics(VOID
)
369 UserAcquireOrReleaseInputOwnership(TRUE
);
370 if (NULL
!= ScreenDeviceContext
)
372 DC_SetOwnership(ScreenDeviceContext
, PsGetCurrentProcess());
373 NtGdiDeleteDC(ScreenDeviceContext
);
374 ScreenDeviceContext
= NULL
;
376 IntHideDesktop(IntGetActiveDesktop());
377 IntDestroyPrimarySurface();
383 return ScreenDeviceContext
;
386 /* PUBLIC FUNCTIONS ***********************************************************/
389 * NtUserCreateWindowStation
391 * Creates a new window station.
394 * lpszWindowStationName
395 * Pointer to a null-terminated string specifying the name of the
396 * window station to be created. Window station names are
397 * case-insensitive and cannot contain backslash characters (\).
398 * Only members of the Administrators group are allowed to specify a
402 * Requested type of access
405 * Security descriptor
407 * Unknown3, Unknown4, Unknown5
411 * If the function succeeds, the return value is a handle to the newly
412 * created window station. If the specified window station already
413 * exists, the function succeeds and returns a handle to the existing
414 * window station. If the function fails, the return value is NULL.
417 * Correct the prototype to match the Windows one (with 7 parameters
425 NtUserCreateWindowStation(
426 PUNICODE_STRING lpszWindowStationName
,
427 ACCESS_MASK dwDesiredAccess
,
428 LPSECURITY_ATTRIBUTES lpSecurity
,
433 PSYSTEM_CURSORINFO CurInfo
;
434 UNICODE_STRING WindowStationName
;
435 PWINSTATION_OBJECT WindowStationObject
;
436 HWINSTA WindowStation
;
437 OBJECT_ATTRIBUTES ObjectAttributes
;
441 * Generate full window station name
444 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
447 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
452 * Try to open already existing window station
455 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
457 /* Initialize ObjectAttributes for the window station object */
458 InitializeObjectAttributes(
465 Status
= ObOpenObjectByName(
467 ExWindowStationObjectType
,
472 (PVOID
*)&WindowStation
);
474 if (NT_SUCCESS(Status
))
476 DPRINT("Successfully opened window station (%wZ)\n", WindowStationName
);
477 ExFreePool(WindowStationName
.Buffer
);
478 return (HWINSTA
)WindowStation
;
482 * No existing window station found, try to create new one
485 DPRINT("Creating window station (%wZ)\n", &WindowStationName
);
487 Status
= ObCreateObject(
489 ExWindowStationObjectType
,
493 sizeof(WINSTATION_OBJECT
),
496 (PVOID
*)&WindowStationObject
);
498 if (!NT_SUCCESS(Status
))
500 DPRINT1("Failed creating window station (%wZ)\n", &WindowStationName
);
501 ExFreePool(WindowStationName
.Buffer
);
502 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
506 WindowStationObject
->Name
= *lpszWindowStationName
;
508 Status
= ObInsertObject(
509 (PVOID
)WindowStationObject
,
511 STANDARD_RIGHTS_REQUIRED
,
514 (PVOID
*)&WindowStation
);
516 if (!NT_SUCCESS(Status
))
518 DPRINT1("Failed creating window station (%wZ)\n", &WindowStationName
);
519 ExFreePool(WindowStationName
.Buffer
);
520 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
521 ObDereferenceObject(WindowStationObject
);
526 * Initialize the new window station object
529 if(!(CurInfo
= ExAllocatePool(PagedPool
, sizeof(SYSTEM_CURSORINFO
))))
531 ExFreePool(WindowStationName
.Buffer
);
532 /* FIXME - Delete window station object */
533 ObDereferenceObject(WindowStationObject
);
534 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
538 WindowStationObject
->HandleTable
= ObmCreateHandleTable();
539 if (!WindowStationObject
->HandleTable
)
541 DPRINT("Failed creating handle table\n");
543 ExFreePool(WindowStationName
.Buffer
);
544 /* FIXME - Delete window station object */
545 ObDereferenceObject(WindowStationObject
);
546 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
550 InitHotKeys(WindowStationObject
);
552 ExInitializeFastMutex(&CurInfo
->CursorMutex
);
553 CurInfo
->Enabled
= FALSE
;
554 CurInfo
->ButtonsDown
= 0;
555 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
556 CurInfo
->LastBtnDown
= 0;
557 CurInfo
->CurrentCursorObject
= NULL
;
558 CurInfo
->ShowingCursor
= 0;
560 /* FIXME: Obtain the following information from the registry */
561 CurInfo
->SwapButtons
= FALSE
;
562 CurInfo
->DblClickSpeed
= 500;
563 CurInfo
->DblClickWidth
= 4;
564 CurInfo
->DblClickHeight
= 4;
566 WindowStationObject
->SystemCursor
= CurInfo
;
568 if (!IntSetupCurIconHandles(WindowStationObject
))
570 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
571 /* FIXME: Complain more loudly? */
574 DPRINT("Window station successfully created (%wZ)\n", lpszWindowStationName
);
575 ExFreePool(WindowStationName
.Buffer
);
576 return WindowStation
;
580 * NtUserOpenWindowStation
582 * Opens an existing window station.
585 * lpszWindowStationName
586 * Name of the existing window station.
589 * Requested type of access.
592 * If the function succeeds, the return value is the handle to the
593 * specified window station. If the function fails, the return value
597 * The returned handle can be closed with NtUserCloseWindowStation.
604 NtUserOpenWindowStation(
605 PUNICODE_STRING lpszWindowStationName
,
606 ACCESS_MASK dwDesiredAccess
)
608 UNICODE_STRING WindowStationName
;
609 HWINSTA WindowStation
;
610 OBJECT_ATTRIBUTES ObjectAttributes
;
614 * Generate full window station name
617 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
620 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
624 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
626 /* Initialize ObjectAttributes for the window station object */
627 InitializeObjectAttributes(
634 Status
= ObOpenObjectByName(
636 ExWindowStationObjectType
,
641 (PVOID
*)&WindowStation
);
643 if (!NT_SUCCESS(Status
))
645 SetLastNtError(Status
);
646 ExFreePool(WindowStationName
.Buffer
);
650 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName
);
651 ExFreePool(WindowStationName
.Buffer
);
653 return WindowStation
;
657 * NtUserCloseWindowStation
659 * Closes a window station handle.
663 * Handle to the window station.
669 * The window station handle can be created with NtUserCreateWindowStation
670 * or NtUserOpenWindowStation. Attemps to close a handle to the window
671 * station assigned to the calling process will fail.
679 NtUserCloseWindowStation(
682 PWINSTATION_OBJECT Object
;
685 DPRINT("About to close window station handle (0x%X)\n", hWinSta
);
687 Status
= IntValidateWindowStationHandle(
693 if (!NT_SUCCESS(Status
))
695 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta
);
700 /* FIXME - free the cursor information when actually deleting the object!! */
701 ASSERT(Object
->SystemCursor
);
702 ExFreePool(Object
->SystemCursor
);
705 ObDereferenceObject(Object
);
707 DPRINT("Closing window station handle (0x%X)\n", hWinSta
);
709 Status
= ZwClose(hWinSta
);
710 if (!NT_SUCCESS(Status
))
712 SetLastNtError(Status
);
720 * NtUserGetObjectInformation
722 * The NtUserGetObjectInformation function retrieves information about a
723 * window station or desktop object.
727 * Handle to the window station or desktop object for which to
728 * return information. This can be a handle of type HDESK or HWINSTA
729 * (for example, a handle returned by NtUserCreateWindowStation,
730 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
733 * Specifies the object information to be retrieved.
736 * Pointer to a buffer to receive the object information.
739 * Specifies the size, in bytes, of the buffer pointed to by the
743 * Pointer to a variable receiving the number of bytes required to
744 * store the requested information. If this variable's value is
745 * greater than the value of the nLength parameter when the function
746 * returns, the function returns FALSE, and none of the information
747 * is copied to the pvInfo buffer. If the value of the variable pointed
748 * to by lpnLengthNeeded is less than or equal to the value of nLength,
749 * the entire information block is copied.
752 * If the function succeeds, the return value is nonzero. If the function
753 * fails, the return value is zero.
760 NtUserGetObjectInformation(
765 PDWORD nLengthNeeded
)
767 PWINSTATION_OBJECT WinStaObject
= NULL
;
768 PDESKTOP_OBJECT DesktopObject
= NULL
;
773 /* try windowstation */
774 DPRINT("Trying to open window station 0x%x\n", hObject
);
775 Status
= IntValidateWindowStationHandle(
777 UserMode
,/*ExGetPreviousMode(),*/
778 GENERIC_READ
, /* FIXME: is this ok? */
782 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
784 DPRINT("Failed: 0x%x\n", Status
);
785 SetLastNtError(Status
);
789 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
792 DPRINT("Trying to open desktop 0x%x\n", hObject
);
793 Status
= IntValidateDesktopHandle(
795 UserMode
,/*ExGetPreviousMode(),*/
796 GENERIC_READ
, /* FIXME: is this ok? */
798 if (!NT_SUCCESS(Status
))
800 DPRINT("Failed: 0x%x\n", Status
);
801 SetLastNtError(Status
);
805 DPRINT("WinSta or Desktop opened!!\n");
811 Status
= STATUS_NOT_IMPLEMENTED
;
812 DPRINT1("UOI_FLAGS unimplemented!\n");
816 if (WinStaObject
!= NULL
)
818 pvData
= WinStaObject
->Name
.Buffer
;
819 nDataSize
= WinStaObject
->Name
.Length
+2;
820 Status
= STATUS_SUCCESS
;
822 else if (DesktopObject
!= NULL
)
824 pvData
= DesktopObject
->Name
.Buffer
;
825 nDataSize
= DesktopObject
->Name
.Length
+2;
826 Status
= STATUS_SUCCESS
;
829 Status
= STATUS_INVALID_PARAMETER
;
833 if (WinStaObject
!= NULL
)
835 pvData
= L
"WindowStation";
836 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
837 Status
= STATUS_SUCCESS
;
839 else if (DesktopObject
!= NULL
)
842 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
843 Status
= STATUS_SUCCESS
;
846 Status
= STATUS_INVALID_PARAMETER
;
850 Status
= STATUS_NOT_IMPLEMENTED
;
851 DPRINT1("UOI_USER_SID unimplemented!\n");
855 Status
= STATUS_INVALID_PARAMETER
;
859 /* try to copy data to caller */
860 if (Status
== STATUS_SUCCESS
)
862 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
863 *nLengthNeeded
= nDataSize
;
864 if (nLength
>= nDataSize
)
865 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
867 Status
= STATUS_BUFFER_TOO_SMALL
;
870 /* release objects */
871 if (WinStaObject
!= NULL
)
872 ObDereferenceObject(WinStaObject
);
873 if (DesktopObject
!= NULL
)
874 ObDereferenceObject(DesktopObject
);
876 SetLastNtError(Status
);
877 return NT_SUCCESS(Status
);
881 * NtUserSetObjectInformation
883 * The NtUserSetObjectInformation function sets information about a
884 * window station or desktop object.
888 * Handle to the window station or desktop object for which to set
889 * object information. This value can be a handle of type HDESK or
893 * Specifies the object information to be set.
896 * Pointer to a buffer containing the object information.
899 * Specifies the size, in bytes, of the information contained in the
900 * buffer pointed to by pvInfo.
903 * If the function succeeds, the return value is nonzero. If the function
904 * fails the return value is zero.
912 NtUserSetObjectInformation(
918 /* FIXME: ZwQueryObject */
919 /* FIXME: ZwSetInformationObject */
920 SetLastNtError(STATUS_UNSUCCESSFUL
);
928 UserGetProcessWindowStation(VOID
)
930 if(PsGetCurrentProcess() != CsrProcess
)
932 return PsGetCurrentProcess()->Win32WindowStation
;
936 /* FIXME - get the pointer to the window station by querying the parent of
937 the desktop of the calling thread (which is a window station),
938 then use ObFindHandleForObject() to find a suitable handle */
939 DPRINT1("CSRSS called NtUserGetProcessWindowStation()!!! returned NULL!\n");
946 * NtUserGetProcessWindowStation
948 * Returns a handle to the current process window station.
951 * If the function succeeds, the return value is handle to the window
952 * station assigned to the current process. If the function fails, the
953 * return value is NULL.
960 NtUserGetProcessWindowStation(VOID
)
962 return UserGetProcessWindowStation();
965 PWINSTATION_OBJECT FASTCALL
966 IntGetWinStaObj(VOID
)
968 PWINSTATION_OBJECT WinStaObj
;
971 * just a temporary hack, this will be gone soon
974 if(PsGetWin32Thread() != NULL
&& PsGetWin32Thread()->Desktop
!= NULL
)
976 WinStaObj
= PsGetWin32Thread()->Desktop
->WindowStation
;
977 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
979 else if(PsGetCurrentProcess() != CsrProcess
)
981 NTSTATUS Status
= IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation
,
985 if(!NT_SUCCESS(Status
))
987 SetLastNtError(Status
);
1000 * NtUserSetProcessWindowStation
1002 * Assigns a window station to the current process.
1006 * Handle to the window station.
1016 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1019 PWINSTATION_OBJECT NewWinSta
;
1022 DPRINT("About to set process window station with handle (0x%X)\n",
1025 if(PsGetCurrentProcess() == CsrProcess
)
1027 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1028 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1032 Status
= IntValidateWindowStationHandle(
1038 if (!NT_SUCCESS(Status
))
1040 DPRINT("Validation of window station handle (0x%X) failed\n",
1042 SetLastNtError(Status
);
1047 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1050 /* FIXME - dereference the old window station, etc... */
1051 hOld
= InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation
, hWindowStation
);
1053 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1054 PsGetCurrentProcess()->Win32WindowStation
);
1060 * NtUserLockWindowStation
1062 * Locks switching desktops. Only the logon application is allowed to call this function.
1069 NtUserLockWindowStation(HWINSTA hWindowStation
)
1071 PWINSTATION_OBJECT Object
;
1074 DPRINT("About to set process window station with handle (0x%X)\n",
1077 if(PsGetWin32Process() != LogonProcess
)
1079 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1080 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1084 Status
= IntValidateWindowStationHandle(
1089 if (!NT_SUCCESS(Status
))
1091 DPRINT("Validation of window station handle (0x%X) failed\n",
1093 SetLastNtError(Status
);
1097 Object
->Flags
|= WSS_LOCKED
;
1099 ObDereferenceObject(Object
);
1104 * NtUserUnlockWindowStation
1106 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1113 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1115 PWINSTATION_OBJECT Object
;
1119 DPRINT("About to set process window station with handle (0x%X)\n",
1122 if(PsGetWin32Process() != LogonProcess
)
1124 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1125 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1129 Status
= IntValidateWindowStationHandle(
1134 if (!NT_SUCCESS(Status
))
1136 DPRINT("Validation of window station handle (0x%X) failed\n",
1138 SetLastNtError(Status
);
1142 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1143 Object
->Flags
&= ~WSS_LOCKED
;
1145 ObDereferenceObject(Object
);
1150 * NtUserSetWindowStationUser
1157 NtUserSetWindowStationUser(
1168 static NTSTATUS FASTCALL
1169 BuildWindowStationNameList(
1172 PULONG pRequiredSize
)
1174 OBJECT_ATTRIBUTES ObjectAttributes
;
1176 HANDLE DirectoryHandle
;
1177 UNICODE_STRING DirectoryName
;
1178 char InitialBuffer
[256], *Buffer
;
1179 ULONG Context
, ReturnLength
, BufferSize
;
1181 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1185 * Generate name of window station directory
1187 if (!IntGetFullWindowStationName(&DirectoryName
, NULL
, NULL
))
1189 return STATUS_INSUFFICIENT_RESOURCES
;
1193 * Try to open the directory.
1195 InitializeObjectAttributes(
1198 OBJ_CASE_INSENSITIVE
,
1202 Status
= ZwOpenDirectoryObject(
1207 ExFreePool(DirectoryName
.Buffer
);
1209 if (!NT_SUCCESS(Status
))
1214 /* First try to query the directory using a fixed-size buffer */
1217 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1218 FALSE
, TRUE
, &Context
, &ReturnLength
);
1219 if (NT_SUCCESS(Status
))
1221 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1222 FALSE
, &Context
, NULL
))
1224 /* Our fixed-size buffer is large enough */
1225 Buffer
= InitialBuffer
;
1231 /* Need a larger buffer, check how large exactly */
1232 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1234 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1236 BufferSize
= ReturnLength
;
1237 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1240 ObDereferenceObject(DirectoryHandle
);
1241 return STATUS_NO_MEMORY
;
1244 /* We should have a sufficiently large buffer now */
1246 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1247 FALSE
, TRUE
, &Context
, &ReturnLength
);
1248 if (! NT_SUCCESS(Status
) ||
1249 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1250 FALSE
, &Context
, NULL
))
1252 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1254 ObDereferenceObject(DirectoryHandle
);
1255 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1260 ZwClose(DirectoryHandle
);
1263 * Count the required size of buffer.
1265 ReturnLength
= sizeof(DWORD
);
1267 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1270 ReturnLength
+= DirEntry
->ObjectName
.Length
+ sizeof(WCHAR
);
1273 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1274 if (NULL
!= pRequiredSize
)
1276 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1277 if (! NT_SUCCESS(Status
))
1279 if (Buffer
!= InitialBuffer
)
1283 return STATUS_BUFFER_TOO_SMALL
;
1288 * Check if the supplied buffer is large enough.
1290 if (dwSize
< ReturnLength
)
1292 if (Buffer
!= InitialBuffer
)
1296 return STATUS_BUFFER_TOO_SMALL
;
1300 * Generate the resulting buffer contents.
1302 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1303 if (! NT_SUCCESS(Status
))
1305 if (Buffer
!= InitialBuffer
)
1311 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1314 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->ObjectName
.Length
;
1317 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->ObjectName
.Buffer
, DirEntry
->ObjectName
.Length
);
1318 if (! NT_SUCCESS(Status
))
1320 if (Buffer
!= InitialBuffer
)
1326 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->ObjectName
.Length
);
1327 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1328 if (! NT_SUCCESS(Status
))
1330 if (Buffer
!= InitialBuffer
)
1336 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1342 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1347 return STATUS_SUCCESS
;
1350 static NTSTATUS FASTCALL
1351 BuildDesktopNameList(
1352 HWINSTA hWindowStation
,
1355 PULONG pRequiredSize
)
1358 PWINSTATION_OBJECT WindowStation
;
1360 PLIST_ENTRY DesktopEntry
;
1361 PDESKTOP_OBJECT DesktopObject
;
1366 Status
= IntValidateWindowStationHandle(hWindowStation
,
1370 if (! NT_SUCCESS(Status
))
1375 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1378 * Count the required size of buffer.
1380 ReturnLength
= sizeof(DWORD
);
1382 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1383 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1384 DesktopEntry
= DesktopEntry
->Flink
)
1386 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1387 ReturnLength
+= DesktopObject
->Name
.Length
+ sizeof(WCHAR
);
1390 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1391 if (NULL
!= pRequiredSize
)
1393 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1394 if (! NT_SUCCESS(Status
))
1396 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1397 ObDereferenceObject(WindowStation
);
1398 return STATUS_BUFFER_TOO_SMALL
;
1403 * Check if the supplied buffer is large enough.
1405 if (dwSize
< ReturnLength
)
1407 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1408 ObDereferenceObject(WindowStation
);
1409 return STATUS_BUFFER_TOO_SMALL
;
1413 * Generate the resulting buffer contents.
1415 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1416 if (! NT_SUCCESS(Status
))
1418 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1419 ObDereferenceObject(WindowStation
);
1422 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1425 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1426 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1427 DesktopEntry
= DesktopEntry
->Flink
)
1429 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP_OBJECT
, ListEntry
);
1430 Status
= MmCopyToCaller(lpBuffer
, DesktopObject
->Name
.Buffer
, DesktopObject
->Name
.Length
);
1431 if (! NT_SUCCESS(Status
))
1433 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1434 ObDereferenceObject(WindowStation
);
1437 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DesktopObject
->Name
.Length
);
1438 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1439 if (! NT_SUCCESS(Status
))
1441 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1442 ObDereferenceObject(WindowStation
);
1445 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1451 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1452 ObDereferenceObject(WindowStation
);
1454 return STATUS_SUCCESS
;
1458 * NtUserBuildNameList
1460 * Function used for enumeration of desktops or window stations.
1464 * For enumeration of window stations this parameter must be set to
1465 * zero. Otherwise it's handle for window station.
1468 * Size of buffer passed by caller.
1471 * Buffer passed by caller. If the function succedes, the buffer is
1472 * filled with window station/desktop count (in first DWORD) and
1473 * NULL-terminated window station/desktop names.
1476 * If the function suceedes, this is the number of bytes copied.
1477 * Otherwise it's size of buffer needed for function to succeed.
1484 NtUserBuildNameList(
1485 HWINSTA hWindowStation
,
1488 PULONG pRequiredSize
)
1490 /* The WindowStation name list and desktop name list are build in completely
1491 different ways. Call the appropriate function */
1492 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1493 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);