2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Window stations
5 * FILE: subsystems/win32/win32k/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 *******************************************************************/
17 /* Currently active window station */
18 PWINSTATION_OBJECT InputWindowStation
= NULL
;
20 /* Winlogon SAS window */
23 /* Full path to WindowStations directory */
24 UNICODE_STRING gustrWindowStationsDir
;
26 /* INITALIZATION FUNCTIONS ****************************************************/
31 InitWindowStationImpl(VOID
)
33 GENERIC_MAPPING IntWindowStationMapping
= { WINSTA_READ
,
38 /* Set Winsta Object Attributes */
39 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
40 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
41 ExWindowStationObjectType
->TypeInfo
.ValidAccessMask
= WINSTA_ACCESS_ALL
;
43 return STATUS_SUCCESS
;
48 UserCreateWinstaDirectoy()
52 WCHAR wstrWindowStationsDir
[MAX_PATH
];
53 OBJECT_ATTRIBUTES ObjectAttributes
;
56 /* Create the WindowStations directory and cache its path for later use */
58 if(Peb
->SessionId
== 0)
60 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, WINSTA_OBJ_DIR
))
62 return STATUS_INSUFFICIENT_RESOURCES
;
67 swprintf(wstrWindowStationsDir
,
73 if (!RtlCreateUnicodeString(&gustrWindowStationsDir
, wstrWindowStationsDir
))
75 return STATUS_INSUFFICIENT_RESOURCES
;
79 InitializeObjectAttributes(&ObjectAttributes
,
80 &gustrWindowStationsDir
,
84 Status
= ZwCreateDirectoryObject(&hWinstaDir
, 0, &ObjectAttributes
);
85 if (!NT_SUCCESS(Status
))
87 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir
, Status
);
91 TRACE("Created directory %wZ for session %d\n", &gustrWindowStationsDir
, Peb
->SessionId
);
96 /* OBJECT CALLBACKS **********************************************************/
99 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
101 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
103 TRACE("Deleting window station (0x%X)\n", WinSta
);
105 UserEmptyClipboardData(WinSta
);
107 RtlDestroyAtomTable(WinSta
->AtomTable
);
109 RtlFreeUnicodeString(&WinSta
->Name
);
114 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters
)
116 PUNICODE_STRING RemainingName
= Parameters
->RemainingName
;
118 /* Assume we don't find anything */
119 *Parameters
->Object
= NULL
;
121 /* Check for an empty name */
122 if (!RemainingName
->Length
)
124 /* Make sure this is a window station, can't parse a desktop now */
125 if (Parameters
->ObjectType
!= ExWindowStationObjectType
)
128 return STATUS_OBJECT_TYPE_MISMATCH
;
131 /* Reference the window station and return */
132 ObReferenceObject(Parameters
->ParseObject
);
133 *Parameters
->Object
= Parameters
->ParseObject
;
134 return STATUS_SUCCESS
;
137 /* Check for leading slash */
138 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
141 RemainingName
->Buffer
++;
142 RemainingName
->Length
-= sizeof(WCHAR
);
143 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
146 /* Check if there is still a slash */
147 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
149 /* In this case, fail */
150 return STATUS_OBJECT_PATH_INVALID
;
154 * Check if we are parsing a desktop.
156 if (Parameters
->ObjectType
== ExDesktopObjectType
)
158 /* Then call the desktop parse routine */
159 return IntDesktopObjectParse(Parameters
->ParseObject
,
160 Parameters
->ObjectType
,
161 Parameters
->AccessState
,
162 Parameters
->AccessMode
,
163 Parameters
->Attributes
,
164 Parameters
->CompleteName
,
167 Parameters
->SecurityQos
,
171 /* Should hopefully never get here */
172 return STATUS_OBJECT_TYPE_MISMATCH
;
177 IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
181 ppi
= PsGetCurrentProcessWin32Process();
183 if(ppi
&& (Parameters
->Handle
== ppi
->hwinsta
))
185 return STATUS_ACCESS_DENIED
;
188 return STATUS_SUCCESS
;
191 /* PRIVATE FUNCTIONS **********************************************************/
194 * IntValidateWindowStationHandle
196 * Validates the window station handle.
199 * If the function succeeds, the handle remains referenced. If the
200 * fucntion fails, last error is set.
204 IntValidateWindowStationHandle(
205 HWINSTA WindowStation
,
206 KPROCESSOR_MODE AccessMode
,
207 ACCESS_MASK DesiredAccess
,
208 PWINSTATION_OBJECT
*Object
)
212 if (WindowStation
== NULL
)
214 ERR("Invalid window station handle\n");
215 EngSetLastError(ERROR_INVALID_HANDLE
);
216 return STATUS_INVALID_HANDLE
;
219 Status
= ObReferenceObjectByHandle(
222 ExWindowStationObjectType
,
227 if (!NT_SUCCESS(Status
))
228 SetLastNtError(Status
);
234 co_IntInitializeDesktopGraphics(VOID
)
237 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
239 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
240 if (NULL
== ScreenDeviceContext
)
242 IntDestroyPrimarySurface();
245 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
247 if (! IntCreatePrimarySurface())
252 /* Setup the cursor */
253 co_IntLoadDefaultCursors();
255 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
257 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
258 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
260 // FIXME: Move these to a update routine.
261 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
262 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
263 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
264 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
265 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
267 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
270 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
271 // Font is realized and this dc was previously set to internal DC_ATTR.
272 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
273 gpsi
->tmSysFont
= tmw
;
279 IntEndDesktopGraphics(VOID
)
281 if (NULL
!= ScreenDeviceContext
)
282 { // No need to allocate a new dcattr.
283 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
284 GreDeleteObject(ScreenDeviceContext
);
285 ScreenDeviceContext
= NULL
;
287 IntHideDesktop(IntGetActiveDesktop());
288 IntDestroyPrimarySurface();
294 return ScreenDeviceContext
;
297 /* PUBLIC FUNCTIONS ***********************************************************/
300 * NtUserCreateWindowStation
302 * Creates a new window station.
305 * lpszWindowStationName
306 * Pointer to a null-terminated string specifying the name of the
307 * window station to be created. Window station names are
308 * case-insensitive and cannot contain backslash characters (\).
309 * Only members of the Administrators group are allowed to specify a
313 * Requested type of access
316 * Security descriptor
318 * Unknown3, Unknown4, Unknown5
322 * If the function succeeds, the return value is a handle to the newly
323 * created window station. If the specified window station already
324 * exists, the function succeeds and returns a handle to the existing
325 * window station. If the function fails, the return value is NULL.
328 * Correct the prototype to match the Windows one (with 7 parameters
336 NtUserCreateWindowStation(
337 POBJECT_ATTRIBUTES ObjectAttributes
,
338 ACCESS_MASK dwDesiredAccess
,
345 UNICODE_STRING WindowStationName
;
346 PWINSTATION_OBJECT WindowStationObject
;
347 HWINSTA WindowStation
;
350 TRACE("NtUserCreateWindowStation called\n");
352 Status
= ObOpenObjectByName(
354 ExWindowStationObjectType
,
359 (PVOID
*)&WindowStation
);
361 if (NT_SUCCESS(Status
))
363 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes
->ObjectName
);
364 return (HWINSTA
)WindowStation
;
368 * No existing window station found, try to create new one
371 /* Capture window station name */
374 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
375 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
, ObjectAttributes
->ObjectName
);
377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
379 Status
=_SEH2_GetExceptionCode();
383 if (! NT_SUCCESS(Status
))
385 ERR("Failed reading capturing window station name\n");
386 SetLastNtError(Status
);
390 /* Create the window station object */
391 Status
= ObCreateObject(
393 ExWindowStationObjectType
,
397 sizeof(WINSTATION_OBJECT
),
400 (PVOID
*)&WindowStationObject
);
402 if (!NT_SUCCESS(Status
))
404 ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName
);
405 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
406 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
410 Status
= ObInsertObject(
411 (PVOID
)WindowStationObject
,
416 (PVOID
*)&WindowStation
);
418 if (!NT_SUCCESS(Status
))
420 ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName
);
421 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
422 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
423 ObDereferenceObject(WindowStationObject
);
427 /* Initialize the window station */
428 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
430 KeInitializeSpinLock(&WindowStationObject
->Lock
);
431 InitializeListHead(&WindowStationObject
->DesktopListHead
);
432 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
433 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
434 WindowStationObject
->Name
= WindowStationName
;
436 if (InputWindowStation
== NULL
)
438 TRACE("Initializeing input window station\n");
439 InputWindowStation
= WindowStationObject
;
444 TRACE("NtUserCreateWindowStation created object 0x%x with name %wZ handle 0x%x\n",
445 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
446 return WindowStation
;
450 * NtUserOpenWindowStation
452 * Opens an existing window station.
455 * lpszWindowStationName
456 * Name of the existing window station.
459 * Requested type of access.
462 * If the function succeeds, the return value is the handle to the
463 * specified window station. If the function fails, the return value
467 * The returned handle can be closed with NtUserCloseWindowStation.
474 NtUserOpenWindowStation(
475 POBJECT_ATTRIBUTES ObjectAttributes
,
476 ACCESS_MASK dwDesiredAccess
)
481 Status
= ObOpenObjectByName(
483 ExWindowStationObjectType
,
490 if (!NT_SUCCESS(Status
))
492 ERR("NtUserOpenWindowStation failed\n");
493 SetLastNtError(Status
);
497 TRACE("Opened window station %wZ with handle 0x%x\n", ObjectAttributes
->ObjectName
, hwinsta
);
503 * NtUserCloseWindowStation
505 * Closes a window station handle.
509 * Handle to the window station.
515 * The window station handle can be created with NtUserCreateWindowStation
516 * or NtUserOpenWindowStation. Attemps to close a handle to the window
517 * station assigned to the calling process will fail.
525 NtUserCloseWindowStation(
528 PWINSTATION_OBJECT Object
;
531 TRACE("NtUserCloseWindowStation called (0x%x)\n", hWinSta
);
533 if (hWinSta
== UserGetProcessWindowStation())
535 ERR("Attempted to close process window station\n");
539 Status
= IntValidateWindowStationHandle(
545 if (!NT_SUCCESS(Status
))
547 ERR("Validation of window station handle (0x%x) failed\n", hWinSta
);
551 ObDereferenceObject(Object
);
553 TRACE("Closing window station handle (0x%x)\n", hWinSta
);
555 Status
= ObCloseHandle(hWinSta
, UserMode
);
556 if (!NT_SUCCESS(Status
))
558 SetLastNtError(Status
);
566 * NtUserGetObjectInformation
568 * The NtUserGetObjectInformation function retrieves information about a
569 * window station or desktop object.
573 * Handle to the window station or desktop object for which to
574 * return information. This can be a handle of type HDESK or HWINSTA
575 * (for example, a handle returned by NtUserCreateWindowStation,
576 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
579 * Specifies the object information to be retrieved.
582 * Pointer to a buffer to receive the object information.
585 * Specifies the size, in bytes, of the buffer pointed to by the
589 * Pointer to a variable receiving the number of bytes required to
590 * store the requested information. If this variable's value is
591 * greater than the value of the nLength parameter when the function
592 * returns, the function returns FALSE, and none of the information
593 * is copied to the pvInfo buffer. If the value of the variable pointed
594 * to by lpnLengthNeeded is less than or equal to the value of nLength,
595 * the entire information block is copied.
598 * If the function succeeds, the return value is nonzero. If the function
599 * fails, the return value is zero.
606 NtUserGetObjectInformation(
611 PDWORD nLengthNeeded
)
613 PWINSTATION_OBJECT WinStaObject
= NULL
;
614 PDESKTOP DesktopObject
= NULL
;
619 /* try windowstation */
620 TRACE("Trying to open window station 0x%x\n", hObject
);
621 Status
= ObReferenceObjectByHandle(
624 ExWindowStationObjectType
,
626 (PVOID
*)&WinStaObject
,
629 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
632 TRACE("Trying to open desktop 0x%x\n", hObject
);
633 Status
= IntValidateDesktopHandle(
640 if (!NT_SUCCESS(Status
))
642 ERR("Failed: 0x%x\n", Status
);
643 SetLastNtError(Status
);
647 TRACE("WinSta or Desktop opened!!\n");
653 Status
= STATUS_NOT_IMPLEMENTED
;
654 ERR("UOI_FLAGS unimplemented!\n");
658 if (WinStaObject
!= NULL
)
660 pvData
= WinStaObject
->Name
.Buffer
;
661 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
662 Status
= STATUS_SUCCESS
;
664 else if (DesktopObject
!= NULL
)
666 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
667 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
668 Status
= STATUS_SUCCESS
;
671 Status
= STATUS_INVALID_PARAMETER
;
675 if (WinStaObject
!= NULL
)
677 pvData
= L
"WindowStation";
678 nDataSize
= sizeof(L
"WindowStation");
679 Status
= STATUS_SUCCESS
;
681 else if (DesktopObject
!= NULL
)
684 nDataSize
= sizeof(L
"Desktop");
685 Status
= STATUS_SUCCESS
;
688 Status
= STATUS_INVALID_PARAMETER
;
692 Status
= STATUS_NOT_IMPLEMENTED
;
693 ERR("UOI_USER_SID unimplemented!\n");
697 Status
= STATUS_INVALID_PARAMETER
;
701 /* try to copy data to caller */
702 if (Status
== STATUS_SUCCESS
)
704 TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
705 *nLengthNeeded
= nDataSize
;
706 if (nLength
>= nDataSize
)
707 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
709 Status
= STATUS_BUFFER_TOO_SMALL
;
712 /* release objects */
713 if (WinStaObject
!= NULL
)
714 ObDereferenceObject(WinStaObject
);
715 if (DesktopObject
!= NULL
)
716 ObDereferenceObject(DesktopObject
);
718 if (!NT_SUCCESS(Status
))
720 SetLastNtError(Status
);
728 * NtUserSetObjectInformation
730 * The NtUserSetObjectInformation function sets information about a
731 * window station or desktop object.
735 * Handle to the window station or desktop object for which to set
736 * object information. This value can be a handle of type HDESK or
740 * Specifies the object information to be set.
743 * Pointer to a buffer containing the object information.
746 * Specifies the size, in bytes, of the information contained in the
747 * buffer pointed to by pvInfo.
750 * If the function succeeds, the return value is nonzero. If the function
751 * fails the return value is zero.
759 NtUserSetObjectInformation(
765 /* FIXME: ZwQueryObject */
766 /* FIXME: ZwSetInformationObject */
767 SetLastNtError(STATUS_UNSUCCESSFUL
);
775 UserGetProcessWindowStation(VOID
)
777 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
784 * NtUserGetProcessWindowStation
786 * Returns a handle to the current process window station.
789 * If the function succeeds, the return value is handle to the window
790 * station assigned to the current process. If the function fails, the
791 * return value is NULL.
798 NtUserGetProcessWindowStation(VOID
)
800 return UserGetProcessWindowStation();
804 UserSetProcessWindowStation(HWINSTA hWindowStation
)
809 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
811 ppi
= PsGetCurrentProcessWin32Process();
813 /* Reference the new window station */
814 if(hWindowStation
!=NULL
)
816 Status
= IntValidateWindowStationHandle( hWindowStation
,
820 if (!NT_SUCCESS(Status
))
822 TRACE("Validation of window station handle (0x%X) failed\n",
824 SetLastNtError(Status
);
829 OldWinSta
= ppi
->prpwinsta
;
830 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
832 /* Dereference the previous window station */
833 if(OldWinSta
!= NULL
)
835 ObDereferenceObject(OldWinSta
);
838 /* Check if we have a stale handle (it should happen for console apps) */
839 if(hwinstaOld
!= ppi
->hwinsta
)
841 ObCloseHandle(hwinstaOld
, UserMode
);
845 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
848 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
850 ppi
->prpwinsta
= NewWinSta
;
851 ppi
->hwinsta
= hWindowStation
;
857 * NtUserSetProcessWindowStation
859 * Assigns a window station to the current process.
863 * Handle to the window station.
873 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
877 UserEnterExclusive();
879 ret
= UserSetProcessWindowStation(hWindowStation
);
887 * NtUserLockWindowStation
889 * Locks switching desktops. Only the logon application is allowed to call this function.
896 NtUserLockWindowStation(HWINSTA hWindowStation
)
898 PWINSTATION_OBJECT Object
;
901 TRACE("About to set process window station with handle (0x%X)\n",
904 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
906 ERR("Unauthorized process attempted to lock the window station!\n");
907 EngSetLastError(ERROR_ACCESS_DENIED
);
911 Status
= IntValidateWindowStationHandle(
916 if (!NT_SUCCESS(Status
))
918 TRACE("Validation of window station handle (0x%X) failed\n",
920 SetLastNtError(Status
);
924 Object
->Flags
|= WSS_LOCKED
;
926 ObDereferenceObject(Object
);
931 * NtUserUnlockWindowStation
933 * Unlocks switching desktops. Only the logon application is allowed to call this function.
940 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
942 PWINSTATION_OBJECT Object
;
946 TRACE("About to set process window station with handle (0x%X)\n",
949 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
951 ERR("Unauthorized process attempted to unlock the window station!\n");
952 EngSetLastError(ERROR_ACCESS_DENIED
);
956 Status
= IntValidateWindowStationHandle(
961 if (!NT_SUCCESS(Status
))
963 TRACE("Validation of window station handle (0x%X) failed\n",
965 SetLastNtError(Status
);
969 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
970 Object
->Flags
&= ~WSS_LOCKED
;
972 ObDereferenceObject(Object
);
976 static NTSTATUS FASTCALL
977 BuildWindowStationNameList(
980 PULONG pRequiredSize
)
982 OBJECT_ATTRIBUTES ObjectAttributes
;
984 HANDLE DirectoryHandle
;
985 char InitialBuffer
[256], *Buffer
;
986 ULONG Context
, ReturnLength
, BufferSize
;
988 POBJECT_DIRECTORY_INFORMATION DirEntry
;
992 * Try to open the directory.
994 InitializeObjectAttributes(
996 &gustrWindowStationsDir
,
997 OBJ_CASE_INSENSITIVE
,
1001 Status
= ZwOpenDirectoryObject(
1006 if (!NT_SUCCESS(Status
))
1011 /* First try to query the directory using a fixed-size buffer */
1014 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1015 FALSE
, TRUE
, &Context
, &ReturnLength
);
1016 if (NT_SUCCESS(Status
))
1018 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1019 FALSE
, &Context
, NULL
))
1021 /* Our fixed-size buffer is large enough */
1022 Buffer
= InitialBuffer
;
1028 /* Need a larger buffer, check how large exactly */
1029 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1031 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1033 ObDereferenceObject(DirectoryHandle
);
1034 return STATUS_NO_MEMORY
;
1037 BufferSize
= ReturnLength
;
1038 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1041 ObDereferenceObject(DirectoryHandle
);
1042 return STATUS_NO_MEMORY
;
1045 /* We should have a sufficiently large buffer now */
1047 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1048 FALSE
, TRUE
, &Context
, &ReturnLength
);
1049 if (! NT_SUCCESS(Status
) ||
1050 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1051 FALSE
, &Context
, NULL
))
1053 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1054 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1055 ObDereferenceObject(DirectoryHandle
);
1056 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1060 ZwClose(DirectoryHandle
);
1063 * Count the required size of buffer.
1065 ReturnLength
= sizeof(DWORD
);
1067 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1070 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1073 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1074 if (NULL
!= pRequiredSize
)
1076 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1077 if (! NT_SUCCESS(Status
))
1079 if (Buffer
!= InitialBuffer
)
1081 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1083 return STATUS_BUFFER_TOO_SMALL
;
1088 * Check if the supplied buffer is large enough.
1090 if (dwSize
< ReturnLength
)
1092 if (Buffer
!= InitialBuffer
)
1094 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1096 return STATUS_BUFFER_TOO_SMALL
;
1100 * Generate the resulting buffer contents.
1102 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1103 if (! NT_SUCCESS(Status
))
1105 if (Buffer
!= InitialBuffer
)
1107 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1111 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1114 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1117 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1118 if (! NT_SUCCESS(Status
))
1120 if (Buffer
!= InitialBuffer
)
1122 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1126 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1127 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1128 if (! NT_SUCCESS(Status
))
1130 if (Buffer
!= InitialBuffer
)
1132 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1136 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1142 if (Buffer
!= InitialBuffer
)
1144 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1147 return STATUS_SUCCESS
;
1150 static NTSTATUS FASTCALL
1151 BuildDesktopNameList(
1152 HWINSTA hWindowStation
,
1155 PULONG pRequiredSize
)
1158 PWINSTATION_OBJECT WindowStation
;
1160 PLIST_ENTRY DesktopEntry
;
1161 PDESKTOP DesktopObject
;
1165 PUNICODE_STRING DesktopName
;
1167 Status
= IntValidateWindowStationHandle(hWindowStation
,
1171 if (! NT_SUCCESS(Status
))
1176 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1179 * Count the required size of buffer.
1181 ReturnLength
= sizeof(DWORD
);
1183 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1184 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1185 DesktopEntry
= DesktopEntry
->Flink
)
1187 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1188 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);
1189 if (DesktopName
) ReturnLength
+= DesktopName
->Length
+ sizeof(WCHAR
);
1192 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1193 if (NULL
!= pRequiredSize
)
1195 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1196 if (! NT_SUCCESS(Status
))
1198 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1199 ObDereferenceObject(WindowStation
);
1200 return STATUS_BUFFER_TOO_SMALL
;
1205 * Check if the supplied buffer is large enough.
1207 if (dwSize
< ReturnLength
)
1209 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1210 ObDereferenceObject(WindowStation
);
1211 return STATUS_BUFFER_TOO_SMALL
;
1215 * Generate the resulting buffer contents.
1217 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1218 if (! NT_SUCCESS(Status
))
1220 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1221 ObDereferenceObject(WindowStation
);
1224 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1227 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1228 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1229 DesktopEntry
= DesktopEntry
->Flink
)
1231 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1232 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
1233 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);/// @todo Don't mess around with the object headers!
1234 if (!DesktopName
) continue;
1236 Status
= MmCopyToCaller(lpBuffer
, DesktopName
->Buffer
, DesktopName
->Length
);
1237 if (! NT_SUCCESS(Status
))
1239 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1240 ObDereferenceObject(WindowStation
);
1243 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
->Length
);
1244 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1245 if (! NT_SUCCESS(Status
))
1247 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1248 ObDereferenceObject(WindowStation
);
1251 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1257 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1258 ObDereferenceObject(WindowStation
);
1260 return STATUS_SUCCESS
;
1264 * NtUserBuildNameList
1266 * Function used for enumeration of desktops or window stations.
1270 * For enumeration of window stations this parameter must be set to
1271 * zero. Otherwise it's handle for window station.
1274 * Size of buffer passed by caller.
1277 * Buffer passed by caller. If the function succedes, the buffer is
1278 * filled with window station/desktop count (in first DWORD) and
1279 * NULL-terminated window station/desktop names.
1282 * If the function suceedes, this is the number of bytes copied.
1283 * Otherwise it's size of buffer needed for function to succeed.
1290 NtUserBuildNameList(
1291 HWINSTA hWindowStation
,
1294 PULONG pRequiredSize
)
1296 /* The WindowStation name list and desktop name list are build in completely
1297 different ways. Call the appropriate function */
1298 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1299 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1306 NtUserSetLogonNotifyWindow(HWND hWnd
)
1308 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1313 if(!IntIsWindow(hWnd
))
1325 NtUserLockWorkStation(VOID
)
1328 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1330 UserEnterExclusive();
1332 if (pti
->rpdesk
== IntGetActiveDesktop())
1334 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);