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