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