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