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 RtlCreateUnicodeString(&gustrWindowStationsDir
, WINSTA_OBJ_DIR
);
64 swprintf(wstrWindowStationsDir
,
70 RtlCreateUnicodeString( &gustrWindowStationsDir
, wstrWindowStationsDir
);
73 InitializeObjectAttributes(&ObjectAttributes
,
74 &gustrWindowStationsDir
,
78 Status
= ZwCreateDirectoryObject(&hWinstaDir
, 0, &ObjectAttributes
);
79 if (!NT_SUCCESS(Status
))
81 ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir
, Status
);
85 TRACE("Created directory %wZ for session %d\n", &gustrWindowStationsDir
, Peb
->SessionId
);
90 /* OBJECT CALLBACKS **********************************************************/
93 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
95 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
97 TRACE("Deleting window station (0x%X)\n", WinSta
);
99 UserEmptyClipboardData(WinSta
);
101 RtlDestroyAtomTable(WinSta
->AtomTable
);
103 RtlFreeUnicodeString(&WinSta
->Name
);
108 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters
)
110 PUNICODE_STRING RemainingName
= Parameters
->RemainingName
;
112 /* Assume we don't find anything */
113 *Parameters
->Object
= NULL
;
115 /* Check for an empty name */
116 if (!RemainingName
->Length
)
118 /* Make sure this is a window station, can't parse a desktop now */
119 if (Parameters
->ObjectType
!= ExWindowStationObjectType
)
122 return STATUS_OBJECT_TYPE_MISMATCH
;
125 /* Reference the window station and return */
126 ObReferenceObject(Parameters
->ParseObject
);
127 *Parameters
->Object
= Parameters
->ParseObject
;
128 return STATUS_SUCCESS
;
131 /* Check for leading slash */
132 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
135 RemainingName
->Buffer
++;
136 RemainingName
->Length
-= sizeof(WCHAR
);
137 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
140 /* Check if there is still a slash */
141 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
143 /* In this case, fail */
144 return STATUS_OBJECT_PATH_INVALID
;
148 * Check if we are parsing a desktop.
150 if (Parameters
->ObjectType
== ExDesktopObjectType
)
152 /* Then call the desktop parse routine */
153 return IntDesktopObjectParse(Parameters
->ParseObject
,
154 Parameters
->ObjectType
,
155 Parameters
->AccessState
,
156 Parameters
->AccessMode
,
157 Parameters
->Attributes
,
158 Parameters
->CompleteName
,
161 Parameters
->SecurityQos
,
165 /* Should hopefully never get here */
166 return STATUS_OBJECT_TYPE_MISMATCH
;
171 IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
175 ppi
= PsGetCurrentProcessWin32Process();
177 if(ppi
&& (Parameters
->Handle
== ppi
->hwinsta
))
179 return STATUS_ACCESS_DENIED
;
182 return STATUS_SUCCESS
;
185 /* PRIVATE FUNCTIONS **********************************************************/
188 * IntValidateWindowStationHandle
190 * Validates the window station handle.
193 * If the function succeeds, the handle remains referenced. If the
194 * fucntion fails, last error is set.
198 IntValidateWindowStationHandle(
199 HWINSTA WindowStation
,
200 KPROCESSOR_MODE AccessMode
,
201 ACCESS_MASK DesiredAccess
,
202 PWINSTATION_OBJECT
*Object
)
206 if (WindowStation
== NULL
)
208 ERR("Invalid window station handle\n");
209 EngSetLastError(ERROR_INVALID_HANDLE
);
210 return STATUS_INVALID_HANDLE
;
213 Status
= ObReferenceObjectByHandle(
216 ExWindowStationObjectType
,
221 if (!NT_SUCCESS(Status
))
222 SetLastNtError(Status
);
228 co_IntInitializeDesktopGraphics(VOID
)
231 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
233 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
234 if (NULL
== ScreenDeviceContext
)
236 IntDestroyPrimarySurface();
239 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
241 if (! IntCreatePrimarySurface())
246 /* Setup the cursor */
247 co_IntLoadDefaultCursors();
249 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
251 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
252 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
254 // FIXME: Move these to a update routine.
255 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
256 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
257 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
258 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
259 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
261 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
264 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
265 // Font is realized and this dc was previously set to internal DC_ATTR.
266 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
267 gpsi
->tmSysFont
= tmw
;
273 IntEndDesktopGraphics(VOID
)
275 if (NULL
!= ScreenDeviceContext
)
276 { // No need to allocate a new dcattr.
277 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
278 GreDeleteObject(ScreenDeviceContext
);
279 ScreenDeviceContext
= NULL
;
281 IntHideDesktop(IntGetActiveDesktop());
282 IntDestroyPrimarySurface();
288 return ScreenDeviceContext
;
291 /* PUBLIC FUNCTIONS ***********************************************************/
294 * NtUserCreateWindowStation
296 * Creates a new window station.
299 * lpszWindowStationName
300 * Pointer to a null-terminated string specifying the name of the
301 * window station to be created. Window station names are
302 * case-insensitive and cannot contain backslash characters (\).
303 * Only members of the Administrators group are allowed to specify a
307 * Requested type of access
310 * Security descriptor
312 * Unknown3, Unknown4, Unknown5
316 * If the function succeeds, the return value is a handle to the newly
317 * created window station. If the specified window station already
318 * exists, the function succeeds and returns a handle to the existing
319 * window station. If the function fails, the return value is NULL.
322 * Correct the prototype to match the Windows one (with 7 parameters
330 NtUserCreateWindowStation(
331 POBJECT_ATTRIBUTES ObjectAttributes
,
332 ACCESS_MASK dwDesiredAccess
,
339 UNICODE_STRING WindowStationName
;
340 PWINSTATION_OBJECT WindowStationObject
;
341 HWINSTA WindowStation
;
344 TRACE("NtUserCreateWindowStation called\n");
346 Status
= ObOpenObjectByName(
348 ExWindowStationObjectType
,
353 (PVOID
*)&WindowStation
);
355 if (NT_SUCCESS(Status
))
357 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes
->ObjectName
);
358 return (HWINSTA
)WindowStation
;
362 * No existing window station found, try to create new one
365 /* Capture window station name */
368 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
369 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
, ObjectAttributes
->ObjectName
);
371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
373 Status
=_SEH2_GetExceptionCode();
377 if (! NT_SUCCESS(Status
))
379 ERR("Failed reading capturing window station name\n");
380 SetLastNtError(Status
);
384 /* Create the window station object */
385 Status
= ObCreateObject(
387 ExWindowStationObjectType
,
391 sizeof(WINSTATION_OBJECT
),
394 (PVOID
*)&WindowStationObject
);
396 if (!NT_SUCCESS(Status
))
398 ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName
);
399 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
400 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
404 Status
= ObInsertObject(
405 (PVOID
)WindowStationObject
,
410 (PVOID
*)&WindowStation
);
412 if (!NT_SUCCESS(Status
))
414 ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName
);
415 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
416 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
417 ObDereferenceObject(WindowStationObject
);
421 /* Initialize the window station */
422 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
424 KeInitializeSpinLock(&WindowStationObject
->Lock
);
425 InitializeListHead(&WindowStationObject
->DesktopListHead
);
426 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
427 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
428 WindowStationObject
->Name
= WindowStationName
;
430 if (InputWindowStation
== NULL
)
432 TRACE("Initializeing input window station\n");
433 InputWindowStation
= WindowStationObject
;
438 TRACE("NtUserCreateWindowStation created object 0x%x with name %wZ handle 0x%x\n",
439 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
440 return WindowStation
;
444 * NtUserOpenWindowStation
446 * Opens an existing window station.
449 * lpszWindowStationName
450 * Name of the existing window station.
453 * Requested type of access.
456 * If the function succeeds, the return value is the handle to the
457 * specified window station. If the function fails, the return value
461 * The returned handle can be closed with NtUserCloseWindowStation.
468 NtUserOpenWindowStation(
469 POBJECT_ATTRIBUTES ObjectAttributes
,
470 ACCESS_MASK dwDesiredAccess
)
475 Status
= ObOpenObjectByName(
477 ExWindowStationObjectType
,
484 if (!NT_SUCCESS(Status
))
486 ERR("NtUserOpenWindowStation failed\n");
487 SetLastNtError(Status
);
491 TRACE("Opened window station %wZ with handle 0x%x\n", ObjectAttributes
->ObjectName
, hwinsta
);
497 * NtUserCloseWindowStation
499 * Closes a window station handle.
503 * Handle to the window station.
509 * The window station handle can be created with NtUserCreateWindowStation
510 * or NtUserOpenWindowStation. Attemps to close a handle to the window
511 * station assigned to the calling process will fail.
519 NtUserCloseWindowStation(
522 PWINSTATION_OBJECT Object
;
525 TRACE("NtUserCloseWindowStation called (0x%x)\n", hWinSta
);
527 if (hWinSta
== UserGetProcessWindowStation())
529 ERR("Attempted to close process window station\n");
533 Status
= IntValidateWindowStationHandle(
539 if (!NT_SUCCESS(Status
))
541 ERR("Validation of window station handle (0x%x) failed\n", hWinSta
);
545 ObDereferenceObject(Object
);
547 TRACE("Closing window station handle (0x%x)\n", hWinSta
);
549 Status
= ObCloseHandle(hWinSta
, UserMode
);
550 if (!NT_SUCCESS(Status
))
552 SetLastNtError(Status
);
560 * NtUserGetObjectInformation
562 * The NtUserGetObjectInformation function retrieves information about a
563 * window station or desktop object.
567 * Handle to the window station or desktop object for which to
568 * return information. This can be a handle of type HDESK or HWINSTA
569 * (for example, a handle returned by NtUserCreateWindowStation,
570 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
573 * Specifies the object information to be retrieved.
576 * Pointer to a buffer to receive the object information.
579 * Specifies the size, in bytes, of the buffer pointed to by the
583 * Pointer to a variable receiving the number of bytes required to
584 * store the requested information. If this variable's value is
585 * greater than the value of the nLength parameter when the function
586 * returns, the function returns FALSE, and none of the information
587 * is copied to the pvInfo buffer. If the value of the variable pointed
588 * to by lpnLengthNeeded is less than or equal to the value of nLength,
589 * the entire information block is copied.
592 * If the function succeeds, the return value is nonzero. If the function
593 * fails, the return value is zero.
600 NtUserGetObjectInformation(
605 PDWORD nLengthNeeded
)
607 PWINSTATION_OBJECT WinStaObject
= NULL
;
608 PDESKTOP DesktopObject
= NULL
;
613 /* try windowstation */
614 TRACE("Trying to open window station 0x%x\n", hObject
);
615 Status
= ObReferenceObjectByHandle(
618 ExWindowStationObjectType
,
620 (PVOID
*)&WinStaObject
,
623 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
626 TRACE("Trying to open desktop 0x%x\n", hObject
);
627 Status
= IntValidateDesktopHandle(
634 if (!NT_SUCCESS(Status
))
636 ERR("Failed: 0x%x\n", Status
);
637 SetLastNtError(Status
);
641 TRACE("WinSta or Desktop opened!!\n");
647 Status
= STATUS_NOT_IMPLEMENTED
;
648 ERR("UOI_FLAGS unimplemented!\n");
652 if (WinStaObject
!= NULL
)
654 pvData
= WinStaObject
->Name
.Buffer
;
655 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
656 Status
= STATUS_SUCCESS
;
658 else if (DesktopObject
!= NULL
)
660 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
661 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
662 Status
= STATUS_SUCCESS
;
665 Status
= STATUS_INVALID_PARAMETER
;
669 if (WinStaObject
!= NULL
)
671 pvData
= L
"WindowStation";
672 nDataSize
= sizeof(L
"WindowStation");
673 Status
= STATUS_SUCCESS
;
675 else if (DesktopObject
!= NULL
)
678 nDataSize
= sizeof(L
"Desktop");
679 Status
= STATUS_SUCCESS
;
682 Status
= STATUS_INVALID_PARAMETER
;
686 Status
= STATUS_NOT_IMPLEMENTED
;
687 ERR("UOI_USER_SID unimplemented!\n");
691 Status
= STATUS_INVALID_PARAMETER
;
695 /* try to copy data to caller */
696 if (Status
== STATUS_SUCCESS
)
698 TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
699 *nLengthNeeded
= nDataSize
;
700 if (nLength
>= nDataSize
)
701 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
703 Status
= STATUS_BUFFER_TOO_SMALL
;
706 /* release objects */
707 if (WinStaObject
!= NULL
)
708 ObDereferenceObject(WinStaObject
);
709 if (DesktopObject
!= NULL
)
710 ObDereferenceObject(DesktopObject
);
712 if (!NT_SUCCESS(Status
))
714 SetLastNtError(Status
);
722 * NtUserSetObjectInformation
724 * The NtUserSetObjectInformation function sets information about a
725 * window station or desktop object.
729 * Handle to the window station or desktop object for which to set
730 * object information. This value can be a handle of type HDESK or
734 * Specifies the object information to be set.
737 * Pointer to a buffer containing the object information.
740 * Specifies the size, in bytes, of the information contained in the
741 * buffer pointed to by pvInfo.
744 * If the function succeeds, the return value is nonzero. If the function
745 * fails the return value is zero.
753 NtUserSetObjectInformation(
759 /* FIXME: ZwQueryObject */
760 /* FIXME: ZwSetInformationObject */
761 SetLastNtError(STATUS_UNSUCCESSFUL
);
769 UserGetProcessWindowStation(VOID
)
771 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
778 * NtUserGetProcessWindowStation
780 * Returns a handle to the current process window station.
783 * If the function succeeds, the return value is handle to the window
784 * station assigned to the current process. If the function fails, the
785 * return value is NULL.
792 NtUserGetProcessWindowStation(VOID
)
794 return UserGetProcessWindowStation();
798 UserSetProcessWindowStation(HWINSTA hWindowStation
)
803 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
805 ppi
= PsGetCurrentProcessWin32Process();
807 /* Reference the new window station */
808 if(hWindowStation
!=NULL
)
810 Status
= IntValidateWindowStationHandle( hWindowStation
,
814 if (!NT_SUCCESS(Status
))
816 TRACE("Validation of window station handle (0x%X) failed\n",
818 SetLastNtError(Status
);
823 OldWinSta
= ppi
->prpwinsta
;
824 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
826 /* Dereference the previous window station */
827 if(OldWinSta
!= NULL
)
829 ObDereferenceObject(OldWinSta
);
832 /* Check if we have a stale handle (it should happen for console apps) */
833 if(hwinstaOld
!= ppi
->hwinsta
)
835 ObCloseHandle(hwinstaOld
, UserMode
);
839 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
842 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
844 ppi
->prpwinsta
= NewWinSta
;
845 ppi
->hwinsta
= hWindowStation
;
851 * NtUserSetProcessWindowStation
853 * Assigns a window station to the current process.
857 * Handle to the window station.
867 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
871 UserEnterExclusive();
873 ret
= UserSetProcessWindowStation(hWindowStation
);
881 * NtUserLockWindowStation
883 * Locks switching desktops. Only the logon application is allowed to call this function.
890 NtUserLockWindowStation(HWINSTA hWindowStation
)
892 PWINSTATION_OBJECT Object
;
895 TRACE("About to set process window station with handle (0x%X)\n",
898 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
900 ERR("Unauthorized process attempted to lock the window station!\n");
901 EngSetLastError(ERROR_ACCESS_DENIED
);
905 Status
= IntValidateWindowStationHandle(
910 if (!NT_SUCCESS(Status
))
912 TRACE("Validation of window station handle (0x%X) failed\n",
914 SetLastNtError(Status
);
918 Object
->Flags
|= WSS_LOCKED
;
920 ObDereferenceObject(Object
);
925 * NtUserUnlockWindowStation
927 * Unlocks switching desktops. Only the logon application is allowed to call this function.
934 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
936 PWINSTATION_OBJECT Object
;
940 TRACE("About to set process window station with handle (0x%X)\n",
943 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
945 ERR("Unauthorized process attempted to unlock the window station!\n");
946 EngSetLastError(ERROR_ACCESS_DENIED
);
950 Status
= IntValidateWindowStationHandle(
955 if (!NT_SUCCESS(Status
))
957 TRACE("Validation of window station handle (0x%X) failed\n",
959 SetLastNtError(Status
);
963 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
964 Object
->Flags
&= ~WSS_LOCKED
;
966 ObDereferenceObject(Object
);
970 static NTSTATUS FASTCALL
971 BuildWindowStationNameList(
974 PULONG pRequiredSize
)
976 OBJECT_ATTRIBUTES ObjectAttributes
;
978 HANDLE DirectoryHandle
;
979 char InitialBuffer
[256], *Buffer
;
980 ULONG Context
, ReturnLength
, BufferSize
;
982 POBJECT_DIRECTORY_INFORMATION DirEntry
;
986 * Try to open the directory.
988 InitializeObjectAttributes(
990 &gustrWindowStationsDir
,
991 OBJ_CASE_INSENSITIVE
,
995 Status
= ZwOpenDirectoryObject(
1000 if (!NT_SUCCESS(Status
))
1005 /* First try to query the directory using a fixed-size buffer */
1008 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1009 FALSE
, TRUE
, &Context
, &ReturnLength
);
1010 if (NT_SUCCESS(Status
))
1012 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1013 FALSE
, &Context
, NULL
))
1015 /* Our fixed-size buffer is large enough */
1016 Buffer
= InitialBuffer
;
1022 /* Need a larger buffer, check how large exactly */
1023 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1025 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1027 BufferSize
= ReturnLength
;
1028 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1031 ObDereferenceObject(DirectoryHandle
);
1032 return STATUS_NO_MEMORY
;
1035 /* We should have a sufficiently large buffer now */
1037 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1038 FALSE
, TRUE
, &Context
, &ReturnLength
);
1039 if (! NT_SUCCESS(Status
) ||
1040 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1041 FALSE
, &Context
, NULL
))
1043 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1044 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1045 ObDereferenceObject(DirectoryHandle
);
1046 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1051 ZwClose(DirectoryHandle
);
1054 * Count the required size of buffer.
1056 ReturnLength
= sizeof(DWORD
);
1058 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1061 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1064 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1065 if (NULL
!= pRequiredSize
)
1067 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1068 if (! NT_SUCCESS(Status
))
1070 if (Buffer
!= InitialBuffer
)
1072 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1074 return STATUS_BUFFER_TOO_SMALL
;
1079 * Check if the supplied buffer is large enough.
1081 if (dwSize
< ReturnLength
)
1083 if (Buffer
!= InitialBuffer
)
1085 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1087 return STATUS_BUFFER_TOO_SMALL
;
1091 * Generate the resulting buffer contents.
1093 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1094 if (! NT_SUCCESS(Status
))
1096 if (Buffer
!= InitialBuffer
)
1098 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1102 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1105 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1108 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1109 if (! NT_SUCCESS(Status
))
1111 if (Buffer
!= InitialBuffer
)
1113 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1117 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1118 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1119 if (! NT_SUCCESS(Status
))
1121 if (Buffer
!= InitialBuffer
)
1123 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1127 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1133 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1135 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1138 return STATUS_SUCCESS
;
1141 static NTSTATUS FASTCALL
1142 BuildDesktopNameList(
1143 HWINSTA hWindowStation
,
1146 PULONG pRequiredSize
)
1149 PWINSTATION_OBJECT WindowStation
;
1151 PLIST_ENTRY DesktopEntry
;
1152 PDESKTOP DesktopObject
;
1157 Status
= IntValidateWindowStationHandle(hWindowStation
,
1161 if (! NT_SUCCESS(Status
))
1166 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1169 * Count the required size of buffer.
1171 ReturnLength
= sizeof(DWORD
);
1173 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1174 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1175 DesktopEntry
= DesktopEntry
->Flink
)
1177 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1178 ReturnLength
+= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ sizeof(WCHAR
);
1181 TRACE("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1182 if (NULL
!= pRequiredSize
)
1184 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1185 if (! NT_SUCCESS(Status
))
1187 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1188 ObDereferenceObject(WindowStation
);
1189 return STATUS_BUFFER_TOO_SMALL
;
1194 * Check if the supplied buffer is large enough.
1196 if (dwSize
< ReturnLength
)
1198 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1199 ObDereferenceObject(WindowStation
);
1200 return STATUS_BUFFER_TOO_SMALL
;
1204 * Generate the resulting buffer contents.
1206 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1207 if (! NT_SUCCESS(Status
))
1209 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1210 ObDereferenceObject(WindowStation
);
1213 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1216 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1217 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1218 DesktopEntry
= DesktopEntry
->Flink
)
1220 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1221 Status
= MmCopyToCaller(lpBuffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1222 if (! NT_SUCCESS(Status
))
1224 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1225 ObDereferenceObject(WindowStation
);
1228 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1229 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1230 if (! NT_SUCCESS(Status
))
1232 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1233 ObDereferenceObject(WindowStation
);
1236 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1242 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1243 ObDereferenceObject(WindowStation
);
1245 return STATUS_SUCCESS
;
1249 * NtUserBuildNameList
1251 * Function used for enumeration of desktops or window stations.
1255 * For enumeration of window stations this parameter must be set to
1256 * zero. Otherwise it's handle for window station.
1259 * Size of buffer passed by caller.
1262 * Buffer passed by caller. If the function succedes, the buffer is
1263 * filled with window station/desktop count (in first DWORD) and
1264 * NULL-terminated window station/desktop names.
1267 * If the function suceedes, this is the number of bytes copied.
1268 * Otherwise it's size of buffer needed for function to succeed.
1275 NtUserBuildNameList(
1276 HWINSTA hWindowStation
,
1279 PULONG pRequiredSize
)
1281 /* The WindowStation name list and desktop name list are build in completely
1282 different ways. Call the appropriate function */
1283 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1284 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1291 NtUserSetLogonNotifyWindow(HWND hWnd
)
1293 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1298 if(!IntIsWindow(hWnd
))