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