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 **********************************************************/
99 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
101 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
103 TRACE("Deleting window station (0x%p)\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");
240 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
241 if (NULL
== ScreenDeviceContext
)
243 IntDestroyPrimarySurface();
246 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
);
248 if (! IntCreatePrimarySurface())
253 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
255 NtGdiSelectFont(hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
256 GreSetDCOwner(hSystemBM
, GDI_OBJ_HMGR_PUBLIC
);
258 /* Update the SERVERINFO */
259 gpsi
->aiSysMet
[SM_CXSCREEN
] = gppdevPrimary
->gdiinfo
.ulHorzRes
;
260 gpsi
->aiSysMet
[SM_CYSCREEN
] = gppdevPrimary
->gdiinfo
.ulVertRes
;
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
;
275 /* Put the pointer in the center of the screen */
276 gpsi
->ptCursor
.x
= gpsi
->aiSysMet
[SM_CXSCREEN
] / 2;
277 gpsi
->ptCursor
.y
= gpsi
->aiSysMet
[SM_CYSCREEN
] / 2;
280 UserAttachMonitor((HDEV
)gppdevPrimary
);
282 /* Setup the cursor */
283 co_IntLoadDefaultCursors();
285 /* Show the desktop */
286 pdesk
= IntGetActiveDesktop();
288 co_IntShowDesktop(pdesk
, gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
], TRUE
);
294 IntEndDesktopGraphics(VOID
)
296 if (NULL
!= ScreenDeviceContext
)
297 { // No need to allocate a new dcattr.
298 GreSetDCOwner(ScreenDeviceContext
, GDI_OBJ_HMGR_POWNED
);
299 GreDeleteObject(ScreenDeviceContext
);
300 ScreenDeviceContext
= NULL
;
302 IntHideDesktop(IntGetActiveDesktop());
303 IntDestroyPrimarySurface();
309 return ScreenDeviceContext
;
312 /* PUBLIC FUNCTIONS ***********************************************************/
315 * NtUserCreateWindowStation
317 * Creates a new window station.
320 * lpszWindowStationName
321 * Pointer to a null-terminated string specifying the name of the
322 * window station to be created. Window station names are
323 * case-insensitive and cannot contain backslash characters (\).
324 * Only members of the Administrators group are allowed to specify a
328 * Requested type of access
331 * Security descriptor
333 * Unknown3, Unknown4, Unknown5
337 * If the function succeeds, the return value is a handle to the newly
338 * created window station. If the specified window station already
339 * exists, the function succeeds and returns a handle to the existing
340 * window station. If the function fails, the return value is NULL.
343 * Correct the prototype to match the Windows one (with 7 parameters
351 NtUserCreateWindowStation(
352 POBJECT_ATTRIBUTES ObjectAttributes
,
353 ACCESS_MASK dwDesiredAccess
,
360 UNICODE_STRING WindowStationName
;
361 PWINSTATION_OBJECT WindowStationObject
;
362 HWINSTA WindowStation
;
365 TRACE("NtUserCreateWindowStation called\n");
367 Status
= ObOpenObjectByName(
369 ExWindowStationObjectType
,
374 (PVOID
*)&WindowStation
);
376 if (NT_SUCCESS(Status
))
378 TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes
->ObjectName
);
379 return (HWINSTA
)WindowStation
;
383 * No existing window station found, try to create new one
386 /* Capture window station name */
389 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
390 Status
= IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName
, ObjectAttributes
->ObjectName
);
392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
394 Status
=_SEH2_GetExceptionCode();
398 if (! NT_SUCCESS(Status
))
400 ERR("Failed reading capturing window station name\n");
401 SetLastNtError(Status
);
405 /* Create the window station object */
406 Status
= ObCreateObject(
408 ExWindowStationObjectType
,
412 sizeof(WINSTATION_OBJECT
),
415 (PVOID
*)&WindowStationObject
);
417 if (!NT_SUCCESS(Status
))
419 ERR("ObCreateObject failed for window station %wZ\n", &WindowStationName
);
420 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
421 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
425 Status
= ObInsertObject(
426 (PVOID
)WindowStationObject
,
431 (PVOID
*)&WindowStation
);
433 if (!NT_SUCCESS(Status
))
435 ERR("ObInsertObject failed for window station %wZ\n", &WindowStationName
);
436 ExFreePoolWithTag(WindowStationName
.Buffer
, TAG_STRING
);
437 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
438 ObDereferenceObject(WindowStationObject
);
442 /* Initialize the window station */
443 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
445 KeInitializeSpinLock(&WindowStationObject
->Lock
);
446 InitializeListHead(&WindowStationObject
->DesktopListHead
);
447 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
448 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
449 WindowStationObject
->Name
= WindowStationName
;
450 WindowStationObject
->dwSessionId
= NtCurrentPeb()->SessionId
;
452 if (InputWindowStation
== NULL
)
454 TRACE("Initializeing input window station\n");
455 InputWindowStation
= WindowStationObject
;
460 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
461 WindowStation
, &WindowStationObject
->Name
, WindowStation
);
462 return WindowStation
;
466 * NtUserOpenWindowStation
468 * Opens an existing window station.
471 * lpszWindowStationName
472 * Name of the existing window station.
475 * Requested type of access.
478 * If the function succeeds, the return value is the handle to the
479 * specified window station. If the function fails, the return value
483 * The returned handle can be closed with NtUserCloseWindowStation.
490 NtUserOpenWindowStation(
491 POBJECT_ATTRIBUTES ObjectAttributes
,
492 ACCESS_MASK dwDesiredAccess
)
497 Status
= ObOpenObjectByName(
499 ExWindowStationObjectType
,
506 if (!NT_SUCCESS(Status
))
508 ERR("NtUserOpenWindowStation failed\n");
509 SetLastNtError(Status
);
513 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes
->ObjectName
, hwinsta
);
519 * NtUserCloseWindowStation
521 * Closes a window station handle.
525 * Handle to the window station.
531 * The window station handle can be created with NtUserCreateWindowStation
532 * or NtUserOpenWindowStation. Attemps to close a handle to the window
533 * station assigned to the calling process will fail.
541 NtUserCloseWindowStation(
544 PWINSTATION_OBJECT Object
;
547 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta
);
549 if (hWinSta
== UserGetProcessWindowStation())
551 ERR("Attempted to close process window station\n");
555 Status
= IntValidateWindowStationHandle(
561 if (!NT_SUCCESS(Status
))
563 ERR("Validation of window station handle (%p) failed\n", hWinSta
);
567 ObDereferenceObject(Object
);
569 TRACE("Closing window station handle (%p)\n", hWinSta
);
571 Status
= ObCloseHandle(hWinSta
, UserMode
);
572 if (!NT_SUCCESS(Status
))
574 SetLastNtError(Status
);
582 * NtUserGetObjectInformation
584 * The NtUserGetObjectInformation function retrieves information about a
585 * window station or desktop object.
589 * Handle to the window station or desktop object for which to
590 * return information. This can be a handle of type HDESK or HWINSTA
591 * (for example, a handle returned by NtUserCreateWindowStation,
592 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
595 * Specifies the object information to be retrieved.
598 * Pointer to a buffer to receive the object information.
601 * Specifies the size, in bytes, of the buffer pointed to by the
605 * Pointer to a variable receiving the number of bytes required to
606 * store the requested information. If this variable's value is
607 * greater than the value of the nLength parameter when the function
608 * returns, the function returns FALSE, and none of the information
609 * is copied to the pvInfo buffer. If the value of the variable pointed
610 * to by lpnLengthNeeded is less than or equal to the value of nLength,
611 * the entire information block is copied.
614 * If the function succeeds, the return value is nonzero. If the function
615 * fails, the return value is zero.
622 NtUserGetObjectInformation(
627 PDWORD nLengthNeeded
)
629 PWINSTATION_OBJECT WinStaObject
= NULL
;
630 PDESKTOP DesktopObject
= NULL
;
635 /* try windowstation */
636 TRACE("Trying to open window station %p\n", hObject
);
637 Status
= ObReferenceObjectByHandle(
640 ExWindowStationObjectType
,
642 (PVOID
*)&WinStaObject
,
645 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
648 TRACE("Trying to open desktop %p\n", hObject
);
649 Status
= IntValidateDesktopHandle(
656 if (!NT_SUCCESS(Status
))
658 ERR("Failed: 0x%x\n", Status
);
659 SetLastNtError(Status
);
663 TRACE("WinSta or Desktop opened!!\n");
669 Status
= STATUS_NOT_IMPLEMENTED
;
670 ERR("UOI_FLAGS unimplemented!\n");
674 if (WinStaObject
!= NULL
)
676 pvData
= WinStaObject
->Name
.Buffer
;
677 nDataSize
= WinStaObject
->Name
.Length
+ sizeof(WCHAR
);
678 Status
= STATUS_SUCCESS
;
680 else if (DesktopObject
!= NULL
)
682 pvData
= DesktopObject
->pDeskInfo
->szDesktopName
;
683 nDataSize
= (wcslen(DesktopObject
->pDeskInfo
->szDesktopName
) + 1) * sizeof(WCHAR
);
684 Status
= STATUS_SUCCESS
;
687 Status
= STATUS_INVALID_PARAMETER
;
691 if (WinStaObject
!= NULL
)
693 pvData
= L
"WindowStation";
694 nDataSize
= sizeof(L
"WindowStation");
695 Status
= STATUS_SUCCESS
;
697 else if (DesktopObject
!= NULL
)
700 nDataSize
= sizeof(L
"Desktop");
701 Status
= STATUS_SUCCESS
;
704 Status
= STATUS_INVALID_PARAMETER
;
708 Status
= STATUS_NOT_IMPLEMENTED
;
709 ERR("UOI_USER_SID unimplemented!\n");
713 Status
= STATUS_INVALID_PARAMETER
;
717 /* try to copy data to caller */
718 if (Status
== STATUS_SUCCESS
)
720 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength
, nDataSize
);
721 *nLengthNeeded
= nDataSize
;
722 if (nLength
>= nDataSize
)
723 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
725 Status
= STATUS_BUFFER_TOO_SMALL
;
728 /* release objects */
729 if (WinStaObject
!= NULL
)
730 ObDereferenceObject(WinStaObject
);
731 if (DesktopObject
!= NULL
)
732 ObDereferenceObject(DesktopObject
);
734 if (!NT_SUCCESS(Status
))
736 SetLastNtError(Status
);
744 * NtUserSetObjectInformation
746 * The NtUserSetObjectInformation function sets information about a
747 * window station or desktop object.
751 * Handle to the window station or desktop object for which to set
752 * object information. This value can be a handle of type HDESK or
756 * Specifies the object information to be set.
759 * Pointer to a buffer containing the object information.
762 * Specifies the size, in bytes, of the information contained in the
763 * buffer pointed to by pvInfo.
766 * If the function succeeds, the return value is nonzero. If the function
767 * fails the return value is zero.
775 NtUserSetObjectInformation(
781 /* FIXME: ZwQueryObject */
782 /* FIXME: ZwSetInformationObject */
783 SetLastNtError(STATUS_UNSUCCESSFUL
);
791 UserGetProcessWindowStation(VOID
)
793 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
800 * NtUserGetProcessWindowStation
802 * Returns a handle to the current process window station.
805 * If the function succeeds, the return value is handle to the window
806 * station assigned to the current process. If the function fails, the
807 * return value is NULL.
814 NtUserGetProcessWindowStation(VOID
)
816 return UserGetProcessWindowStation();
820 UserSetProcessWindowStation(HWINSTA hWindowStation
)
825 PWINSTATION_OBJECT NewWinSta
= NULL
, OldWinSta
;
827 ppi
= PsGetCurrentProcessWin32Process();
829 /* Reference the new window station */
830 if(hWindowStation
!=NULL
)
832 Status
= IntValidateWindowStationHandle( hWindowStation
,
836 if (!NT_SUCCESS(Status
))
838 TRACE("Validation of window station handle (%p) failed\n",
840 SetLastNtError(Status
);
845 OldWinSta
= ppi
->prpwinsta
;
846 hwinstaOld
= PsGetProcessWin32WindowStation(ppi
->peProcess
);
848 /* Dereference the previous window station */
849 if(OldWinSta
!= NULL
)
851 ObDereferenceObject(OldWinSta
);
854 /* Check if we have a stale handle (it should happen for console apps) */
855 if(hwinstaOld
!= ppi
->hwinsta
)
857 ObCloseHandle(hwinstaOld
, UserMode
);
861 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
864 PsSetProcessWindowStation(ppi
->peProcess
, hWindowStation
);
866 ppi
->prpwinsta
= NewWinSta
;
867 ppi
->hwinsta
= hWindowStation
;
873 * NtUserSetProcessWindowStation
875 * Assigns a window station to the current process.
879 * Handle to the window station.
889 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
893 UserEnterExclusive();
895 ret
= UserSetProcessWindowStation(hWindowStation
);
903 * NtUserLockWindowStation
905 * Locks switching desktops. Only the logon application is allowed to call this function.
912 NtUserLockWindowStation(HWINSTA hWindowStation
)
914 PWINSTATION_OBJECT Object
;
917 TRACE("About to set process window station with handle (%p)\n",
920 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
922 ERR("Unauthorized process attempted to lock the window station!\n");
923 EngSetLastError(ERROR_ACCESS_DENIED
);
927 Status
= IntValidateWindowStationHandle(
932 if (!NT_SUCCESS(Status
))
934 TRACE("Validation of window station handle (%p) failed\n",
936 SetLastNtError(Status
);
940 Object
->Flags
|= WSS_LOCKED
;
942 ObDereferenceObject(Object
);
947 * NtUserUnlockWindowStation
949 * Unlocks switching desktops. Only the logon application is allowed to call this function.
956 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
958 PWINSTATION_OBJECT Object
;
962 TRACE("About to set process window station with handle (%p)\n",
965 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
967 ERR("Unauthorized process attempted to unlock the window station!\n");
968 EngSetLastError(ERROR_ACCESS_DENIED
);
972 Status
= IntValidateWindowStationHandle(
977 if (!NT_SUCCESS(Status
))
979 TRACE("Validation of window station handle (%p) failed\n",
981 SetLastNtError(Status
);
985 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
986 Object
->Flags
&= ~WSS_LOCKED
;
988 ObDereferenceObject(Object
);
992 static NTSTATUS FASTCALL
993 BuildWindowStationNameList(
996 PULONG pRequiredSize
)
998 OBJECT_ATTRIBUTES ObjectAttributes
;
1000 HANDLE DirectoryHandle
;
1001 char InitialBuffer
[256], *Buffer
;
1002 ULONG Context
, ReturnLength
, BufferSize
;
1004 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1008 * Try to open the directory.
1010 InitializeObjectAttributes(
1012 &gustrWindowStationsDir
,
1013 OBJ_CASE_INSENSITIVE
,
1017 Status
= ZwOpenDirectoryObject(
1022 if (!NT_SUCCESS(Status
))
1027 /* First try to query the directory using a fixed-size buffer */
1030 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1031 FALSE
, TRUE
, &Context
, &ReturnLength
);
1032 if (NT_SUCCESS(Status
))
1034 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1035 FALSE
, &Context
, NULL
))
1037 /* Our fixed-size buffer is large enough */
1038 Buffer
= InitialBuffer
;
1044 /* Need a larger buffer, check how large exactly */
1045 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1047 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1049 ObDereferenceObject(DirectoryHandle
);
1050 return STATUS_NO_MEMORY
;
1053 BufferSize
= ReturnLength
;
1054 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1057 ObDereferenceObject(DirectoryHandle
);
1058 return STATUS_NO_MEMORY
;
1061 /* We should have a sufficiently large buffer now */
1063 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1064 FALSE
, TRUE
, &Context
, &ReturnLength
);
1065 if (! NT_SUCCESS(Status
) ||
1066 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1067 FALSE
, &Context
, NULL
))
1069 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1070 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1071 ObDereferenceObject(DirectoryHandle
);
1072 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1076 ZwClose(DirectoryHandle
);
1079 * Count the required size of buffer.
1081 ReturnLength
= sizeof(DWORD
);
1083 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1086 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1089 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1090 if (NULL
!= pRequiredSize
)
1092 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1093 if (! NT_SUCCESS(Status
))
1095 if (Buffer
!= InitialBuffer
)
1097 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1099 return STATUS_BUFFER_TOO_SMALL
;
1104 * Check if the supplied buffer is large enough.
1106 if (dwSize
< ReturnLength
)
1108 if (Buffer
!= InitialBuffer
)
1110 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1112 return STATUS_BUFFER_TOO_SMALL
;
1116 * Generate the resulting buffer contents.
1118 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1119 if (! NT_SUCCESS(Status
))
1121 if (Buffer
!= InitialBuffer
)
1123 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1127 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1130 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1133 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1134 if (! NT_SUCCESS(Status
))
1136 if (Buffer
!= InitialBuffer
)
1138 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1142 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1143 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1144 if (! NT_SUCCESS(Status
))
1146 if (Buffer
!= InitialBuffer
)
1148 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1152 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1158 if (Buffer
!= InitialBuffer
)
1160 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1163 return STATUS_SUCCESS
;
1166 static NTSTATUS FASTCALL
1167 BuildDesktopNameList(
1168 HWINSTA hWindowStation
,
1171 PULONG pRequiredSize
)
1174 PWINSTATION_OBJECT WindowStation
;
1176 PLIST_ENTRY DesktopEntry
;
1177 PDESKTOP DesktopObject
;
1181 PUNICODE_STRING DesktopName
;
1183 Status
= IntValidateWindowStationHandle(hWindowStation
,
1187 if (! NT_SUCCESS(Status
))
1192 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1195 * Count the required size of buffer.
1197 ReturnLength
= sizeof(DWORD
);
1199 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1200 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1201 DesktopEntry
= DesktopEntry
->Flink
)
1203 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1204 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);
1205 if (DesktopName
) ReturnLength
+= DesktopName
->Length
+ sizeof(WCHAR
);
1208 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength
, EntryCount
);
1209 if (NULL
!= pRequiredSize
)
1211 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1212 if (! NT_SUCCESS(Status
))
1214 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1215 ObDereferenceObject(WindowStation
);
1216 return STATUS_BUFFER_TOO_SMALL
;
1221 * Check if the supplied buffer is large enough.
1223 if (dwSize
< ReturnLength
)
1225 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1226 ObDereferenceObject(WindowStation
);
1227 return STATUS_BUFFER_TOO_SMALL
;
1231 * Generate the resulting buffer contents.
1233 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1234 if (! NT_SUCCESS(Status
))
1236 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1237 ObDereferenceObject(WindowStation
);
1240 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1243 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1244 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1245 DesktopEntry
= DesktopEntry
->Flink
)
1247 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1248 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
1249 DesktopName
= GET_DESKTOP_NAME(DesktopObject
);/// @todo Don't mess around with the object headers!
1250 if (!DesktopName
) continue;
1252 Status
= MmCopyToCaller(lpBuffer
, DesktopName
->Buffer
, DesktopName
->Length
);
1253 if (! NT_SUCCESS(Status
))
1255 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1256 ObDereferenceObject(WindowStation
);
1259 lpBuffer
= (PVOID
) ((PCHAR
)lpBuffer
+ DesktopName
->Length
);
1260 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1261 if (! NT_SUCCESS(Status
))
1263 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1264 ObDereferenceObject(WindowStation
);
1267 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1273 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1274 ObDereferenceObject(WindowStation
);
1276 return STATUS_SUCCESS
;
1280 * NtUserBuildNameList
1282 * Function used for enumeration of desktops or window stations.
1286 * For enumeration of window stations this parameter must be set to
1287 * zero. Otherwise it's handle for window station.
1290 * Size of buffer passed by caller.
1293 * Buffer passed by caller. If the function succedes, the buffer is
1294 * filled with window station/desktop count (in first DWORD) and
1295 * NULL-terminated window station/desktop names.
1298 * If the function suceedes, this is the number of bytes copied.
1299 * Otherwise it's size of buffer needed for function to succeed.
1306 NtUserBuildNameList(
1307 HWINSTA hWindowStation
,
1310 PULONG pRequiredSize
)
1312 /* The WindowStation name list and desktop name list are build in completely
1313 different ways. Call the appropriate function */
1314 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1315 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);
1322 NtUserSetLogonNotifyWindow(HWND hWnd
)
1324 if(LogonProcess
!= PsGetCurrentProcessWin32Process())
1329 if(!IntIsWindow(hWnd
))
1341 NtUserLockWorkStation(VOID
)
1344 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1346 UserEnterExclusive();
1348 if (pti
->rpdesk
== IntGetActiveDesktop())
1350 ret
= UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_LOCK_WORKSTATION
, 0);