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