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 ******************************************************************/
38 DBG_DEFAULT_CHANNEL(UserWinsta
);
40 /* GLOBALS *******************************************************************/
42 /* Currently active window station */
43 PWINSTATION_OBJECT InputWindowStation
= NULL
;
45 /* Winlogon sas window*/
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
64 InitWindowStationImpl(VOID
)
66 OBJECT_ATTRIBUTES ObjectAttributes
;
67 HANDLE WindowStationsDirectory
;
68 UNICODE_STRING UnicodeString
;
72 * Create the '\Windows\WindowStations' directory
75 RtlInitUnicodeString(&UnicodeString
, WINSTA_ROOT_NAME
);
76 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeString
,
78 Status
= ZwCreateDirectoryObject(&WindowStationsDirectory
, 0,
80 if (!NT_SUCCESS(Status
))
82 TRACE("Could not create \\Windows\\WindowStations directory "
83 "(Status 0x%X)\n", Status
);
87 /* Set Winsta Object Attributes */
88 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
89 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
91 return STATUS_SUCCESS
;
95 CleanupWindowStationImpl(VOID
)
97 return STATUS_SUCCESS
;
100 /* OBJECT CALLBACKS **********************************************************/
103 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
105 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
107 TRACE("Deleting window station (0x%X)\n", WinSta
);
109 UserEmptyClipboardData(WinSta
);
111 RtlDestroyAtomTable(WinSta
->AtomTable
);
113 RtlFreeUnicodeString(&WinSta
->Name
);
118 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters
)
120 PUNICODE_STRING RemainingName
= Parameters
->RemainingName
;
122 /* Assume we don't find anything */
123 *Parameters
->Object
= NULL
;
125 /* Check for an empty name */
126 if (!RemainingName
->Length
)
128 /* Make sure this is a window station, can't parse a desktop now */
129 if (Parameters
->ObjectType
!= ExWindowStationObjectType
)
132 return STATUS_OBJECT_TYPE_MISMATCH
;
135 /* Reference the window station and return */
136 ObReferenceObject(Parameters
->ParseObject
);
137 *Parameters
->Object
= Parameters
->ParseObject
;
138 return STATUS_SUCCESS
;
141 /* Check for leading slash */
142 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
145 RemainingName
->Buffer
++;
146 RemainingName
->Length
-= sizeof(WCHAR
);
147 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
150 /* Check if there is still a slash */
151 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
153 /* In this case, fail */
154 return STATUS_OBJECT_PATH_INVALID
;
158 * Check if we are parsing a desktop.
160 if (Parameters
->ObjectType
== ExDesktopObjectType
)
162 /* Then call the desktop parse routine */
163 return IntDesktopObjectParse(Parameters
->ParseObject
,
164 Parameters
->ObjectType
,
165 Parameters
->AccessState
,
166 Parameters
->AccessMode
,
167 Parameters
->Attributes
,
168 Parameters
->CompleteName
,
171 Parameters
->SecurityQos
,
175 /* Should hopefully never get here */
176 return STATUS_OBJECT_TYPE_MISMATCH
;
181 IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
185 ppi
= PsGetCurrentProcessWin32Process();
187 if(ppi
&& (Parameters
->Handle
== ppi
->hwinsta
))
189 return STATUS_ACCESS_DENIED
;
192 return STATUS_SUCCESS
;
195 /* PRIVATE FUNCTIONS **********************************************************/
198 * IntGetFullWindowStationName
200 * Get a full window station object name from a name specified in
201 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
202 * or NtUserOpenDesktop.
205 * TRUE on success, FALSE on failure.
209 IntGetFullWindowStationName(
210 OUT PUNICODE_STRING FullName
,
211 IN PUNICODE_STRING WinStaName
,
212 IN OPTIONAL PUNICODE_STRING DesktopName
)
216 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
217 if (WinStaName
!= NULL
)
218 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
219 if (DesktopName
!= NULL
)
220 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
221 FullName
->MaximumLength
= FullName
->Length
;
222 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
223 if (FullName
->Buffer
== NULL
)
228 Buffer
= FullName
->Buffer
;
229 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
230 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
231 if (WinStaName
!= NULL
)
235 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
237 if (DesktopName
!= NULL
)
239 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
242 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
250 * IntValidateWindowStationHandle
252 * Validates the window station handle.
255 * If the function succeeds, the handle remains referenced. If the
256 * fucntion fails, last error is set.
260 IntValidateWindowStationHandle(
261 HWINSTA WindowStation
,
262 KPROCESSOR_MODE AccessMode
,
263 ACCESS_MASK DesiredAccess
,
264 PWINSTATION_OBJECT
*Object
)
268 if (WindowStation
== NULL
)
270 // ERR("Invalid window station handle\n");
271 EngSetLastError(ERROR_INVALID_HANDLE
);
272 return STATUS_INVALID_HANDLE
;
275 Status
= ObReferenceObjectByHandle(
278 ExWindowStationObjectType
,
283 if (!NT_SUCCESS(Status
))
284 SetLastNtError(Status
);
290 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
294 Status
= ObReferenceObjectByPointer(
297 ExWindowStationObjectType
,
300 return NT_SUCCESS(Status
);
305 co_IntInitializeDesktopGraphics(VOID
)
308 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
309 if (! IntCreatePrimarySurface())
313 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
314 if (NULL
== ScreenDeviceContext
)
316 IntDestroyPrimarySurface();
319 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
321 /* Setup the cursor */
322 co_IntLoadDefaultCursors();
324 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
326 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
327 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
329 // FIXME! Move these to a update routine.
330 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
331 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
332 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
333 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
334 // Font is realized and this dc was previously set to internal DC_ATTR.
335 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
336 gpsi
->tmSysFont
= tmw
;
342 IntEndDesktopGraphics(VOID
)
344 if (NULL
!= ScreenDeviceContext
)
345 { // No need to allocate a new dcattr.
346 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
347 GreDeleteObject(ScreenDeviceContext
);
348 ScreenDeviceContext
= NULL
;
350 IntHideDesktop(IntGetActiveDesktop());
351 IntDestroyPrimarySurface();
357 return ScreenDeviceContext
;
360 /* PUBLIC FUNCTIONS ***********************************************************/
363 * NtUserCreateWindowStation
365 * Creates a new window station.
368 * lpszWindowStationName
369 * Pointer to a null-terminated string specifying the name of the
370 * window station to be created. Window station names are
371 * case-insensitive and cannot contain backslash characters (\).
372 * Only members of the Administrators group are allowed to specify a
376 * Requested type of access
379 * Security descriptor
381 * Unknown3, Unknown4, Unknown5
385 * If the function succeeds, the return value is a handle to the newly
386 * created window station. If the specified window station already
387 * exists, the function succeeds and returns a handle to the existing
388 * window station. If the function fails, the return value is NULL.
391 * Correct the prototype to match the Windows one (with 7 parameters
399 NtUserCreateWindowStation(
400 POBJECT_ATTRIBUTES ObjectAttributes
,
401 ACCESS_MASK dwDesiredAccess
,
408 UNICODE_STRING WindowStationName
;
409 PWINSTATION_OBJECT WindowStationObject
;
410 HWINSTA WindowStation
;
413 Status
= ObOpenObjectByName(
415 ExWindowStationObjectType
,
420 (PVOID
*)&WindowStation
);
422 if (NT_SUCCESS(Status
))
424 return (HWINSTA
)WindowStation
;
429 * No existing window station found, try to create new one
432 /* Capture window station name */
435 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
436 Status
= IntSafeCopyUnicodeString(&WindowStationName
, ObjectAttributes
->ObjectName
);
438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
440 Status
=_SEH2_GetExceptionCode();
444 if (! NT_SUCCESS(Status
))
446 ERR("Failed reading capturing window station name\n");
447 SetLastNtError(Status
);
451 /* Create the window station object */
452 Status
= ObCreateObject(
454 ExWindowStationObjectType
,
458 sizeof(WINSTATION_OBJECT
),
461 (PVOID
*)&WindowStationObject
);
463 if (!NT_SUCCESS(Status
))
465 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
466 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
470 Status
= ObInsertObject(
471 (PVOID
)WindowStationObject
,
473 STANDARD_RIGHTS_REQUIRED
,
476 (PVOID
*)&WindowStation
);
478 if (!NT_SUCCESS(Status
))
480 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
481 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
482 ObDereferenceObject(WindowStationObject
);
486 /* Initialize the window station */
487 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
489 KeInitializeSpinLock(&WindowStationObject
->Lock
);
490 InitializeListHead(&WindowStationObject
->DesktopListHead
);
491 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
492 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
493 WindowStationObject
->Name
= WindowStationName
;
494 WindowStationObject
->ScreenSaverRunning
= FALSE
;
495 WindowStationObject
->FlatMenu
= FALSE
;
497 if (InputWindowStation
== NULL
)
499 InputWindowStation
= WindowStationObject
;
504 return WindowStation
;
508 * NtUserOpenWindowStation
510 * Opens an existing window station.
513 * lpszWindowStationName
514 * Name of the existing window station.
517 * Requested type of access.
520 * If the function succeeds, the return value is the handle to the
521 * specified window station. If the function fails, the return value
525 * The returned handle can be closed with NtUserCloseWindowStation.
532 NtUserOpenWindowStation(
533 POBJECT_ATTRIBUTES ObjectAttributes
,
534 ACCESS_MASK dwDesiredAccess
)
536 HWINSTA WindowStation
;
539 Status
= ObOpenObjectByName(
541 ExWindowStationObjectType
,
546 (PVOID
*)&WindowStation
);
548 if (!NT_SUCCESS(Status
))
550 SetLastNtError(Status
);
554 return WindowStation
;
558 * NtUserCloseWindowStation
560 * Closes a window station handle.
564 * Handle to the window station.
570 * The window station handle can be created with NtUserCreateWindowStation
571 * or NtUserOpenWindowStation. Attemps to close a handle to the window
572 * station assigned to the calling process will fail.
580 NtUserCloseWindowStation(
583 PWINSTATION_OBJECT Object
;
586 TRACE("About to close window station handle (0x%X)\n", hWinSta
);
588 if (hWinSta
== UserGetProcessWindowStation())
593 Status
= IntValidateWindowStationHandle(
599 if (!NT_SUCCESS(Status
))
601 TRACE("Validation of window station handle (0x%X) failed\n", hWinSta
);
605 ObDereferenceObject(Object
);
607 TRACE("Closing window station handle (0x%X)\n", hWinSta
);
609 Status
= ObCloseHandle(hWinSta
, UserMode
);
610 if (!NT_SUCCESS(Status
))
612 SetLastNtError(Status
);
620 * NtUserGetObjectInformation
622 * The NtUserGetObjectInformation function retrieves information about a
623 * window station or desktop object.
627 * Handle to the window station or desktop object for which to
628 * return information. This can be a handle of type HDESK or HWINSTA
629 * (for example, a handle returned by NtUserCreateWindowStation,
630 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
633 * Specifies the object information to be retrieved.
636 * Pointer to a buffer to receive the object information.
639 * Specifies the size, in bytes, of the buffer pointed to by the
643 * Pointer to a variable receiving the number of bytes required to
644 * store the requested information. If this variable's value is
645 * greater than the value of the nLength parameter when the function
646 * returns, the function returns FALSE, and none of the information
647 * is copied to the pvInfo buffer. If the value of the variable pointed
648 * to by lpnLengthNeeded is less than or equal to the value of nLength,
649 * the entire information block is copied.
652 * If the function succeeds, the return value is nonzero. If the function
653 * fails, the return value is zero.
660 NtUserGetObjectInformation(
665 PDWORD nLengthNeeded
)
667 PWINSTATION_OBJECT WinStaObject
= NULL
;
668 PDESKTOP DesktopObject
= NULL
;
673 /* try windowstation */
674 TRACE("Trying to open window station 0x%x\n", hObject
);
675 Status
= IntValidateWindowStationHandle(
677 UserMode
,/*ExGetPreviousMode(),*/
678 GENERIC_READ
, /* FIXME: is this ok? */
682 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
684 TRACE("Failed: 0x%x\n", Status
);
685 SetLastNtError(Status
);
689 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
692 TRACE("Trying to open desktop 0x%x\n", hObject
);
693 Status
= IntValidateDesktopHandle(
695 UserMode
,/*ExGetPreviousMode(),*/
696 GENERIC_READ
, /* FIXME: is this ok? */
698 if (!NT_SUCCESS(Status
))
700 TRACE("Failed: 0x%x\n", Status
);
701 SetLastNtError(Status
);
705 TRACE("WinSta or Desktop opened!!\n");
711 Status
= STATUS_NOT_IMPLEMENTED
;
712 ERR("UOI_FLAGS unimplemented!\n");
716 if (WinStaObject
!= NULL
)
718 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Buffer
;
719 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Length
+ 2;
720 Status
= STATUS_SUCCESS
;
722 else if (DesktopObject
!= NULL
)
724 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
;
725 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ 2;
726 Status
= STATUS_SUCCESS
;
729 Status
= STATUS_INVALID_PARAMETER
;
733 if (WinStaObject
!= NULL
)
735 pvData
= L
"WindowStation";
736 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
737 Status
= STATUS_SUCCESS
;
739 else if (DesktopObject
!= NULL
)
742 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
743 Status
= STATUS_SUCCESS
;
746 Status
= STATUS_INVALID_PARAMETER
;
750 Status
= STATUS_NOT_IMPLEMENTED
;
751 ERR("UOI_USER_SID unimplemented!\n");
755 Status
= STATUS_INVALID_PARAMETER
;
759 /* try to copy data to caller */
760 if (Status
== STATUS_SUCCESS
)
762 TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
763 *nLengthNeeded
= nDataSize
;
764 if (nLength
>= nDataSize
)
765 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
767 Status
= STATUS_BUFFER_TOO_SMALL
;
770 /* release objects */
771 if (WinStaObject
!= NULL
)
772 ObDereferenceObject(WinStaObject
);
773 if (DesktopObject
!= NULL
)
774 ObDereferenceObject(DesktopObject
);
776 SetLastNtError(Status
);
777 return NT_SUCCESS(Status
);
781 * NtUserSetObjectInformation
783 * The NtUserSetObjectInformation function sets information about a
784 * window station or desktop object.
788 * Handle to the window station or desktop object for which to set
789 * object information. This value can be a handle of type HDESK or
793 * Specifies the object information to be set.
796 * Pointer to a buffer containing the object information.
799 * Specifies the size, in bytes, of the information contained in the
800 * buffer pointed to by pvInfo.
803 * If the function succeeds, the return value is nonzero. If the function
804 * fails the return value is zero.
812 NtUserSetObjectInformation(
818 /* FIXME: ZwQueryObject */
819 /* FIXME: ZwSetInformationObject */
820 SetLastNtError(STATUS_UNSUCCESSFUL
);
828 UserGetProcessWindowStation(VOID
)
834 if(PsGetCurrentProcess() != CsrProcess
)
836 return PsGetCurrentProcess()->Win32WindowStation
;
840 ERR("Should use ObFindHandleForObject\n");
841 pti
= PsGetCurrentThreadWin32Thread();
842 Status
= ObOpenObjectByPointer(pti
->rpdesk
->rpwinstaParent
,
846 ExWindowStationObjectType
,
849 if (! NT_SUCCESS(Status
))
851 SetLastNtError(Status
);
852 ERR("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
862 * NtUserGetProcessWindowStation
864 * Returns a handle to the current process window station.
867 * If the function succeeds, the return value is handle to the window
868 * station assigned to the current process. If the function fails, the
869 * return value is NULL.
876 NtUserGetProcessWindowStation(VOID
)
878 return UserGetProcessWindowStation();
881 PWINSTATION_OBJECT FASTCALL
882 IntGetWinStaObj(VOID
)
884 PWINSTATION_OBJECT WinStaObj
;
885 PTHREADINFO Win32Thread
;
886 PEPROCESS CurrentProcess
;
889 * just a temporary hack, this will be gone soon
892 Win32Thread
= PsGetCurrentThreadWin32Thread();
893 if(Win32Thread
!= NULL
&& Win32Thread
->rpdesk
!= NULL
)
895 WinStaObj
= Win32Thread
->rpdesk
->rpwinstaParent
;
896 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
898 else if((CurrentProcess
= PsGetCurrentProcess()) != CsrProcess
)
900 NTSTATUS Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
904 if(!NT_SUCCESS(Status
))
906 SetLastNtError(Status
);
919 UserSetProcessWindowStation(HWINSTA hWindowStation
)
924 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
926 ppi
= PsGetCurrentProcessWin32Process();
928 /* Reference the new window station */
929 if(hWindowStation
!=NULL
)
931 Status
= IntValidateWindowStationHandle( hWindowStation
,
935 if (!NT_SUCCESS(Status
))
937 TRACE("Validation of window station handle (0x%X) failed\n",
939 SetLastNtError(Status
);
944 OldWinSta
= ppi
->prpwinsta
;
945 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
947 /* Dereference the previous window station */
948 if(OldWinSta
!= NULL
)
950 ObDereferenceObject(OldWinSta
);
953 /* Check if we have a stale handle (it should happen for console apps) */
954 if(hwinstaOld
!= ppi
->hwinsta
)
956 ObCloseHandle(hwinstaOld
, UserMode
);
960 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
963 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
965 ppi
->prpwinsta
= NewWinSta
;
966 ppi
->hwinsta
= hWindowStation
;
972 * NtUserSetProcessWindowStation
974 * Assigns a window station to the current process.
978 * Handle to the window station.
988 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
992 UserEnterExclusive();
994 ret
= UserSetProcessWindowStation(hWindowStation
);
1002 * NtUserLockWindowStation
1004 * Locks switching desktops. Only the logon application is allowed to call this function.
1011 NtUserLockWindowStation(HWINSTA hWindowStation
)
1013 PWINSTATION_OBJECT Object
;
1016 TRACE("About to set process window station with handle (0x%X)\n",
1019 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1021 ERR("Unauthorized process attempted to lock the window station!\n");
1022 EngSetLastError(ERROR_ACCESS_DENIED
);
1026 Status
= IntValidateWindowStationHandle(
1031 if (!NT_SUCCESS(Status
))
1033 TRACE("Validation of window station handle (0x%X) failed\n",
1035 SetLastNtError(Status
);
1039 Object
->Flags
|= WSS_LOCKED
;
1041 ObDereferenceObject(Object
);
1046 * NtUserUnlockWindowStation
1048 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1055 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1057 PWINSTATION_OBJECT Object
;
1061 TRACE("About to set process window station with handle (0x%X)\n",
1064 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1066 ERR("Unauthorized process attempted to unlock the window station!\n");
1067 EngSetLastError(ERROR_ACCESS_DENIED
);
1071 Status
= IntValidateWindowStationHandle(
1076 if (!NT_SUCCESS(Status
))
1078 TRACE("Validation of window station handle (0x%X) failed\n",
1080 SetLastNtError(Status
);
1084 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1085 Object
->Flags
&= ~WSS_LOCKED
;
1087 ObDereferenceObject(Object
);
1091 static NTSTATUS FASTCALL
1092 BuildWindowStationNameList(
1095 PULONG pRequiredSize
)
1097 OBJECT_ATTRIBUTES ObjectAttributes
;
1099 HANDLE DirectoryHandle
;
1100 UNICODE_STRING DirectoryName
= RTL_CONSTANT_STRING(WINSTA_ROOT_NAME
);
1101 char InitialBuffer
[256], *Buffer
;
1102 ULONG Context
, ReturnLength
, BufferSize
;
1104 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1108 * Try to open the directory.
1110 InitializeObjectAttributes(
1113 OBJ_CASE_INSENSITIVE
,
1117 Status
= ZwOpenDirectoryObject(
1122 if (!NT_SUCCESS(Status
))
1127 /* First try to query the directory using a fixed-size buffer */
1130 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1131 FALSE
, TRUE
, &Context
, &ReturnLength
);
1132 if (NT_SUCCESS(Status
))
1134 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1135 FALSE
, &Context
, NULL
))
1137 /* Our fixed-size buffer is large enough */
1138 Buffer
= InitialBuffer
;
1144 /* Need a larger buffer, check how large exactly */
1145 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1147 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1149 BufferSize
= ReturnLength
;
1150 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1153 ObDereferenceObject(DirectoryHandle
);
1154 return STATUS_NO_MEMORY
;
1157 /* We should have a sufficiently large buffer now */
1159 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1160 FALSE
, TRUE
, &Context
, &ReturnLength
);
1161 if (! NT_SUCCESS(Status
) ||
1162 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1163 FALSE
, &Context
, NULL
))
1165 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1166 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1167 ObDereferenceObject(DirectoryHandle
);
1168 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1173 ZwClose(DirectoryHandle
);
1176 * Count the required size of buffer.
1178 ReturnLength
= sizeof(DWORD
);
1180 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1183 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1186 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1187 if (NULL
!= pRequiredSize
)
1189 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1190 if (! NT_SUCCESS(Status
))
1192 if (Buffer
!= InitialBuffer
)
1194 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1196 return STATUS_BUFFER_TOO_SMALL
;
1201 * Check if the supplied buffer is large enough.
1203 if (dwSize
< ReturnLength
)
1205 if (Buffer
!= InitialBuffer
)
1207 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1209 return STATUS_BUFFER_TOO_SMALL
;
1213 * Generate the resulting buffer contents.
1215 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1216 if (! NT_SUCCESS(Status
))
1218 if (Buffer
!= InitialBuffer
)
1224 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1227 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1230 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1231 if (! NT_SUCCESS(Status
))
1233 if (Buffer
!= InitialBuffer
)
1239 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1240 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1241 if (! NT_SUCCESS(Status
))
1243 if (Buffer
!= InitialBuffer
)
1249 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1255 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1260 return STATUS_SUCCESS
;
1263 static NTSTATUS FASTCALL
1264 BuildDesktopNameList(
1265 HWINSTA hWindowStation
,
1268 PULONG pRequiredSize
)
1271 PWINSTATION_OBJECT WindowStation
;
1273 PLIST_ENTRY DesktopEntry
;
1274 PDESKTOP DesktopObject
;
1279 Status
= IntValidateWindowStationHandle(hWindowStation
,
1283 if (! NT_SUCCESS(Status
))
1288 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1291 * Count the required size of buffer.
1293 ReturnLength
= sizeof(DWORD
);
1295 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1296 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1297 DesktopEntry
= DesktopEntry
->Flink
)
1299 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1300 ReturnLength
+= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ sizeof(WCHAR
);
1303 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1304 if (NULL
!= pRequiredSize
)
1306 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1307 if (! NT_SUCCESS(Status
))
1309 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1310 ObDereferenceObject(WindowStation
);
1311 return STATUS_BUFFER_TOO_SMALL
;
1316 * Check if the supplied buffer is large enough.
1318 if (dwSize
< ReturnLength
)
1320 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1321 ObDereferenceObject(WindowStation
);
1322 return STATUS_BUFFER_TOO_SMALL
;
1326 * Generate the resulting buffer contents.
1328 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1329 if (! NT_SUCCESS(Status
))
1331 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1332 ObDereferenceObject(WindowStation
);
1335 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1338 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1339 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1340 DesktopEntry
= DesktopEntry
->Flink
)
1342 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1343 Status
= MmCopyToCaller(lpBuffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1344 if (! NT_SUCCESS(Status
))
1346 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1347 ObDereferenceObject(WindowStation
);
1350 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1351 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1352 if (! NT_SUCCESS(Status
))
1354 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1355 ObDereferenceObject(WindowStation
);
1358 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1364 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1365 ObDereferenceObject(WindowStation
);
1367 return STATUS_SUCCESS
;
1371 * NtUserBuildNameList
1373 * Function used for enumeration of desktops or window stations.
1377 * For enumeration of window stations this parameter must be set to
1378 * zero. Otherwise it's handle for window station.
1381 * Size of buffer passed by caller.
1384 * Buffer passed by caller. If the function succedes, the buffer is
1385 * filled with window station/desktop count (in first DWORD) and
1386 * NULL-terminated window station/desktop names.
1389 * If the function suceedes, this is the number of bytes copied.
1390 * Otherwise it's size of buffer needed for function to succeed.
1397 NtUserBuildNameList(
1398 HWINSTA hWindowStation
,
1401 PULONG pRequiredSize
)
1403 /* The WindowStation name list and desktop name list are build in completely
1404 different ways. Call the appropriate function */
1405 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1406 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1413 NtUserSetLogonNotifyWindow(HWND hWnd
)
1415 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1420 if(!IntIsWindow(hWnd
))