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 UserCreateWinstaDirectory()
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
;
435 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
437 if (InputWindowStation
== NULL
)
439 TRACE("Initializeing input window station\n");
440 InputWindowStation
= WindowStationObject
;
445 TRACE("NtUserCreateWindowStation created object 0x%x with name %wZ handle 0x%x\n",
446 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
447 return WindowStation
;
451 * NtUserOpenWindowStation
453 * Opens an existing window station.
456 * lpszWindowStationName
457 * Name of the existing window station.
460 * Requested type of access.
463 * If the function succeeds, the return value is the handle to the
464 * specified window station. If the function fails, the return value
468 * The returned handle can be closed with NtUserCloseWindowStation.
475 NtUserOpenWindowStation(
476 POBJECT_ATTRIBUTES ObjectAttributes
,
477 ACCESS_MASK dwDesiredAccess
)
482 Status
= ObOpenObjectByName(
484 ExWindowStationObjectType
,
491 if (!NT_SUCCESS(Status
))
493 ERR("NtUserOpenWindowStation failed\n");
494 SetLastNtError(Status
);
498 TRACE("Opened window station %wZ with handle 0x%x\n", ObjectAttributes
->ObjectName
, hwinsta
);
504 * NtUserCloseWindowStation
506 * Closes a window station handle.
510 * Handle to the window station.
516 * The window station handle can be created with NtUserCreateWindowStation
517 * or NtUserOpenWindowStation. Attemps to close a handle to the window
518 * station assigned to the calling process will fail.
526 NtUserCloseWindowStation(
529 PWINSTATION_OBJECT Object
;
532 TRACE("NtUserCloseWindowStation called (0x%x)\n", hWinSta
);
534 if (hWinSta
== UserGetProcessWindowStation())
536 ERR("Attempted to close process window station\n");
540 Status
= IntValidateWindowStationHandle(
546 if (!NT_SUCCESS(Status
))
548 ERR("Validation of window station handle (0x%x) failed\n", hWinSta
);
552 ObDereferenceObject(Object
);
554 TRACE("Closing window station handle (0x%x)\n", hWinSta
);
556 Status
= ObCloseHandle(hWinSta
, UserMode
);
557 if (!NT_SUCCESS(Status
))
559 SetLastNtError(Status
);
567 * NtUserGetObjectInformation
569 * The NtUserGetObjectInformation function retrieves information about a
570 * window station or desktop object.
574 * Handle to the window station or desktop object for which to
575 * return information. This can be a handle of type HDESK or HWINSTA
576 * (for example, a handle returned by NtUserCreateWindowStation,
577 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
580 * Specifies the object information to be retrieved.
583 * Pointer to a buffer to receive the object information.
586 * Specifies the size, in bytes, of the buffer pointed to by the
590 * Pointer to a variable receiving the number of bytes required to
591 * store the requested information. If this variable's value is
592 * greater than the value of the nLength parameter when the function
593 * returns, the function returns FALSE, and none of the information
594 * is copied to the pvInfo buffer. If the value of the variable pointed
595 * to by lpnLengthNeeded is less than or equal to the value of nLength,
596 * the entire information block is copied.
599 * If the function succeeds, the return value is nonzero. If the function
600 * fails, the return value is zero.
607 NtUserGetObjectInformation(
612 PDWORD nLengthNeeded
)
614 PWINSTATION_OBJECT WinStaObject
= NULL
;
615 PDESKTOP DesktopObject
= NULL
;
620 /* try windowstation */
621 TRACE("Trying to open window station 0x%x\n", hObject
);
622 Status
= ObReferenceObjectByHandle(
625 ExWindowStationObjectType
,
627 (PVOID
*)&WinStaObject
,
630 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
633 TRACE("Trying to open desktop 0x%x\n", hObject
);
634 Status
= IntValidateDesktopHandle(
641 if (!NT_SUCCESS(Status
))
643 ERR("Failed: 0x%x\n", Status
);
644 SetLastNtError(Status
);
648 TRACE("WinSta or Desktop opened!!\n");
654 Status
= STATUS_NOT_IMPLEMENTED
;
655 ERR("UOI_FLAGS unimplemented!\n");
659 if (WinStaObject
!= NULL
)
661 pvData
= WinStaObject
->Name
.Buffer
;
662 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
663 Status
= STATUS_SUCCESS
;
665 else if (DesktopObject
!= NULL
)
667 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
668 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
669 Status
= STATUS_SUCCESS
;
672 Status
= STATUS_INVALID_PARAMETER
;
676 if (WinStaObject
!= NULL
)
678 pvData
= L
"WindowStation";
679 nDataSize
= sizeof(L
"WindowStation");
680 Status
= STATUS_SUCCESS
;
682 else if (DesktopObject
!= NULL
)
685 nDataSize
= sizeof(L
"Desktop");
686 Status
= STATUS_SUCCESS
;
689 Status
= STATUS_INVALID_PARAMETER
;
693 Status
= STATUS_NOT_IMPLEMENTED
;
694 ERR("UOI_USER_SID unimplemented!\n");
698 Status
= STATUS_INVALID_PARAMETER
;
702 /* try to copy data to caller */
703 if (Status
== STATUS_SUCCESS
)
705 TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
706 *nLengthNeeded
= nDataSize
;
707 if (nLength
>= nDataSize
)
708 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
710 Status
= STATUS_BUFFER_TOO_SMALL
;
713 /* release objects */
714 if (WinStaObject
!= NULL
)
715 ObDereferenceObject(WinStaObject
);
716 if (DesktopObject
!= NULL
)
717 ObDereferenceObject(DesktopObject
);
719 if (!NT_SUCCESS(Status
))
721 SetLastNtError(Status
);
729 * NtUserSetObjectInformation
731 * The NtUserSetObjectInformation function sets information about a
732 * window station or desktop object.
736 * Handle to the window station or desktop object for which to set
737 * object information. This value can be a handle of type HDESK or
741 * Specifies the object information to be set.
744 * Pointer to a buffer containing the object information.
747 * Specifies the size, in bytes, of the information contained in the
748 * buffer pointed to by pvInfo.
751 * If the function succeeds, the return value is nonzero. If the function
752 * fails the return value is zero.
760 NtUserSetObjectInformation(
766 /* FIXME: ZwQueryObject */
767 /* FIXME: ZwSetInformationObject */
768 SetLastNtError(STATUS_UNSUCCESSFUL
);
776 UserGetProcessWindowStation(VOID
)
778 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
785 * NtUserGetProcessWindowStation
787 * Returns a handle to the current process window station.
790 * If the function succeeds, the return value is handle to the window
791 * station assigned to the current process. If the function fails, the
792 * return value is NULL.
799 NtUserGetProcessWindowStation(VOID
)
801 return UserGetProcessWindowStation();
805 UserSetProcessWindowStation(HWINSTA hWindowStation
)
810 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
812 ppi
= PsGetCurrentProcessWin32Process();
814 /* Reference the new window station */
815 if(hWindowStation
!=NULL
)
817 Status
= IntValidateWindowStationHandle( hWindowStation
,
821 if (!NT_SUCCESS(Status
))
823 TRACE("Validation of window station handle (0x%X) failed\n",
825 SetLastNtError(Status
);
830 OldWinSta
= ppi
->prpwinsta
;
831 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
833 /* Dereference the previous window station */
834 if(OldWinSta
!= NULL
)
836 ObDereferenceObject(OldWinSta
);
839 /* Check if we have a stale handle (it should happen for console apps) */
840 if(hwinstaOld
!= ppi
->hwinsta
)
842 ObCloseHandle(hwinstaOld
, UserMode
);
846 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
849 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
851 ppi
->prpwinsta
= NewWinSta
;
852 ppi
->hwinsta
= hWindowStation
;
858 * NtUserSetProcessWindowStation
860 * Assigns a window station to the current process.
864 * Handle to the window station.
874 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
878 UserEnterExclusive();
880 ret
= UserSetProcessWindowStation(hWindowStation
);
888 * NtUserLockWindowStation
890 * Locks switching desktops. Only the logon application is allowed to call this function.
897 NtUserLockWindowStation(HWINSTA hWindowStation
)
899 PWINSTATION_OBJECT Object
;
902 TRACE("About to set process window station with handle (0x%X)\n",
905 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
907 ERR("Unauthorized process attempted to lock the window station!\n");
908 EngSetLastError(ERROR_ACCESS_DENIED
);
912 Status
= IntValidateWindowStationHandle(
917 if (!NT_SUCCESS(Status
))
919 TRACE("Validation of window station handle (0x%X) failed\n",
921 SetLastNtError(Status
);
925 Object
->Flags
|= WSS_LOCKED
;
927 ObDereferenceObject(Object
);
932 * NtUserUnlockWindowStation
934 * Unlocks switching desktops. Only the logon application is allowed to call this function.
941 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
943 PWINSTATION_OBJECT Object
;
947 TRACE("About to set process window station with handle (0x%X)\n",
950 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
952 ERR("Unauthorized process attempted to unlock the window station!\n");
953 EngSetLastError(ERROR_ACCESS_DENIED
);
957 Status
= IntValidateWindowStationHandle(
962 if (!NT_SUCCESS(Status
))
964 TRACE("Validation of window station handle (0x%X) failed\n",
966 SetLastNtError(Status
);
970 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
971 Object
->Flags
&= ~WSS_LOCKED
;
973 ObDereferenceObject(Object
);
977 static NTSTATUS FASTCALL
978 BuildWindowStationNameList(
981 PULONG pRequiredSize
)
983 OBJECT_ATTRIBUTES ObjectAttributes
;
985 HANDLE DirectoryHandle
;
986 char InitialBuffer
[256], *Buffer
;
987 ULONG Context
, ReturnLength
, BufferSize
;
989 POBJECT_DIRECTORY_INFORMATION DirEntry
;
993 * Try to open the directory.
995 InitializeObjectAttributes(
997 &gustrWindowStationsDir
,
998 OBJ_CASE_INSENSITIVE
,
1002 Status
= ZwOpenDirectoryObject(
1007 if (!NT_SUCCESS(Status
))
1012 /* First try to query the directory using a fixed-size buffer */
1015 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1016 FALSE
, TRUE
, &Context
, &ReturnLength
);
1017 if (NT_SUCCESS(Status
))
1019 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1020 FALSE
, &Context
, NULL
))
1022 /* Our fixed-size buffer is large enough */
1023 Buffer
= InitialBuffer
;
1029 /* Need a larger buffer, check how large exactly */
1030 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1032 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1034 ObDereferenceObject(DirectoryHandle
);
1035 return STATUS_NO_MEMORY
;
1038 BufferSize
= ReturnLength
;
1039 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1042 ObDereferenceObject(DirectoryHandle
);
1043 return STATUS_NO_MEMORY
;
1046 /* We should have a sufficiently large buffer now */
1048 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1049 FALSE
, TRUE
, &Context
, &ReturnLength
);
1050 if (! NT_SUCCESS(Status
) ||
1051 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1052 FALSE
, &Context
, NULL
))
1054 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1055 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1056 ObDereferenceObject(DirectoryHandle
);
1057 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1061 ZwClose(DirectoryHandle
);
1064 * Count the required size of buffer.
1066 ReturnLength
= sizeof(DWORD
);
1068 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1071 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1074 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1075 if (NULL
!= pRequiredSize
)
1077 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1078 if (! NT_SUCCESS(Status
))
1080 if (Buffer
!= InitialBuffer
)
1082 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1084 return STATUS_BUFFER_TOO_SMALL
;
1089 * Check if the supplied buffer is large enough.
1091 if (dwSize
< ReturnLength
)
1093 if (Buffer
!= InitialBuffer
)
1095 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1097 return STATUS_BUFFER_TOO_SMALL
;
1101 * Generate the resulting buffer contents.
1103 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1104 if (! NT_SUCCESS(Status
))
1106 if (Buffer
!= InitialBuffer
)
1108 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1112 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1115 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1118 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1119 if (! NT_SUCCESS(Status
))
1121 if (Buffer
!= InitialBuffer
)
1123 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1127 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1128 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1129 if (! NT_SUCCESS(Status
))
1131 if (Buffer
!= InitialBuffer
)
1133 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1137 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1143 if (Buffer
!= InitialBuffer
)
1145 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1148 return STATUS_SUCCESS
;
1151 static NTSTATUS FASTCALL
1152 BuildDesktopNameList(
1153 HWINSTA hWindowStation
,
1156 PULONG pRequiredSize
)
1159 PWINSTATION_OBJECT WindowStation
;
1161 PLIST_ENTRY DesktopEntry
;
1162 PDESKTOP DesktopObject
;
1166 PUNICODE_STRING DesktopName
;
1168 Status
= IntValidateWindowStationHandle(hWindowStation
,
1172 if (! NT_SUCCESS(Status
))
1177 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1180 * Count the required size of buffer.
1182 ReturnLength
= sizeof(DWORD
);
1184 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1185 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1186 DesktopEntry
= DesktopEntry
->Flink
)
1188 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1189 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);
1190 if (DesktopName
) ReturnLength
+= DesktopName
->Length
+ sizeof(WCHAR
);
1193 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1194 if (NULL
!= pRequiredSize
)
1196 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1197 if (! NT_SUCCESS(Status
))
1199 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1200 ObDereferenceObject(WindowStation
);
1201 return STATUS_BUFFER_TOO_SMALL
;
1206 * Check if the supplied buffer is large enough.
1208 if (dwSize
< ReturnLength
)
1210 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1211 ObDereferenceObject(WindowStation
);
1212 return STATUS_BUFFER_TOO_SMALL
;
1216 * Generate the resulting buffer contents.
1218 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1219 if (! NT_SUCCESS(Status
))
1221 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1222 ObDereferenceObject(WindowStation
);
1225 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1228 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1229 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1230 DesktopEntry
= DesktopEntry
->Flink
)
1232 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1233 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
1234 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);/// @todo Don't mess around with the object headers!
1235 if (!DesktopName
) continue;
1237 Status
= MmCopyToCaller(lpBuffer
, DesktopName
->Buffer
, DesktopName
->Length
);
1238 if (! NT_SUCCESS(Status
))
1240 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1241 ObDereferenceObject(WindowStation
);
1244 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
->Length
);
1245 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1246 if (! NT_SUCCESS(Status
))
1248 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1249 ObDereferenceObject(WindowStation
);
1252 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1258 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1259 ObDereferenceObject(WindowStation
);
1261 return STATUS_SUCCESS
;
1265 * NtUserBuildNameList
1267 * Function used for enumeration of desktops or window stations.
1271 * For enumeration of window stations this parameter must be set to
1272 * zero. Otherwise it's handle for window station.
1275 * Size of buffer passed by caller.
1278 * Buffer passed by caller. If the function succedes, the buffer is
1279 * filled with window station/desktop count (in first DWORD) and
1280 * NULL-terminated window station/desktop names.
1283 * If the function suceedes, this is the number of bytes copied.
1284 * Otherwise it's size of buffer needed for function to succeed.
1291 NtUserBuildNameList(
1292 HWINSTA hWindowStation
,
1295 PULONG pRequiredSize
)
1297 /* The WindowStation name list and desktop name list are build in completely
1298 different ways. Call the appropriate function */
1299 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1300 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1307 NtUserSetLogonNotifyWindow(HWND hWnd
)
1309 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1314 if(!IntIsWindow(hWnd
))
1326 NtUserLockWorkStation(VOID
)
1329 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1331 UserEnterExclusive();
1333 if (pti
->rpdesk
== IntGetActiveDesktop())
1335 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);