93e27043083af0e485294d0922cd4915f826fc14
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / winsta.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
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)
24 * REVISION HISTORY:
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
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <win32k.h>
37
38 DBG_DEFAULT_CHANNEL(UserWinsta);
39
40 /* GLOBALS *******************************************************************/
41
42 /* Currently active window station */
43 PWINSTATION_OBJECT InputWindowStation = NULL;
44
45 /* Winlogon sas window*/
46 HWND hwndSAS = NULL;
47
48 /* INITALIZATION FUNCTIONS ****************************************************/
49
50 static GENERIC_MAPPING IntWindowStationMapping =
51 {
52 STANDARD_RIGHTS_READ | WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_READATTRIBUTES | WINSTA_READSCREEN,
53 STANDARD_RIGHTS_WRITE | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES,
54 STANDARD_RIGHTS_EXECUTE | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS,
55 STANDARD_RIGHTS_REQUIRED | WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | WINSTA_CREATEDESKTOP |
56 WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_EXITWINDOWS |
57 WINSTA_READATTRIBUTES | WINSTA_READSCREEN | WINSTA_WRITEATTRIBUTES
58 };
59
60
61 INIT_FUNCTION
62 NTSTATUS
63 NTAPI
64 InitWindowStationImpl(VOID)
65 {
66 OBJECT_ATTRIBUTES ObjectAttributes;
67 HANDLE WindowStationsDirectory;
68 UNICODE_STRING UnicodeString;
69 NTSTATUS Status;
70
71 /*
72 * Create the '\Windows\WindowStations' directory
73 */
74
75 RtlInitUnicodeString(&UnicodeString, WINSTA_ROOT_NAME);
76 InitializeObjectAttributes(&ObjectAttributes, &UnicodeString,
77 0, NULL, NULL);
78 Status = ZwCreateDirectoryObject(&WindowStationsDirectory, 0,
79 &ObjectAttributes);
80 if (!NT_SUCCESS(Status))
81 {
82 TRACE("Could not create \\Windows\\WindowStations directory "
83 "(Status 0x%X)\n", Status);
84 return Status;
85 }
86
87 /* Set Winsta Object Attributes */
88 ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
89 ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
90
91 return STATUS_SUCCESS;
92 }
93
94 NTSTATUS FASTCALL
95 CleanupWindowStationImpl(VOID)
96 {
97 return STATUS_SUCCESS;
98 }
99
100 /* OBJECT CALLBACKS **********************************************************/
101
102 VOID APIENTRY
103 IntWinStaObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters)
104 {
105 PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)Parameters->Object;
106
107 TRACE("Deleting window station (0x%X)\n", WinSta);
108
109 UserEmptyClipboardData(WinSta);
110
111 RtlDestroyAtomTable(WinSta->AtomTable);
112
113 RtlFreeUnicodeString(&WinSta->Name);
114 }
115
116 NTSTATUS
117 APIENTRY
118 IntWinStaObjectParse(PWIN32_PARSEMETHOD_PARAMETERS Parameters)
119 {
120 PUNICODE_STRING RemainingName = Parameters->RemainingName;
121
122 /* Assume we don't find anything */
123 *Parameters->Object = NULL;
124
125 /* Check for an empty name */
126 if (!RemainingName->Length)
127 {
128 /* Make sure this is a window station, can't parse a desktop now */
129 if (Parameters->ObjectType != ExWindowStationObjectType)
130 {
131 /* Fail */
132 return STATUS_OBJECT_TYPE_MISMATCH;
133 }
134
135 /* Reference the window station and return */
136 ObReferenceObject(Parameters->ParseObject);
137 *Parameters->Object = Parameters->ParseObject;
138 return STATUS_SUCCESS;
139 }
140
141 /* Check for leading slash */
142 if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
143 {
144 /* Skip it */
145 RemainingName->Buffer++;
146 RemainingName->Length -= sizeof(WCHAR);
147 RemainingName->MaximumLength -= sizeof(WCHAR);
148 }
149
150 /* Check if there is still a slash */
151 if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
152 {
153 /* In this case, fail */
154 return STATUS_OBJECT_PATH_INVALID;
155 }
156
157 /*
158 * Check if we are parsing a desktop.
159 */
160 if (Parameters->ObjectType == ExDesktopObjectType)
161 {
162 /* Then call the desktop parse routine */
163 return IntDesktopObjectParse(Parameters->ParseObject,
164 Parameters->ObjectType,
165 Parameters->AccessState,
166 Parameters->AccessMode,
167 Parameters->Attributes,
168 Parameters->CompleteName,
169 RemainingName,
170 Parameters->Context,
171 Parameters->SecurityQos,
172 Parameters->Object);
173 }
174
175 /* Should hopefully never get here */
176 return STATUS_OBJECT_TYPE_MISMATCH;
177 }
178
179 NTSTATUS
180 NTAPI
181 IntWinstaOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters)
182 {
183 PPROCESSINFO ppi;
184
185 ppi = PsGetCurrentProcessWin32Process();
186
187 if(ppi && (Parameters->Handle == ppi->hwinsta))
188 {
189 return STATUS_ACCESS_DENIED;
190 }
191
192 return STATUS_SUCCESS;
193 }
194
195 /* PRIVATE FUNCTIONS **********************************************************/
196
197 /*
198 * IntGetFullWindowStationName
199 *
200 * Get a full window station object name from a name specified in
201 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
202 * or NtUserOpenDesktop.
203 *
204 * Return Value
205 * TRUE on success, FALSE on failure.
206 */
207
208 BOOL FASTCALL
209 IntGetFullWindowStationName(
210 OUT PUNICODE_STRING FullName,
211 IN PUNICODE_STRING WinStaName,
212 IN OPTIONAL PUNICODE_STRING DesktopName)
213 {
214 PWCHAR Buffer;
215
216 FullName->Length = WINSTA_ROOT_NAME_LENGTH * sizeof(WCHAR);
217 if (WinStaName != NULL)
218 FullName->Length += WinStaName->Length + sizeof(WCHAR);
219 if (DesktopName != NULL)
220 FullName->Length += DesktopName->Length + sizeof(WCHAR);
221 FullName->MaximumLength = FullName->Length;
222 FullName->Buffer = ExAllocatePoolWithTag(PagedPool, FullName->Length, TAG_STRING);
223 if (FullName->Buffer == NULL)
224 {
225 return FALSE;
226 }
227
228 Buffer = FullName->Buffer;
229 memcpy(Buffer, WINSTA_ROOT_NAME, WINSTA_ROOT_NAME_LENGTH * sizeof(WCHAR));
230 Buffer += WINSTA_ROOT_NAME_LENGTH;
231 if (WinStaName != NULL)
232 {
233 *Buffer = L'\\';
234 Buffer ++;
235 memcpy(Buffer, WinStaName->Buffer, WinStaName->Length);
236
237 if (DesktopName != NULL)
238 {
239 Buffer += WinStaName->Length / sizeof(WCHAR);
240 *Buffer = L'\\';
241 Buffer ++;
242 memcpy(Buffer, DesktopName->Buffer, DesktopName->Length);
243 }
244 }
245
246 return TRUE;
247 }
248
249 /*
250 * IntValidateWindowStationHandle
251 *
252 * Validates the window station handle.
253 *
254 * Remarks
255 * If the function succeeds, the handle remains referenced. If the
256 * fucntion fails, last error is set.
257 */
258
259 NTSTATUS FASTCALL
260 IntValidateWindowStationHandle(
261 HWINSTA WindowStation,
262 KPROCESSOR_MODE AccessMode,
263 ACCESS_MASK DesiredAccess,
264 PWINSTATION_OBJECT *Object)
265 {
266 NTSTATUS Status;
267
268 if (WindowStation == NULL)
269 {
270 // ERR("Invalid window station handle\n");
271 EngSetLastError(ERROR_INVALID_HANDLE);
272 return STATUS_INVALID_HANDLE;
273 }
274
275 Status = ObReferenceObjectByHandle(
276 WindowStation,
277 DesiredAccess,
278 ExWindowStationObjectType,
279 AccessMode,
280 (PVOID*)Object,
281 NULL);
282
283 if (!NT_SUCCESS(Status))
284 SetLastNtError(Status);
285
286 return Status;
287 }
288
289 BOOL FASTCALL
290 IntGetWindowStationObject(PWINSTATION_OBJECT Object)
291 {
292 NTSTATUS Status;
293
294 Status = ObReferenceObjectByPointer(
295 Object,
296 KernelMode,
297 ExWindowStationObjectType,
298 0);
299
300 return NT_SUCCESS(Status);
301 }
302
303
304 BOOL FASTCALL
305 co_IntInitializeDesktopGraphics(VOID)
306 {
307 TEXTMETRICW tmw;
308 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
309 if (! IntCreatePrimarySurface())
310 {
311 return FALSE;
312 }
313 ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
314 if (NULL == ScreenDeviceContext)
315 {
316 IntDestroyPrimarySurface();
317 return FALSE;
318 }
319 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
320
321 /* Setup the cursor */
322 co_IntLoadDefaultCursors();
323
324 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
325
326 NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
327 GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
328
329 // FIXME! Move these to a update routine.
330 gpsi->Planes = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
331 gpsi->BitsPixel = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
332 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
333 gpsi->dmLogPixels = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
334 // Font is realized and this dc was previously set to internal DC_ATTR.
335 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
336 gpsi->tmSysFont = tmw;
337
338 return TRUE;
339 }
340
341 VOID FASTCALL
342 IntEndDesktopGraphics(VOID)
343 {
344 if (NULL != ScreenDeviceContext)
345 { // No need to allocate a new dcattr.
346 GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
347 GreDeleteObject(ScreenDeviceContext);
348 ScreenDeviceContext = NULL;
349 }
350 IntHideDesktop(IntGetActiveDesktop());
351 IntDestroyPrimarySurface();
352 }
353
354 HDC FASTCALL
355 IntGetScreenDC(VOID)
356 {
357 return ScreenDeviceContext;
358 }
359
360 /* PUBLIC FUNCTIONS ***********************************************************/
361
362 /*
363 * NtUserCreateWindowStation
364 *
365 * Creates a new window station.
366 *
367 * Parameters
368 * lpszWindowStationName
369 * Pointer to a null-terminated string specifying the name of the
370 * window station to be created. Window station names are
371 * case-insensitive and cannot contain backslash characters (\).
372 * Only members of the Administrators group are allowed to specify a
373 * name.
374 *
375 * dwDesiredAccess
376 * Requested type of access
377 *
378 * lpSecurity
379 * Security descriptor
380 *
381 * Unknown3, Unknown4, Unknown5
382 * Unused
383 *
384 * Return Value
385 * If the function succeeds, the return value is a handle to the newly
386 * created window station. If the specified window station already
387 * exists, the function succeeds and returns a handle to the existing
388 * window station. If the function fails, the return value is NULL.
389 *
390 * Todo
391 * Correct the prototype to match the Windows one (with 7 parameters
392 * on Windows XP).
393 *
394 * Status
395 * @implemented
396 */
397
398 HWINSTA APIENTRY
399 NtUserCreateWindowStation(
400 POBJECT_ATTRIBUTES ObjectAttributes,
401 ACCESS_MASK dwDesiredAccess,
402 DWORD Unknown2,
403 DWORD Unknown3,
404 DWORD Unknown4,
405 DWORD Unknown5,
406 DWORD Unknown6)
407 {
408 UNICODE_STRING WindowStationName;
409 PWINSTATION_OBJECT WindowStationObject;
410 HWINSTA WindowStation;
411 NTSTATUS Status;
412
413 Status = ObOpenObjectByName(
414 ObjectAttributes,
415 ExWindowStationObjectType,
416 UserMode,
417 NULL,
418 dwDesiredAccess,
419 NULL,
420 (PVOID*)&WindowStation);
421
422 if (NT_SUCCESS(Status))
423 {
424 return (HWINSTA)WindowStation;
425 }
426
427
428 /*
429 * No existing window station found, try to create new one
430 */
431
432 /* Capture window station name */
433 _SEH2_TRY
434 {
435 ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
436 Status = IntSafeCopyUnicodeString(&WindowStationName, ObjectAttributes->ObjectName);
437 }
438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
439 {
440 Status =_SEH2_GetExceptionCode();
441 }
442 _SEH2_END
443
444 if (! NT_SUCCESS(Status))
445 {
446 ERR("Failed reading capturing window station name\n");
447 SetLastNtError(Status);
448 return NULL;
449 }
450
451 /* Create the window station object */
452 Status = ObCreateObject(
453 UserMode,
454 ExWindowStationObjectType,
455 ObjectAttributes,
456 UserMode,
457 NULL,
458 sizeof(WINSTATION_OBJECT),
459 0,
460 0,
461 (PVOID*)&WindowStationObject);
462
463 if (!NT_SUCCESS(Status))
464 {
465 ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
466 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
467 return 0;
468 }
469
470 Status = ObInsertObject(
471 (PVOID)WindowStationObject,
472 NULL,
473 STANDARD_RIGHTS_REQUIRED,
474 0,
475 NULL,
476 (PVOID*)&WindowStation);
477
478 if (!NT_SUCCESS(Status))
479 {
480 ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
481 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
482 ObDereferenceObject(WindowStationObject);
483 return 0;
484 }
485
486 /* Initialize the window station */
487 RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
488
489 KeInitializeSpinLock(&WindowStationObject->Lock);
490 InitializeListHead(&WindowStationObject->DesktopListHead);
491 Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
492 WindowStationObject->SystemMenuTemplate = (HANDLE)0;
493 WindowStationObject->Name = WindowStationName;
494 WindowStationObject->ScreenSaverRunning = FALSE;
495 WindowStationObject->FlatMenu = FALSE;
496
497 if (InputWindowStation == NULL)
498 {
499 InputWindowStation = WindowStationObject;
500
501 InitCursorImpl();
502 }
503
504 return WindowStation;
505 }
506
507 /*
508 * NtUserOpenWindowStation
509 *
510 * Opens an existing window station.
511 *
512 * Parameters
513 * lpszWindowStationName
514 * Name of the existing window station.
515 *
516 * dwDesiredAccess
517 * Requested type of access.
518 *
519 * Return Value
520 * If the function succeeds, the return value is the handle to the
521 * specified window station. If the function fails, the return value
522 * is NULL.
523 *
524 * Remarks
525 * The returned handle can be closed with NtUserCloseWindowStation.
526 *
527 * Status
528 * @implemented
529 */
530
531 HWINSTA APIENTRY
532 NtUserOpenWindowStation(
533 POBJECT_ATTRIBUTES ObjectAttributes,
534 ACCESS_MASK dwDesiredAccess)
535 {
536 HWINSTA WindowStation;
537 NTSTATUS Status;
538
539 Status = ObOpenObjectByName(
540 ObjectAttributes,
541 ExWindowStationObjectType,
542 UserMode,
543 NULL,
544 dwDesiredAccess,
545 NULL,
546 (PVOID*)&WindowStation);
547
548 if (!NT_SUCCESS(Status))
549 {
550 SetLastNtError(Status);
551 return 0;
552 }
553
554 return WindowStation;
555 }
556
557 /*
558 * NtUserCloseWindowStation
559 *
560 * Closes a window station handle.
561 *
562 * Parameters
563 * hWinSta
564 * Handle to the window station.
565 *
566 * Return Value
567 * Status
568 *
569 * Remarks
570 * The window station handle can be created with NtUserCreateWindowStation
571 * or NtUserOpenWindowStation. Attemps to close a handle to the window
572 * station assigned to the calling process will fail.
573 *
574 * Status
575 * @implemented
576 */
577
578 BOOL
579 APIENTRY
580 NtUserCloseWindowStation(
581 HWINSTA hWinSta)
582 {
583 PWINSTATION_OBJECT Object;
584 NTSTATUS Status;
585
586 TRACE("About to close window station handle (0x%X)\n", hWinSta);
587
588 if (hWinSta == UserGetProcessWindowStation())
589 {
590 return FALSE;
591 }
592
593 Status = IntValidateWindowStationHandle(
594 hWinSta,
595 KernelMode,
596 0,
597 &Object);
598
599 if (!NT_SUCCESS(Status))
600 {
601 TRACE("Validation of window station handle (0x%X) failed\n", hWinSta);
602 return FALSE;
603 }
604
605 ObDereferenceObject(Object);
606
607 TRACE("Closing window station handle (0x%X)\n", hWinSta);
608
609 Status = ObCloseHandle(hWinSta, UserMode);
610 if (!NT_SUCCESS(Status))
611 {
612 SetLastNtError(Status);
613 return FALSE;
614 }
615
616 return TRUE;
617 }
618
619 /*
620 * NtUserGetObjectInformation
621 *
622 * The NtUserGetObjectInformation function retrieves information about a
623 * window station or desktop object.
624 *
625 * Parameters
626 * hObj
627 * Handle to the window station or desktop object for which to
628 * return information. This can be a handle of type HDESK or HWINSTA
629 * (for example, a handle returned by NtUserCreateWindowStation,
630 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
631 *
632 * nIndex
633 * Specifies the object information to be retrieved.
634 *
635 * pvInfo
636 * Pointer to a buffer to receive the object information.
637 *
638 * nLength
639 * Specifies the size, in bytes, of the buffer pointed to by the
640 * pvInfo parameter.
641 *
642 * lpnLengthNeeded
643 * Pointer to a variable receiving the number of bytes required to
644 * store the requested information. If this variable's value is
645 * greater than the value of the nLength parameter when the function
646 * returns, the function returns FALSE, and none of the information
647 * is copied to the pvInfo buffer. If the value of the variable pointed
648 * to by lpnLengthNeeded is less than or equal to the value of nLength,
649 * the entire information block is copied.
650 *
651 * Return Value
652 * If the function succeeds, the return value is nonzero. If the function
653 * fails, the return value is zero.
654 *
655 * Status
656 * @unimplemented
657 */
658
659 BOOL APIENTRY
660 NtUserGetObjectInformation(
661 HANDLE hObject,
662 DWORD nIndex,
663 PVOID pvInformation,
664 DWORD nLength,
665 PDWORD nLengthNeeded)
666 {
667 PWINSTATION_OBJECT WinStaObject = NULL;
668 PDESKTOP DesktopObject = NULL;
669 NTSTATUS Status;
670 PVOID pvData = NULL;
671 DWORD nDataSize = 0;
672
673 /* try windowstation */
674 TRACE("Trying to open window station 0x%x\n", hObject);
675 Status = IntValidateWindowStationHandle(
676 hObject,
677 UserMode,/*ExGetPreviousMode(),*/
678 GENERIC_READ, /* FIXME: is this ok? */
679 &WinStaObject);
680
681
682 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_TYPE_MISMATCH)
683 {
684 TRACE("Failed: 0x%x\n", Status);
685 SetLastNtError(Status);
686 return FALSE;
687 }
688
689 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
690 {
691 /* try desktop */
692 TRACE("Trying to open desktop 0x%x\n", hObject);
693 Status = IntValidateDesktopHandle(
694 hObject,
695 UserMode,/*ExGetPreviousMode(),*/
696 GENERIC_READ, /* FIXME: is this ok? */
697 &DesktopObject);
698 if (!NT_SUCCESS(Status))
699 {
700 TRACE("Failed: 0x%x\n", Status);
701 SetLastNtError(Status);
702 return FALSE;
703 }
704 }
705 TRACE("WinSta or Desktop opened!!\n");
706
707 /* get data */
708 switch (nIndex)
709 {
710 case UOI_FLAGS:
711 Status = STATUS_NOT_IMPLEMENTED;
712 ERR("UOI_FLAGS unimplemented!\n");
713 break;
714
715 case UOI_NAME:
716 if (WinStaObject != NULL)
717 {
718 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Buffer;
719 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Length + 2;
720 Status = STATUS_SUCCESS;
721 }
722 else if (DesktopObject != NULL)
723 {
724 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer;
725 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + 2;
726 Status = STATUS_SUCCESS;
727 }
728 else
729 Status = STATUS_INVALID_PARAMETER;
730 break;
731
732 case UOI_TYPE:
733 if (WinStaObject != NULL)
734 {
735 pvData = L"WindowStation";
736 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
737 Status = STATUS_SUCCESS;
738 }
739 else if (DesktopObject != NULL)
740 {
741 pvData = L"Desktop";
742 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
743 Status = STATUS_SUCCESS;
744 }
745 else
746 Status = STATUS_INVALID_PARAMETER;
747 break;
748
749 case UOI_USER_SID:
750 Status = STATUS_NOT_IMPLEMENTED;
751 ERR("UOI_USER_SID unimplemented!\n");
752 break;
753
754 default:
755 Status = STATUS_INVALID_PARAMETER;
756 break;
757 }
758
759 /* try to copy data to caller */
760 if (Status == STATUS_SUCCESS)
761 {
762 TRACE("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength, nDataSize);
763 *nLengthNeeded = nDataSize;
764 if (nLength >= nDataSize)
765 Status = MmCopyToCaller(pvInformation, pvData, nDataSize);
766 else
767 Status = STATUS_BUFFER_TOO_SMALL;
768 }
769
770 /* release objects */
771 if (WinStaObject != NULL)
772 ObDereferenceObject(WinStaObject);
773 if (DesktopObject != NULL)
774 ObDereferenceObject(DesktopObject);
775
776 SetLastNtError(Status);
777 return NT_SUCCESS(Status);
778 }
779
780 /*
781 * NtUserSetObjectInformation
782 *
783 * The NtUserSetObjectInformation function sets information about a
784 * window station or desktop object.
785 *
786 * Parameters
787 * hObj
788 * Handle to the window station or desktop object for which to set
789 * object information. This value can be a handle of type HDESK or
790 * HWINSTA.
791 *
792 * nIndex
793 * Specifies the object information to be set.
794 *
795 * pvInfo
796 * Pointer to a buffer containing the object information.
797 *
798 * nLength
799 * Specifies the size, in bytes, of the information contained in the
800 * buffer pointed to by pvInfo.
801 *
802 * Return Value
803 * If the function succeeds, the return value is nonzero. If the function
804 * fails the return value is zero.
805 *
806 * Status
807 * @unimplemented
808 */
809
810 BOOL
811 APIENTRY
812 NtUserSetObjectInformation(
813 HANDLE hObject,
814 DWORD nIndex,
815 PVOID pvInformation,
816 DWORD nLength)
817 {
818 /* FIXME: ZwQueryObject */
819 /* FIXME: ZwSetInformationObject */
820 SetLastNtError(STATUS_UNSUCCESSFUL);
821 return FALSE;
822 }
823
824
825
826
827 HWINSTA FASTCALL
828 UserGetProcessWindowStation(VOID)
829 {
830 NTSTATUS Status;
831 PTHREADINFO pti;
832 HWINSTA WinSta;
833
834 if(PsGetCurrentProcess() != CsrProcess)
835 {
836 return PsGetCurrentProcess()->Win32WindowStation;
837 }
838 else
839 {
840 ERR("Should use ObFindHandleForObject\n");
841 pti = PsGetCurrentThreadWin32Thread();
842 Status = ObOpenObjectByPointer(pti->rpdesk->rpwinstaParent,
843 0,
844 NULL,
845 WINSTA_ALL_ACCESS,
846 ExWindowStationObjectType,
847 UserMode,
848 (PHANDLE) &WinSta);
849 if (! NT_SUCCESS(Status))
850 {
851 SetLastNtError(Status);
852 ERR("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
853 Status);
854 return NULL;
855 }
856 return WinSta;
857 }
858 }
859
860
861 /*
862 * NtUserGetProcessWindowStation
863 *
864 * Returns a handle to the current process window station.
865 *
866 * Return Value
867 * If the function succeeds, the return value is handle to the window
868 * station assigned to the current process. If the function fails, the
869 * return value is NULL.
870 *
871 * Status
872 * @implemented
873 */
874
875 HWINSTA APIENTRY
876 NtUserGetProcessWindowStation(VOID)
877 {
878 return UserGetProcessWindowStation();
879 }
880
881 PWINSTATION_OBJECT FASTCALL
882 IntGetWinStaObj(VOID)
883 {
884 PWINSTATION_OBJECT WinStaObj;
885 PTHREADINFO Win32Thread;
886 PEPROCESS CurrentProcess;
887
888 /*
889 * just a temporary hack, this will be gone soon
890 */
891
892 Win32Thread = PsGetCurrentThreadWin32Thread();
893 if(Win32Thread != NULL && Win32Thread->rpdesk != NULL)
894 {
895 WinStaObj = Win32Thread->rpdesk->rpwinstaParent;
896 ObReferenceObjectByPointer(WinStaObj, KernelMode, ExWindowStationObjectType, 0);
897 }
898 else if((CurrentProcess = PsGetCurrentProcess()) != CsrProcess)
899 {
900 NTSTATUS Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
901 KernelMode,
902 0,
903 &WinStaObj);
904 if(!NT_SUCCESS(Status))
905 {
906 SetLastNtError(Status);
907 return NULL;
908 }
909 }
910 else
911 {
912 WinStaObj = NULL;
913 }
914
915 return WinStaObj;
916 }
917
918 BOOL FASTCALL
919 UserSetProcessWindowStation(HWINSTA hWindowStation)
920 {
921 PPROCESSINFO ppi;
922 NTSTATUS Status;
923 HWINSTA hwinstaOld;
924 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
925
926 ppi = PsGetCurrentProcessWin32Process();
927
928 /* Reference the new window station */
929 if(hWindowStation !=NULL)
930 {
931 Status = IntValidateWindowStationHandle( hWindowStation,
932 KernelMode,
933 0,
934 &NewWinSta);
935 if (!NT_SUCCESS(Status))
936 {
937 TRACE("Validation of window station handle (0x%X) failed\n",
938 hWindowStation);
939 SetLastNtError(Status);
940 return FALSE;
941 }
942 }
943
944 OldWinSta = ppi->prpwinsta;
945 hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
946
947 /* Dereference the previous window station */
948 if(OldWinSta != NULL)
949 {
950 ObDereferenceObject(OldWinSta);
951 }
952
953 /* Check if we have a stale handle (it should happen for console apps) */
954 if(hwinstaOld != ppi->hwinsta)
955 {
956 ObCloseHandle(hwinstaOld, UserMode);
957 }
958
959 /*
960 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
961 */
962
963 PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
964
965 ppi->prpwinsta = NewWinSta;
966 ppi->hwinsta = hWindowStation;
967
968 return TRUE;
969 }
970
971 /*
972 * NtUserSetProcessWindowStation
973 *
974 * Assigns a window station to the current process.
975 *
976 * Parameters
977 * hWinSta
978 * Handle to the window station.
979 *
980 * Return Value
981 * Status
982 *
983 * Status
984 * @implemented
985 */
986
987 BOOL APIENTRY
988 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
989 {
990 BOOL ret;
991
992 UserEnterExclusive();
993
994 ret = UserSetProcessWindowStation(hWindowStation);
995
996 UserLeave();
997
998 return ret;
999 }
1000
1001 /*
1002 * NtUserLockWindowStation
1003 *
1004 * Locks switching desktops. Only the logon application is allowed to call this function.
1005 *
1006 * Status
1007 * @implemented
1008 */
1009
1010 BOOL APIENTRY
1011 NtUserLockWindowStation(HWINSTA hWindowStation)
1012 {
1013 PWINSTATION_OBJECT Object;
1014 NTSTATUS Status;
1015
1016 TRACE("About to set process window station with handle (0x%X)\n",
1017 hWindowStation);
1018
1019 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1020 {
1021 ERR("Unauthorized process attempted to lock the window station!\n");
1022 EngSetLastError(ERROR_ACCESS_DENIED);
1023 return FALSE;
1024 }
1025
1026 Status = IntValidateWindowStationHandle(
1027 hWindowStation,
1028 KernelMode,
1029 0,
1030 &Object);
1031 if (!NT_SUCCESS(Status))
1032 {
1033 TRACE("Validation of window station handle (0x%X) failed\n",
1034 hWindowStation);
1035 SetLastNtError(Status);
1036 return FALSE;
1037 }
1038
1039 Object->Flags |= WSS_LOCKED;
1040
1041 ObDereferenceObject(Object);
1042 return TRUE;
1043 }
1044
1045 /*
1046 * NtUserUnlockWindowStation
1047 *
1048 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1049 *
1050 * Status
1051 * @implemented
1052 */
1053
1054 BOOL APIENTRY
1055 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1056 {
1057 PWINSTATION_OBJECT Object;
1058 NTSTATUS Status;
1059 BOOL Ret;
1060
1061 TRACE("About to set process window station with handle (0x%X)\n",
1062 hWindowStation);
1063
1064 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1065 {
1066 ERR("Unauthorized process attempted to unlock the window station!\n");
1067 EngSetLastError(ERROR_ACCESS_DENIED);
1068 return FALSE;
1069 }
1070
1071 Status = IntValidateWindowStationHandle(
1072 hWindowStation,
1073 KernelMode,
1074 0,
1075 &Object);
1076 if (!NT_SUCCESS(Status))
1077 {
1078 TRACE("Validation of window station handle (0x%X) failed\n",
1079 hWindowStation);
1080 SetLastNtError(Status);
1081 return FALSE;
1082 }
1083
1084 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1085 Object->Flags &= ~WSS_LOCKED;
1086
1087 ObDereferenceObject(Object);
1088 return Ret;
1089 }
1090
1091 static NTSTATUS FASTCALL
1092 BuildWindowStationNameList(
1093 ULONG dwSize,
1094 PVOID lpBuffer,
1095 PULONG pRequiredSize)
1096 {
1097 OBJECT_ATTRIBUTES ObjectAttributes;
1098 NTSTATUS Status;
1099 HANDLE DirectoryHandle;
1100 UNICODE_STRING DirectoryName = RTL_CONSTANT_STRING(WINSTA_ROOT_NAME);
1101 char InitialBuffer[256], *Buffer;
1102 ULONG Context, ReturnLength, BufferSize;
1103 DWORD EntryCount;
1104 POBJECT_DIRECTORY_INFORMATION DirEntry;
1105 WCHAR NullWchar;
1106
1107 /*
1108 * Try to open the directory.
1109 */
1110 InitializeObjectAttributes(
1111 &ObjectAttributes,
1112 &DirectoryName,
1113 OBJ_CASE_INSENSITIVE,
1114 NULL,
1115 NULL);
1116
1117 Status = ZwOpenDirectoryObject(
1118 &DirectoryHandle,
1119 DIRECTORY_QUERY,
1120 &ObjectAttributes);
1121
1122 if (!NT_SUCCESS(Status))
1123 {
1124 return Status;
1125 }
1126
1127 /* First try to query the directory using a fixed-size buffer */
1128 Context = 0;
1129 Buffer = NULL;
1130 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1131 FALSE, TRUE, &Context, &ReturnLength);
1132 if (NT_SUCCESS(Status))
1133 {
1134 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1135 FALSE, &Context, NULL))
1136 {
1137 /* Our fixed-size buffer is large enough */
1138 Buffer = InitialBuffer;
1139 }
1140 }
1141
1142 if (NULL == Buffer)
1143 {
1144 /* Need a larger buffer, check how large exactly */
1145 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1146 &ReturnLength);
1147 if (STATUS_BUFFER_TOO_SMALL == Status)
1148 {
1149 BufferSize = ReturnLength;
1150 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1151 if (NULL == Buffer)
1152 {
1153 ObDereferenceObject(DirectoryHandle);
1154 return STATUS_NO_MEMORY;
1155 }
1156
1157 /* We should have a sufficiently large buffer now */
1158 Context = 0;
1159 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1160 FALSE, TRUE, &Context, &ReturnLength);
1161 if (! NT_SUCCESS(Status) ||
1162 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1163 FALSE, &Context, NULL))
1164 {
1165 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1166 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1167 ObDereferenceObject(DirectoryHandle);
1168 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1169 }
1170 }
1171 }
1172
1173 ZwClose(DirectoryHandle);
1174
1175 /*
1176 * Count the required size of buffer.
1177 */
1178 ReturnLength = sizeof(DWORD);
1179 EntryCount = 0;
1180 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1181 DirEntry++)
1182 {
1183 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1184 EntryCount++;
1185 }
1186 TRACE("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1187 if (NULL != pRequiredSize)
1188 {
1189 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1190 if (! NT_SUCCESS(Status))
1191 {
1192 if (Buffer != InitialBuffer)
1193 {
1194 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1195 }
1196 return STATUS_BUFFER_TOO_SMALL;
1197 }
1198 }
1199
1200 /*
1201 * Check if the supplied buffer is large enough.
1202 */
1203 if (dwSize < ReturnLength)
1204 {
1205 if (Buffer != InitialBuffer)
1206 {
1207 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1208 }
1209 return STATUS_BUFFER_TOO_SMALL;
1210 }
1211
1212 /*
1213 * Generate the resulting buffer contents.
1214 */
1215 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1216 if (! NT_SUCCESS(Status))
1217 {
1218 if (Buffer != InitialBuffer)
1219 {
1220 ExFreePool(Buffer);
1221 }
1222 return Status;
1223 }
1224 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1225
1226 NullWchar = L'\0';
1227 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1228 DirEntry++)
1229 {
1230 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1231 if (! NT_SUCCESS(Status))
1232 {
1233 if (Buffer != InitialBuffer)
1234 {
1235 ExFreePool(Buffer);
1236 }
1237 return Status;
1238 }
1239 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1240 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1241 if (! NT_SUCCESS(Status))
1242 {
1243 if (Buffer != InitialBuffer)
1244 {
1245 ExFreePool(Buffer);
1246 }
1247 return Status;
1248 }
1249 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1250 }
1251
1252 /*
1253 * Clean up
1254 */
1255 if (NULL != Buffer && Buffer != InitialBuffer)
1256 {
1257 ExFreePool(Buffer);
1258 }
1259
1260 return STATUS_SUCCESS;
1261 }
1262
1263 static NTSTATUS FASTCALL
1264 BuildDesktopNameList(
1265 HWINSTA hWindowStation,
1266 ULONG dwSize,
1267 PVOID lpBuffer,
1268 PULONG pRequiredSize)
1269 {
1270 NTSTATUS Status;
1271 PWINSTATION_OBJECT WindowStation;
1272 KIRQL OldLevel;
1273 PLIST_ENTRY DesktopEntry;
1274 PDESKTOP DesktopObject;
1275 DWORD EntryCount;
1276 ULONG ReturnLength;
1277 WCHAR NullWchar;
1278
1279 Status = IntValidateWindowStationHandle(hWindowStation,
1280 KernelMode,
1281 0,
1282 &WindowStation);
1283 if (! NT_SUCCESS(Status))
1284 {
1285 return Status;
1286 }
1287
1288 KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
1289
1290 /*
1291 * Count the required size of buffer.
1292 */
1293 ReturnLength = sizeof(DWORD);
1294 EntryCount = 0;
1295 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1296 DesktopEntry != &WindowStation->DesktopListHead;
1297 DesktopEntry = DesktopEntry->Flink)
1298 {
1299 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1300 ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
1301 EntryCount++;
1302 }
1303 TRACE("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1304 if (NULL != pRequiredSize)
1305 {
1306 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1307 if (! NT_SUCCESS(Status))
1308 {
1309 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1310 ObDereferenceObject(WindowStation);
1311 return STATUS_BUFFER_TOO_SMALL;
1312 }
1313 }
1314
1315 /*
1316 * Check if the supplied buffer is large enough.
1317 */
1318 if (dwSize < ReturnLength)
1319 {
1320 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1321 ObDereferenceObject(WindowStation);
1322 return STATUS_BUFFER_TOO_SMALL;
1323 }
1324
1325 /*
1326 * Generate the resulting buffer contents.
1327 */
1328 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1329 if (! NT_SUCCESS(Status))
1330 {
1331 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1332 ObDereferenceObject(WindowStation);
1333 return Status;
1334 }
1335 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1336
1337 NullWchar = L'\0';
1338 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1339 DesktopEntry != &WindowStation->DesktopListHead;
1340 DesktopEntry = DesktopEntry->Flink)
1341 {
1342 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1343 Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1344 if (! NT_SUCCESS(Status))
1345 {
1346 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1347 ObDereferenceObject(WindowStation);
1348 return Status;
1349 }
1350 lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1351 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1352 if (! NT_SUCCESS(Status))
1353 {
1354 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1355 ObDereferenceObject(WindowStation);
1356 return Status;
1357 }
1358 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1359 }
1360
1361 /*
1362 * Clean up
1363 */
1364 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1365 ObDereferenceObject(WindowStation);
1366
1367 return STATUS_SUCCESS;
1368 }
1369
1370 /*
1371 * NtUserBuildNameList
1372 *
1373 * Function used for enumeration of desktops or window stations.
1374 *
1375 * Parameters
1376 * hWinSta
1377 * For enumeration of window stations this parameter must be set to
1378 * zero. Otherwise it's handle for window station.
1379 *
1380 * dwSize
1381 * Size of buffer passed by caller.
1382 *
1383 * lpBuffer
1384 * Buffer passed by caller. If the function succedes, the buffer is
1385 * filled with window station/desktop count (in first DWORD) and
1386 * NULL-terminated window station/desktop names.
1387 *
1388 * pRequiredSize
1389 * If the function suceedes, this is the number of bytes copied.
1390 * Otherwise it's size of buffer needed for function to succeed.
1391 *
1392 * Status
1393 * @implemented
1394 */
1395
1396 NTSTATUS APIENTRY
1397 NtUserBuildNameList(
1398 HWINSTA hWindowStation,
1399 ULONG dwSize,
1400 PVOID lpBuffer,
1401 PULONG pRequiredSize)
1402 {
1403 /* The WindowStation name list and desktop name list are build in completely
1404 different ways. Call the appropriate function */
1405 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1406 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1407 }
1408
1409 /*
1410 * @implemented
1411 */
1412 BOOL APIENTRY
1413 NtUserSetLogonNotifyWindow(HWND hWnd)
1414 {
1415 if(LogonProcess != PsGetCurrentProcessWin32Process())
1416 {
1417 return FALSE;
1418 }
1419
1420 if(!IntIsWindow(hWnd))
1421 {
1422 return FALSE;
1423 }
1424
1425 hwndSAS = hWnd;
1426
1427 return TRUE;
1428 }
1429
1430 /* EOF */