2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window stations
5 * FILE: win32ss/user/ntuser/winsta.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * TODO: The process window station is created on
8 * the first USER32/GDI32 call not related
9 * to window station/desktop handling
13 DBG_DEFAULT_CHANNEL(UserWinsta
);
15 /* GLOBALS *******************************************************************/
18 * The currently active window station. This is the
19 * only one interactive window station on the system.
21 PWINSTATION_OBJECT InputWindowStation
= NULL
;
23 /* Winlogon SAS window */
26 /* Full path to WindowStations directory */
27 UNICODE_STRING gustrWindowStationsDir
;
29 /* INITIALIZATION FUNCTIONS ****************************************************/
34 InitWindowStationImpl(VOID
)
36 GENERIC_MAPPING IntWindowStationMapping
= { WINSTA_READ
,
41 /* Set Winsta Object Attributes */
42 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
43 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
44 ExWindowStationObjectType
->TypeInfo
.ValidAccessMask
= WINSTA_ACCESS_ALL
;
46 return STATUS_SUCCESS
;
51 UserCreateWinstaDirectory(VOID
)
55 OBJECT_ATTRIBUTES ObjectAttributes
;
57 WCHAR wstrWindowStationsDir
[MAX_PATH
];
59 /* Create the WindowStations directory and cache its path for later use */
61 if(Peb
->SessionId
== 0)
63 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, WINSTA_OBJ_DIR
))
65 return STATUS_INSUFFICIENT_RESOURCES
;
70 Status
= RtlStringCbPrintfW(wstrWindowStationsDir
,
71 sizeof(wstrWindowStationsDir
),
76 if (!NT_SUCCESS(Status
))
79 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, wstrWindowStationsDir
))
81 return STATUS_INSUFFICIENT_RESOURCES
;
85 InitializeObjectAttributes(&ObjectAttributes
,
86 &gustrWindowStationsDir
,
90 Status
= ZwCreateDirectoryObject(&hWinstaDir
, DIRECTORY_CREATE_OBJECT
, &ObjectAttributes
);
91 if (!NT_SUCCESS(Status
))
93 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir
, Status
);
97 TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir
, Peb
->SessionId
);
102 /* OBJECT CALLBACKS ***********************************************************/
106 IntWinStaObjectDelete(
107 _In_ PVOID Parameters
)
109 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
110 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeleteParameters
->Object
;
112 TRACE("Deleting window station 0x%p\n", WinSta
);
114 if (WinSta
== InputWindowStation
)
116 ERR("WARNING: Deleting the interactive window station '%wZ'!\n",
117 &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(InputWindowStation
))->Name
));
119 /* Only Winlogon can close and delete the interactive window station */
120 ASSERT(gpidLogon
== PsGetCurrentProcessId());
122 InputWindowStation
= NULL
;
125 WinSta
->Flags
|= WSS_DYING
;
127 UserEmptyClipboardData(WinSta
);
129 RtlDestroyAtomTable(WinSta
->AtomTable
);
131 return STATUS_SUCCESS
;
136 IntWinStaObjectParse(
137 _In_ PVOID Parameters
)
139 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters
= Parameters
;
140 PUNICODE_STRING RemainingName
= ParseParameters
->RemainingName
;
142 /* Assume we don't find anything */
143 *ParseParameters
->Object
= NULL
;
145 /* Check for an empty name */
146 if (!RemainingName
->Length
)
148 /* Make sure this is a window station, can't parse a desktop now */
149 if (ParseParameters
->ObjectType
!= ExWindowStationObjectType
)
152 return STATUS_OBJECT_TYPE_MISMATCH
;
155 /* Reference the window station and return */
156 ObReferenceObject(ParseParameters
->ParseObject
);
157 *ParseParameters
->Object
= ParseParameters
->ParseObject
;
158 return STATUS_SUCCESS
;
161 /* Check for leading slash */
162 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
165 RemainingName
->Buffer
++;
166 RemainingName
->Length
-= sizeof(WCHAR
);
167 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
170 /* Check if there is still a slash */
171 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
173 /* In this case, fail */
174 return STATUS_OBJECT_PATH_INVALID
;
178 * Check if we are parsing a desktop.
180 if (ParseParameters
->ObjectType
== ExDesktopObjectType
)
182 /* Then call the desktop parse routine */
183 return IntDesktopObjectParse(ParseParameters
->ParseObject
,
184 ParseParameters
->ObjectType
,
185 ParseParameters
->AccessState
,
186 ParseParameters
->AccessMode
,
187 ParseParameters
->Attributes
,
188 ParseParameters
->CompleteName
,
190 ParseParameters
->Context
,
191 ParseParameters
->SecurityQos
,
192 ParseParameters
->Object
);
195 /* Should hopefully never get here */
196 return STATUS_OBJECT_TYPE_MISMATCH
;
202 _In_ PVOID Parameters
)
204 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
207 ppi
= PsGetCurrentProcessWin32Process();
209 if (ppi
&& (OkToCloseParameters
->Handle
== ppi
->hwinsta
))
211 return STATUS_ACCESS_DENIED
;
214 return STATUS_SUCCESS
;
217 /* PRIVATE FUNCTIONS **********************************************************/
220 * IntValidateWindowStationHandle
222 * Validates the window station handle.
225 * If the function succeeds, the handle remains referenced. If the
226 * fucntion fails, last error is set.
230 IntValidateWindowStationHandle(
231 HWINSTA WindowStation
,
232 KPROCESSOR_MODE AccessMode
,
233 ACCESS_MASK DesiredAccess
,
234 PWINSTATION_OBJECT
*Object
,
235 POBJECT_HANDLE_INFORMATION pObjectHandleInfo
)
239 if (WindowStation
== NULL
)
241 ERR("Invalid window station handle\n");
242 EngSetLastError(ERROR_INVALID_HANDLE
);
243 return STATUS_INVALID_HANDLE
;
246 Status
= ObReferenceObjectByHandle(WindowStation
,
248 ExWindowStationObjectType
,
253 if (!NT_SUCCESS(Status
))
254 SetLastNtError(Status
);
260 co_IntInitializeDesktopGraphics(VOID
)
263 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
266 if (PDEVOBJ_lChangeDisplaySettings(NULL
, NULL
, NULL
, &gpmdev
, TRUE
) != DISP_CHANGE_SUCCESSFUL
)
268 ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
272 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
273 if (NULL
== ScreenDeviceContext
)
275 IntDestroyPrimarySurface();
278 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
280 if (!IntCreatePrimarySurface())
285 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
287 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
288 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
290 /* Update the system metrics */
293 /* Set new size of the monitor */
294 UserUpdateMonitorSize((HDEV
)gpmdev
->ppdevGlobal
);
296 /* Update the SERVERINFO */
297 gpsi
->aiSysMet
[SM_CXSCREEN
] = gpmdev
->ppdevGlobal
->gdiinfo
.ulHorzRes
;
298 gpsi
->aiSysMet
[SM_CYSCREEN
] = gpmdev
->ppdevGlobal
->gdiinfo
.ulVertRes
;
299 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
300 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
301 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
302 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
303 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
305 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
309 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
311 // Font is realized and this dc was previously set to internal DC_ATTR.
312 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
313 gpsi
->tmSysFont
= tmw
;
315 /* Put the pointer in the center of the screen */
316 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
317 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
320 UserAttachMonitor((HDEV
)gpmdev
->ppdevGlobal
);
322 /* Setup the cursor */
323 co_IntLoadDefaultCursors();
325 /* Setup the icons */
331 /* Show the desktop */
332 pdesk
= IntGetActiveDesktop();
334 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
336 /* HACK: display wallpaper on all secondary displays */
338 PGRAPHICS_DEVICE pGraphicsDevice
;
339 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
340 UNICODE_STRING DisplayName
;
344 for (iDevNum
= 1; (pGraphicsDevice
= EngpFindGraphicsDevice(NULL
, iDevNum
)) != NULL
; iDevNum
++)
346 RtlInitUnicodeString(&DisplayName
, pGraphicsDevice
->szWinDeviceName
);
347 hdc
= IntGdiCreateDC(&DriverName
, &DisplayName
, NULL
, NULL
, FALSE
);
348 IntPaintDesktop(hdc
);
356 IntEndDesktopGraphics(VOID
)
358 if (NULL
!= ScreenDeviceContext
)
359 { // No need to allocate a new dcattr.
360 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
361 GreDeleteObject(ScreenDeviceContext
);
362 ScreenDeviceContext
= NULL
;
364 IntHideDesktop(IntGetActiveDesktop());
365 IntDestroyPrimarySurface();
371 return ScreenDeviceContext
;
375 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess
)
377 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
378 if ( gpidLogon
!= PsGetCurrentProcessId() )
380 if (!(ppi
->W32PF_flags
& W32PF_IOWINSTA
))
382 ERR("Requires Interactive Window Station\n");
383 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
);
386 if (!RtlAreAllAccessesGranted(ppi
->amwinsta
, DesiredAccess
))
388 ERR("Access Denied\n");
389 EngSetLastError(ERROR_ACCESS_DENIED
);
397 /* PUBLIC FUNCTIONS ***********************************************************/
400 * NtUserCreateWindowStation
402 * Creates a new window station.
405 * lpszWindowStationName
406 * Pointer to a null-terminated string specifying the name of the
407 * window station to be created. Window station names are
408 * case-insensitive and cannot contain backslash characters (\).
409 * Only members of the Administrators group are allowed to specify a
413 * Requested type of access
416 * Security descriptor
418 * Unknown3, Unknown4, Unknown5, Unknown6
422 * If the function succeeds, the return value is a handle to the newly
423 * created window station. If the specified window station already
424 * exists, the function succeeds and returns a handle to the existing
425 * window station. If the function fails, the return value is NULL.
433 IntCreateWindowStation(
434 OUT HWINSTA
* phWinSta
,
435 IN POBJECT_ATTRIBUTES ObjectAttributes
,
436 IN KPROCESSOR_MODE AccessMode
,
437 IN KPROCESSOR_MODE OwnerMode
,
438 IN ACCESS_MASK dwDesiredAccess
,
447 PWINSTATION_OBJECT WindowStation
;
449 TRACE("IntCreateWindowStation called\n");
454 Status
= ObOpenObjectByName(ObjectAttributes
,
455 ExWindowStationObjectType
,
461 if (NT_SUCCESS(Status
))
463 TRACE("IntCreateWindowStation opened window station '%wZ'\n",
464 ObjectAttributes
->ObjectName
);
470 * No existing window station found, try to create a new one.
473 /* Create the window station object */
474 Status
= ObCreateObject(AccessMode
,
475 ExWindowStationObjectType
,
479 sizeof(WINSTATION_OBJECT
),
482 (PVOID
*)&WindowStation
);
483 if (!NT_SUCCESS(Status
))
485 ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
486 ObjectAttributes
->ObjectName
, Status
);
487 SetLastNtError(Status
);
491 /* Initialize the window station */
492 RtlZeroMemory(WindowStation
, sizeof(WINSTATION_OBJECT
));
494 InitializeListHead(&WindowStation
->DesktopListHead
);
495 WindowStation
->dwSessionId
= NtCurrentPeb()->SessionId
;
496 Status
= RtlCreateAtomTable(37, &WindowStation
->AtomTable
);
497 if (!NT_SUCCESS(Status
))
499 ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
500 ObjectAttributes
->ObjectName
, Status
);
501 ObDereferenceObject(WindowStation
);
502 SetLastNtError(Status
);
506 Status
= ObInsertObject(WindowStation
,
512 if (!NT_SUCCESS(Status
))
514 ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status
);
515 SetLastNtError(Status
);
519 // FIXME! TODO: Add this new window station to a linked list
521 if (InputWindowStation
== NULL
)
523 ERR("Initializing input window station\n");
525 /* Only Winlogon can create the interactive window station */
526 ASSERT(gpidLogon
== PsGetCurrentProcessId());
528 InputWindowStation
= WindowStation
;
529 WindowStation
->Flags
&= ~WSS_NOIO
;
533 UserCreateSystemThread(ST_DESKTOP_THREAD
);
534 UserCreateSystemThread(ST_RIT
);
536 /* Desktop functions require the desktop thread running so wait for it to initialize */
538 KeWaitForSingleObject(gpDesktopThreadStartedEvent
,
547 WindowStation
->Flags
|= WSS_NOIO
;
550 TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
551 ObjectAttributes
->ObjectName
, WindowStation
, hWinSta
);
554 EngSetLastError(ERROR_SUCCESS
);
556 return STATUS_SUCCESS
;
560 FreeUserModeWindowStationName(
561 IN OUT PUNICODE_STRING WindowStationName
,
562 IN PUNICODE_STRING TebStaticUnicodeString
,
563 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL
,
564 IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL
)
568 /* Try to restore the user's UserModeObjectAttributes */
569 if (UserModeObjectAttributes
&& LocalObjectAttributes
)
573 ProbeForWrite(UserModeObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
574 *UserModeObjectAttributes
= *LocalObjectAttributes
;
576 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
583 /* Free the user-mode memory */
584 if (WindowStationName
&& (WindowStationName
!= TebStaticUnicodeString
))
586 ZwFreeVirtualMemory(ZwCurrentProcess(),
587 (PVOID
*)&WindowStationName
,
594 BuildUserModeWindowStationName(
595 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes
,
596 IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes
,
597 OUT PUNICODE_STRING
* WindowStationName
,
598 OUT PUNICODE_STRING
* TebStaticUnicodeString
)
607 *WindowStationName
= NULL
;
608 *TebStaticUnicodeString
= NULL
;
610 /* Retrieve the current process LUID */
611 Status
= GetProcessLuid(NULL
, NULL
, &CallerLuid
);
612 if (!NT_SUCCESS(Status
))
614 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status
);
618 /* Compute the needed string size */
619 MemSize
= _scwprintf(L
"%wZ\\Service-0x%x-%x$",
620 &gustrWindowStationsDir
,
623 MemSize
= MemSize
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
624 if (MemSize
> MAXUSHORT
)
626 ERR("Window station name length is too long.\n");
627 return STATUS_NAME_TOO_LONG
;
629 StrSize
= (USHORT
)MemSize
;
632 * Check whether it's short enough so that we can use the static buffer
633 * in the TEB. Otherwise continue with virtual memory allocation.
635 Teb
= NtCurrentTeb();
636 if (Teb
&& (StrSize
<= sizeof(Teb
->StaticUnicodeBuffer
)))
638 /* We can use the TEB's static unicode string */
639 ASSERT(Teb
->StaticUnicodeString
.Buffer
== Teb
->StaticUnicodeBuffer
);
640 ASSERT(Teb
->StaticUnicodeString
.MaximumLength
== sizeof(Teb
->StaticUnicodeBuffer
));
642 /* Remember the TEB's static unicode string address for later */
643 *TebStaticUnicodeString
= &Teb
->StaticUnicodeString
;
645 *WindowStationName
= *TebStaticUnicodeString
;
646 (*WindowStationName
)->Length
= 0;
650 /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
651 MemSize
+= ALIGN_UP(sizeof(UNICODE_STRING
), sizeof(PVOID
));
653 /* Allocate the memory in user-mode */
654 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(),
655 (PVOID
*)WindowStationName
,
660 if (!NT_SUCCESS(Status
))
662 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status
);
666 RtlInitEmptyUnicodeString(*WindowStationName
,
667 (PWCHAR
)((ULONG_PTR
)*WindowStationName
+
668 ALIGN_UP(sizeof(UNICODE_STRING
), sizeof(PVOID
))),
672 /* Build a valid window station name from the LUID */
673 Status
= RtlStringCbPrintfW((*WindowStationName
)->Buffer
,
674 (*WindowStationName
)->MaximumLength
,
675 L
"%wZ\\Service-0x%x-%x$",
676 &gustrWindowStationsDir
,
679 if (!NT_SUCCESS(Status
))
681 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status
);
684 (*WindowStationName
)->Length
= (USHORT
)(wcslen((*WindowStationName
)->Buffer
) * sizeof(WCHAR
));
686 /* Try to update the user's UserModeObjectAttributes */
689 ProbeForWrite(UserModeObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
690 *LocalObjectAttributes
= *UserModeObjectAttributes
;
692 UserModeObjectAttributes
->ObjectName
= *WindowStationName
;
693 UserModeObjectAttributes
->RootDirectory
= NULL
;
695 Status
= STATUS_SUCCESS
;
697 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
699 Status
= _SEH2_GetExceptionCode();
704 if (!NT_SUCCESS(Status
))
706 /* Release the window station name */
707 FreeUserModeWindowStationName(*WindowStationName
,
708 *TebStaticUnicodeString
,
717 NtUserCreateWindowStation(
718 IN POBJECT_ATTRIBUTES ObjectAttributes
,
719 IN ACCESS_MASK dwDesiredAccess
,
726 NTSTATUS Status
= STATUS_SUCCESS
;
727 HWINSTA hWinSta
= NULL
;
728 OBJECT_ATTRIBUTES LocalObjectAttributes
;
729 PUNICODE_STRING WindowStationName
= NULL
;
730 PUNICODE_STRING TebStaticUnicodeString
= NULL
;
731 KPROCESSOR_MODE OwnerMode
= UserMode
;
733 TRACE("NtUserCreateWindowStation called\n");
735 /* Capture the object attributes and the window station name */
738 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
739 LocalObjectAttributes
= *ObjectAttributes
;
740 if (LocalObjectAttributes
.Length
!= sizeof(OBJECT_ATTRIBUTES
))
742 ERR("Invalid ObjectAttributes length!\n");
743 Status
= STATUS_INVALID_PARAMETER
;
748 * Check whether the caller provided a window station name together
749 * with a RootDirectory handle.
751 * If the caller did not provide a window station name, build a new one
752 * based on the logon session identifier for the calling process.
753 * The new name is allocated in user-mode, as the rest of ObjectAttributes
754 * already is, so that the validation performed by the Object Manager
755 * can be done adequately.
757 if ((LocalObjectAttributes
.ObjectName
== NULL
||
758 LocalObjectAttributes
.ObjectName
->Buffer
== NULL
||
759 LocalObjectAttributes
.ObjectName
->Length
== 0 ||
760 LocalObjectAttributes
.ObjectName
->Buffer
[0] == UNICODE_NULL
)
762 LocalObjectAttributes.RootDirectory == NULL */)
764 /* No, build the new window station name */
765 Status
= BuildUserModeWindowStationName(ObjectAttributes
,
766 &LocalObjectAttributes
,
768 &TebStaticUnicodeString
);
769 if (!NT_SUCCESS(Status
))
771 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status
);
774 OwnerMode
= KernelMode
;
777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
779 Status
=_SEH2_GetExceptionCode();
780 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status
);
784 if (!NT_SUCCESS(Status
))
786 SetLastNtError(Status
);
790 UserEnterExclusive();
792 /* Create the window station */
793 Status
= IntCreateWindowStation(&hWinSta
,
805 if (NT_SUCCESS(Status
))
807 TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
808 ObjectAttributes
->ObjectName
, hWinSta
);
812 ASSERT(hWinSta
== NULL
);
813 ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
814 ObjectAttributes
->ObjectName
, Status
);
817 /* Try to restore the user's ObjectAttributes and release the window station name */
818 FreeUserModeWindowStationName(WindowStationName
,
819 TebStaticUnicodeString
,
820 (OwnerMode
== KernelMode
? ObjectAttributes
: NULL
),
821 &LocalObjectAttributes
);
823 if (!NT_SUCCESS(Status
))
825 ASSERT(hWinSta
== NULL
);
826 SetLastNtError(Status
);
833 * NtUserOpenWindowStation
835 * Opens an existing window station.
838 * lpszWindowStationName
839 * Name of the existing window station.
842 * Requested type of access.
845 * If the function succeeds, the return value is the handle to the
846 * specified window station. If the function fails, the return value
850 * The returned handle can be closed with NtUserCloseWindowStation.
858 NtUserOpenWindowStation(
859 IN POBJECT_ATTRIBUTES ObjectAttributes
,
860 IN ACCESS_MASK dwDesiredAccess
)
862 NTSTATUS Status
= STATUS_SUCCESS
;
863 HWINSTA hWinSta
= NULL
;
864 OBJECT_ATTRIBUTES LocalObjectAttributes
;
865 PUNICODE_STRING WindowStationName
= NULL
;
866 PUNICODE_STRING TebStaticUnicodeString
= NULL
;
867 KPROCESSOR_MODE OwnerMode
= UserMode
;
869 TRACE("NtUserOpenWindowStation called\n");
871 /* Capture the object attributes and the window station name */
874 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
875 LocalObjectAttributes
= *ObjectAttributes
;
876 if (LocalObjectAttributes
.Length
!= sizeof(OBJECT_ATTRIBUTES
))
878 ERR("Invalid ObjectAttributes length!\n");
879 Status
= STATUS_INVALID_PARAMETER
;
884 * Check whether the caller did not provide a window station name,
885 * or provided the special "Service-0x00000000-00000000$" name.
887 * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
888 * is used instead of an empty name (observed when API-monitoring
889 * OpenWindowStation() called with an empty window station name).
891 if ((LocalObjectAttributes
.ObjectName
== NULL
||
892 LocalObjectAttributes
.ObjectName
->Buffer
== NULL
||
893 LocalObjectAttributes
.ObjectName
->Length
== 0 ||
894 LocalObjectAttributes
.ObjectName
->Buffer
[0] == UNICODE_NULL
)
896 LocalObjectAttributes.RootDirectory == NULL */)
898 /* No, remember that for later */
899 LocalObjectAttributes
.ObjectName
= NULL
;
901 if (LocalObjectAttributes
.ObjectName
&&
902 LocalObjectAttributes
.ObjectName
->Length
==
903 sizeof(L
"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL
) &&
904 _wcsnicmp(LocalObjectAttributes
.ObjectName
->Buffer
,
905 L
"Service-0x00000000-00000000$",
906 LocalObjectAttributes
.ObjectName
->Length
/ sizeof(WCHAR
)) == 0)
908 /* No, remember that for later */
909 LocalObjectAttributes
.ObjectName
= NULL
;
913 * If the caller did not provide a window station name, build a new one
914 * based on the logon session identifier for the calling process.
915 * The new name is allocated in user-mode, as the rest of ObjectAttributes
916 * already is, so that the validation performed by the Object Manager
917 * can be done adequately.
919 if (!LocalObjectAttributes
.ObjectName
)
921 /* No, build the new window station name */
922 Status
= BuildUserModeWindowStationName(ObjectAttributes
,
923 &LocalObjectAttributes
,
925 &TebStaticUnicodeString
);
926 if (!NT_SUCCESS(Status
))
928 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status
);
931 OwnerMode
= KernelMode
;
934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
936 Status
=_SEH2_GetExceptionCode();
937 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status
);
941 if (!NT_SUCCESS(Status
))
943 SetLastNtError(Status
);
947 /* Open the window station */
948 Status
= ObOpenObjectByName(ObjectAttributes
,
949 ExWindowStationObjectType
,
955 if (NT_SUCCESS(Status
))
957 TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
958 ObjectAttributes
->ObjectName
, hWinSta
);
962 ASSERT(hWinSta
== NULL
);
963 ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
964 ObjectAttributes
->ObjectName
, Status
);
967 /* Try to restore the user's ObjectAttributes and release the window station name */
968 FreeUserModeWindowStationName(WindowStationName
,
969 TebStaticUnicodeString
,
970 (OwnerMode
== KernelMode
? ObjectAttributes
: NULL
),
971 &LocalObjectAttributes
);
973 if (!NT_SUCCESS(Status
))
975 ASSERT(hWinSta
== NULL
);
976 SetLastNtError(Status
);
983 * NtUserCloseWindowStation
985 * Closes a window station handle.
989 * Handle to the window station.
995 * The window station handle can be created with NtUserCreateWindowStation
996 * or NtUserOpenWindowStation. Attempts to close a handle to the window
997 * station assigned to the calling process will fail.
1005 NtUserCloseWindowStation(
1008 PWINSTATION_OBJECT Object
;
1011 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
1013 if (hWinSta
== UserGetProcessWindowStation())
1015 ERR("Attempted to close process window station\n");
1019 Status
= IntValidateWindowStationHandle(hWinSta
,
1024 if (!NT_SUCCESS(Status
))
1026 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
1030 ObDereferenceObject(Object
);
1032 TRACE("Closing window station handle (%p)\n", hWinSta
);
1034 Status
= ObCloseHandle(hWinSta
, UserMode
);
1035 if (!NT_SUCCESS(Status
))
1037 SetLastNtError(Status
);
1045 * NtUserGetObjectInformation
1047 * The NtUserGetObjectInformation function retrieves information about a
1048 * window station or desktop object.
1052 * Handle to the window station or desktop object for which to
1053 * return information. This can be a handle of type HDESK or HWINSTA
1054 * (for example, a handle returned by NtUserCreateWindowStation,
1055 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1058 * Specifies the object information to be retrieved.
1061 * Pointer to a buffer to receive the object information.
1064 * Specifies the size, in bytes, of the buffer pointed to by the
1068 * Pointer to a variable receiving the number of bytes required to
1069 * store the requested information. If this variable's value is
1070 * greater than the value of the nLength parameter when the function
1071 * returns, the function returns FALSE, and none of the information
1072 * is copied to the pvInfo buffer. If the value of the variable pointed
1073 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1074 * the entire information block is copied.
1077 * If the function succeeds, the return value is nonzero. If the function
1078 * fails, the return value is zero.
1085 NtUserGetObjectInformation(
1088 PVOID pvInformation
,
1090 PDWORD nLengthNeeded
)
1093 PWINSTATION_OBJECT WinStaObject
= NULL
;
1094 PDESKTOP DesktopObject
= NULL
;
1095 POBJECT_HEADER ObjectHeader
;
1096 POBJECT_HEADER_NAME_INFO NameInfo
;
1097 OBJECT_HANDLE_INFORMATION HandleInfo
;
1098 USEROBJECTFLAGS ObjectFlags
;
1099 PUNICODE_STRING pStrNameU
= NULL
;
1100 PVOID pvData
= NULL
;
1101 SIZE_T nDataSize
= 0;
1106 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
1107 ProbeForWrite(pvInformation
, nLength
, 1);
1109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1111 SetLastNtError(_SEH2_GetExceptionCode());
1116 /* Try window station */
1117 TRACE("Trying to open window station 0x%p\n", hObject
);
1118 Status
= ObReferenceObjectByHandle(hObject
,
1120 ExWindowStationObjectType
,
1122 (PVOID
*)&WinStaObject
,
1125 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
1128 TRACE("Trying to open desktop %p\n", hObject
);
1129 WinStaObject
= NULL
;
1130 Status
= IntValidateDesktopHandle(hObject
,
1136 if (!NT_SUCCESS(Status
))
1138 ERR("Failed: 0x%x\n", Status
);
1142 TRACE("WinSta or Desktop opened!\n");
1149 ObjectFlags
.fReserved
= FALSE
;
1150 ObjectFlags
.fInherit
= !!(HandleInfo
.HandleAttributes
& OBJ_INHERIT
);
1152 ObjectFlags
.dwFlags
= 0;
1153 if (WinStaObject
!= NULL
)
1155 if (!(WinStaObject
->Flags
& WSS_NOIO
))
1156 ObjectFlags
.dwFlags
|= WSF_VISIBLE
;
1158 else if (DesktopObject
!= NULL
)
1160 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1164 ERR("No associated WinStaObject nor DesktopObject!\n");
1167 pvData
= &ObjectFlags
;
1168 nDataSize
= sizeof(ObjectFlags
);
1169 Status
= STATUS_SUCCESS
;
1175 if (WinStaObject
!= NULL
)
1177 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(WinStaObject
);
1178 NameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1180 if (NameInfo
&& (NameInfo
->Name
.Length
> 0))
1182 /* Named window station */
1183 pStrNameU
= &NameInfo
->Name
;
1184 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1188 /* Unnamed window station (should never happen!) */
1191 nDataSize
= sizeof(UNICODE_NULL
);
1193 Status
= STATUS_SUCCESS
;
1195 else if (DesktopObject
!= NULL
)
1197 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
1198 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
1199 Status
= STATUS_SUCCESS
;
1203 Status
= STATUS_INVALID_PARAMETER
;
1210 if (WinStaObject
!= NULL
)
1212 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(WinStaObject
);
1213 pStrNameU
= &ObjectHeader
->Type
->Name
;
1214 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1215 Status
= STATUS_SUCCESS
;
1217 else if (DesktopObject
!= NULL
)
1219 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(DesktopObject
);
1220 pStrNameU
= &ObjectHeader
->Type
->Name
;
1221 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1222 Status
= STATUS_SUCCESS
;
1226 Status
= STATUS_INVALID_PARAMETER
;
1232 Status
= STATUS_NOT_IMPLEMENTED
;
1233 ERR("UOI_USER_SID unimplemented!\n");
1237 Status
= STATUS_INVALID_PARAMETER
;
1242 if ((Status
== STATUS_SUCCESS
) && (nLength
< nDataSize
))
1243 Status
= STATUS_BUFFER_TOO_SMALL
;
1248 *nLengthNeeded
= nDataSize
;
1250 /* Try to copy data to caller */
1251 if (Status
== STATUS_SUCCESS
&& (nDataSize
> 0))
1253 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
1257 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
1261 /* Copy and NULL-terminate the string */
1262 RtlCopyMemory(pvInformation
, pStrNameU
->Buffer
, pStrNameU
->Length
);
1263 ((PWCHAR
)pvInformation
)[pStrNameU
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1267 /* Zero the memory */
1268 RtlZeroMemory(pvInformation
, nDataSize
);
1272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1274 Status
= _SEH2_GetExceptionCode();
1278 /* Release objects */
1279 if (DesktopObject
!= NULL
)
1280 ObDereferenceObject(DesktopObject
);
1281 if (WinStaObject
!= NULL
)
1282 ObDereferenceObject(WinStaObject
);
1284 if (!NT_SUCCESS(Status
))
1286 SetLastNtError(Status
);
1294 * NtUserSetObjectInformation
1296 * The NtUserSetObjectInformation function sets information about a
1297 * window station or desktop object.
1301 * Handle to the window station or desktop object for which to set
1302 * object information. This value can be a handle of type HDESK or
1306 * Specifies the object information to be set.
1309 * Pointer to a buffer containing the object information.
1312 * Specifies the size, in bytes, of the information contained in the
1313 * buffer pointed to by pvInfo.
1316 * If the function succeeds, the return value is nonzero. If the function
1317 * fails the return value is zero.
1325 NtUserSetObjectInformation(
1328 PVOID pvInformation
,
1331 /* FIXME: ZwQueryObject */
1332 /* FIXME: ZwSetInformationObject */
1333 SetLastNtError(STATUS_UNSUCCESSFUL
);
1339 UserGetProcessWindowStation(VOID
)
1341 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
1343 return ppi
->hwinsta
;
1348 * NtUserGetProcessWindowStation
1350 * Returns a handle to the current process window station.
1353 * If the function succeeds, the return value is handle to the window
1354 * station assigned to the current process. If the function fails, the
1355 * return value is NULL.
1362 NtUserGetProcessWindowStation(VOID
)
1364 return UserGetProcessWindowStation();
1368 UserSetProcessWindowStation(HWINSTA hWindowStation
)
1372 OBJECT_HANDLE_INFORMATION ObjectHandleInfo
;
1373 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
1374 HWINSTA hCacheWinSta
;
1376 ppi
= PsGetCurrentProcessWin32Process();
1378 /* Reference the new window station */
1379 if (hWindowStation
!= NULL
)
1381 Status
= IntValidateWindowStationHandle(hWindowStation
,
1386 if (!NT_SUCCESS(Status
))
1388 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation
);
1389 SetLastNtError(Status
);
1394 OldWinSta
= ppi
->prpwinsta
;
1395 hCacheWinSta
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
1397 /* Dereference the previous window station */
1398 if (OldWinSta
!= NULL
)
1400 ObDereferenceObject(OldWinSta
);
1404 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1407 /* Close the cached EPROCESS window station handle if needed */
1408 if (hCacheWinSta
!= NULL
)
1410 /* Reference the window station */
1411 Status
= ObReferenceObjectByHandle(hCacheWinSta
,
1413 ExWindowStationObjectType
,
1417 if (!NT_SUCCESS(Status
))
1419 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status
);
1420 /* We failed, reset the cache */
1421 hCacheWinSta
= NULL
;
1422 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1427 * Close the old handle and reset the cache only
1428 * if we are setting a different window station.
1430 if (NewWinSta
!= OldWinSta
)
1432 ObCloseHandle(hCacheWinSta
, UserMode
);
1433 hCacheWinSta
= NULL
;
1434 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1437 /* Dereference the window station */
1438 ObDereferenceObject(OldWinSta
);
1442 /* Duplicate and save a new cached EPROCESS window station handle */
1443 if ((hCacheWinSta
== NULL
) && (hWindowStation
!= NULL
))
1445 Status
= ZwDuplicateObject(ZwCurrentProcess(),
1448 (PHANDLE
)&hCacheWinSta
,
1451 DUPLICATE_SAME_ACCESS
);
1452 if (!NT_SUCCESS(Status
))
1454 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status
);
1458 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1462 ppi
->prpwinsta
= NewWinSta
;
1463 ppi
->hwinsta
= hWindowStation
;
1464 ppi
->amwinsta
= hWindowStation
!= NULL
? ObjectHandleInfo
.GrantedAccess
: 0;
1465 TRACE("WS : Granted Access 0x%08lx\n",ppi
->amwinsta
);
1467 if (RtlAreAllAccessesGranted(ppi
->amwinsta
, WINSTA_READSCREEN
))
1469 ppi
->W32PF_flags
|= W32PF_READSCREENACCESSGRANTED
;
1473 ppi
->W32PF_flags
&= ~W32PF_READSCREENACCESSGRANTED
;
1476 if (NewWinSta
&& !(NewWinSta
->Flags
& WSS_NOIO
))
1478 ppi
->W32PF_flags
|= W32PF_IOWINSTA
;
1480 else /* Might be closed if the handle is NULL */
1482 ppi
->W32PF_flags
&= ~W32PF_IOWINSTA
;
1488 * NtUserSetProcessWindowStation
1490 * Assigns a window station to the current process.
1494 * Handle to the window station.
1504 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1508 UserEnterExclusive();
1510 ret
= UserSetProcessWindowStation(hWindowStation
);
1518 * NtUserLockWindowStation
1520 * Locks switching desktops. Only the logon application is allowed to call this function.
1527 NtUserLockWindowStation(HWINSTA hWindowStation
)
1529 PWINSTATION_OBJECT Object
;
1532 TRACE("About to set process window station with handle (%p)\n",
1535 if (gpidLogon
!= PsGetCurrentProcessId())
1537 ERR("Unauthorized process attempted to lock the window station!\n");
1538 EngSetLastError(ERROR_ACCESS_DENIED
);
1542 Status
= IntValidateWindowStationHandle(hWindowStation
,
1547 if (!NT_SUCCESS(Status
))
1549 TRACE("Validation of window station handle (%p) failed\n",
1551 SetLastNtError(Status
);
1555 Object
->Flags
|= WSS_LOCKED
;
1557 ObDereferenceObject(Object
);
1562 * NtUserUnlockWindowStation
1564 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1571 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1573 PWINSTATION_OBJECT Object
;
1577 TRACE("About to set process window station with handle (%p)\n",
1580 if (gpidLogon
!= PsGetCurrentProcessId())
1582 ERR("Unauthorized process attempted to unlock the window station!\n");
1583 EngSetLastError(ERROR_ACCESS_DENIED
);
1587 Status
= IntValidateWindowStationHandle(hWindowStation
,
1592 if (!NT_SUCCESS(Status
))
1594 TRACE("Validation of window station handle (%p) failed\n",
1596 SetLastNtError(Status
);
1600 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1601 Object
->Flags
&= ~WSS_LOCKED
;
1603 ObDereferenceObject(Object
);
1607 static NTSTATUS FASTCALL
1608 BuildWindowStationNameList(
1611 PULONG pRequiredSize
)
1613 OBJECT_ATTRIBUTES ObjectAttributes
;
1615 HANDLE DirectoryHandle
;
1616 char InitialBuffer
[256], *Buffer
;
1617 ULONG Context
, ReturnLength
, BufferSize
;
1619 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1623 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1624 // with judicious parameters one can create window stations elsewhere
1625 // than in Windows\WindowStations directory, Win32k definitely MUST
1626 // maintain a list of window stations it has created, and not rely
1627 // on the enumeration of Windows\WindowStations !!!
1631 * Try to open the directory.
1633 InitializeObjectAttributes(&ObjectAttributes
,
1634 &gustrWindowStationsDir
,
1635 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1639 Status
= ZwOpenDirectoryObject(&DirectoryHandle
,
1643 if (!NT_SUCCESS(Status
))
1648 /* First try to query the directory using a fixed-size buffer */
1651 Status
= ZwQueryDirectoryObject(DirectoryHandle
,
1653 sizeof(InitialBuffer
),
1658 if (NT_SUCCESS(Status
))
1660 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1661 FALSE
, &Context
, NULL
))
1663 /* Our fixed-size buffer is large enough */
1664 Buffer
= InitialBuffer
;
1670 /* Need a larger buffer, check how large exactly */
1671 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1673 if (!NT_SUCCESS(Status
))
1675 ERR("ZwQueryDirectoryObject failed\n");
1676 ZwClose(DirectoryHandle
);
1680 BufferSize
= ReturnLength
;
1681 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1684 ZwClose(DirectoryHandle
);
1685 return STATUS_NO_MEMORY
;
1688 /* We should have a sufficiently large buffer now */
1690 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1691 FALSE
, TRUE
, &Context
, &ReturnLength
);
1692 if (! NT_SUCCESS(Status
) ||
1693 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1694 FALSE
, &Context
, NULL
))
1696 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1697 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1698 ZwClose(DirectoryHandle
);
1699 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1703 ZwClose(DirectoryHandle
);
1706 * Count the required size of buffer.
1708 ReturnLength
= sizeof(DWORD
);
1710 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1711 0 != DirEntry
->Name
.Length
;
1714 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1717 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1718 if (NULL
!= pRequiredSize
)
1720 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1721 if (! NT_SUCCESS(Status
))
1723 if (Buffer
!= InitialBuffer
)
1725 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1727 return STATUS_BUFFER_TOO_SMALL
;
1732 * Check if the supplied buffer is large enough.
1734 if (dwSize
< ReturnLength
)
1736 if (Buffer
!= InitialBuffer
)
1738 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1740 return STATUS_BUFFER_TOO_SMALL
;
1744 * Generate the resulting buffer contents.
1746 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1747 if (! NT_SUCCESS(Status
))
1749 if (Buffer
!= InitialBuffer
)
1751 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1755 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1758 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1759 0 != DirEntry
->Name
.Length
;
1762 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1763 if (! NT_SUCCESS(Status
))
1765 if (Buffer
!= InitialBuffer
)
1767 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1771 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1772 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1773 if (! NT_SUCCESS(Status
))
1775 if (Buffer
!= InitialBuffer
)
1777 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1781 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1787 if (Buffer
!= InitialBuffer
)
1789 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1792 return STATUS_SUCCESS
;
1795 static NTSTATUS FASTCALL
1796 BuildDesktopNameList(
1797 HWINSTA hWindowStation
,
1800 PULONG pRequiredSize
)
1803 PWINSTATION_OBJECT WindowStation
;
1804 PLIST_ENTRY DesktopEntry
;
1805 PDESKTOP DesktopObject
;
1809 UNICODE_STRING DesktopName
;
1811 Status
= IntValidateWindowStationHandle(hWindowStation
,
1816 if (! NT_SUCCESS(Status
))
1822 * Count the required size of buffer.
1824 ReturnLength
= sizeof(DWORD
);
1826 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1827 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1828 DesktopEntry
= DesktopEntry
->Flink
)
1830 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1831 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1832 ReturnLength
+= DesktopName
.Length
+ sizeof(WCHAR
);
1835 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1836 if (NULL
!= pRequiredSize
)
1838 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1839 if (! NT_SUCCESS(Status
))
1841 ObDereferenceObject(WindowStation
);
1842 return STATUS_BUFFER_TOO_SMALL
;
1847 * Check if the supplied buffer is large enough.
1849 if (dwSize
< ReturnLength
)
1851 ObDereferenceObject(WindowStation
);
1852 return STATUS_BUFFER_TOO_SMALL
;
1856 * Generate the resulting buffer contents.
1858 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1859 if (! NT_SUCCESS(Status
))
1861 ObDereferenceObject(WindowStation
);
1864 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1867 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1868 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1869 DesktopEntry
= DesktopEntry
->Flink
)
1871 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1872 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1873 Status
= MmCopyToCaller(lpBuffer
, DesktopName
.Buffer
, DesktopName
.Length
);
1874 if (! NT_SUCCESS(Status
))
1876 ObDereferenceObject(WindowStation
);
1879 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
.Length
);
1880 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1881 if (! NT_SUCCESS(Status
))
1883 ObDereferenceObject(WindowStation
);
1886 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1890 * Clean up and return
1892 ObDereferenceObject(WindowStation
);
1893 return STATUS_SUCCESS
;
1897 * NtUserBuildNameList
1899 * Function used for enumeration of desktops or window stations.
1903 * For enumeration of window stations this parameter must be set to
1904 * zero. Otherwise it's handle for window station.
1907 * Size of buffer passed by caller.
1910 * Buffer passed by caller. If the function succeeds, the buffer is
1911 * filled with window station/desktop count (in first DWORD) and
1912 * NULL-terminated window station/desktop names.
1915 * If the function succeeds, this is the number of bytes copied.
1916 * Otherwise it's size of buffer needed for function to succeed.
1923 NtUserBuildNameList(
1924 HWINSTA hWindowStation
,
1927 PULONG pRequiredSize
)
1929 /* The WindowStation name list and desktop name list are build in completely
1930 different ways. Call the appropriate function */
1931 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1932 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1939 NtUserSetLogonNotifyWindow(HWND hWnd
)
1941 if (gpidLogon
!= PsGetCurrentProcessId())
1946 if (!IntIsWindow(hWnd
))
1958 NtUserLockWorkStation(VOID
)
1961 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1963 UserEnterExclusive();
1965 if (pti
->rpdesk
== IntGetActiveDesktop())
1967 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);
1981 NtUserSetWindowStationUser(
1982 IN HWINSTA hWindowStation
,
1984 IN PSID psid OPTIONAL
,
1989 PWINSTATION_OBJECT WindowStation
= NULL
;
1992 UserEnterExclusive();
1994 if (gpidLogon
!= PsGetCurrentProcessId())
1996 EngSetLastError(ERROR_ACCESS_DENIED
);
2000 /* Validate the window station */
2001 Status
= IntValidateWindowStationHandle(hWindowStation
,
2006 if (!NT_SUCCESS(Status
))
2011 /* Capture the user LUID */
2014 ProbeForRead(pluid
, sizeof(LUID
), 1);
2017 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2019 Status
= _SEH2_GetExceptionCode();
2020 _SEH2_YIELD(goto Leave
);
2024 /* Reset the window station user LUID */
2025 RtlZeroMemory(&WindowStation
->luidUser
, sizeof(LUID
));
2027 /* Reset the window station user SID */
2028 if (WindowStation
->psidUser
)
2030 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
2031 WindowStation
->psidUser
= NULL
;
2034 /* Copy the new user SID if one has been provided */
2037 WindowStation
->psidUser
= ExAllocatePoolWithTag(PagedPool
, size
, USERTAG_SECURITY
);
2038 if (WindowStation
->psidUser
== NULL
)
2040 EngSetLastError(ERROR_OUTOFMEMORY
);
2044 Status
= STATUS_SUCCESS
;
2047 ProbeForRead(psid
, size
, 1);
2048 RtlCopyMemory(WindowStation
->psidUser
, psid
, size
);
2050 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2052 Status
= _SEH2_GetExceptionCode();
2056 if (!NT_SUCCESS(Status
))
2058 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
2059 WindowStation
->psidUser
= NULL
;
2064 /* Copy the new user LUID */
2065 WindowStation
->luidUser
= luidUser
;
2071 ObDereferenceObject(WindowStation
);