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 KeInitializeSpinLock(&WindowStationObject
->Lock
);
455 InitializeListHead(&WindowStationObject
->DesktopListHead
);
456 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
457 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
458 WindowStationObject
->Name
= WindowStationName
;
459 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
461 if (InputWindowStation
== NULL
)
463 TRACE("Initializeing input window station\n");
464 InputWindowStation
= WindowStationObject
;
469 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
470 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
471 return WindowStation
;
475 * NtUserOpenWindowStation
477 * Opens an existing window station.
480 * lpszWindowStationName
481 * Name of the existing window station.
484 * Requested type of access.
487 * If the function succeeds, the return value is the handle to the
488 * specified window station. If the function fails, the return value
492 * The returned handle can be closed with NtUserCloseWindowStation.
499 NtUserOpenWindowStation(
500 POBJECT_ATTRIBUTES ObjectAttributes
,
501 ACCESS_MASK dwDesiredAccess
)
506 Status
= ObOpenObjectByName(
508 ExWindowStationObjectType
,
515 if (!NT_SUCCESS(Status
))
517 ERR("NtUserOpenWindowStation failed\n");
518 SetLastNtError(Status
);
522 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes
->ObjectName
, hwinsta
);
528 * NtUserCloseWindowStation
530 * Closes a window station handle.
534 * Handle to the window station.
540 * The window station handle can be created with NtUserCreateWindowStation
541 * or NtUserOpenWindowStation. Attemps to close a handle to the window
542 * station assigned to the calling process will fail.
550 NtUserCloseWindowStation(
553 PWINSTATION_OBJECT Object
;
556 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
558 if (hWinSta
== UserGetProcessWindowStation())
560 ERR("Attempted to close process window station\n");
564 Status
= IntValidateWindowStationHandle(
570 if (!NT_SUCCESS(Status
))
572 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
576 ObDereferenceObject(Object
);
578 TRACE("Closing window station handle (%p)\n", hWinSta
);
580 Status
= ObCloseHandle(hWinSta
, UserMode
);
581 if (!NT_SUCCESS(Status
))
583 SetLastNtError(Status
);
591 * NtUserGetObjectInformation
593 * The NtUserGetObjectInformation function retrieves information about a
594 * window station or desktop object.
598 * Handle to the window station or desktop object for which to
599 * return information. This can be a handle of type HDESK or HWINSTA
600 * (for example, a handle returned by NtUserCreateWindowStation,
601 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
604 * Specifies the object information to be retrieved.
607 * Pointer to a buffer to receive the object information.
610 * Specifies the size, in bytes, of the buffer pointed to by the
614 * Pointer to a variable receiving the number of bytes required to
615 * store the requested information. If this variable's value is
616 * greater than the value of the nLength parameter when the function
617 * returns, the function returns FALSE, and none of the information
618 * is copied to the pvInfo buffer. If the value of the variable pointed
619 * to by lpnLengthNeeded is less than or equal to the value of nLength,
620 * the entire information block is copied.
623 * If the function succeeds, the return value is nonzero. If the function
624 * fails, the return value is zero.
631 NtUserGetObjectInformation(
636 PDWORD nLengthNeeded
)
638 PWINSTATION_OBJECT WinStaObject
= NULL
;
639 PDESKTOP DesktopObject
= NULL
;
647 ProbeForWrite(nLengthNeeded
, sizeof(*nLengthNeeded
), 1);
648 ProbeForWrite(pvInformation
, nLength
, 1);
650 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
652 SetLastNtError(_SEH2_GetExceptionCode());
657 /* try windowstation */
658 TRACE("Trying to open window station %p\n", hObject
);
659 Status
= ObReferenceObjectByHandle(
662 ExWindowStationObjectType
,
664 (PVOID
*)&WinStaObject
,
667 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
670 TRACE("Trying to open desktop %p\n", hObject
);
671 Status
= IntValidateDesktopHandle(
678 if (!NT_SUCCESS(Status
))
680 ERR("Failed: 0x%x\n", Status
);
684 TRACE("WinSta or Desktop opened!!\n");
690 Status
= STATUS_NOT_IMPLEMENTED
;
691 ERR("UOI_FLAGS unimplemented!\n");
695 if (WinStaObject
!= NULL
)
697 pvData
= WinStaObject
->Name
.Buffer
;
698 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
699 Status
= STATUS_SUCCESS
;
701 else if (DesktopObject
!= NULL
)
703 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
704 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
705 Status
= STATUS_SUCCESS
;
708 Status
= STATUS_INVALID_PARAMETER
;
712 if (WinStaObject
!= NULL
)
714 pvData
= L
"WindowStation";
715 nDataSize
= sizeof(L
"WindowStation");
716 Status
= STATUS_SUCCESS
;
718 else if (DesktopObject
!= NULL
)
721 nDataSize
= sizeof(L
"Desktop");
722 Status
= STATUS_SUCCESS
;
725 Status
= STATUS_INVALID_PARAMETER
;
729 Status
= STATUS_NOT_IMPLEMENTED
;
730 ERR("UOI_USER_SID unimplemented!\n");
734 Status
= STATUS_INVALID_PARAMETER
;
739 if (Status
== STATUS_SUCCESS
&& nLength
< nDataSize
)
740 Status
= STATUS_BUFFER_TOO_SMALL
;
745 *nLengthNeeded
= nDataSize
;
747 /* try to copy data to caller */
748 if (Status
== STATUS_SUCCESS
)
750 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
751 RtlCopyMemory(pvInformation
, pvData
, nDataSize
);
754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
756 Status
= _SEH2_GetExceptionCode();
760 /* release objects */
761 if (WinStaObject
!= NULL
)
762 ObDereferenceObject(WinStaObject
);
763 if (DesktopObject
!= NULL
)
764 ObDereferenceObject(DesktopObject
);
766 if (!NT_SUCCESS(Status
))
768 SetLastNtError(Status
);
776 * NtUserSetObjectInformation
778 * The NtUserSetObjectInformation function sets information about a
779 * window station or desktop object.
783 * Handle to the window station or desktop object for which to set
784 * object information. This value can be a handle of type HDESK or
788 * Specifies the object information to be set.
791 * Pointer to a buffer containing the object information.
794 * Specifies the size, in bytes, of the information contained in the
795 * buffer pointed to by pvInfo.
798 * If the function succeeds, the return value is nonzero. If the function
799 * fails the return value is zero.
807 NtUserSetObjectInformation(
813 /* FIXME: ZwQueryObject */
814 /* FIXME: ZwSetInformationObject */
815 SetLastNtError(STATUS_UNSUCCESSFUL
);
823 UserGetProcessWindowStation(VOID
)
825 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
832 * NtUserGetProcessWindowStation
834 * Returns a handle to the current process window station.
837 * If the function succeeds, the return value is handle to the window
838 * station assigned to the current process. If the function fails, the
839 * return value is NULL.
846 NtUserGetProcessWindowStation(VOID
)
848 return UserGetProcessWindowStation();
852 UserSetProcessWindowStation(HWINSTA hWindowStation
)
857 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
859 ppi
= PsGetCurrentProcessWin32Process();
861 /* Reference the new window station */
862 if(hWindowStation
!=NULL
)
864 Status
= IntValidateWindowStationHandle( hWindowStation
,
868 if (!NT_SUCCESS(Status
))
870 TRACE("Validation of window station handle (%p) failed\n",
872 SetLastNtError(Status
);
877 OldWinSta
= ppi
->prpwinsta
;
878 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
880 /* Dereference the previous window station */
881 if(OldWinSta
!= NULL
)
883 ObDereferenceObject(OldWinSta
);
886 /* Check if we have a stale handle (it should happen for console apps) */
887 if(hwinstaOld
!= ppi
->hwinsta
)
889 ObCloseHandle(hwinstaOld
, UserMode
);
893 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
896 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
898 ppi
->prpwinsta
= NewWinSta
;
899 ppi
->hwinsta
= hWindowStation
;
905 * NtUserSetProcessWindowStation
907 * Assigns a window station to the current process.
911 * Handle to the window station.
921 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
925 UserEnterExclusive();
927 ret
= UserSetProcessWindowStation(hWindowStation
);
935 * NtUserLockWindowStation
937 * Locks switching desktops. Only the logon application is allowed to call this function.
944 NtUserLockWindowStation(HWINSTA hWindowStation
)
946 PWINSTATION_OBJECT Object
;
949 TRACE("About to set process window station with handle (%p)\n",
952 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
954 ERR("Unauthorized process attempted to lock the window station!\n");
955 EngSetLastError(ERROR_ACCESS_DENIED
);
959 Status
= IntValidateWindowStationHandle(
964 if (!NT_SUCCESS(Status
))
966 TRACE("Validation of window station handle (%p) failed\n",
968 SetLastNtError(Status
);
972 Object
->Flags
|= WSS_LOCKED
;
974 ObDereferenceObject(Object
);
979 * NtUserUnlockWindowStation
981 * Unlocks switching desktops. Only the logon application is allowed to call this function.
988 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
990 PWINSTATION_OBJECT Object
;
994 TRACE("About to set process window station with handle (%p)\n",
997 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
999 ERR("Unauthorized process attempted to unlock the window station!\n");
1000 EngSetLastError(ERROR_ACCESS_DENIED
);
1004 Status
= IntValidateWindowStationHandle(
1009 if (!NT_SUCCESS(Status
))
1011 TRACE("Validation of window station handle (%p) failed\n",
1013 SetLastNtError(Status
);
1017 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1018 Object
->Flags
&= ~WSS_LOCKED
;
1020 ObDereferenceObject(Object
);
1024 static NTSTATUS FASTCALL
1025 BuildWindowStationNameList(
1028 PULONG pRequiredSize
)
1030 OBJECT_ATTRIBUTES ObjectAttributes
;
1032 HANDLE DirectoryHandle
;
1033 char InitialBuffer
[256], *Buffer
;
1034 ULONG Context
, ReturnLength
, BufferSize
;
1036 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1040 * Try to open the directory.
1042 InitializeObjectAttributes(
1044 &gustrWindowStationsDir
,
1045 OBJ_CASE_INSENSITIVE
,
1049 Status
= ZwOpenDirectoryObject(
1054 if (!NT_SUCCESS(Status
))
1059 /* First try to query the directory using a fixed-size buffer */
1062 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1063 FALSE
, TRUE
, &Context
, &ReturnLength
);
1064 if (NT_SUCCESS(Status
))
1066 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1067 FALSE
, &Context
, NULL
))
1069 /* Our fixed-size buffer is large enough */
1070 Buffer
= InitialBuffer
;
1076 /* Need a larger buffer, check how large exactly */
1077 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1079 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1081 ObDereferenceObject(DirectoryHandle
);
1082 return STATUS_NO_MEMORY
;
1085 BufferSize
= ReturnLength
;
1086 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1089 ObDereferenceObject(DirectoryHandle
);
1090 return STATUS_NO_MEMORY
;
1093 /* We should have a sufficiently large buffer now */
1095 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1096 FALSE
, TRUE
, &Context
, &ReturnLength
);
1097 if (! NT_SUCCESS(Status
) ||
1098 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1099 FALSE
, &Context
, NULL
))
1101 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1102 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1103 ObDereferenceObject(DirectoryHandle
);
1104 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1108 ZwClose(DirectoryHandle
);
1111 * Count the required size of buffer.
1113 ReturnLength
= sizeof(DWORD
);
1115 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1118 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1121 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1122 if (NULL
!= pRequiredSize
)
1124 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1125 if (! NT_SUCCESS(Status
))
1127 if (Buffer
!= InitialBuffer
)
1129 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1131 return STATUS_BUFFER_TOO_SMALL
;
1136 * Check if the supplied buffer is large enough.
1138 if (dwSize
< ReturnLength
)
1140 if (Buffer
!= InitialBuffer
)
1142 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1144 return STATUS_BUFFER_TOO_SMALL
;
1148 * Generate the resulting buffer contents.
1150 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1151 if (! NT_SUCCESS(Status
))
1153 if (Buffer
!= InitialBuffer
)
1155 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1159 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1162 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1165 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1166 if (! NT_SUCCESS(Status
))
1168 if (Buffer
!= InitialBuffer
)
1170 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1174 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1175 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1176 if (! NT_SUCCESS(Status
))
1178 if (Buffer
!= InitialBuffer
)
1180 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1184 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1190 if (Buffer
!= InitialBuffer
)
1192 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1195 return STATUS_SUCCESS
;
1198 static NTSTATUS FASTCALL
1199 BuildDesktopNameList(
1200 HWINSTA hWindowStation
,
1203 PULONG pRequiredSize
)
1206 PWINSTATION_OBJECT WindowStation
;
1208 PLIST_ENTRY DesktopEntry
;
1209 PDESKTOP DesktopObject
;
1213 PUNICODE_STRING DesktopName
;
1215 Status
= IntValidateWindowStationHandle(hWindowStation
,
1219 if (! NT_SUCCESS(Status
))
1224 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1227 * Count the required size of buffer.
1229 ReturnLength
= sizeof(DWORD
);
1231 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1232 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1233 DesktopEntry
= DesktopEntry
->Flink
)
1235 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1236 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);
1237 if (DesktopName
) ReturnLength
+= DesktopName
->Length
+ sizeof(WCHAR
);
1240 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1241 if (NULL
!= pRequiredSize
)
1243 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1244 if (! NT_SUCCESS(Status
))
1246 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1247 ObDereferenceObject(WindowStation
);
1248 return STATUS_BUFFER_TOO_SMALL
;
1253 * Check if the supplied buffer is large enough.
1255 if (dwSize
< ReturnLength
)
1257 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1258 ObDereferenceObject(WindowStation
);
1259 return STATUS_BUFFER_TOO_SMALL
;
1263 * Generate the resulting buffer contents.
1265 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1266 if (! NT_SUCCESS(Status
))
1268 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1269 ObDereferenceObject(WindowStation
);
1272 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1275 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1276 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1277 DesktopEntry
= DesktopEntry
->Flink
)
1279 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1280 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
1281 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);/// @todo Don't mess around with the object headers!
1282 if (!DesktopName
) continue;
1284 Status
= MmCopyToCaller(lpBuffer
, DesktopName
->Buffer
, DesktopName
->Length
);
1285 if (! NT_SUCCESS(Status
))
1287 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1288 ObDereferenceObject(WindowStation
);
1291 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
->Length
);
1292 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1293 if (! NT_SUCCESS(Status
))
1295 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1296 ObDereferenceObject(WindowStation
);
1299 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1305 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1306 ObDereferenceObject(WindowStation
);
1308 return STATUS_SUCCESS
;
1312 * NtUserBuildNameList
1314 * Function used for enumeration of desktops or window stations.
1318 * For enumeration of window stations this parameter must be set to
1319 * zero. Otherwise it's handle for window station.
1322 * Size of buffer passed by caller.
1325 * Buffer passed by caller. If the function succedes, the buffer is
1326 * filled with window station/desktop count (in first DWORD) and
1327 * NULL-terminated window station/desktop names.
1330 * If the function suceedes, this is the number of bytes copied.
1331 * Otherwise it's size of buffer needed for function to succeed.
1338 NtUserBuildNameList(
1339 HWINSTA hWindowStation
,
1342 PULONG pRequiredSize
)
1344 /* The WindowStation name list and desktop name list are build in completely
1345 different ways. Call the appropriate function */
1346 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1347 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1354 NtUserSetLogonNotifyWindow(HWND hWnd
)
1356 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1361 if(!IntIsWindow(hWnd
))
1373 NtUserLockWorkStation(VOID
)
1376 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1378 UserEnterExclusive();
1380 if (pti
->rpdesk
== IntGetActiveDesktop())
1382 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);