[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / winsta.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * PURPOSE: Window stations
22 * FILE: subsys/win32k/ntuser/winsta.c
23 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * REVISION HISTORY:
25 * 06-06-2001 CSH Created
26 * NOTES: Exported functions set the Win32 last error value
27 * on errors. The value can be retrieved with the Win32
28 * function GetLastError().
29 * TODO: The process window station is created on
30 * the first USER32/GDI32 call not related
31 * to window station/desktop handling
32 */
33
34 /* INCLUDES ******************************************************************/
35
36 #include <win32k.h>
37
38 #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 IntGdiSetDCOwnerEx(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC, FALSE);
330
331 /* Setup the cursor */
332 co_IntLoadDefaultCursors();
333
334 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
335
336 NtGdiSelectFont( hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
337 IntGdiSetDCOwnerEx( hSystemBM, GDI_OBJ_HMGR_PUBLIC, FALSE);
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 DC_SetOwnership(ScreenDeviceContext, PsGetCurrentProcess());
357 NtGdiDeleteObjectApp(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 = ZwClose(hWinSta);
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 if(hWindowStation !=NULL)
944 {
945 Status = IntValidateWindowStationHandle( hWindowStation,
946 KernelMode,
947 0,
948 &NewWinSta);
949 if (!NT_SUCCESS(Status))
950 {
951 DPRINT("Validation of window station handle (0x%X) failed\n",
952 hWindowStation);
953 SetLastNtError(Status);
954 return FALSE;
955 }
956 }
957
958 OldWinSta = ppi->prpwinsta;
959 hwinstaOld = ppi->hwinsta;
960
961 /*
962 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
963 */
964
965 InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
966
967 ppi->prpwinsta = NewWinSta;
968 ppi->hwinsta = hWindowStation;
969
970
971 if(OldWinSta != NULL)
972 {
973 ObDereferenceObject(OldWinSta);
974 }
975
976 if(hwinstaOld != NULL)
977 {
978 ZwClose(hwinstaOld);
979 }
980
981 return TRUE;
982 }
983
984 /*
985 * NtUserSetProcessWindowStation
986 *
987 * Assigns a window station to the current process.
988 *
989 * Parameters
990 * hWinSta
991 * Handle to the window station.
992 *
993 * Return Value
994 * Status
995 *
996 * Status
997 * @implemented
998 */
999
1000 BOOL APIENTRY
1001 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1002 {
1003 BOOL ret;
1004
1005 UserEnterExclusive();
1006
1007 ret = UserSetProcessWindowStation(hWindowStation);
1008
1009 UserLeave();
1010
1011 return ret;
1012 }
1013
1014 /*
1015 * NtUserLockWindowStation
1016 *
1017 * Locks switching desktops. Only the logon application is allowed to call this function.
1018 *
1019 * Status
1020 * @implemented
1021 */
1022
1023 BOOL APIENTRY
1024 NtUserLockWindowStation(HWINSTA hWindowStation)
1025 {
1026 PWINSTATION_OBJECT Object;
1027 NTSTATUS Status;
1028
1029 DPRINT("About to set process window station with handle (0x%X)\n",
1030 hWindowStation);
1031
1032 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1033 {
1034 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1035 EngSetLastError(ERROR_ACCESS_DENIED);
1036 return FALSE;
1037 }
1038
1039 Status = IntValidateWindowStationHandle(
1040 hWindowStation,
1041 KernelMode,
1042 0,
1043 &Object);
1044 if (!NT_SUCCESS(Status))
1045 {
1046 DPRINT("Validation of window station handle (0x%X) failed\n",
1047 hWindowStation);
1048 SetLastNtError(Status);
1049 return FALSE;
1050 }
1051
1052 Object->Flags |= WSS_LOCKED;
1053
1054 ObDereferenceObject(Object);
1055 return TRUE;
1056 }
1057
1058 /*
1059 * NtUserUnlockWindowStation
1060 *
1061 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1062 *
1063 * Status
1064 * @implemented
1065 */
1066
1067 BOOL APIENTRY
1068 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1069 {
1070 PWINSTATION_OBJECT Object;
1071 NTSTATUS Status;
1072 BOOL Ret;
1073
1074 DPRINT("About to set process window station with handle (0x%X)\n",
1075 hWindowStation);
1076
1077 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1078 {
1079 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1080 EngSetLastError(ERROR_ACCESS_DENIED);
1081 return FALSE;
1082 }
1083
1084 Status = IntValidateWindowStationHandle(
1085 hWindowStation,
1086 KernelMode,
1087 0,
1088 &Object);
1089 if (!NT_SUCCESS(Status))
1090 {
1091 DPRINT("Validation of window station handle (0x%X) failed\n",
1092 hWindowStation);
1093 SetLastNtError(Status);
1094 return FALSE;
1095 }
1096
1097 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1098 Object->Flags &= ~WSS_LOCKED;
1099
1100 ObDereferenceObject(Object);
1101 return Ret;
1102 }
1103
1104 static NTSTATUS FASTCALL
1105 BuildWindowStationNameList(
1106 ULONG dwSize,
1107 PVOID lpBuffer,
1108 PULONG pRequiredSize)
1109 {
1110 OBJECT_ATTRIBUTES ObjectAttributes;
1111 NTSTATUS Status;
1112 HANDLE DirectoryHandle;
1113 UNICODE_STRING DirectoryName = RTL_CONSTANT_STRING(WINSTA_ROOT_NAME);
1114 char InitialBuffer[256], *Buffer;
1115 ULONG Context, ReturnLength, BufferSize;
1116 DWORD EntryCount;
1117 POBJECT_DIRECTORY_INFORMATION DirEntry;
1118 WCHAR NullWchar;
1119
1120 /*
1121 * Try to open the directory.
1122 */
1123 InitializeObjectAttributes(
1124 &ObjectAttributes,
1125 &DirectoryName,
1126 OBJ_CASE_INSENSITIVE,
1127 NULL,
1128 NULL);
1129
1130 Status = ZwOpenDirectoryObject(
1131 &DirectoryHandle,
1132 DIRECTORY_QUERY,
1133 &ObjectAttributes);
1134
1135 if (!NT_SUCCESS(Status))
1136 {
1137 return Status;
1138 }
1139
1140 /* First try to query the directory using a fixed-size buffer */
1141 Context = 0;
1142 Buffer = NULL;
1143 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1144 FALSE, TRUE, &Context, &ReturnLength);
1145 if (NT_SUCCESS(Status))
1146 {
1147 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1148 FALSE, &Context, NULL))
1149 {
1150 /* Our fixed-size buffer is large enough */
1151 Buffer = InitialBuffer;
1152 }
1153 }
1154
1155 if (NULL == Buffer)
1156 {
1157 /* Need a larger buffer, check how large exactly */
1158 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1159 &ReturnLength);
1160 if (STATUS_BUFFER_TOO_SMALL == Status)
1161 {
1162 BufferSize = ReturnLength;
1163 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1164 if (NULL == Buffer)
1165 {
1166 ObDereferenceObject(DirectoryHandle);
1167 return STATUS_NO_MEMORY;
1168 }
1169
1170 /* We should have a sufficiently large buffer now */
1171 Context = 0;
1172 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1173 FALSE, TRUE, &Context, &ReturnLength);
1174 if (! NT_SUCCESS(Status) ||
1175 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1176 FALSE, &Context, NULL))
1177 {
1178 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1179 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1180 ObDereferenceObject(DirectoryHandle);
1181 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1182 }
1183 }
1184 }
1185
1186 ZwClose(DirectoryHandle);
1187
1188 /*
1189 * Count the required size of buffer.
1190 */
1191 ReturnLength = sizeof(DWORD);
1192 EntryCount = 0;
1193 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1194 DirEntry++)
1195 {
1196 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1197 EntryCount++;
1198 }
1199 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1200 if (NULL != pRequiredSize)
1201 {
1202 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1203 if (! NT_SUCCESS(Status))
1204 {
1205 if (Buffer != InitialBuffer)
1206 {
1207 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1208 }
1209 return STATUS_BUFFER_TOO_SMALL;
1210 }
1211 }
1212
1213 /*
1214 * Check if the supplied buffer is large enough.
1215 */
1216 if (dwSize < ReturnLength)
1217 {
1218 if (Buffer != InitialBuffer)
1219 {
1220 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1221 }
1222 return STATUS_BUFFER_TOO_SMALL;
1223 }
1224
1225 /*
1226 * Generate the resulting buffer contents.
1227 */
1228 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1229 if (! NT_SUCCESS(Status))
1230 {
1231 if (Buffer != InitialBuffer)
1232 {
1233 ExFreePool(Buffer);
1234 }
1235 return Status;
1236 }
1237 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1238
1239 NullWchar = L'\0';
1240 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1241 DirEntry++)
1242 {
1243 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1244 if (! NT_SUCCESS(Status))
1245 {
1246 if (Buffer != InitialBuffer)
1247 {
1248 ExFreePool(Buffer);
1249 }
1250 return Status;
1251 }
1252 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1253 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1254 if (! NT_SUCCESS(Status))
1255 {
1256 if (Buffer != InitialBuffer)
1257 {
1258 ExFreePool(Buffer);
1259 }
1260 return Status;
1261 }
1262 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1263 }
1264
1265 /*
1266 * Clean up
1267 */
1268 if (NULL != Buffer && Buffer != InitialBuffer)
1269 {
1270 ExFreePool(Buffer);
1271 }
1272
1273 return STATUS_SUCCESS;
1274 }
1275
1276 static NTSTATUS FASTCALL
1277 BuildDesktopNameList(
1278 HWINSTA hWindowStation,
1279 ULONG dwSize,
1280 PVOID lpBuffer,
1281 PULONG pRequiredSize)
1282 {
1283 NTSTATUS Status;
1284 PWINSTATION_OBJECT WindowStation;
1285 KIRQL OldLevel;
1286 PLIST_ENTRY DesktopEntry;
1287 PDESKTOP DesktopObject;
1288 DWORD EntryCount;
1289 ULONG ReturnLength;
1290 WCHAR NullWchar;
1291
1292 Status = IntValidateWindowStationHandle(hWindowStation,
1293 KernelMode,
1294 0,
1295 &WindowStation);
1296 if (! NT_SUCCESS(Status))
1297 {
1298 return Status;
1299 }
1300
1301 KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
1302
1303 /*
1304 * Count the required size of buffer.
1305 */
1306 ReturnLength = sizeof(DWORD);
1307 EntryCount = 0;
1308 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1309 DesktopEntry != &WindowStation->DesktopListHead;
1310 DesktopEntry = DesktopEntry->Flink)
1311 {
1312 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1313 ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
1314 EntryCount++;
1315 }
1316 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1317 if (NULL != pRequiredSize)
1318 {
1319 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1320 if (! NT_SUCCESS(Status))
1321 {
1322 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1323 ObDereferenceObject(WindowStation);
1324 return STATUS_BUFFER_TOO_SMALL;
1325 }
1326 }
1327
1328 /*
1329 * Check if the supplied buffer is large enough.
1330 */
1331 if (dwSize < ReturnLength)
1332 {
1333 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1334 ObDereferenceObject(WindowStation);
1335 return STATUS_BUFFER_TOO_SMALL;
1336 }
1337
1338 /*
1339 * Generate the resulting buffer contents.
1340 */
1341 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1342 if (! NT_SUCCESS(Status))
1343 {
1344 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1345 ObDereferenceObject(WindowStation);
1346 return Status;
1347 }
1348 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1349
1350 NullWchar = L'\0';
1351 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1352 DesktopEntry != &WindowStation->DesktopListHead;
1353 DesktopEntry = DesktopEntry->Flink)
1354 {
1355 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1356 Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1357 if (! NT_SUCCESS(Status))
1358 {
1359 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1360 ObDereferenceObject(WindowStation);
1361 return Status;
1362 }
1363 lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1364 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1365 if (! NT_SUCCESS(Status))
1366 {
1367 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1368 ObDereferenceObject(WindowStation);
1369 return Status;
1370 }
1371 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1372 }
1373
1374 /*
1375 * Clean up
1376 */
1377 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1378 ObDereferenceObject(WindowStation);
1379
1380 return STATUS_SUCCESS;
1381 }
1382
1383 /*
1384 * NtUserBuildNameList
1385 *
1386 * Function used for enumeration of desktops or window stations.
1387 *
1388 * Parameters
1389 * hWinSta
1390 * For enumeration of window stations this parameter must be set to
1391 * zero. Otherwise it's handle for window station.
1392 *
1393 * dwSize
1394 * Size of buffer passed by caller.
1395 *
1396 * lpBuffer
1397 * Buffer passed by caller. If the function succedes, the buffer is
1398 * filled with window station/desktop count (in first DWORD) and
1399 * NULL-terminated window station/desktop names.
1400 *
1401 * pRequiredSize
1402 * If the function suceedes, this is the number of bytes copied.
1403 * Otherwise it's size of buffer needed for function to succeed.
1404 *
1405 * Status
1406 * @implemented
1407 */
1408
1409 NTSTATUS APIENTRY
1410 NtUserBuildNameList(
1411 HWINSTA hWindowStation,
1412 ULONG dwSize,
1413 PVOID lpBuffer,
1414 PULONG pRequiredSize)
1415 {
1416 /* The WindowStation name list and desktop name list are build in completely
1417 different ways. Call the appropriate function */
1418 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1419 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1420 }
1421
1422 /*
1423 * @implemented
1424 */
1425 BOOL APIENTRY
1426 NtUserSetLogonNotifyWindow(HWND hWnd)
1427 {
1428 if(LogonProcess != PsGetCurrentProcessWin32Process())
1429 {
1430 return FALSE;
1431 }
1432
1433 if(!IntIsWindow(hWnd))
1434 {
1435 return FALSE;
1436 }
1437
1438 hwndSAS = hWnd;
1439
1440 return TRUE;
1441 }
1442
1443 /* EOF */