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 UserAssignmentUnlock((PVOID
*)&WinSta
->spklList
);
133 return STATUS_SUCCESS
;
138 IntWinStaObjectParse(
139 _In_ PVOID Parameters
)
141 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters
= Parameters
;
142 PUNICODE_STRING RemainingName
= ParseParameters
->RemainingName
;
144 /* Assume we don't find anything */
145 *ParseParameters
->Object
= NULL
;
147 /* Check for an empty name */
148 if (!RemainingName
->Length
)
150 /* Make sure this is a window station, can't parse a desktop now */
151 if (ParseParameters
->ObjectType
!= ExWindowStationObjectType
)
154 return STATUS_OBJECT_TYPE_MISMATCH
;
157 /* Reference the window station and return */
158 ObReferenceObject(ParseParameters
->ParseObject
);
159 *ParseParameters
->Object
= ParseParameters
->ParseObject
;
160 return STATUS_SUCCESS
;
163 /* Check for leading slash */
164 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
167 RemainingName
->Buffer
++;
168 RemainingName
->Length
-= sizeof(WCHAR
);
169 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
172 /* Check if there is still a slash */
173 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
175 /* In this case, fail */
176 return STATUS_OBJECT_PATH_INVALID
;
180 * Check if we are parsing a desktop.
182 if (ParseParameters
->ObjectType
== ExDesktopObjectType
)
184 /* Then call the desktop parse routine */
185 return IntDesktopObjectParse(ParseParameters
->ParseObject
,
186 ParseParameters
->ObjectType
,
187 ParseParameters
->AccessState
,
188 ParseParameters
->AccessMode
,
189 ParseParameters
->Attributes
,
190 ParseParameters
->CompleteName
,
192 ParseParameters
->Context
,
193 ParseParameters
->SecurityQos
,
194 ParseParameters
->Object
);
197 /* Should hopefully never get here */
198 return STATUS_OBJECT_TYPE_MISMATCH
;
204 _In_ PVOID Parameters
)
206 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
209 ppi
= PsGetCurrentProcessWin32Process();
211 if (ppi
&& (OkToCloseParameters
->Handle
== ppi
->hwinsta
))
213 return STATUS_ACCESS_DENIED
;
216 return STATUS_SUCCESS
;
219 /* PRIVATE FUNCTIONS **********************************************************/
222 * IntValidateWindowStationHandle
224 * Validates the window station handle.
227 * If the function succeeds, the handle remains referenced. If the
228 * fucntion fails, last error is set.
232 IntValidateWindowStationHandle(
233 HWINSTA WindowStation
,
234 KPROCESSOR_MODE AccessMode
,
235 ACCESS_MASK DesiredAccess
,
236 PWINSTATION_OBJECT
*Object
,
237 POBJECT_HANDLE_INFORMATION pObjectHandleInfo
)
241 if (WindowStation
== NULL
)
243 ERR("Invalid window station handle\n");
244 EngSetLastError(ERROR_INVALID_HANDLE
);
245 return STATUS_INVALID_HANDLE
;
248 Status
= ObReferenceObjectByHandle(WindowStation
,
250 ExWindowStationObjectType
,
255 if (!NT_SUCCESS(Status
))
256 SetLastNtError(Status
);
262 co_IntInitializeDesktopGraphics(VOID
)
265 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
268 if (PDEVOBJ_lChangeDisplaySettings(NULL
, NULL
, NULL
, &gpmdev
, TRUE
) != DISP_CHANGE_SUCCESSFUL
)
270 ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
274 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
275 if (NULL
== ScreenDeviceContext
)
277 IntDestroyPrimarySurface();
280 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
282 if (!IntCreatePrimarySurface())
287 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
289 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
290 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
292 /* Update the system metrics */
295 /* Set new size of the monitor */
296 UserUpdateMonitorSize((HDEV
)gpmdev
->ppdevGlobal
);
298 /* Update the SERVERINFO */
299 gpsi
->aiSysMet
[SM_CXSCREEN
] = gpmdev
->ppdevGlobal
->gdiinfo
.ulHorzRes
;
300 gpsi
->aiSysMet
[SM_CYSCREEN
] = gpmdev
->ppdevGlobal
->gdiinfo
.ulVertRes
;
301 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
302 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
303 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
304 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
305 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
307 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
311 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
313 // Font is realized and this dc was previously set to internal DC_ATTR.
314 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
315 gpsi
->tmSysFont
= tmw
;
317 /* Put the pointer in the center of the screen */
318 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
319 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
322 UserAttachMonitor((HDEV
)gpmdev
->ppdevGlobal
);
324 /* Setup the cursor */
325 co_IntLoadDefaultCursors();
327 /* Setup the icons */
333 /* Show the desktop */
334 pdesk
= IntGetActiveDesktop();
336 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
338 /* HACK: display wallpaper on all secondary displays */
340 PGRAPHICS_DEVICE pGraphicsDevice
;
341 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
342 UNICODE_STRING DisplayName
;
346 for (iDevNum
= 1; (pGraphicsDevice
= EngpFindGraphicsDevice(NULL
, iDevNum
)) != NULL
; iDevNum
++)
348 RtlInitUnicodeString(&DisplayName
, pGraphicsDevice
->szWinDeviceName
);
349 hdc
= IntGdiCreateDC(&DriverName
, &DisplayName
, NULL
, NULL
, FALSE
);
350 IntPaintDesktop(hdc
);
358 IntEndDesktopGraphics(VOID
)
360 if (NULL
!= ScreenDeviceContext
)
361 { // No need to allocate a new dcattr.
362 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
363 GreDeleteObject(ScreenDeviceContext
);
364 ScreenDeviceContext
= NULL
;
366 IntHideDesktop(IntGetActiveDesktop());
367 IntDestroyPrimarySurface();
373 return ScreenDeviceContext
;
377 CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess
)
379 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
380 if ( gpidLogon
!= PsGetCurrentProcessId() )
382 if (!(ppi
->W32PF_flags
& W32PF_IOWINSTA
))
384 ERR("Requires Interactive Window Station\n");
385 EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
);
388 if (!RtlAreAllAccessesGranted(ppi
->amwinsta
, DesiredAccess
))
390 ERR("Access Denied\n");
391 EngSetLastError(ERROR_ACCESS_DENIED
);
399 /* PUBLIC FUNCTIONS ***********************************************************/
402 * NtUserCreateWindowStation
404 * Creates a new window station.
407 * lpszWindowStationName
408 * Pointer to a null-terminated string specifying the name of the
409 * window station to be created. Window station names are
410 * case-insensitive and cannot contain backslash characters (\).
411 * Only members of the Administrators group are allowed to specify a
415 * Requested type of access
418 * Security descriptor
420 * Unknown3, Unknown4, Unknown5, Unknown6
424 * If the function succeeds, the return value is a handle to the newly
425 * created window station. If the specified window station already
426 * exists, the function succeeds and returns a handle to the existing
427 * window station. If the function fails, the return value is NULL.
435 IntCreateWindowStation(
436 OUT HWINSTA
* phWinSta
,
437 IN POBJECT_ATTRIBUTES ObjectAttributes
,
438 IN KPROCESSOR_MODE AccessMode
,
439 IN KPROCESSOR_MODE OwnerMode
,
440 IN ACCESS_MASK dwDesiredAccess
,
449 PWINSTATION_OBJECT WindowStation
;
451 TRACE("IntCreateWindowStation called\n");
456 Status
= ObOpenObjectByName(ObjectAttributes
,
457 ExWindowStationObjectType
,
463 if (NT_SUCCESS(Status
))
465 TRACE("IntCreateWindowStation opened window station '%wZ'\n",
466 ObjectAttributes
->ObjectName
);
472 * No existing window station found, try to create a new one.
475 /* Create the window station object */
476 Status
= ObCreateObject(AccessMode
,
477 ExWindowStationObjectType
,
481 sizeof(WINSTATION_OBJECT
),
484 (PVOID
*)&WindowStation
);
485 if (!NT_SUCCESS(Status
))
487 ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
488 ObjectAttributes
->ObjectName
, Status
);
489 SetLastNtError(Status
);
493 /* Initialize the window station */
494 RtlZeroMemory(WindowStation
, sizeof(WINSTATION_OBJECT
));
496 InitializeListHead(&WindowStation
->DesktopListHead
);
497 WindowStation
->dwSessionId
= NtCurrentPeb()->SessionId
;
498 Status
= RtlCreateAtomTable(37, &WindowStation
->AtomTable
);
499 if (!NT_SUCCESS(Status
))
501 ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
502 ObjectAttributes
->ObjectName
, Status
);
503 ObDereferenceObject(WindowStation
);
504 SetLastNtError(Status
);
508 Status
= ObInsertObject(WindowStation
,
514 if (!NT_SUCCESS(Status
))
516 ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status
);
517 SetLastNtError(Status
);
521 // FIXME! TODO: Add this new window station to a linked list
523 if (InputWindowStation
== NULL
)
525 ERR("Initializing input window station\n");
527 /* Only Winlogon can create the interactive window station */
528 ASSERT(gpidLogon
== PsGetCurrentProcessId());
530 InputWindowStation
= WindowStation
;
531 WindowStation
->Flags
&= ~WSS_NOIO
;
535 UserCreateSystemThread(ST_DESKTOP_THREAD
);
536 UserCreateSystemThread(ST_RIT
);
538 /* Desktop functions require the desktop thread running so wait for it to initialize */
540 KeWaitForSingleObject(gpDesktopThreadStartedEvent
,
549 WindowStation
->Flags
|= WSS_NOIO
;
552 TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
553 ObjectAttributes
->ObjectName
, WindowStation
, hWinSta
);
556 EngSetLastError(ERROR_SUCCESS
);
558 return STATUS_SUCCESS
;
562 FreeUserModeWindowStationName(
563 IN OUT PUNICODE_STRING WindowStationName
,
564 IN PUNICODE_STRING TebStaticUnicodeString
,
565 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL
,
566 IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL
)
570 /* Try to restore the user's UserModeObjectAttributes */
571 if (UserModeObjectAttributes
&& LocalObjectAttributes
)
575 ProbeForWrite(UserModeObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
576 *UserModeObjectAttributes
= *LocalObjectAttributes
;
578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
585 /* Free the user-mode memory */
586 if (WindowStationName
&& (WindowStationName
!= TebStaticUnicodeString
))
588 ZwFreeVirtualMemory(ZwCurrentProcess(),
589 (PVOID
*)&WindowStationName
,
596 BuildUserModeWindowStationName(
597 IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes
,
598 IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes
,
599 OUT PUNICODE_STRING
* WindowStationName
,
600 OUT PUNICODE_STRING
* TebStaticUnicodeString
)
609 *WindowStationName
= NULL
;
610 *TebStaticUnicodeString
= NULL
;
612 /* Retrieve the current process LUID */
613 Status
= GetProcessLuid(NULL
, NULL
, &CallerLuid
);
614 if (!NT_SUCCESS(Status
))
616 ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status
);
620 /* Compute the needed string size */
621 MemSize
= _scwprintf(L
"%wZ\\Service-0x%x-%x$",
622 &gustrWindowStationsDir
,
625 MemSize
= MemSize
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
626 if (MemSize
> MAXUSHORT
)
628 ERR("Window station name length is too long.\n");
629 return STATUS_NAME_TOO_LONG
;
631 StrSize
= (USHORT
)MemSize
;
634 * Check whether it's short enough so that we can use the static buffer
635 * in the TEB. Otherwise continue with virtual memory allocation.
637 Teb
= NtCurrentTeb();
638 if (Teb
&& (StrSize
<= sizeof(Teb
->StaticUnicodeBuffer
)))
640 /* We can use the TEB's static unicode string */
641 ASSERT(Teb
->StaticUnicodeString
.Buffer
== Teb
->StaticUnicodeBuffer
);
642 ASSERT(Teb
->StaticUnicodeString
.MaximumLength
== sizeof(Teb
->StaticUnicodeBuffer
));
644 /* Remember the TEB's static unicode string address for later */
645 *TebStaticUnicodeString
= &Teb
->StaticUnicodeString
;
647 *WindowStationName
= *TebStaticUnicodeString
;
648 (*WindowStationName
)->Length
= 0;
652 /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
653 MemSize
+= ALIGN_UP(sizeof(UNICODE_STRING
), sizeof(PVOID
));
655 /* Allocate the memory in user-mode */
656 Status
= ZwAllocateVirtualMemory(ZwCurrentProcess(),
657 (PVOID
*)WindowStationName
,
662 if (!NT_SUCCESS(Status
))
664 ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status
);
668 RtlInitEmptyUnicodeString(*WindowStationName
,
669 (PWCHAR
)((ULONG_PTR
)*WindowStationName
+
670 ALIGN_UP(sizeof(UNICODE_STRING
), sizeof(PVOID
))),
674 /* Build a valid window station name from the LUID */
675 Status
= RtlStringCbPrintfW((*WindowStationName
)->Buffer
,
676 (*WindowStationName
)->MaximumLength
,
677 L
"%wZ\\Service-0x%x-%x$",
678 &gustrWindowStationsDir
,
681 if (!NT_SUCCESS(Status
))
683 ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status
);
686 (*WindowStationName
)->Length
= (USHORT
)(wcslen((*WindowStationName
)->Buffer
) * sizeof(WCHAR
));
688 /* Try to update the user's UserModeObjectAttributes */
691 ProbeForWrite(UserModeObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
692 *LocalObjectAttributes
= *UserModeObjectAttributes
;
694 UserModeObjectAttributes
->ObjectName
= *WindowStationName
;
695 UserModeObjectAttributes
->RootDirectory
= NULL
;
697 Status
= STATUS_SUCCESS
;
699 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
701 Status
= _SEH2_GetExceptionCode();
706 if (!NT_SUCCESS(Status
))
708 /* Release the window station name */
709 FreeUserModeWindowStationName(*WindowStationName
,
710 *TebStaticUnicodeString
,
719 NtUserCreateWindowStation(
720 IN POBJECT_ATTRIBUTES ObjectAttributes
,
721 IN ACCESS_MASK dwDesiredAccess
,
728 NTSTATUS Status
= STATUS_SUCCESS
;
729 HWINSTA hWinSta
= NULL
;
730 OBJECT_ATTRIBUTES LocalObjectAttributes
;
731 PUNICODE_STRING WindowStationName
= NULL
;
732 PUNICODE_STRING TebStaticUnicodeString
= NULL
;
733 KPROCESSOR_MODE OwnerMode
= UserMode
;
735 TRACE("NtUserCreateWindowStation called\n");
737 /* Capture the object attributes and the window station name */
740 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
741 LocalObjectAttributes
= *ObjectAttributes
;
742 if (LocalObjectAttributes
.Length
!= sizeof(OBJECT_ATTRIBUTES
))
744 ERR("Invalid ObjectAttributes length!\n");
745 Status
= STATUS_INVALID_PARAMETER
;
750 * Check whether the caller provided a window station name together
751 * with a RootDirectory handle.
753 * If the caller did not provide a window station name, build a new one
754 * based on the logon session identifier for the calling process.
755 * The new name is allocated in user-mode, as the rest of ObjectAttributes
756 * already is, so that the validation performed by the Object Manager
757 * can be done adequately.
759 if ((LocalObjectAttributes
.ObjectName
== NULL
||
760 LocalObjectAttributes
.ObjectName
->Buffer
== NULL
||
761 LocalObjectAttributes
.ObjectName
->Length
== 0 ||
762 LocalObjectAttributes
.ObjectName
->Buffer
[0] == UNICODE_NULL
)
764 LocalObjectAttributes.RootDirectory == NULL */)
766 /* No, build the new window station name */
767 Status
= BuildUserModeWindowStationName(ObjectAttributes
,
768 &LocalObjectAttributes
,
770 &TebStaticUnicodeString
);
771 if (!NT_SUCCESS(Status
))
773 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status
);
776 OwnerMode
= KernelMode
;
779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
781 Status
=_SEH2_GetExceptionCode();
782 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status
);
786 if (!NT_SUCCESS(Status
))
788 SetLastNtError(Status
);
792 UserEnterExclusive();
794 /* Create the window station */
795 Status
= IntCreateWindowStation(&hWinSta
,
807 if (NT_SUCCESS(Status
))
809 TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
810 ObjectAttributes
->ObjectName
, hWinSta
);
814 ASSERT(hWinSta
== NULL
);
815 ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
816 ObjectAttributes
->ObjectName
, Status
);
819 /* Try to restore the user's ObjectAttributes and release the window station name */
820 FreeUserModeWindowStationName(WindowStationName
,
821 TebStaticUnicodeString
,
822 (OwnerMode
== KernelMode
? ObjectAttributes
: NULL
),
823 &LocalObjectAttributes
);
825 if (!NT_SUCCESS(Status
))
827 ASSERT(hWinSta
== NULL
);
828 SetLastNtError(Status
);
835 * NtUserOpenWindowStation
837 * Opens an existing window station.
840 * lpszWindowStationName
841 * Name of the existing window station.
844 * Requested type of access.
847 * If the function succeeds, the return value is the handle to the
848 * specified window station. If the function fails, the return value
852 * The returned handle can be closed with NtUserCloseWindowStation.
860 NtUserOpenWindowStation(
861 IN POBJECT_ATTRIBUTES ObjectAttributes
,
862 IN ACCESS_MASK dwDesiredAccess
)
864 NTSTATUS Status
= STATUS_SUCCESS
;
865 HWINSTA hWinSta
= NULL
;
866 OBJECT_ATTRIBUTES LocalObjectAttributes
;
867 PUNICODE_STRING WindowStationName
= NULL
;
868 PUNICODE_STRING TebStaticUnicodeString
= NULL
;
869 KPROCESSOR_MODE OwnerMode
= UserMode
;
871 TRACE("NtUserOpenWindowStation called\n");
873 /* Capture the object attributes and the window station name */
876 ProbeForRead(ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), sizeof(ULONG
));
877 LocalObjectAttributes
= *ObjectAttributes
;
878 if (LocalObjectAttributes
.Length
!= sizeof(OBJECT_ATTRIBUTES
))
880 ERR("Invalid ObjectAttributes length!\n");
881 Status
= STATUS_INVALID_PARAMETER
;
886 * Check whether the caller did not provide a window station name,
887 * or provided the special "Service-0x00000000-00000000$" name.
889 * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
890 * is used instead of an empty name (observed when API-monitoring
891 * OpenWindowStation() called with an empty window station name).
893 if ((LocalObjectAttributes
.ObjectName
== NULL
||
894 LocalObjectAttributes
.ObjectName
->Buffer
== NULL
||
895 LocalObjectAttributes
.ObjectName
->Length
== 0 ||
896 LocalObjectAttributes
.ObjectName
->Buffer
[0] == UNICODE_NULL
)
898 LocalObjectAttributes.RootDirectory == NULL */)
900 /* No, remember that for later */
901 LocalObjectAttributes
.ObjectName
= NULL
;
903 if (LocalObjectAttributes
.ObjectName
&&
904 LocalObjectAttributes
.ObjectName
->Length
==
905 sizeof(L
"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL
) &&
906 _wcsnicmp(LocalObjectAttributes
.ObjectName
->Buffer
,
907 L
"Service-0x00000000-00000000$",
908 LocalObjectAttributes
.ObjectName
->Length
/ sizeof(WCHAR
)) == 0)
910 /* No, remember that for later */
911 LocalObjectAttributes
.ObjectName
= NULL
;
915 * If the caller did not provide a window station name, build a new one
916 * based on the logon session identifier for the calling process.
917 * The new name is allocated in user-mode, as the rest of ObjectAttributes
918 * already is, so that the validation performed by the Object Manager
919 * can be done adequately.
921 if (!LocalObjectAttributes
.ObjectName
)
923 /* No, build the new window station name */
924 Status
= BuildUserModeWindowStationName(ObjectAttributes
,
925 &LocalObjectAttributes
,
927 &TebStaticUnicodeString
);
928 if (!NT_SUCCESS(Status
))
930 ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status
);
933 OwnerMode
= KernelMode
;
936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
938 Status
=_SEH2_GetExceptionCode();
939 ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status
);
943 if (!NT_SUCCESS(Status
))
945 SetLastNtError(Status
);
949 /* Open the window station */
950 Status
= ObOpenObjectByName(ObjectAttributes
,
951 ExWindowStationObjectType
,
957 if (NT_SUCCESS(Status
))
959 TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
960 ObjectAttributes
->ObjectName
, hWinSta
);
964 ASSERT(hWinSta
== NULL
);
965 ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
966 ObjectAttributes
->ObjectName
, Status
);
969 /* Try to restore the user's ObjectAttributes and release the window station name */
970 FreeUserModeWindowStationName(WindowStationName
,
971 TebStaticUnicodeString
,
972 (OwnerMode
== KernelMode
? ObjectAttributes
: NULL
),
973 &LocalObjectAttributes
);
975 if (!NT_SUCCESS(Status
))
977 ASSERT(hWinSta
== NULL
);
978 SetLastNtError(Status
);
985 * NtUserCloseWindowStation
987 * Closes a window station handle.
991 * Handle to the window station.
997 * The window station handle can be created with NtUserCreateWindowStation
998 * or NtUserOpenWindowStation. Attempts to close a handle to the window
999 * station assigned to the calling process will fail.
1007 NtUserCloseWindowStation(
1010 PWINSTATION_OBJECT Object
;
1013 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
1015 if (hWinSta
== UserGetProcessWindowStation())
1017 ERR("Attempted to close process window station\n");
1021 Status
= IntValidateWindowStationHandle(hWinSta
,
1026 if (!NT_SUCCESS(Status
))
1028 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
1032 ObDereferenceObject(Object
);
1034 TRACE("Closing window station handle (%p)\n", hWinSta
);
1036 Status
= ObCloseHandle(hWinSta
, UserMode
);
1037 if (!NT_SUCCESS(Status
))
1039 SetLastNtError(Status
);
1047 * NtUserGetObjectInformation
1049 * The NtUserGetObjectInformation function retrieves information about a
1050 * window station or desktop object.
1054 * Handle to the window station or desktop object for which to
1055 * return information. This can be a handle of type HDESK or HWINSTA
1056 * (for example, a handle returned by NtUserCreateWindowStation,
1057 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
1060 * Specifies the object information to be retrieved.
1063 * Pointer to a buffer to receive the object information.
1066 * Specifies the size, in bytes, of the buffer pointed to by the
1070 * Pointer to a variable receiving the number of bytes required to
1071 * store the requested information. If this variable's value is
1072 * greater than the value of the nLength parameter when the function
1073 * returns, the function returns FALSE, and none of the information
1074 * is copied to the pvInfo buffer. If the value of the variable pointed
1075 * to by lpnLengthNeeded is less than or equal to the value of nLength,
1076 * the entire information block is copied.
1079 * If the function succeeds, the return value is nonzero. If the function
1080 * fails, the return value is zero.
1087 NtUserGetObjectInformation(
1090 PVOID pvInformation
,
1092 PDWORD nLengthNeeded
)
1095 PWINSTATION_OBJECT WinStaObject
= NULL
;
1096 PDESKTOP DesktopObject
= NULL
;
1097 POBJECT_HEADER ObjectHeader
;
1098 POBJECT_HEADER_NAME_INFO NameInfo
;
1099 OBJECT_HANDLE_INFORMATION HandleInfo
;
1100 USEROBJECTFLAGS ObjectFlags
;
1101 PUNICODE_STRING pStrNameU
= NULL
;
1102 PVOID pvData
= NULL
;
1103 SIZE_T nDataSize
= 0;
1108 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
1109 ProbeForWrite(pvInformation
, nLength
, 1);
1111 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1113 SetLastNtError(_SEH2_GetExceptionCode());
1118 /* Try window station */
1119 TRACE("Trying to open window station 0x%p\n", hObject
);
1120 Status
= ObReferenceObjectByHandle(hObject
,
1122 ExWindowStationObjectType
,
1124 (PVOID
*)&WinStaObject
,
1127 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
1130 TRACE("Trying to open desktop %p\n", hObject
);
1131 WinStaObject
= NULL
;
1132 Status
= IntValidateDesktopHandle(hObject
,
1138 if (!NT_SUCCESS(Status
))
1140 ERR("Failed: 0x%x\n", Status
);
1144 TRACE("WinSta or Desktop opened!\n");
1151 ObjectFlags
.fReserved
= FALSE
;
1152 ObjectFlags
.fInherit
= !!(HandleInfo
.HandleAttributes
& OBJ_INHERIT
);
1154 ObjectFlags
.dwFlags
= 0;
1155 if (WinStaObject
!= NULL
)
1157 if (!(WinStaObject
->Flags
& WSS_NOIO
))
1158 ObjectFlags
.dwFlags
|= WSF_VISIBLE
;
1160 else if (DesktopObject
!= NULL
)
1162 FIXME("Setting DF_ALLOWOTHERACCOUNTHOOK is unimplemented.\n");
1166 ERR("No associated WinStaObject nor DesktopObject!\n");
1169 pvData
= &ObjectFlags
;
1170 nDataSize
= sizeof(ObjectFlags
);
1171 Status
= STATUS_SUCCESS
;
1177 if (WinStaObject
!= NULL
)
1179 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(WinStaObject
);
1180 NameInfo
= OBJECT_HEADER_TO_NAME_INFO(ObjectHeader
);
1182 if (NameInfo
&& (NameInfo
->Name
.Length
> 0))
1184 /* Named window station */
1185 pStrNameU
= &NameInfo
->Name
;
1186 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1190 /* Unnamed window station (should never happen!) */
1193 nDataSize
= sizeof(UNICODE_NULL
);
1195 Status
= STATUS_SUCCESS
;
1197 else if (DesktopObject
!= NULL
)
1199 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
1200 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
1201 Status
= STATUS_SUCCESS
;
1205 Status
= STATUS_INVALID_PARAMETER
;
1212 if (WinStaObject
!= NULL
)
1214 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(WinStaObject
);
1215 pStrNameU
= &ObjectHeader
->Type
->Name
;
1216 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1217 Status
= STATUS_SUCCESS
;
1219 else if (DesktopObject
!= NULL
)
1221 ObjectHeader
= OBJECT_TO_OBJECT_HEADER(DesktopObject
);
1222 pStrNameU
= &ObjectHeader
->Type
->Name
;
1223 nDataSize
= pStrNameU
->Length
+ sizeof(UNICODE_NULL
);
1224 Status
= STATUS_SUCCESS
;
1228 Status
= STATUS_INVALID_PARAMETER
;
1234 Status
= STATUS_NOT_IMPLEMENTED
;
1235 ERR("UOI_USER_SID unimplemented!\n");
1239 Status
= STATUS_INVALID_PARAMETER
;
1244 if ((Status
== STATUS_SUCCESS
) && (nLength
< nDataSize
))
1245 Status
= STATUS_BUFFER_TOO_SMALL
;
1250 *nLengthNeeded
= nDataSize
;
1252 /* Try to copy data to caller */
1253 if (Status
== STATUS_SUCCESS
&& (nDataSize
> 0))
1255 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
1259 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
1263 /* Copy and NULL-terminate the string */
1264 RtlCopyMemory(pvInformation
, pStrNameU
->Buffer
, pStrNameU
->Length
);
1265 ((PWCHAR
)pvInformation
)[pStrNameU
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1269 /* Zero the memory */
1270 RtlZeroMemory(pvInformation
, nDataSize
);
1274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1276 Status
= _SEH2_GetExceptionCode();
1280 /* Release objects */
1281 if (DesktopObject
!= NULL
)
1282 ObDereferenceObject(DesktopObject
);
1283 if (WinStaObject
!= NULL
)
1284 ObDereferenceObject(WinStaObject
);
1286 if (!NT_SUCCESS(Status
))
1288 SetLastNtError(Status
);
1296 * NtUserSetObjectInformation
1298 * The NtUserSetObjectInformation function sets information about a
1299 * window station or desktop object.
1303 * Handle to the window station or desktop object for which to set
1304 * object information. This value can be a handle of type HDESK or
1308 * Specifies the object information to be set.
1311 * Pointer to a buffer containing the object information.
1314 * Specifies the size, in bytes, of the information contained in the
1315 * buffer pointed to by pvInfo.
1318 * If the function succeeds, the return value is nonzero. If the function
1319 * fails the return value is zero.
1327 NtUserSetObjectInformation(
1330 PVOID pvInformation
,
1333 /* FIXME: ZwQueryObject */
1334 /* FIXME: ZwSetInformationObject */
1335 SetLastNtError(STATUS_UNSUCCESSFUL
);
1341 UserGetProcessWindowStation(VOID
)
1343 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
1345 return ppi
->hwinsta
;
1350 * NtUserGetProcessWindowStation
1352 * Returns a handle to the current process window station.
1355 * If the function succeeds, the return value is handle to the window
1356 * station assigned to the current process. If the function fails, the
1357 * return value is NULL.
1364 NtUserGetProcessWindowStation(VOID
)
1366 return UserGetProcessWindowStation();
1370 UserSetProcessWindowStation(HWINSTA hWindowStation
)
1374 OBJECT_HANDLE_INFORMATION ObjectHandleInfo
;
1375 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
1376 HWINSTA hCacheWinSta
;
1378 ppi
= PsGetCurrentProcessWin32Process();
1380 /* Reference the new window station */
1381 if (hWindowStation
!= NULL
)
1383 Status
= IntValidateWindowStationHandle(hWindowStation
,
1388 if (!NT_SUCCESS(Status
))
1390 TRACE("Validation of window station handle 0x%p failed\n", hWindowStation
);
1391 SetLastNtError(Status
);
1396 OldWinSta
= ppi
->prpwinsta
;
1397 hCacheWinSta
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
1399 /* Dereference the previous window station */
1400 if (OldWinSta
!= NULL
)
1402 ObDereferenceObject(OldWinSta
);
1406 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
1409 /* Close the cached EPROCESS window station handle if needed */
1410 if (hCacheWinSta
!= NULL
)
1412 /* Reference the window station */
1413 Status
= ObReferenceObjectByHandle(hCacheWinSta
,
1415 ExWindowStationObjectType
,
1419 if (!NT_SUCCESS(Status
))
1421 ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status
);
1422 /* We failed, reset the cache */
1423 hCacheWinSta
= NULL
;
1424 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1429 * Close the old handle and reset the cache only
1430 * if we are setting a different window station.
1432 if (NewWinSta
!= OldWinSta
)
1434 ObCloseHandle(hCacheWinSta
, UserMode
);
1435 hCacheWinSta
= NULL
;
1436 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1439 /* Dereference the window station */
1440 ObDereferenceObject(OldWinSta
);
1444 /* Duplicate and save a new cached EPROCESS window station handle */
1445 if ((hCacheWinSta
== NULL
) && (hWindowStation
!= NULL
))
1447 Status
= ZwDuplicateObject(ZwCurrentProcess(),
1450 (PHANDLE
)&hCacheWinSta
,
1453 DUPLICATE_SAME_ACCESS
);
1454 if (!NT_SUCCESS(Status
))
1456 ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status
);
1460 PsSetProcessWindowStation(ppi
->peProcess
, hCacheWinSta
);
1464 ppi
->prpwinsta
= NewWinSta
;
1465 ppi
->hwinsta
= hWindowStation
;
1466 ppi
->amwinsta
= hWindowStation
!= NULL
? ObjectHandleInfo
.GrantedAccess
: 0;
1467 TRACE("WS : Granted Access 0x%08lx\n",ppi
->amwinsta
);
1469 if (RtlAreAllAccessesGranted(ppi
->amwinsta
, WINSTA_READSCREEN
))
1471 ppi
->W32PF_flags
|= W32PF_READSCREENACCESSGRANTED
;
1475 ppi
->W32PF_flags
&= ~W32PF_READSCREENACCESSGRANTED
;
1478 if (NewWinSta
&& !(NewWinSta
->Flags
& WSS_NOIO
))
1480 ppi
->W32PF_flags
|= W32PF_IOWINSTA
;
1482 else /* Might be closed if the handle is NULL */
1484 ppi
->W32PF_flags
&= ~W32PF_IOWINSTA
;
1490 * NtUserSetProcessWindowStation
1492 * Assigns a window station to the current process.
1496 * Handle to the window station.
1506 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1510 UserEnterExclusive();
1512 ret
= UserSetProcessWindowStation(hWindowStation
);
1520 * NtUserLockWindowStation
1522 * Locks switching desktops. Only the logon application is allowed to call this function.
1529 NtUserLockWindowStation(HWINSTA hWindowStation
)
1531 PWINSTATION_OBJECT Object
;
1534 TRACE("About to set process window station with handle (%p)\n",
1537 if (gpidLogon
!= PsGetCurrentProcessId())
1539 ERR("Unauthorized process attempted to lock the window station!\n");
1540 EngSetLastError(ERROR_ACCESS_DENIED
);
1544 Status
= IntValidateWindowStationHandle(hWindowStation
,
1549 if (!NT_SUCCESS(Status
))
1551 TRACE("Validation of window station handle (%p) failed\n",
1553 SetLastNtError(Status
);
1557 Object
->Flags
|= WSS_LOCKED
;
1559 ObDereferenceObject(Object
);
1564 * NtUserUnlockWindowStation
1566 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1573 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1575 PWINSTATION_OBJECT Object
;
1579 TRACE("About to set process window station with handle (%p)\n",
1582 if (gpidLogon
!= PsGetCurrentProcessId())
1584 ERR("Unauthorized process attempted to unlock the window station!\n");
1585 EngSetLastError(ERROR_ACCESS_DENIED
);
1589 Status
= IntValidateWindowStationHandle(hWindowStation
,
1594 if (!NT_SUCCESS(Status
))
1596 TRACE("Validation of window station handle (%p) failed\n",
1598 SetLastNtError(Status
);
1602 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1603 Object
->Flags
&= ~WSS_LOCKED
;
1605 ObDereferenceObject(Object
);
1609 static NTSTATUS FASTCALL
1610 BuildWindowStationNameList(
1613 PULONG pRequiredSize
)
1615 OBJECT_ATTRIBUTES ObjectAttributes
;
1617 HANDLE DirectoryHandle
;
1618 char InitialBuffer
[256], *Buffer
;
1619 ULONG Context
, ReturnLength
, BufferSize
;
1621 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1625 // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
1626 // with judicious parameters one can create window stations elsewhere
1627 // than in Windows\WindowStations directory, Win32k definitely MUST
1628 // maintain a list of window stations it has created, and not rely
1629 // on the enumeration of Windows\WindowStations !!!
1633 * Try to open the directory.
1635 InitializeObjectAttributes(&ObjectAttributes
,
1636 &gustrWindowStationsDir
,
1637 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1641 Status
= ZwOpenDirectoryObject(&DirectoryHandle
,
1645 if (!NT_SUCCESS(Status
))
1650 /* First try to query the directory using a fixed-size buffer */
1653 Status
= ZwQueryDirectoryObject(DirectoryHandle
,
1655 sizeof(InitialBuffer
),
1660 if (NT_SUCCESS(Status
))
1662 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1663 FALSE
, &Context
, NULL
))
1665 /* Our fixed-size buffer is large enough */
1666 Buffer
= InitialBuffer
;
1672 /* Need a larger buffer, check how large exactly */
1673 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1675 if (!NT_SUCCESS(Status
))
1677 ERR("ZwQueryDirectoryObject failed\n");
1678 ZwClose(DirectoryHandle
);
1682 BufferSize
= ReturnLength
;
1683 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1686 ZwClose(DirectoryHandle
);
1687 return STATUS_NO_MEMORY
;
1690 /* We should have a sufficiently large buffer now */
1692 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1693 FALSE
, TRUE
, &Context
, &ReturnLength
);
1694 if (! NT_SUCCESS(Status
) ||
1695 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1696 FALSE
, &Context
, NULL
))
1698 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1699 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1700 ZwClose(DirectoryHandle
);
1701 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1705 ZwClose(DirectoryHandle
);
1708 * Count the required size of buffer.
1710 ReturnLength
= sizeof(DWORD
);
1712 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1713 0 != DirEntry
->Name
.Length
;
1716 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1719 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1720 if (NULL
!= pRequiredSize
)
1722 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1723 if (! NT_SUCCESS(Status
))
1725 if (Buffer
!= InitialBuffer
)
1727 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1729 return STATUS_BUFFER_TOO_SMALL
;
1734 * Check if the supplied buffer is large enough.
1736 if (dwSize
< ReturnLength
)
1738 if (Buffer
!= InitialBuffer
)
1740 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1742 return STATUS_BUFFER_TOO_SMALL
;
1746 * Generate the resulting buffer contents.
1748 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1749 if (! NT_SUCCESS(Status
))
1751 if (Buffer
!= InitialBuffer
)
1753 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1757 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1760 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
;
1761 0 != DirEntry
->Name
.Length
;
1764 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1765 if (! NT_SUCCESS(Status
))
1767 if (Buffer
!= InitialBuffer
)
1769 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1773 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1774 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1775 if (! NT_SUCCESS(Status
))
1777 if (Buffer
!= InitialBuffer
)
1779 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1783 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1789 if (Buffer
!= InitialBuffer
)
1791 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1794 return STATUS_SUCCESS
;
1797 static NTSTATUS FASTCALL
1798 BuildDesktopNameList(
1799 HWINSTA hWindowStation
,
1802 PULONG pRequiredSize
)
1805 PWINSTATION_OBJECT WindowStation
;
1806 PLIST_ENTRY DesktopEntry
;
1807 PDESKTOP DesktopObject
;
1811 UNICODE_STRING DesktopName
;
1813 Status
= IntValidateWindowStationHandle(hWindowStation
,
1818 if (! NT_SUCCESS(Status
))
1824 * Count the required size of buffer.
1826 ReturnLength
= sizeof(DWORD
);
1828 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1829 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1830 DesktopEntry
= DesktopEntry
->Flink
)
1832 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1833 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1834 ReturnLength
+= DesktopName
.Length
+ sizeof(WCHAR
);
1837 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1838 if (NULL
!= pRequiredSize
)
1840 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1841 if (! NT_SUCCESS(Status
))
1843 ObDereferenceObject(WindowStation
);
1844 return STATUS_BUFFER_TOO_SMALL
;
1849 * Check if the supplied buffer is large enough.
1851 if (dwSize
< ReturnLength
)
1853 ObDereferenceObject(WindowStation
);
1854 return STATUS_BUFFER_TOO_SMALL
;
1858 * Generate the resulting buffer contents.
1860 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1861 if (! NT_SUCCESS(Status
))
1863 ObDereferenceObject(WindowStation
);
1866 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1869 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1870 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1871 DesktopEntry
= DesktopEntry
->Flink
)
1873 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1874 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1875 Status
= MmCopyToCaller(lpBuffer
, DesktopName
.Buffer
, DesktopName
.Length
);
1876 if (! NT_SUCCESS(Status
))
1878 ObDereferenceObject(WindowStation
);
1881 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
.Length
);
1882 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1883 if (! NT_SUCCESS(Status
))
1885 ObDereferenceObject(WindowStation
);
1888 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1892 * Clean up and return
1894 ObDereferenceObject(WindowStation
);
1895 return STATUS_SUCCESS
;
1899 * NtUserBuildNameList
1901 * Function used for enumeration of desktops or window stations.
1905 * For enumeration of window stations this parameter must be set to
1906 * zero. Otherwise it's handle for window station.
1909 * Size of buffer passed by caller.
1912 * Buffer passed by caller. If the function succeeds, the buffer is
1913 * filled with window station/desktop count (in first DWORD) and
1914 * NULL-terminated window station/desktop names.
1917 * If the function succeeds, this is the number of bytes copied.
1918 * Otherwise it's size of buffer needed for function to succeed.
1925 NtUserBuildNameList(
1926 HWINSTA hWindowStation
,
1929 PULONG pRequiredSize
)
1931 /* The WindowStation name list and desktop name list are build in completely
1932 different ways. Call the appropriate function */
1933 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1934 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1941 NtUserSetLogonNotifyWindow(HWND hWnd
)
1943 if (gpidLogon
!= PsGetCurrentProcessId())
1948 if (!IntIsWindow(hWnd
))
1960 NtUserLockWorkStation(VOID
)
1963 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1965 UserEnterExclusive();
1967 if (pti
->rpdesk
== IntGetActiveDesktop())
1969 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);
1983 NtUserSetWindowStationUser(
1984 IN HWINSTA hWindowStation
,
1986 IN PSID psid OPTIONAL
,
1991 PWINSTATION_OBJECT WindowStation
= NULL
;
1994 UserEnterExclusive();
1996 if (gpidLogon
!= PsGetCurrentProcessId())
1998 EngSetLastError(ERROR_ACCESS_DENIED
);
2002 /* Validate the window station */
2003 Status
= IntValidateWindowStationHandle(hWindowStation
,
2008 if (!NT_SUCCESS(Status
))
2013 /* Capture the user LUID */
2016 ProbeForRead(pluid
, sizeof(LUID
), 1);
2019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2021 Status
= _SEH2_GetExceptionCode();
2022 _SEH2_YIELD(goto Leave
);
2026 /* Reset the window station user LUID */
2027 RtlZeroMemory(&WindowStation
->luidUser
, sizeof(LUID
));
2029 /* Reset the window station user SID */
2030 if (WindowStation
->psidUser
)
2032 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
2033 WindowStation
->psidUser
= NULL
;
2036 /* Copy the new user SID if one has been provided */
2039 WindowStation
->psidUser
= ExAllocatePoolWithTag(PagedPool
, size
, USERTAG_SECURITY
);
2040 if (WindowStation
->psidUser
== NULL
)
2042 EngSetLastError(ERROR_OUTOFMEMORY
);
2046 Status
= STATUS_SUCCESS
;
2049 ProbeForRead(psid
, size
, 1);
2050 RtlCopyMemory(WindowStation
->psidUser
, psid
, size
);
2052 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2054 Status
= _SEH2_GetExceptionCode();
2058 if (!NT_SUCCESS(Status
))
2060 ExFreePoolWithTag(WindowStation
->psidUser
, USERTAG_SECURITY
);
2061 WindowStation
->psidUser
= NULL
;
2066 /* Copy the new user LUID */
2067 WindowStation
->luidUser
= luidUser
;
2073 ObDereferenceObject(WindowStation
);