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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 /* Winlogon sas window*/
49 /* INITALIZATION FUNCTIONS ****************************************************/
51 static GENERIC_MAPPING IntWindowStationMapping
=
53 STANDARD_RIGHTS_READ
| WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
,
54 STANDARD_RIGHTS_WRITE
| WINSTA_ACCESSCLIPBOARD
| WINSTA_CREATEDESKTOP
| WINSTA_WRITEATTRIBUTES
,
55 STANDARD_RIGHTS_EXECUTE
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_EXITWINDOWS
,
56 STANDARD_RIGHTS_REQUIRED
| WINSTA_ACCESSCLIPBOARD
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_CREATEDESKTOP
|
57 WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_EXITWINDOWS
|
58 WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
| WINSTA_WRITEATTRIBUTES
65 InitWindowStationImpl(VOID
)
67 OBJECT_ATTRIBUTES ObjectAttributes
;
68 HANDLE WindowStationsDirectory
;
69 UNICODE_STRING UnicodeString
;
73 * Create the '\Windows\WindowStations' directory
76 RtlInitUnicodeString(&UnicodeString
, WINSTA_ROOT_NAME
);
77 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeString
,
79 Status
= ZwCreateDirectoryObject(&WindowStationsDirectory
, 0,
81 if (!NT_SUCCESS(Status
))
83 DPRINT("Could not create \\Windows\\WindowStations directory "
84 "(Status 0x%X)\n", Status
);
88 /* Set Winsta Object Attributes */
89 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
90 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
92 return STATUS_SUCCESS
;
96 CleanupWindowStationImpl(VOID
)
98 return STATUS_SUCCESS
;
102 IntSetupClipboard(PWINSTATION_OBJECT WinStaObj
)
104 WinStaObj
->Clipboard
= ExAllocatePoolWithTag(PagedPool
, sizeof(CLIPBOARDSYSTEM
), TAG_WINSTA
);
105 if (WinStaObj
->Clipboard
)
107 RtlZeroMemory(WinStaObj
->Clipboard
, sizeof(CLIPBOARDSYSTEM
));
113 /* OBJECT CALLBACKS **********************************************************/
116 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
118 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
120 DPRINT("Deleting window station (0x%X)\n", WinSta
);
122 RtlDestroyAtomTable(WinSta
->AtomTable
);
124 RtlFreeUnicodeString(&WinSta
->Name
);
129 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters
)
131 PUNICODE_STRING RemainingName
= Parameters
->RemainingName
;
133 /* Assume we don't find anything */
134 *Parameters
->Object
= NULL
;
136 /* Check for an empty name */
137 if (!RemainingName
->Length
)
139 /* Make sure this is a window station, can't parse a desktop now */
140 if (Parameters
->ObjectType
!= ExWindowStationObjectType
)
143 return STATUS_OBJECT_TYPE_MISMATCH
;
146 /* Reference the window station and return */
147 ObReferenceObject(Parameters
->ParseObject
);
148 *Parameters
->Object
= Parameters
->ParseObject
;
149 return STATUS_SUCCESS
;
152 /* Check for leading slash */
153 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
156 RemainingName
->Buffer
++;
157 RemainingName
->Length
-= sizeof(WCHAR
);
158 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
161 /* Check if there is still a slash */
162 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
164 /* In this case, fail */
165 return STATUS_OBJECT_PATH_INVALID
;
169 * Check if we are parsing a desktop.
171 if (Parameters
->ObjectType
== ExDesktopObjectType
)
173 /* Then call the desktop parse routine */
174 return IntDesktopObjectParse(Parameters
->ParseObject
,
175 Parameters
->ObjectType
,
176 Parameters
->AccessState
,
177 Parameters
->AccessMode
,
178 Parameters
->Attributes
,
179 Parameters
->CompleteName
,
182 Parameters
->SecurityQos
,
186 /* Should hopefully never get here */
187 return STATUS_OBJECT_TYPE_MISMATCH
;
191 IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
195 ppi
= PsGetCurrentProcessWin32Process();
197 if(Parameters
->Handle
== ppi
->hwinsta
)
205 /* PRIVATE FUNCTIONS **********************************************************/
208 * IntGetFullWindowStationName
210 * Get a full window station object name from a name specified in
211 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
212 * or NtUserOpenDesktop.
215 * TRUE on success, FALSE on failure.
219 IntGetFullWindowStationName(
220 OUT PUNICODE_STRING FullName
,
221 IN PUNICODE_STRING WinStaName
,
222 IN OPTIONAL PUNICODE_STRING DesktopName
)
226 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
227 if (WinStaName
!= NULL
)
228 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
229 if (DesktopName
!= NULL
)
230 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
231 FullName
->MaximumLength
= FullName
->Length
;
232 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
233 if (FullName
->Buffer
== NULL
)
238 Buffer
= FullName
->Buffer
;
239 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
240 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
241 if (WinStaName
!= NULL
)
243 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
245 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
247 if (DesktopName
!= NULL
)
249 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
250 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
252 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
260 * IntValidateWindowStationHandle
262 * Validates the window station handle.
265 * If the function succeeds, the handle remains referenced. If the
266 * fucntion fails, last error is set.
270 IntValidateWindowStationHandle(
271 HWINSTA WindowStation
,
272 KPROCESSOR_MODE AccessMode
,
273 ACCESS_MASK DesiredAccess
,
274 PWINSTATION_OBJECT
*Object
)
278 if (WindowStation
== NULL
)
280 // DPRINT1("Invalid window station handle\n");
281 EngSetLastError(ERROR_INVALID_HANDLE
);
282 return STATUS_INVALID_HANDLE
;
285 Status
= ObReferenceObjectByHandle(
288 ExWindowStationObjectType
,
293 if (!NT_SUCCESS(Status
))
294 SetLastNtError(Status
);
300 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
304 Status
= ObReferenceObjectByPointer(
307 ExWindowStationObjectType
,
310 return NT_SUCCESS(Status
);
315 co_IntInitializeDesktopGraphics(VOID
)
318 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
319 if (! IntCreatePrimarySurface())
323 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
324 if (NULL
== ScreenDeviceContext
)
326 IntDestroyPrimarySurface();
329 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
331 /* Setup the cursor */
332 co_IntLoadDefaultCursors();
334 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
336 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
337 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
339 // FIXME! Move these to a update routine.
340 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
341 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
342 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
343 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
344 // Font is realized and this dc was previously set to internal DC_ATTR.
345 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
346 gpsi
->tmSysFont
= tmw
;
352 IntEndDesktopGraphics(VOID
)
354 if (NULL
!= ScreenDeviceContext
)
355 { // No need to allocate a new dcattr.
356 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
357 GreDeleteObject(ScreenDeviceContext
);
358 ScreenDeviceContext
= NULL
;
360 IntHideDesktop(IntGetActiveDesktop());
361 IntDestroyPrimarySurface();
367 return ScreenDeviceContext
;
370 /* PUBLIC FUNCTIONS ***********************************************************/
373 * NtUserCreateWindowStation
375 * Creates a new window station.
378 * lpszWindowStationName
379 * Pointer to a null-terminated string specifying the name of the
380 * window station to be created. Window station names are
381 * case-insensitive and cannot contain backslash characters (\).
382 * Only members of the Administrators group are allowed to specify a
386 * Requested type of access
389 * Security descriptor
391 * Unknown3, Unknown4, Unknown5
395 * If the function succeeds, the return value is a handle to the newly
396 * created window station. If the specified window station already
397 * exists, the function succeeds and returns a handle to the existing
398 * window station. If the function fails, the return value is NULL.
401 * Correct the prototype to match the Windows one (with 7 parameters
409 NtUserCreateWindowStation(
410 POBJECT_ATTRIBUTES ObjectAttributes
,
411 ACCESS_MASK dwDesiredAccess
,
418 UNICODE_STRING WindowStationName
;
419 PWINSTATION_OBJECT WindowStationObject
;
420 HWINSTA WindowStation
;
423 Status
= ObOpenObjectByName(
425 ExWindowStationObjectType
,
430 (PVOID
*)&WindowStation
);
432 if (NT_SUCCESS(Status
))
434 return (HWINSTA
)WindowStation
;
439 * No existing window station found, try to create new one
442 /* Capture window station name */
445 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
446 Status
= IntSafeCopyUnicodeString(&WindowStationName
, ObjectAttributes
->ObjectName
);
448 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
450 Status
=_SEH2_GetExceptionCode();
454 if (! NT_SUCCESS(Status
))
456 DPRINT1("Failed reading capturing window station name\n");
457 SetLastNtError(Status
);
461 /* Create the window station object */
462 Status
= ObCreateObject(
464 ExWindowStationObjectType
,
468 sizeof(WINSTATION_OBJECT
),
471 (PVOID
*)&WindowStationObject
);
473 if (!NT_SUCCESS(Status
))
475 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
476 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
480 Status
= ObInsertObject(
481 (PVOID
)WindowStationObject
,
483 STANDARD_RIGHTS_REQUIRED
,
486 (PVOID
*)&WindowStation
);
488 if (!NT_SUCCESS(Status
))
490 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
491 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
492 ObDereferenceObject(WindowStationObject
);
496 /* Initialize the window station */
497 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
499 KeInitializeSpinLock(&WindowStationObject
->Lock
);
500 InitializeListHead(&WindowStationObject
->DesktopListHead
);
501 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
502 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
503 WindowStationObject
->Name
= WindowStationName
;
504 WindowStationObject
->ScreenSaverRunning
= FALSE
;
505 WindowStationObject
->FlatMenu
= FALSE
;
507 if (!IntSetupClipboard(WindowStationObject
))
509 DPRINT1("WindowStation: Error Setting up the clipboard!!!\n");
512 if (InputWindowStation
== NULL
)
514 InputWindowStation
= WindowStationObject
;
519 return WindowStation
;
523 * NtUserOpenWindowStation
525 * Opens an existing window station.
528 * lpszWindowStationName
529 * Name of the existing window station.
532 * Requested type of access.
535 * If the function succeeds, the return value is the handle to the
536 * specified window station. If the function fails, the return value
540 * The returned handle can be closed with NtUserCloseWindowStation.
547 NtUserOpenWindowStation(
548 POBJECT_ATTRIBUTES ObjectAttributes
,
549 ACCESS_MASK dwDesiredAccess
)
551 HWINSTA WindowStation
;
554 Status
= ObOpenObjectByName(
556 ExWindowStationObjectType
,
561 (PVOID
*)&WindowStation
);
563 if (!NT_SUCCESS(Status
))
565 SetLastNtError(Status
);
569 return WindowStation
;
573 * NtUserCloseWindowStation
575 * Closes a window station handle.
579 * Handle to the window station.
585 * The window station handle can be created with NtUserCreateWindowStation
586 * or NtUserOpenWindowStation. Attemps to close a handle to the window
587 * station assigned to the calling process will fail.
595 NtUserCloseWindowStation(
598 PWINSTATION_OBJECT Object
;
601 DPRINT("About to close window station handle (0x%X)\n", hWinSta
);
603 if (hWinSta
== UserGetProcessWindowStation())
608 Status
= IntValidateWindowStationHandle(
614 if (!NT_SUCCESS(Status
))
616 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta
);
620 ObDereferenceObject(Object
);
622 DPRINT("Closing window station handle (0x%X)\n", hWinSta
);
624 Status
= ObCloseHandle(hWinSta
, UserMode
);
625 if (!NT_SUCCESS(Status
))
627 SetLastNtError(Status
);
635 * NtUserGetObjectInformation
637 * The NtUserGetObjectInformation function retrieves information about a
638 * window station or desktop object.
642 * Handle to the window station or desktop object for which to
643 * return information. This can be a handle of type HDESK or HWINSTA
644 * (for example, a handle returned by NtUserCreateWindowStation,
645 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
648 * Specifies the object information to be retrieved.
651 * Pointer to a buffer to receive the object information.
654 * Specifies the size, in bytes, of the buffer pointed to by the
658 * Pointer to a variable receiving the number of bytes required to
659 * store the requested information. If this variable's value is
660 * greater than the value of the nLength parameter when the function
661 * returns, the function returns FALSE, and none of the information
662 * is copied to the pvInfo buffer. If the value of the variable pointed
663 * to by lpnLengthNeeded is less than or equal to the value of nLength,
664 * the entire information block is copied.
667 * If the function succeeds, the return value is nonzero. If the function
668 * fails, the return value is zero.
675 NtUserGetObjectInformation(
680 PDWORD nLengthNeeded
)
682 PWINSTATION_OBJECT WinStaObject
= NULL
;
683 PDESKTOP DesktopObject
= NULL
;
688 /* try windowstation */
689 DPRINT("Trying to open window station 0x%x\n", hObject
);
690 Status
= IntValidateWindowStationHandle(
692 UserMode
,/*ExGetPreviousMode(),*/
693 GENERIC_READ
, /* FIXME: is this ok? */
697 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
699 DPRINT("Failed: 0x%x\n", Status
);
700 SetLastNtError(Status
);
704 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
707 DPRINT("Trying to open desktop 0x%x\n", hObject
);
708 Status
= IntValidateDesktopHandle(
710 UserMode
,/*ExGetPreviousMode(),*/
711 GENERIC_READ
, /* FIXME: is this ok? */
713 if (!NT_SUCCESS(Status
))
715 DPRINT("Failed: 0x%x\n", Status
);
716 SetLastNtError(Status
);
720 DPRINT("WinSta or Desktop opened!!\n");
726 Status
= STATUS_NOT_IMPLEMENTED
;
727 DPRINT1("UOI_FLAGS unimplemented!\n");
731 if (WinStaObject
!= NULL
)
733 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Buffer
;
734 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Length
+ 2;
735 Status
= STATUS_SUCCESS
;
737 else if (DesktopObject
!= NULL
)
739 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
;
740 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ 2;
741 Status
= STATUS_SUCCESS
;
744 Status
= STATUS_INVALID_PARAMETER
;
748 if (WinStaObject
!= NULL
)
750 pvData
= L
"WindowStation";
751 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
752 Status
= STATUS_SUCCESS
;
754 else if (DesktopObject
!= NULL
)
757 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
758 Status
= STATUS_SUCCESS
;
761 Status
= STATUS_INVALID_PARAMETER
;
765 Status
= STATUS_NOT_IMPLEMENTED
;
766 DPRINT1("UOI_USER_SID unimplemented!\n");
770 Status
= STATUS_INVALID_PARAMETER
;
774 /* try to copy data to caller */
775 if (Status
== STATUS_SUCCESS
)
777 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
778 *nLengthNeeded
= nDataSize
;
779 if (nLength
>= nDataSize
)
780 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
782 Status
= STATUS_BUFFER_TOO_SMALL
;
785 /* release objects */
786 if (WinStaObject
!= NULL
)
787 ObDereferenceObject(WinStaObject
);
788 if (DesktopObject
!= NULL
)
789 ObDereferenceObject(DesktopObject
);
791 SetLastNtError(Status
);
792 return NT_SUCCESS(Status
);
796 * NtUserSetObjectInformation
798 * The NtUserSetObjectInformation function sets information about a
799 * window station or desktop object.
803 * Handle to the window station or desktop object for which to set
804 * object information. This value can be a handle of type HDESK or
808 * Specifies the object information to be set.
811 * Pointer to a buffer containing the object information.
814 * Specifies the size, in bytes, of the information contained in the
815 * buffer pointed to by pvInfo.
818 * If the function succeeds, the return value is nonzero. If the function
819 * fails the return value is zero.
827 NtUserSetObjectInformation(
833 /* FIXME: ZwQueryObject */
834 /* FIXME: ZwSetInformationObject */
835 SetLastNtError(STATUS_UNSUCCESSFUL
);
843 UserGetProcessWindowStation(VOID
)
849 if(PsGetCurrentProcess() != CsrProcess
)
851 return PsGetCurrentProcess()->Win32WindowStation
;
855 DPRINT1("Should use ObFindHandleForObject\n");
856 pti
= PsGetCurrentThreadWin32Thread();
857 Status
= ObOpenObjectByPointer(pti
->rpdesk
->rpwinstaParent
,
861 ExWindowStationObjectType
,
864 if (! NT_SUCCESS(Status
))
866 SetLastNtError(Status
);
867 DPRINT1("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
877 * NtUserGetProcessWindowStation
879 * Returns a handle to the current process window station.
882 * If the function succeeds, the return value is handle to the window
883 * station assigned to the current process. If the function fails, the
884 * return value is NULL.
891 NtUserGetProcessWindowStation(VOID
)
893 return UserGetProcessWindowStation();
896 PWINSTATION_OBJECT FASTCALL
897 IntGetWinStaObj(VOID
)
899 PWINSTATION_OBJECT WinStaObj
;
900 PTHREADINFO Win32Thread
;
901 PEPROCESS CurrentProcess
;
904 * just a temporary hack, this will be gone soon
907 Win32Thread
= PsGetCurrentThreadWin32Thread();
908 if(Win32Thread
!= NULL
&& Win32Thread
->rpdesk
!= NULL
)
910 WinStaObj
= Win32Thread
->rpdesk
->rpwinstaParent
;
911 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
913 else if((CurrentProcess
= PsGetCurrentProcess()) != CsrProcess
)
915 NTSTATUS Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
919 if(!NT_SUCCESS(Status
))
921 SetLastNtError(Status
);
934 UserSetProcessWindowStation(HWINSTA hWindowStation
)
939 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
941 ppi
= PsGetCurrentProcessWin32Process();
943 /* Reference the new window station */
944 if(hWindowStation
!=NULL
)
946 Status
= IntValidateWindowStationHandle( hWindowStation
,
950 if (!NT_SUCCESS(Status
))
952 DPRINT("Validation of window station handle (0x%X) failed\n",
954 SetLastNtError(Status
);
959 OldWinSta
= ppi
->prpwinsta
;
960 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
962 /* Dereference the previous window station */
963 if(OldWinSta
!= NULL
)
965 ObDereferenceObject(OldWinSta
);
968 /* Check if we have a stale handle (it should happen for console apps) */
969 if(hwinstaOld
!= ppi
->hwinsta
)
971 ObCloseHandle(hwinstaOld
, UserMode
);
975 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
978 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
980 ppi
->prpwinsta
= NewWinSta
;
981 ppi
->hwinsta
= hWindowStation
;
987 * NtUserSetProcessWindowStation
989 * Assigns a window station to the current process.
993 * Handle to the window station.
1003 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1007 UserEnterExclusive();
1009 ret
= UserSetProcessWindowStation(hWindowStation
);
1017 * NtUserLockWindowStation
1019 * Locks switching desktops. Only the logon application is allowed to call this function.
1026 NtUserLockWindowStation(HWINSTA hWindowStation
)
1028 PWINSTATION_OBJECT Object
;
1031 DPRINT("About to set process window station with handle (0x%X)\n",
1034 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1036 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1037 EngSetLastError(ERROR_ACCESS_DENIED
);
1041 Status
= IntValidateWindowStationHandle(
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT("Validation of window station handle (0x%X) failed\n",
1050 SetLastNtError(Status
);
1054 Object
->Flags
|= WSS_LOCKED
;
1056 ObDereferenceObject(Object
);
1061 * NtUserUnlockWindowStation
1063 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1070 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1072 PWINSTATION_OBJECT Object
;
1076 DPRINT("About to set process window station with handle (0x%X)\n",
1079 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1081 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1082 EngSetLastError(ERROR_ACCESS_DENIED
);
1086 Status
= IntValidateWindowStationHandle(
1091 if (!NT_SUCCESS(Status
))
1093 DPRINT("Validation of window station handle (0x%X) failed\n",
1095 SetLastNtError(Status
);
1099 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1100 Object
->Flags
&= ~WSS_LOCKED
;
1102 ObDereferenceObject(Object
);
1106 static NTSTATUS FASTCALL
1107 BuildWindowStationNameList(
1110 PULONG pRequiredSize
)
1112 OBJECT_ATTRIBUTES ObjectAttributes
;
1114 HANDLE DirectoryHandle
;
1115 UNICODE_STRING DirectoryName
= RTL_CONSTANT_STRING(WINSTA_ROOT_NAME
);
1116 char InitialBuffer
[256], *Buffer
;
1117 ULONG Context
, ReturnLength
, BufferSize
;
1119 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1123 * Try to open the directory.
1125 InitializeObjectAttributes(
1128 OBJ_CASE_INSENSITIVE
,
1132 Status
= ZwOpenDirectoryObject(
1137 if (!NT_SUCCESS(Status
))
1142 /* First try to query the directory using a fixed-size buffer */
1145 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1146 FALSE
, TRUE
, &Context
, &ReturnLength
);
1147 if (NT_SUCCESS(Status
))
1149 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1150 FALSE
, &Context
, NULL
))
1152 /* Our fixed-size buffer is large enough */
1153 Buffer
= InitialBuffer
;
1159 /* Need a larger buffer, check how large exactly */
1160 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1162 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1164 BufferSize
= ReturnLength
;
1165 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1168 ObDereferenceObject(DirectoryHandle
);
1169 return STATUS_NO_MEMORY
;
1172 /* We should have a sufficiently large buffer now */
1174 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1175 FALSE
, TRUE
, &Context
, &ReturnLength
);
1176 if (! NT_SUCCESS(Status
) ||
1177 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1178 FALSE
, &Context
, NULL
))
1180 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1181 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1182 ObDereferenceObject(DirectoryHandle
);
1183 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1188 ZwClose(DirectoryHandle
);
1191 * Count the required size of buffer.
1193 ReturnLength
= sizeof(DWORD
);
1195 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1198 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1201 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1202 if (NULL
!= pRequiredSize
)
1204 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1205 if (! NT_SUCCESS(Status
))
1207 if (Buffer
!= InitialBuffer
)
1209 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1211 return STATUS_BUFFER_TOO_SMALL
;
1216 * Check if the supplied buffer is large enough.
1218 if (dwSize
< ReturnLength
)
1220 if (Buffer
!= InitialBuffer
)
1222 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1224 return STATUS_BUFFER_TOO_SMALL
;
1228 * Generate the resulting buffer contents.
1230 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1231 if (! NT_SUCCESS(Status
))
1233 if (Buffer
!= InitialBuffer
)
1239 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1242 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1245 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1246 if (! NT_SUCCESS(Status
))
1248 if (Buffer
!= InitialBuffer
)
1254 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1255 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1256 if (! NT_SUCCESS(Status
))
1258 if (Buffer
!= InitialBuffer
)
1264 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1270 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1275 return STATUS_SUCCESS
;
1278 static NTSTATUS FASTCALL
1279 BuildDesktopNameList(
1280 HWINSTA hWindowStation
,
1283 PULONG pRequiredSize
)
1286 PWINSTATION_OBJECT WindowStation
;
1288 PLIST_ENTRY DesktopEntry
;
1289 PDESKTOP DesktopObject
;
1294 Status
= IntValidateWindowStationHandle(hWindowStation
,
1298 if (! NT_SUCCESS(Status
))
1303 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1306 * Count the required size of buffer.
1308 ReturnLength
= sizeof(DWORD
);
1310 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1311 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1312 DesktopEntry
= DesktopEntry
->Flink
)
1314 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1315 ReturnLength
+= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ sizeof(WCHAR
);
1318 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1319 if (NULL
!= pRequiredSize
)
1321 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1322 if (! NT_SUCCESS(Status
))
1324 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1325 ObDereferenceObject(WindowStation
);
1326 return STATUS_BUFFER_TOO_SMALL
;
1331 * Check if the supplied buffer is large enough.
1333 if (dwSize
< ReturnLength
)
1335 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1336 ObDereferenceObject(WindowStation
);
1337 return STATUS_BUFFER_TOO_SMALL
;
1341 * Generate the resulting buffer contents.
1343 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1344 if (! NT_SUCCESS(Status
))
1346 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1347 ObDereferenceObject(WindowStation
);
1350 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1353 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1354 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1355 DesktopEntry
= DesktopEntry
->Flink
)
1357 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1358 Status
= MmCopyToCaller(lpBuffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1359 if (! NT_SUCCESS(Status
))
1361 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1362 ObDereferenceObject(WindowStation
);
1365 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1366 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1367 if (! NT_SUCCESS(Status
))
1369 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1370 ObDereferenceObject(WindowStation
);
1373 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1379 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1380 ObDereferenceObject(WindowStation
);
1382 return STATUS_SUCCESS
;
1386 * NtUserBuildNameList
1388 * Function used for enumeration of desktops or window stations.
1392 * For enumeration of window stations this parameter must be set to
1393 * zero. Otherwise it's handle for window station.
1396 * Size of buffer passed by caller.
1399 * Buffer passed by caller. If the function succedes, the buffer is
1400 * filled with window station/desktop count (in first DWORD) and
1401 * NULL-terminated window station/desktop names.
1404 * If the function suceedes, this is the number of bytes copied.
1405 * Otherwise it's size of buffer needed for function to succeed.
1412 NtUserBuildNameList(
1413 HWINSTA hWindowStation
,
1416 PULONG pRequiredSize
)
1418 /* The WindowStation name list and desktop name list are build in completely
1419 different ways. Call the appropriate function */
1420 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1421 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1428 NtUserSetLogonNotifyWindow(HWND hWnd
)
1430 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1435 if(!IntIsWindow(hWnd
))