2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * PURPOSE: Window stations
22 * FILE: subsys/win32k/ntuser/winsta.c
23 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * 06-06-2001 CSH Created
26 * NOTES: Exported functions set the Win32 last error value
27 * on errors. The value can be retrieved with the Win32
28 * function GetLastError().
29 * TODO: The process window station is created on
30 * the first USER32/GDI32 call not related
31 * to window station/desktop handling
34 /* INCLUDES ******************************************************************/
41 /* GLOBALS *******************************************************************/
43 /* Currently active window station */
44 PWINSTATION_OBJECT InputWindowStation
= NULL
;
46 /* INITALIZATION FUNCTIONS ****************************************************/
48 static GENERIC_MAPPING IntWindowStationMapping
=
50 STANDARD_RIGHTS_READ
| WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
,
51 STANDARD_RIGHTS_WRITE
| WINSTA_ACCESSCLIPBOARD
| WINSTA_CREATEDESKTOP
| WINSTA_WRITEATTRIBUTES
,
52 STANDARD_RIGHTS_EXECUTE
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_EXITWINDOWS
,
53 STANDARD_RIGHTS_REQUIRED
| WINSTA_ACCESSCLIPBOARD
| WINSTA_ACCESSGLOBALATOMS
| WINSTA_CREATEDESKTOP
|
54 WINSTA_ENUMDESKTOPS
| WINSTA_ENUMERATE
| WINSTA_EXITWINDOWS
|
55 WINSTA_READATTRIBUTES
| WINSTA_READSCREEN
| WINSTA_WRITEATTRIBUTES
60 InitWindowStationImpl(VOID
)
62 OBJECT_ATTRIBUTES ObjectAttributes
;
63 HANDLE WindowStationsDirectory
;
64 UNICODE_STRING UnicodeString
;
68 * Create the '\Windows\WindowStations' directory
71 RtlInitUnicodeString(&UnicodeString
, WINSTA_ROOT_NAME
);
72 InitializeObjectAttributes(&ObjectAttributes
, &UnicodeString
,
74 Status
= ZwCreateDirectoryObject(&WindowStationsDirectory
, 0,
76 if (!NT_SUCCESS(Status
))
78 DPRINT("Could not create \\Windows\\WindowStations directory "
79 "(Status 0x%X)\n", Status
);
83 /* Set Winsta Object Attributes */
84 ExWindowStationObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(WINSTATION_OBJECT
);
85 ExWindowStationObjectType
->TypeInfo
.GenericMapping
= IntWindowStationMapping
;
87 return STATUS_SUCCESS
;
91 CleanupWindowStationImpl(VOID
)
93 return STATUS_SUCCESS
;
97 IntSetupClipboard(PWINSTATION_OBJECT WinStaObj
)
99 WinStaObj
->Clipboard
= ExAllocatePool(PagedPool
, sizeof(CLIPBOARDSYSTEM
));
100 if (WinStaObj
->Clipboard
)
102 RtlZeroMemory(WinStaObj
->Clipboard
, sizeof(CLIPBOARDSYSTEM
));
108 /* OBJECT CALLBACKS **********************************************************/
111 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
113 PWINSTATION_OBJECT WinSta
= (PWINSTATION_OBJECT
)Parameters
->Object
;
115 DPRINT("Deleting window station (0x%X)\n", WinSta
);
117 RtlDestroyAtomTable(WinSta
->AtomTable
);
119 RtlFreeUnicodeString(&WinSta
->Name
);
124 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters
)
126 PUNICODE_STRING RemainingName
= Parameters
->RemainingName
;
128 /* Assume we don't find anything */
129 *Parameters
->Object
= NULL
;
131 /* Check for an empty name */
132 if (!RemainingName
->Length
)
134 /* Make sure this is a window station, can't parse a desktop now */
135 if (Parameters
->ObjectType
!= ExWindowStationObjectType
)
138 return STATUS_OBJECT_TYPE_MISMATCH
;
141 /* Reference the window station and return */
142 ObReferenceObject(Parameters
->ParseObject
);
143 *Parameters
->Object
= Parameters
->ParseObject
;
144 return STATUS_SUCCESS
;
147 /* Check for leading slash */
148 if (RemainingName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
151 RemainingName
->Buffer
++;
152 RemainingName
->Length
-= sizeof(WCHAR
);
153 RemainingName
->MaximumLength
-= sizeof(WCHAR
);
156 /* Check if there is still a slash */
157 if (wcschr(RemainingName
->Buffer
, OBJ_NAME_PATH_SEPARATOR
))
159 /* In this case, fail */
160 return STATUS_OBJECT_PATH_INVALID
;
164 * Check if we are parsing a desktop.
166 if (Parameters
->ObjectType
== ExDesktopObjectType
)
168 /* Then call the desktop parse routine */
169 return IntDesktopObjectParse(Parameters
->ParseObject
,
170 Parameters
->ObjectType
,
171 Parameters
->AccessState
,
172 Parameters
->AccessMode
,
173 Parameters
->Attributes
,
174 Parameters
->CompleteName
,
177 Parameters
->SecurityQos
,
181 /* Should hopefully never get here */
182 return STATUS_OBJECT_TYPE_MISMATCH
;
185 /* PRIVATE FUNCTIONS **********************************************************/
188 * IntGetFullWindowStationName
190 * Get a full window station object name from a name specified in
191 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
192 * or NtUserOpenDesktop.
195 * TRUE on success, FALSE on failure.
199 IntGetFullWindowStationName(
200 OUT PUNICODE_STRING FullName
,
201 IN PUNICODE_STRING WinStaName
,
202 IN OPTIONAL PUNICODE_STRING DesktopName
)
206 FullName
->Length
= WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
);
207 if (WinStaName
!= NULL
)
208 FullName
->Length
+= WinStaName
->Length
+ sizeof(WCHAR
);
209 if (DesktopName
!= NULL
)
210 FullName
->Length
+= DesktopName
->Length
+ sizeof(WCHAR
);
211 FullName
->MaximumLength
= FullName
->Length
;
212 FullName
->Buffer
= ExAllocatePoolWithTag(PagedPool
, FullName
->Length
, TAG_STRING
);
213 if (FullName
->Buffer
== NULL
)
218 Buffer
= FullName
->Buffer
;
219 memcpy(Buffer
, WINSTA_ROOT_NAME
, WINSTA_ROOT_NAME_LENGTH
* sizeof(WCHAR
));
220 Buffer
+= WINSTA_ROOT_NAME_LENGTH
;
221 if (WinStaName
!= NULL
)
223 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
225 memcpy(Buffer
, WinStaName
->Buffer
, WinStaName
->Length
);
227 if (DesktopName
!= NULL
)
229 Buffer
+= WinStaName
->Length
/ sizeof(WCHAR
);
230 memcpy(Buffer
, L
"\\", sizeof(WCHAR
));
232 memcpy(Buffer
, DesktopName
->Buffer
, DesktopName
->Length
);
240 * IntValidateWindowStationHandle
242 * Validates the window station handle.
245 * If the function succeeds, the handle remains referenced. If the
246 * fucntion fails, last error is set.
250 IntValidateWindowStationHandle(
251 HWINSTA WindowStation
,
252 KPROCESSOR_MODE AccessMode
,
253 ACCESS_MASK DesiredAccess
,
254 PWINSTATION_OBJECT
*Object
)
258 if (WindowStation
== NULL
)
260 // DPRINT1("Invalid window station handle\n");
261 SetLastWin32Error(ERROR_INVALID_HANDLE
);
262 return STATUS_INVALID_HANDLE
;
265 Status
= ObReferenceObjectByHandle(
268 ExWindowStationObjectType
,
273 if (!NT_SUCCESS(Status
))
274 SetLastNtError(Status
);
280 IntGetWindowStationObject(PWINSTATION_OBJECT Object
)
284 Status
= ObReferenceObjectByPointer(
287 ExWindowStationObjectType
,
290 return NT_SUCCESS(Status
);
295 co_IntInitializeDesktopGraphics(VOID
)
298 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
299 if (! IntCreatePrimarySurface())
303 ScreenDeviceContext
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
304 if (NULL
== ScreenDeviceContext
)
306 IntDestroyPrimarySurface();
309 IntGdiSetDCOwnerEx(ScreenDeviceContext
, GDI_OBJ_HMGR_PUBLIC
, FALSE
);
311 /* Setup the cursor */
312 co_IntLoadDefaultCursors();
314 hSystemBM
= NtGdiCreateCompatibleDC(ScreenDeviceContext
);
316 NtGdiSelectFont( hSystemBM
, NtGdiGetStockObject(SYSTEM_FONT
));
317 IntGdiSetDCOwnerEx( hSystemBM
, GDI_OBJ_HMGR_PUBLIC
, FALSE
);
319 // FIXME! Move these to a update routine.
320 gpsi
->Planes
= NtGdiGetDeviceCaps(ScreenDeviceContext
, PLANES
);
321 gpsi
->BitsPixel
= NtGdiGetDeviceCaps(ScreenDeviceContext
, BITSPIXEL
);
322 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
323 gpsi
->dmLogPixels
= NtGdiGetDeviceCaps(ScreenDeviceContext
, LOGPIXELSY
);
324 // Font is realized and this dc was previously set to internal DC_ATTR.
325 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
326 gpsi
->tmSysFont
= tmw
;
332 IntEndDesktopGraphics(VOID
)
334 if (NULL
!= ScreenDeviceContext
)
335 { // No need to allocate a new dcattr.
336 DC_SetOwnership(ScreenDeviceContext
, PsGetCurrentProcess());
337 NtGdiDeleteObjectApp(ScreenDeviceContext
);
338 ScreenDeviceContext
= NULL
;
340 IntHideDesktop(IntGetActiveDesktop());
341 IntDestroyPrimarySurface();
347 return ScreenDeviceContext
;
350 /* PUBLIC FUNCTIONS ***********************************************************/
353 * NtUserCreateWindowStation
355 * Creates a new window station.
358 * lpszWindowStationName
359 * Pointer to a null-terminated string specifying the name of the
360 * window station to be created. Window station names are
361 * case-insensitive and cannot contain backslash characters (\).
362 * Only members of the Administrators group are allowed to specify a
366 * Requested type of access
369 * Security descriptor
371 * Unknown3, Unknown4, Unknown5
375 * If the function succeeds, the return value is a handle to the newly
376 * created window station. If the specified window station already
377 * exists, the function succeeds and returns a handle to the existing
378 * window station. If the function fails, the return value is NULL.
381 * Correct the prototype to match the Windows one (with 7 parameters
389 NtUserCreateWindowStation(
390 PUNICODE_STRING lpszWindowStationName
,
391 ACCESS_MASK dwDesiredAccess
,
392 LPSECURITY_ATTRIBUTES lpSecurity
,
398 PSYSTEM_CURSORINFO CurInfo
;
399 UNICODE_STRING WindowStationName
;
400 UNICODE_STRING FullWindowStationName
;
401 PWINSTATION_OBJECT WindowStationObject
;
402 HWINSTA WindowStation
;
403 OBJECT_ATTRIBUTES ObjectAttributes
;
407 * Generate full window station name
409 Status
= ProbeAndCaptureUnicodeString(&WindowStationName
,
411 lpszWindowStationName
);
412 if (!NT_SUCCESS(Status
))
414 DPRINT1("Failed to capture window station name (status 0x%08x)\n",
416 SetLastNtError(Status
);
419 if (!IntGetFullWindowStationName(&FullWindowStationName
,
423 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
424 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
429 * Try to open already existing window station
432 DPRINT("Trying to open window station (%wZ)\n", &FullWindowStationName
);
434 /* Initialize ObjectAttributes for the window station object */
435 InitializeObjectAttributes(
437 &FullWindowStationName
,
442 Status
= ObOpenObjectByName(
444 ExWindowStationObjectType
,
449 (PVOID
*)&WindowStation
);
451 if (NT_SUCCESS(Status
))
453 DPRINT("Successfully opened window station (%wZ)\n",
454 FullWindowStationName
);
455 ExFreePool(FullWindowStationName
.Buffer
);
456 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
457 return (HWINSTA
)WindowStation
;
461 * No existing window station found, try to create new one
464 DPRINT("Creating window station (%wZ)\n", &FullWindowStationName
);
466 Status
= ObCreateObject(
468 ExWindowStationObjectType
,
472 sizeof(WINSTATION_OBJECT
),
475 (PVOID
*)&WindowStationObject
);
477 if (!NT_SUCCESS(Status
))
479 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName
);
480 ExFreePool(FullWindowStationName
.Buffer
);
481 ReleaseCapturedUnicodeString(&WindowStationName
, UserMode
);
482 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
486 /* Zero out the buffer */
487 RtlZeroMemory(WindowStationObject
, sizeof(WINSTATION_OBJECT
));
489 KeInitializeSpinLock(&WindowStationObject
->Lock
);
491 InitializeListHead(&WindowStationObject
->DesktopListHead
);
493 WindowStationObject
->AtomTable
= NULL
;
494 Status
= RtlCreateAtomTable(37, &WindowStationObject
->AtomTable
);
495 WindowStationObject
->SystemMenuTemplate
= (HANDLE
)0;
497 WindowStationObject
->Name
= WindowStationName
;
499 Status
= ObInsertObject(
500 (PVOID
)WindowStationObject
,
502 STANDARD_RIGHTS_REQUIRED
,
505 (PVOID
*)&WindowStation
);
507 if (!NT_SUCCESS(Status
))
509 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName
);
510 ExFreePool(FullWindowStationName
.Buffer
);
511 ExFreePool(WindowStationName
.Buffer
);
512 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
513 ObDereferenceObject(WindowStationObject
);
518 * Initialize the new window station object
521 WindowStationObject
->ScreenSaverRunning
= FALSE
;
523 WindowStationObject
->FlatMenu
= FALSE
;
525 if(!(CurInfo
= ExAllocatePool(PagedPool
, sizeof(SYSTEM_CURSORINFO
))))
527 ExFreePool(FullWindowStationName
.Buffer
);
528 /* FIXME - Delete window station object */
529 ObDereferenceObject(WindowStationObject
);
530 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
534 CurInfo
->Enabled
= FALSE
;
535 CurInfo
->ButtonsDown
= 0;
536 CurInfo
->CursorClipInfo
.IsClipped
= FALSE
;
537 CurInfo
->LastBtnDown
= 0;
538 CurInfo
->CurrentCursorObject
= NULL
;
539 CurInfo
->ShowingCursor
= 0;
540 CurInfo
->ClickLockActive
= FALSE
;
541 CurInfo
->ClickLockTime
= 0;
545 CurInfo->WheelScroLines = gspv.iWheelScrollLines;
546 #if (_WIN32_WINNT >= 0x0600)
547 CurInfo->WheelScroChars = gspv.iWheelScrollChars;
549 CurInfo->SwapButtons = gspv.bMouseBtnSwap;
550 CurInfo->DblClickSpeed = gspv.iDblClickTime;
551 CurInfo->DblClickWidth = gspv.iDblClickWidth;
552 CurInfo->DblClickHeight = gspv.iDblClickHeight;
554 CurInfo->MouseSpeed = gspv.iMouseSpeed;
555 CurInfo->CursorAccelerationInfo.FirstThreshold = gspv.caiMouse.FirstThreshold;
556 CurInfo->CursorAccelerationInfo.SecondThreshold = gspv.caiMouse.SecondThreshold;
557 CurInfo->CursorAccelerationInfo.Acceleration = gspv.caiMouse.Acceleration;
559 CurInfo->MouseHoverTime = gspv.iMouseHoverTime;
560 CurInfo->MouseHoverWidth = gspv.iMouseHoverWidth;
561 CurInfo->MouseHoverHeight = gspv.iMouseHoverHeight;
564 // WindowStationObject->ScreenSaverActive = FALSE;
565 // WindowStationObject->ScreenSaverTimeOut = 10;
566 WindowStationObject
->SystemCursor
= CurInfo
;
568 /* END FIXME loading from register */
570 if (!IntSetupClipboard(WindowStationObject
))
572 DPRINT1("WindowStation: Error Setting up the clipboard!!!\n");
575 if (!IntSetupCurIconHandles(WindowStationObject
))
577 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
578 /* FIXME: Complain more loudly? */
579 ExFreePool(FullWindowStationName
.Buffer
);
582 DPRINT("Window station successfully created (%wZ)\n", &FullWindowStationName
);
583 ExFreePool(FullWindowStationName
.Buffer
);
584 return WindowStation
;
588 * NtUserOpenWindowStation
590 * Opens an existing window station.
593 * lpszWindowStationName
594 * Name of the existing window station.
597 * Requested type of access.
600 * If the function succeeds, the return value is the handle to the
601 * specified window station. If the function fails, the return value
605 * The returned handle can be closed with NtUserCloseWindowStation.
612 NtUserOpenWindowStation(
613 PUNICODE_STRING lpszWindowStationName
,
614 ACCESS_MASK dwDesiredAccess
)
616 UNICODE_STRING WindowStationName
;
617 HWINSTA WindowStation
;
618 OBJECT_ATTRIBUTES ObjectAttributes
;
622 * Generate full window station name
625 if (!IntGetFullWindowStationName(&WindowStationName
, lpszWindowStationName
,
628 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
632 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName
);
634 /* Initialize ObjectAttributes for the window station object */
635 InitializeObjectAttributes(
638 OBJ_CASE_INSENSITIVE
,
642 Status
= ObOpenObjectByName(
644 ExWindowStationObjectType
,
649 (PVOID
*)&WindowStation
);
651 if (!NT_SUCCESS(Status
))
653 SetLastNtError(Status
);
654 ExFreePool(WindowStationName
.Buffer
);
658 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName
);
659 ExFreePool(WindowStationName
.Buffer
);
661 return WindowStation
;
665 * NtUserCloseWindowStation
667 * Closes a window station handle.
671 * Handle to the window station.
677 * The window station handle can be created with NtUserCreateWindowStation
678 * or NtUserOpenWindowStation. Attemps to close a handle to the window
679 * station assigned to the calling process will fail.
687 NtUserCloseWindowStation(
690 PWINSTATION_OBJECT Object
;
693 DPRINT("About to close window station handle (0x%X)\n", hWinSta
);
695 if (hWinSta
== UserGetProcessWindowStation())
700 Status
= IntValidateWindowStationHandle(
706 if (!NT_SUCCESS(Status
))
708 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta
);
713 /* FIXME - free the cursor information when actually deleting the object!! */
714 ASSERT(Object
->SystemCursor
);
715 ExFreePool(Object
->SystemCursor
);
718 ObDereferenceObject(Object
);
720 DPRINT("Closing window station handle (0x%X)\n", hWinSta
);
722 Status
= ZwClose(hWinSta
);
723 if (!NT_SUCCESS(Status
))
725 SetLastNtError(Status
);
733 * NtUserGetObjectInformation
735 * The NtUserGetObjectInformation function retrieves information about a
736 * window station or desktop object.
740 * Handle to the window station or desktop object for which to
741 * return information. This can be a handle of type HDESK or HWINSTA
742 * (for example, a handle returned by NtUserCreateWindowStation,
743 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
746 * Specifies the object information to be retrieved.
749 * Pointer to a buffer to receive the object information.
752 * Specifies the size, in bytes, of the buffer pointed to by the
756 * Pointer to a variable receiving the number of bytes required to
757 * store the requested information. If this variable's value is
758 * greater than the value of the nLength parameter when the function
759 * returns, the function returns FALSE, and none of the information
760 * is copied to the pvInfo buffer. If the value of the variable pointed
761 * to by lpnLengthNeeded is less than or equal to the value of nLength,
762 * the entire information block is copied.
765 * If the function succeeds, the return value is nonzero. If the function
766 * fails, the return value is zero.
773 NtUserGetObjectInformation(
778 PDWORD nLengthNeeded
)
780 PWINSTATION_OBJECT WinStaObject
= NULL
;
781 PDESKTOP DesktopObject
= NULL
;
786 /* try windowstation */
787 DPRINT("Trying to open window station 0x%x\n", hObject
);
788 Status
= IntValidateWindowStationHandle(
790 UserMode
,/*ExGetPreviousMode(),*/
791 GENERIC_READ
, /* FIXME: is this ok? */
795 if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_TYPE_MISMATCH
)
797 DPRINT("Failed: 0x%x\n", Status
);
798 SetLastNtError(Status
);
802 if (Status
== STATUS_OBJECT_TYPE_MISMATCH
)
805 DPRINT("Trying to open desktop 0x%x\n", hObject
);
806 Status
= IntValidateDesktopHandle(
808 UserMode
,/*ExGetPreviousMode(),*/
809 GENERIC_READ
, /* FIXME: is this ok? */
811 if (!NT_SUCCESS(Status
))
813 DPRINT("Failed: 0x%x\n", Status
);
814 SetLastNtError(Status
);
818 DPRINT("WinSta or Desktop opened!!\n");
824 Status
= STATUS_NOT_IMPLEMENTED
;
825 DPRINT1("UOI_FLAGS unimplemented!\n");
829 if (WinStaObject
!= NULL
)
831 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Buffer
;
832 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(WinStaObject
))->Length
+ 2;
833 Status
= STATUS_SUCCESS
;
835 else if (DesktopObject
!= NULL
)
837 pvData
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
;
838 nDataSize
= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ 2;
839 Status
= STATUS_SUCCESS
;
842 Status
= STATUS_INVALID_PARAMETER
;
846 if (WinStaObject
!= NULL
)
848 pvData
= L
"WindowStation";
849 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
850 Status
= STATUS_SUCCESS
;
852 else if (DesktopObject
!= NULL
)
855 nDataSize
= (wcslen(pvData
) + 1) * sizeof(WCHAR
);
856 Status
= STATUS_SUCCESS
;
859 Status
= STATUS_INVALID_PARAMETER
;
863 Status
= STATUS_NOT_IMPLEMENTED
;
864 DPRINT1("UOI_USER_SID unimplemented!\n");
868 Status
= STATUS_INVALID_PARAMETER
;
872 /* try to copy data to caller */
873 if (Status
== STATUS_SUCCESS
)
875 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength
, nDataSize
);
876 *nLengthNeeded
= nDataSize
;
877 if (nLength
>= nDataSize
)
878 Status
= MmCopyToCaller(pvInformation
, pvData
, nDataSize
);
880 Status
= STATUS_BUFFER_TOO_SMALL
;
883 /* release objects */
884 if (WinStaObject
!= NULL
)
885 ObDereferenceObject(WinStaObject
);
886 if (DesktopObject
!= NULL
)
887 ObDereferenceObject(DesktopObject
);
889 SetLastNtError(Status
);
890 return NT_SUCCESS(Status
);
894 * NtUserSetObjectInformation
896 * The NtUserSetObjectInformation function sets information about a
897 * window station or desktop object.
901 * Handle to the window station or desktop object for which to set
902 * object information. This value can be a handle of type HDESK or
906 * Specifies the object information to be set.
909 * Pointer to a buffer containing the object information.
912 * Specifies the size, in bytes, of the information contained in the
913 * buffer pointed to by pvInfo.
916 * If the function succeeds, the return value is nonzero. If the function
917 * fails the return value is zero.
925 NtUserSetObjectInformation(
931 /* FIXME: ZwQueryObject */
932 /* FIXME: ZwSetInformationObject */
933 SetLastNtError(STATUS_UNSUCCESSFUL
);
941 UserGetProcessWindowStation(VOID
)
947 if(PsGetCurrentProcess() != CsrProcess
)
949 return PsGetCurrentProcess()->Win32WindowStation
;
953 DPRINT1("Should use ObFindHandleForObject\n");
954 pti
= PsGetCurrentThreadWin32Thread();
955 Status
= ObOpenObjectByPointer(pti
->Desktop
->WindowStation
,
959 ExWindowStationObjectType
,
962 if (! NT_SUCCESS(Status
))
964 SetLastNtError(Status
);
965 DPRINT1("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
975 * NtUserGetProcessWindowStation
977 * Returns a handle to the current process window station.
980 * If the function succeeds, the return value is handle to the window
981 * station assigned to the current process. If the function fails, the
982 * return value is NULL.
989 NtUserGetProcessWindowStation(VOID
)
991 return UserGetProcessWindowStation();
994 PWINSTATION_OBJECT FASTCALL
995 IntGetWinStaObj(VOID
)
997 PWINSTATION_OBJECT WinStaObj
;
998 PTHREADINFO Win32Thread
;
999 PEPROCESS CurrentProcess
;
1002 * just a temporary hack, this will be gone soon
1005 Win32Thread
= PsGetCurrentThreadWin32Thread();
1006 if(Win32Thread
!= NULL
&& Win32Thread
->Desktop
!= NULL
)
1008 WinStaObj
= Win32Thread
->Desktop
->WindowStation
;
1009 ObReferenceObjectByPointer(WinStaObj
, KernelMode
, ExWindowStationObjectType
, 0);
1011 else if((CurrentProcess
= PsGetCurrentProcess()) != CsrProcess
)
1013 NTSTATUS Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
1017 if(!NT_SUCCESS(Status
))
1019 SetLastNtError(Status
);
1032 * NtUserSetProcessWindowStation
1034 * Assigns a window station to the current process.
1038 * Handle to the window station.
1048 NtUserSetProcessWindowStation(HWINSTA hWindowStation
)
1051 PWINSTATION_OBJECT NewWinSta
;
1054 DPRINT("About to set process window station with handle (0x%X)\n",
1057 if(PsGetCurrentProcess() == CsrProcess
)
1059 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1060 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1064 Status
= IntValidateWindowStationHandle(
1070 if (!NT_SUCCESS(Status
))
1072 DPRINT("Validation of window station handle (0x%X) failed\n",
1074 SetLastNtError(Status
);
1079 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1082 /* FIXME - dereference the old window station, etc... */
1083 hOld
= InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation
, hWindowStation
);
1085 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1086 PsGetCurrentProcess()->Win32WindowStation
);
1092 * NtUserLockWindowStation
1094 * Locks switching desktops. Only the logon application is allowed to call this function.
1101 NtUserLockWindowStation(HWINSTA hWindowStation
)
1103 PWINSTATION_OBJECT Object
;
1106 DPRINT("About to set process window station with handle (0x%X)\n",
1109 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1111 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1112 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1116 Status
= IntValidateWindowStationHandle(
1121 if (!NT_SUCCESS(Status
))
1123 DPRINT("Validation of window station handle (0x%X) failed\n",
1125 SetLastNtError(Status
);
1129 Object
->Flags
|= WSS_LOCKED
;
1131 ObDereferenceObject(Object
);
1136 * NtUserUnlockWindowStation
1138 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1145 NtUserUnlockWindowStation(HWINSTA hWindowStation
)
1147 PWINSTATION_OBJECT Object
;
1151 DPRINT("About to set process window station with handle (0x%X)\n",
1154 if(PsGetCurrentProcessWin32Process() != LogonProcess
)
1156 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1157 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1161 Status
= IntValidateWindowStationHandle(
1166 if (!NT_SUCCESS(Status
))
1168 DPRINT("Validation of window station handle (0x%X) failed\n",
1170 SetLastNtError(Status
);
1174 Ret
= (Object
->Flags
& WSS_LOCKED
) == WSS_LOCKED
;
1175 Object
->Flags
&= ~WSS_LOCKED
;
1177 ObDereferenceObject(Object
);
1182 * NtUserSetWindowStationUser
1189 NtUserSetWindowStationUser(
1200 static NTSTATUS FASTCALL
1201 BuildWindowStationNameList(
1204 PULONG pRequiredSize
)
1206 OBJECT_ATTRIBUTES ObjectAttributes
;
1208 HANDLE DirectoryHandle
;
1209 UNICODE_STRING DirectoryName
;
1210 char InitialBuffer
[256], *Buffer
;
1211 ULONG Context
, ReturnLength
, BufferSize
;
1213 POBJECT_DIRECTORY_INFORMATION DirEntry
;
1217 * Generate name of window station directory
1219 if (!IntGetFullWindowStationName(&DirectoryName
, NULL
, NULL
))
1221 return STATUS_INSUFFICIENT_RESOURCES
;
1225 * Try to open the directory.
1227 InitializeObjectAttributes(
1230 OBJ_CASE_INSENSITIVE
,
1234 Status
= ZwOpenDirectoryObject(
1239 ExFreePool(DirectoryName
.Buffer
);
1241 if (!NT_SUCCESS(Status
))
1246 /* First try to query the directory using a fixed-size buffer */
1249 Status
= ZwQueryDirectoryObject(DirectoryHandle
, InitialBuffer
, sizeof(InitialBuffer
),
1250 FALSE
, TRUE
, &Context
, &ReturnLength
);
1251 if (NT_SUCCESS(Status
))
1253 if (STATUS_NO_MORE_ENTRIES
== ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1254 FALSE
, &Context
, NULL
))
1256 /* Our fixed-size buffer is large enough */
1257 Buffer
= InitialBuffer
;
1263 /* Need a larger buffer, check how large exactly */
1264 Status
= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
, TRUE
, &Context
,
1266 if (STATUS_BUFFER_TOO_SMALL
== Status
)
1268 BufferSize
= ReturnLength
;
1269 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_WINSTA
);
1272 ObDereferenceObject(DirectoryHandle
);
1273 return STATUS_NO_MEMORY
;
1276 /* We should have a sufficiently large buffer now */
1278 Status
= ZwQueryDirectoryObject(DirectoryHandle
, Buffer
, BufferSize
,
1279 FALSE
, TRUE
, &Context
, &ReturnLength
);
1280 if (! NT_SUCCESS(Status
) ||
1281 STATUS_NO_MORE_ENTRIES
!= ZwQueryDirectoryObject(DirectoryHandle
, NULL
, 0, FALSE
,
1282 FALSE
, &Context
, NULL
))
1284 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1285 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1286 ObDereferenceObject(DirectoryHandle
);
1287 return NT_SUCCESS(Status
) ? STATUS_INTERNAL_ERROR
: Status
;
1292 ZwClose(DirectoryHandle
);
1295 * Count the required size of buffer.
1297 ReturnLength
= sizeof(DWORD
);
1299 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1302 ReturnLength
+= DirEntry
->Name
.Length
+ sizeof(WCHAR
);
1305 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1306 if (NULL
!= pRequiredSize
)
1308 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1309 if (! NT_SUCCESS(Status
))
1311 if (Buffer
!= InitialBuffer
)
1313 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1315 return STATUS_BUFFER_TOO_SMALL
;
1320 * Check if the supplied buffer is large enough.
1322 if (dwSize
< ReturnLength
)
1324 if (Buffer
!= InitialBuffer
)
1326 ExFreePoolWithTag(Buffer
, TAG_WINSTA
);
1328 return STATUS_BUFFER_TOO_SMALL
;
1332 * Generate the resulting buffer contents.
1334 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1335 if (! NT_SUCCESS(Status
))
1337 if (Buffer
!= InitialBuffer
)
1343 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1346 for (DirEntry
= (POBJECT_DIRECTORY_INFORMATION
) Buffer
; 0 != DirEntry
->Name
.Length
;
1349 Status
= MmCopyToCaller(lpBuffer
, DirEntry
->Name
.Buffer
, DirEntry
->Name
.Length
);
1350 if (! NT_SUCCESS(Status
))
1352 if (Buffer
!= InitialBuffer
)
1358 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ DirEntry
->Name
.Length
);
1359 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1360 if (! NT_SUCCESS(Status
))
1362 if (Buffer
!= InitialBuffer
)
1368 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1374 if (NULL
!= Buffer
&& Buffer
!= InitialBuffer
)
1379 return STATUS_SUCCESS
;
1382 static NTSTATUS FASTCALL
1383 BuildDesktopNameList(
1384 HWINSTA hWindowStation
,
1387 PULONG pRequiredSize
)
1390 PWINSTATION_OBJECT WindowStation
;
1392 PLIST_ENTRY DesktopEntry
;
1393 PDESKTOP DesktopObject
;
1398 Status
= IntValidateWindowStationHandle(hWindowStation
,
1402 if (! NT_SUCCESS(Status
))
1407 KeAcquireSpinLock(&WindowStation
->Lock
, &OldLevel
);
1410 * Count the required size of buffer.
1412 ReturnLength
= sizeof(DWORD
);
1414 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1415 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1416 DesktopEntry
= DesktopEntry
->Flink
)
1418 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1419 ReturnLength
+= ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
+ sizeof(WCHAR
);
1422 DPRINT("Required size: %d Entry count: %d\n", ReturnLength
, EntryCount
);
1423 if (NULL
!= pRequiredSize
)
1425 Status
= MmCopyToCaller(pRequiredSize
, &ReturnLength
, sizeof(ULONG
));
1426 if (! NT_SUCCESS(Status
))
1428 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1429 ObDereferenceObject(WindowStation
);
1430 return STATUS_BUFFER_TOO_SMALL
;
1435 * Check if the supplied buffer is large enough.
1437 if (dwSize
< ReturnLength
)
1439 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1440 ObDereferenceObject(WindowStation
);
1441 return STATUS_BUFFER_TOO_SMALL
;
1445 * Generate the resulting buffer contents.
1447 Status
= MmCopyToCaller(lpBuffer
, &EntryCount
, sizeof(DWORD
));
1448 if (! NT_SUCCESS(Status
))
1450 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1451 ObDereferenceObject(WindowStation
);
1454 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(DWORD
));
1457 for (DesktopEntry
= WindowStation
->DesktopListHead
.Flink
;
1458 DesktopEntry
!= &WindowStation
->DesktopListHead
;
1459 DesktopEntry
= DesktopEntry
->Flink
)
1461 DesktopObject
= CONTAINING_RECORD(DesktopEntry
, DESKTOP
, ListEntry
);
1462 Status
= MmCopyToCaller(lpBuffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Buffer
, ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1463 if (! NT_SUCCESS(Status
))
1465 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1466 ObDereferenceObject(WindowStation
);
1469 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ ((PUNICODE_STRING
)GET_DESKTOP_NAME(DesktopObject
))->Length
);
1470 Status
= MmCopyToCaller(lpBuffer
, &NullWchar
, sizeof(WCHAR
));
1471 if (! NT_SUCCESS(Status
))
1473 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1474 ObDereferenceObject(WindowStation
);
1477 lpBuffer
= (PVOID
) ((PCHAR
) lpBuffer
+ sizeof(WCHAR
));
1483 KeReleaseSpinLock(&WindowStation
->Lock
, OldLevel
);
1484 ObDereferenceObject(WindowStation
);
1486 return STATUS_SUCCESS
;
1490 * NtUserBuildNameList
1492 * Function used for enumeration of desktops or window stations.
1496 * For enumeration of window stations this parameter must be set to
1497 * zero. Otherwise it's handle for window station.
1500 * Size of buffer passed by caller.
1503 * Buffer passed by caller. If the function succedes, the buffer is
1504 * filled with window station/desktop count (in first DWORD) and
1505 * NULL-terminated window station/desktop names.
1508 * If the function suceedes, this is the number of bytes copied.
1509 * Otherwise it's size of buffer needed for function to succeed.
1516 NtUserBuildNameList(
1517 HWINSTA hWindowStation
,
1520 PULONG pRequiredSize
)
1522 /* The WindowStation name list and desktop name list are build in completely
1523 different ways. Call the appropriate function */
1524 return NULL
== hWindowStation
? BuildWindowStationNameList(dwSize
, lpBuffer
, pRequiredSize
) :
1525 BuildDesktopNameList(hWindowStation
, dwSize
, lpBuffer
, pRequiredSize
);