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 /* INITIALIZATION 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 %lu\n", &gustrWindowStationsDir
, Peb
->SessionId
);
96 /* OBJECT CALLBACKS **********************************************************/
100 IntWinStaObjectDelete(
101 _In_ PVOID Parameters
)
103 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
104 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)DeleteParameters
->Object
;
106 TRACE("Deleting window station (0x%p)\n", WinSta
);
108 UserEmptyClipboardData(WinSta
);
110 RtlDestroyAtomTable(WinSta
->AtomTable
);
112 RtlFreeUnicodeString(&WinSta
->Name
);
114 return STATUS_SUCCESS
;
119 IntWinStaObjectParse(
120 _In_ PVOID Parameters
)
122 PWIN32_PARSEMETHOD_PARAMETERS ParseParameters
= Parameters
;
123 PUNICODE_STRING RemainingName
= ParseParameters
->RemainingName
;
125 /* Assume we don't find anything */
126 *ParseParameters
->Object
= NULL
;
128 /* Check for an empty name */
129 if (!RemainingName
->Length
)
131 /* Make sure this is a window station, can't parse a desktop now */
132 if (ParseParameters
->ObjectType
!= ExWindowStationObjectType
)
135 return STATUS_OBJECT_TYPE_MISMATCH
;
138 /* Reference the window station and return */
139 ObReferenceObject(ParseParameters
->ParseObject
);
140 *ParseParameters
->Object
= ParseParameters
->ParseObject
;
141 return STATUS_SUCCESS
;
144 /* Check for leading slash */
145 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
148 RemainingName
->Buffer
++;
149 RemainingName
->Length
-= sizeof(WCHAR
);
150 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
153 /* Check if there is still a slash */
154 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
156 /* In this case, fail */
157 return STATUS_OBJECT_PATH_INVALID
;
161 * Check if we are parsing a desktop.
163 if (ParseParameters
->ObjectType
== ExDesktopObjectType
)
165 /* Then call the desktop parse routine */
166 return IntDesktopObjectParse(ParseParameters
->ParseObject
,
167 ParseParameters
->ObjectType
,
168 ParseParameters
->AccessState
,
169 ParseParameters
->AccessMode
,
170 ParseParameters
->Attributes
,
171 ParseParameters
->CompleteName
,
173 ParseParameters
->Context
,
174 ParseParameters
->SecurityQos
,
175 ParseParameters
->Object
);
178 /* Should hopefully never get here */
179 return STATUS_OBJECT_TYPE_MISMATCH
;
185 _In_ PVOID Parameters
)
187 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
190 ppi
= PsGetCurrentProcessWin32Process();
192 if(ppi
&& (OkToCloseParameters
->Handle
== ppi
->hwinsta
))
194 return STATUS_ACCESS_DENIED
;
197 return STATUS_SUCCESS
;
200 /* PRIVATE FUNCTIONS **********************************************************/
203 * IntValidateWindowStationHandle
205 * Validates the window station handle.
208 * If the function succeeds, the handle remains referenced. If the
209 * fucntion fails, last error is set.
213 IntValidateWindowStationHandle(
214 HWINSTA WindowStation
,
215 KPROCESSOR_MODE AccessMode
,
216 ACCESS_MASK DesiredAccess
,
217 PWINSTATION_OBJECT
*Object
)
221 if (WindowStation
== NULL
)
223 ERR("Invalid window station handle\n");
224 EngSetLastError(ERROR_INVALID_HANDLE
);
225 return STATUS_INVALID_HANDLE
;
228 Status
= ObReferenceObjectByHandle(
231 ExWindowStationObjectType
,
236 if (!NT_SUCCESS(Status
))
237 SetLastNtError(Status
);
243 co_IntInitializeDesktopGraphics(VOID
)
246 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
249 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
250 if (NULL
== ScreenDeviceContext
)
252 IntDestroyPrimarySurface();
255 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
257 if (! IntCreatePrimarySurface())
262 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
264 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
265 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
267 /* Update the SERVERINFO */
268 gpsi
->aiSysMet
[SM_CXSCREEN
] = gppdevPrimary
->gdiinfo
.ulHorzRes
;
269 gpsi
->aiSysMet
[SM_CYSCREEN
] = gppdevPrimary
->gdiinfo
.ulVertRes
;
270 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
271 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
272 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
273 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
274 if (NtGdiGetDeviceCaps(ScreenDeviceContext
, RASTERCAPS
) & RC_PALETTE
)
276 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
279 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
280 // Font is realized and this dc was previously set to internal DC_ATTR.
281 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
282 gpsi
->tmSysFont
= tmw
;
284 /* Put the pointer in the center of the screen */
285 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
286 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
289 UserAttachMonitor((HDEV
)gppdevPrimary
);
291 /* Setup the cursor */
292 co_IntLoadDefaultCursors();
294 /* Show the desktop */
295 pdesk
= IntGetActiveDesktop();
297 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
303 IntEndDesktopGraphics(VOID
)
305 if (NULL
!= ScreenDeviceContext
)
306 { // No need to allocate a new dcattr.
307 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
308 GreDeleteObject(ScreenDeviceContext
);
309 ScreenDeviceContext
= NULL
;
311 IntHideDesktop(IntGetActiveDesktop());
312 IntDestroyPrimarySurface();
318 return ScreenDeviceContext
;
321 /* PUBLIC FUNCTIONS ***********************************************************/
324 * NtUserCreateWindowStation
326 * Creates a new window station.
329 * lpszWindowStationName
330 * Pointer to a null-terminated string specifying the name of the
331 * window station to be created. Window station names are
332 * case-insensitive and cannot contain backslash characters (\).
333 * Only members of the Administrators group are allowed to specify a
337 * Requested type of access
340 * Security descriptor
342 * Unknown3, Unknown4, Unknown5
346 * If the function succeeds, the return value is a handle to the newly
347 * created window station. If the specified window station already
348 * exists, the function succeeds and returns a handle to the existing
349 * window station. If the function fails, the return value is NULL.
352 * Correct the prototype to match the Windows one (with 7 parameters
360 NtUserCreateWindowStation(
361 POBJECT_ATTRIBUTES ObjectAttributes
,
362 ACCESS_MASK dwDesiredAccess
,
369 UNICODE_STRING WindowStationName
;
370 PWINSTATION_OBJECT WindowStationObject
;
371 HWINSTA WindowStation
;
374 TRACE("NtUserCreateWindowStation called\n");
376 Status
= ObOpenObjectByName(
378 ExWindowStationObjectType
,
383 (PVOID
*)&WindowStation
);
385 if (NT_SUCCESS(Status
))
387 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes
->ObjectName
);
388 return (HWINSTA
)WindowStation
;
392 * No existing window station found, try to create new one
395 /* Capture window station name */
398 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
399 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
, ObjectAttributes
->ObjectName
);
401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
403 Status
=_SEH2_GetExceptionCode();
407 if (! NT_SUCCESS(Status
))
409 ERR("Failed reading capturing window station name\n");
410 SetLastNtError(Status
);
414 /* Create the window station object */
415 Status
= ObCreateObject(
417 ExWindowStationObjectType
,
421 sizeof(WINSTATION_OBJECT
),
424 (PVOID
*)&WindowStationObject
);
426 if (!NT_SUCCESS(Status
))
428 ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName
);
429 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
430 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
434 Status
= ObInsertObject(
435 (PVOID
)WindowStationObject
,
440 (PVOID
*)&WindowStation
);
442 if (!NT_SUCCESS(Status
))
444 ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName
);
445 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
446 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
447 ObDereferenceObject(WindowStationObject
);
451 /* Initialize the window station */
452 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
454 InitializeListHead(&WindowStationObject
->DesktopListHead
);
455 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
456 WindowStationObject
->Name
= WindowStationName
;
457 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
459 if (InputWindowStation
== NULL
)
461 TRACE("Initializeing input window station\n");
462 InputWindowStation
= WindowStationObject
;
467 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
468 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
469 return WindowStation
;
473 * NtUserOpenWindowStation
475 * Opens an existing window station.
478 * lpszWindowStationName
479 * Name of the existing window station.
482 * Requested type of access.
485 * If the function succeeds, the return value is the handle to the
486 * specified window station. If the function fails, the return value
490 * The returned handle can be closed with NtUserCloseWindowStation.
497 NtUserOpenWindowStation(
498 POBJECT_ATTRIBUTES ObjectAttributes
,
499 ACCESS_MASK dwDesiredAccess
)
504 Status
= ObOpenObjectByName(
506 ExWindowStationObjectType
,
513 if (!NT_SUCCESS(Status
))
515 ERR("NtUserOpenWindowStation failed\n");
516 SetLastNtError(Status
);
520 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes
->ObjectName
, hwinsta
);
526 * NtUserCloseWindowStation
528 * Closes a window station handle.
532 * Handle to the window station.
538 * The window station handle can be created with NtUserCreateWindowStation
539 * or NtUserOpenWindowStation. Attemps to close a handle to the window
540 * station assigned to the calling process will fail.
548 NtUserCloseWindowStation(
551 PWINSTATION_OBJECT Object
;
554 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
556 if (hWinSta
== UserGetProcessWindowStation())
558 ERR("Attempted to close process window station\n");
562 Status
= IntValidateWindowStationHandle(
568 if (!NT_SUCCESS(Status
))
570 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
574 ObDereferenceObject(Object
);
576 TRACE("Closing window station handle (%p)\n", hWinSta
);
578 Status
= ObCloseHandle(hWinSta
, UserMode
);
579 if (!NT_SUCCESS(Status
))
581 SetLastNtError(Status
);
589 * NtUserGetObjectInformation
591 * The NtUserGetObjectInformation function retrieves information about a
592 * window station or desktop object.
596 * Handle to the window station or desktop object for which to
597 * return information. This can be a handle of type HDESK or HWINSTA
598 * (for example, a handle returned by NtUserCreateWindowStation,
599 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
602 * Specifies the object information to be retrieved.
605 * Pointer to a buffer to receive the object information.
608 * Specifies the size, in bytes, of the buffer pointed to by the
612 * Pointer to a variable receiving the number of bytes required to
613 * store the requested information. If this variable's value is
614 * greater than the value of the nLength parameter when the function
615 * returns, the function returns FALSE, and none of the information
616 * is copied to the pvInfo buffer. If the value of the variable pointed
617 * to by lpnLengthNeeded is less than or equal to the value of nLength,
618 * the entire information block is copied.
621 * If the function succeeds, the return value is nonzero. If the function
622 * fails, the return value is zero.
629 NtUserGetObjectInformation(
634 PDWORD nLengthNeeded
)
636 PWINSTATION_OBJECT WinStaObject
= NULL
;
637 PDESKTOP DesktopObject
= NULL
;
645 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
646 ProbeForWrite(pvInformation
, nLength
, 1);
648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
650 SetLastNtError(_SEH2_GetExceptionCode());
655 /* try windowstation */
656 TRACE("Trying to open window station %p\n", hObject
);
657 Status
= ObReferenceObjectByHandle(
660 ExWindowStationObjectType
,
662 (PVOID
*)&WinStaObject
,
665 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
668 TRACE("Trying to open desktop %p\n", hObject
);
669 Status
= IntValidateDesktopHandle(
676 if (!NT_SUCCESS(Status
))
678 ERR("Failed: 0x%x\n", Status
);
682 TRACE("WinSta or Desktop opened!!\n");
688 Status
= STATUS_NOT_IMPLEMENTED
;
689 ERR("UOI_FLAGS unimplemented!\n");
693 if (WinStaObject
!= NULL
)
695 pvData
= WinStaObject
->Name
.Buffer
;
696 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
697 Status
= STATUS_SUCCESS
;
699 else if (DesktopObject
!= NULL
)
701 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
702 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
703 Status
= STATUS_SUCCESS
;
706 Status
= STATUS_INVALID_PARAMETER
;
710 if (WinStaObject
!= NULL
)
712 pvData
= L
"WindowStation";
713 nDataSize
= sizeof(L
"WindowStation");
714 Status
= STATUS_SUCCESS
;
716 else if (DesktopObject
!= NULL
)
719 nDataSize
= sizeof(L
"Desktop");
720 Status
= STATUS_SUCCESS
;
723 Status
= STATUS_INVALID_PARAMETER
;
727 Status
= STATUS_NOT_IMPLEMENTED
;
728 ERR("UOI_USER_SID unimplemented!\n");
732 Status
= STATUS_INVALID_PARAMETER
;
737 if (Status
== STATUS_SUCCESS
&& nLength
< nDataSize
)
738 Status
= STATUS_BUFFER_TOO_SMALL
;
743 *nLengthNeeded
= nDataSize
;
745 /* try to copy data to caller */
746 if (Status
== STATUS_SUCCESS
)
748 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
749 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
752 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
754 Status
= _SEH2_GetExceptionCode();
758 /* release objects */
759 if (WinStaObject
!= NULL
)
760 ObDereferenceObject(WinStaObject
);
761 if (DesktopObject
!= NULL
)
762 ObDereferenceObject(DesktopObject
);
764 if (!NT_SUCCESS(Status
))
766 SetLastNtError(Status
);
774 * NtUserSetObjectInformation
776 * The NtUserSetObjectInformation function sets information about a
777 * window station or desktop object.
781 * Handle to the window station or desktop object for which to set
782 * object information. This value can be a handle of type HDESK or
786 * Specifies the object information to be set.
789 * Pointer to a buffer containing the object information.
792 * Specifies the size, in bytes, of the information contained in the
793 * buffer pointed to by pvInfo.
796 * If the function succeeds, the return value is nonzero. If the function
797 * fails the return value is zero.
805 NtUserSetObjectInformation(
811 /* FIXME: ZwQueryObject */
812 /* FIXME: ZwSetInformationObject */
813 SetLastNtError(STATUS_UNSUCCESSFUL
);
821 UserGetProcessWindowStation(VOID
)
823 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
830 * NtUserGetProcessWindowStation
832 * Returns a handle to the current process window station.
835 * If the function succeeds, the return value is handle to the window
836 * station assigned to the current process. If the function fails, the
837 * return value is NULL.
844 NtUserGetProcessWindowStation(VOID
)
846 return UserGetProcessWindowStation();
850 UserSetProcessWindowStation(HWINSTA hWindowStation
)
855 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
857 ppi
= PsGetCurrentProcessWin32Process();
859 /* Reference the new window station */
860 if(hWindowStation
!=NULL
)
862 Status
= IntValidateWindowStationHandle( hWindowStation
,
866 if (!NT_SUCCESS(Status
))
868 TRACE("Validation of window station handle (%p) failed\n",
870 SetLastNtError(Status
);
875 OldWinSta
= ppi
->prpwinsta
;
876 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
878 /* Dereference the previous window station */
879 if(OldWinSta
!= NULL
)
881 ObDereferenceObject(OldWinSta
);
884 /* Check if we have a stale handle (it should happen for console apps) */
885 if(hwinstaOld
!= ppi
->hwinsta
)
887 ObCloseHandle(hwinstaOld
, UserMode
);
891 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
894 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
896 ppi
->prpwinsta
= NewWinSta
;
897 ppi
->hwinsta
= hWindowStation
;
903 * NtUserSetProcessWindowStation
905 * Assigns a window station to the current process.
909 * Handle to the window station.
919 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
923 UserEnterExclusive();
925 ret
= UserSetProcessWindowStation(hWindowStation
);
933 * NtUserLockWindowStation
935 * Locks switching desktops. Only the logon application is allowed to call this function.
942 NtUserLockWindowStation(HWINSTA hWindowStation
)
944 PWINSTATION_OBJECT Object
;
947 TRACE("About to set process window station with handle (%p)\n",
950 if (gpidLogon
!= PsGetCurrentProcessId())
952 ERR("Unauthorized process attempted to lock the window station!\n");
953 EngSetLastError(ERROR_ACCESS_DENIED
);
957 Status
= IntValidateWindowStationHandle(
962 if (!NT_SUCCESS(Status
))
964 TRACE("Validation of window station handle (%p) failed\n",
966 SetLastNtError(Status
);
970 Object
->Flags
|= WSS_LOCKED
;
972 ObDereferenceObject(Object
);
977 * NtUserUnlockWindowStation
979 * Unlocks switching desktops. Only the logon application is allowed to call this function.
986 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
988 PWINSTATION_OBJECT Object
;
992 TRACE("About to set process window station with handle (%p)\n",
995 if (gpidLogon
!= PsGetCurrentProcessId())
997 ERR("Unauthorized process attempted to unlock the window station!\n");
998 EngSetLastError(ERROR_ACCESS_DENIED
);
1002 Status
= IntValidateWindowStationHandle(
1007 if (!NT_SUCCESS(Status
))
1009 TRACE("Validation of window station handle (%p) failed\n",
1011 SetLastNtError(Status
);
1015 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1016 Object
->Flags
&= ~WSS_LOCKED
;
1018 ObDereferenceObject(Object
);
1022 static NTSTATUS FASTCALL
1023 BuildWindowStationNameList(
1026 PULONG pRequiredSize
)
1028 OBJECT_ATTRIBUTES ObjectAttributes
;
1030 HANDLE DirectoryHandle
;
1031 char InitialBuffer
[256], *Buffer
;
1032 ULONG Context
, ReturnLength
, BufferSize
;
1034 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1038 * Try to open the directory.
1040 InitializeObjectAttributes(
1042 &gustrWindowStationsDir
,
1043 OBJ_CASE_INSENSITIVE
,
1047 Status
= ZwOpenDirectoryObject(
1052 if (!NT_SUCCESS(Status
))
1057 /* First try to query the directory using a fixed-size buffer */
1060 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1061 FALSE
, TRUE
, &Context
, &ReturnLength
);
1062 if (NT_SUCCESS(Status
))
1064 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1065 FALSE
, &Context
, NULL
))
1067 /* Our fixed-size buffer is large enough */
1068 Buffer
= InitialBuffer
;
1074 /* Need a larger buffer, check how large exactly */
1075 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1077 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1079 ObDereferenceObject(DirectoryHandle
);
1080 return STATUS_NO_MEMORY
;
1083 BufferSize
= ReturnLength
;
1084 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1087 ObDereferenceObject(DirectoryHandle
);
1088 return STATUS_NO_MEMORY
;
1091 /* We should have a sufficiently large buffer now */
1093 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1094 FALSE
, TRUE
, &Context
, &ReturnLength
);
1095 if (! NT_SUCCESS(Status
) ||
1096 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1097 FALSE
, &Context
, NULL
))
1099 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1100 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1101 ObDereferenceObject(DirectoryHandle
);
1102 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1106 ZwClose(DirectoryHandle
);
1109 * Count the required size of buffer.
1111 ReturnLength
= sizeof(DWORD
);
1113 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1116 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1119 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1120 if (NULL
!= pRequiredSize
)
1122 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1123 if (! NT_SUCCESS(Status
))
1125 if (Buffer
!= InitialBuffer
)
1127 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1129 return STATUS_BUFFER_TOO_SMALL
;
1134 * Check if the supplied buffer is large enough.
1136 if (dwSize
< ReturnLength
)
1138 if (Buffer
!= InitialBuffer
)
1140 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1142 return STATUS_BUFFER_TOO_SMALL
;
1146 * Generate the resulting buffer contents.
1148 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1149 if (! NT_SUCCESS(Status
))
1151 if (Buffer
!= InitialBuffer
)
1153 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1157 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1160 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1163 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1164 if (! NT_SUCCESS(Status
))
1166 if (Buffer
!= InitialBuffer
)
1168 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1172 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1173 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1174 if (! NT_SUCCESS(Status
))
1176 if (Buffer
!= InitialBuffer
)
1178 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1182 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1188 if (Buffer
!= InitialBuffer
)
1190 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1193 return STATUS_SUCCESS
;
1196 static NTSTATUS FASTCALL
1197 BuildDesktopNameList(
1198 HWINSTA hWindowStation
,
1201 PULONG pRequiredSize
)
1204 PWINSTATION_OBJECT WindowStation
;
1205 PLIST_ENTRY DesktopEntry
;
1206 PDESKTOP DesktopObject
;
1210 UNICODE_STRING DesktopName
;
1212 Status
= IntValidateWindowStationHandle(hWindowStation
,
1216 if (! NT_SUCCESS(Status
))
1222 * Count the required size of buffer.
1224 ReturnLength
= sizeof(DWORD
);
1226 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1227 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1228 DesktopEntry
= DesktopEntry
->Flink
)
1230 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1231 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1232 ReturnLength
+= DesktopName
.Length
+ sizeof(WCHAR
);
1235 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1236 if (NULL
!= pRequiredSize
)
1238 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1239 if (! NT_SUCCESS(Status
))
1241 ObDereferenceObject(WindowStation
);
1242 return STATUS_BUFFER_TOO_SMALL
;
1247 * Check if the supplied buffer is large enough.
1249 if (dwSize
< ReturnLength
)
1251 ObDereferenceObject(WindowStation
);
1252 return STATUS_BUFFER_TOO_SMALL
;
1256 * Generate the resulting buffer contents.
1258 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1259 if (! NT_SUCCESS(Status
))
1261 ObDereferenceObject(WindowStation
);
1264 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1267 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1268 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1269 DesktopEntry
= DesktopEntry
->Flink
)
1271 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1272 RtlInitUnicodeString(&DesktopName
, DesktopObject
->pDeskInfo
->szDesktopName
);
1273 Status
= MmCopyToCaller(lpBuffer
, DesktopName
.Buffer
, DesktopName
.Length
);
1274 if (! NT_SUCCESS(Status
))
1276 ObDereferenceObject(WindowStation
);
1279 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
.Length
);
1280 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1281 if (! NT_SUCCESS(Status
))
1283 ObDereferenceObject(WindowStation
);
1286 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1290 * Clean up and return
1292 ObDereferenceObject(WindowStation
);
1293 return STATUS_SUCCESS
;
1297 * NtUserBuildNameList
1299 * Function used for enumeration of desktops or window stations.
1303 * For enumeration of window stations this parameter must be set to
1304 * zero. Otherwise it's handle for window station.
1307 * Size of buffer passed by caller.
1310 * Buffer passed by caller. If the function succedes, the buffer is
1311 * filled with window station/desktop count (in first DWORD) and
1312 * NULL-terminated window station/desktop names.
1315 * If the function suceedes, this is the number of bytes copied.
1316 * Otherwise it's size of buffer needed for function to succeed.
1323 NtUserBuildNameList(
1324 HWINSTA hWindowStation
,
1327 PULONG pRequiredSize
)
1329 /* The WindowStation name list and desktop name list are build in completely
1330 different ways. Call the appropriate function */
1331 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1332 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1339 NtUserSetLogonNotifyWindow(HWND hWnd
)
1341 if (gpidLogon
!= PsGetCurrentProcessId())
1346 if (!IntIsWindow(hWnd
))
1358 NtUserLockWorkStation(VOID
)
1361 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1363 UserEnterExclusive();
1365 if (pti
->rpdesk
== IntGetActiveDesktop())
1367 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);