[KERNEL32][CONSRV]
[reactos.git] / 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 InitializeListHead(&WindowStationObject->DesktopListHead);
455 Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
456 WindowStationObject->Name = WindowStationName;
457 WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
458
459 if (InputWindowStation == NULL)
460 {
461 TRACE("Initializeing input window station\n");
462 InputWindowStation = WindowStationObject;
463
464 InitCursorImpl();
465 }
466
467 TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
468 WindowStation, &WindowStationObject->Name, WindowStation);
469 return WindowStation;
470 }
471
472 /*
473 * NtUserOpenWindowStation
474 *
475 * Opens an existing window station.
476 *
477 * Parameters
478 * lpszWindowStationName
479 * Name of the existing window station.
480 *
481 * dwDesiredAccess
482 * Requested type of access.
483 *
484 * Return Value
485 * If the function succeeds, the return value is the handle to the
486 * specified window station. If the function fails, the return value
487 * is NULL.
488 *
489 * Remarks
490 * The returned handle can be closed with NtUserCloseWindowStation.
491 *
492 * Status
493 * @implemented
494 */
495
496 HWINSTA APIENTRY
497 NtUserOpenWindowStation(
498 POBJECT_ATTRIBUTES ObjectAttributes,
499 ACCESS_MASK dwDesiredAccess)
500 {
501 HWINSTA hwinsta;
502 NTSTATUS Status;
503
504 Status = ObOpenObjectByName(
505 ObjectAttributes,
506 ExWindowStationObjectType,
507 UserMode,
508 NULL,
509 dwDesiredAccess,
510 NULL,
511 (PVOID*)&hwinsta);
512
513 if (!NT_SUCCESS(Status))
514 {
515 ERR("NtUserOpenWindowStation failed\n");
516 SetLastNtError(Status);
517 return 0;
518 }
519
520 TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
521
522 return hwinsta;
523 }
524
525 /*
526 * NtUserCloseWindowStation
527 *
528 * Closes a window station handle.
529 *
530 * Parameters
531 * hWinSta
532 * Handle to the window station.
533 *
534 * Return Value
535 * Status
536 *
537 * Remarks
538 * The window station handle can be created with NtUserCreateWindowStation
539 * or NtUserOpenWindowStation. Attemps to close a handle to the window
540 * station assigned to the calling process will fail.
541 *
542 * Status
543 * @implemented
544 */
545
546 BOOL
547 APIENTRY
548 NtUserCloseWindowStation(
549 HWINSTA hWinSta)
550 {
551 PWINSTATION_OBJECT Object;
552 NTSTATUS Status;
553
554 TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
555
556 if (hWinSta == UserGetProcessWindowStation())
557 {
558 ERR("Attempted to close process window station\n");
559 return FALSE;
560 }
561
562 Status = IntValidateWindowStationHandle(
563 hWinSta,
564 KernelMode,
565 0,
566 &Object);
567
568 if (!NT_SUCCESS(Status))
569 {
570 ERR("Validation of window station handle (%p) failed\n", hWinSta);
571 return FALSE;
572 }
573
574 ObDereferenceObject(Object);
575
576 TRACE("Closing window station handle (%p)\n", hWinSta);
577
578 Status = ObCloseHandle(hWinSta, UserMode);
579 if (!NT_SUCCESS(Status))
580 {
581 SetLastNtError(Status);
582 return FALSE;
583 }
584
585 return TRUE;
586 }
587
588 /*
589 * NtUserGetObjectInformation
590 *
591 * The NtUserGetObjectInformation function retrieves information about a
592 * window station or desktop object.
593 *
594 * Parameters
595 * hObj
596 * Handle to the window station or desktop object for which to
597 * return information. This can be a handle of type HDESK or HWINSTA
598 * (for example, a handle returned by NtUserCreateWindowStation,
599 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
600 *
601 * nIndex
602 * Specifies the object information to be retrieved.
603 *
604 * pvInfo
605 * Pointer to a buffer to receive the object information.
606 *
607 * nLength
608 * Specifies the size, in bytes, of the buffer pointed to by the
609 * pvInfo parameter.
610 *
611 * lpnLengthNeeded
612 * Pointer to a variable receiving the number of bytes required to
613 * store the requested information. If this variable's value is
614 * greater than the value of the nLength parameter when the function
615 * returns, the function returns FALSE, and none of the information
616 * is copied to the pvInfo buffer. If the value of the variable pointed
617 * to by lpnLengthNeeded is less than or equal to the value of nLength,
618 * the entire information block is copied.
619 *
620 * Return Value
621 * If the function succeeds, the return value is nonzero. If the function
622 * fails, the return value is zero.
623 *
624 * Status
625 * @unimplemented
626 */
627
628 BOOL APIENTRY
629 NtUserGetObjectInformation(
630 HANDLE hObject,
631 DWORD nIndex,
632 PVOID pvInformation,
633 DWORD nLength,
634 PDWORD nLengthNeeded)
635 {
636 PWINSTATION_OBJECT WinStaObject = NULL;
637 PDESKTOP DesktopObject = NULL;
638 NTSTATUS Status;
639 PVOID pvData = NULL;
640 DWORD nDataSize = 0;
641
642 _SEH2_TRY
643 {
644 if (nLengthNeeded)
645 ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
646 ProbeForWrite(pvInformation, nLength, 1);
647 }
648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
649 {
650 SetLastNtError(_SEH2_GetExceptionCode());
651 return FALSE;
652 }
653 _SEH2_END;
654
655 /* try windowstation */
656 TRACE("Trying to open window station %p\n", hObject);
657 Status = ObReferenceObjectByHandle(
658 hObject,
659 0,
660 ExWindowStationObjectType,
661 UserMode,
662 (PVOID*)&WinStaObject,
663 NULL);
664
665 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
666 {
667 /* try desktop */
668 TRACE("Trying to open desktop %p\n", hObject);
669 Status = IntValidateDesktopHandle(
670 hObject,
671 UserMode,
672 0,
673 &DesktopObject);
674 }
675
676 if (!NT_SUCCESS(Status))
677 {
678 ERR("Failed: 0x%x\n", Status);
679 goto Exit;
680 }
681
682 TRACE("WinSta or Desktop opened!!\n");
683
684 /* get data */
685 switch (nIndex)
686 {
687 case UOI_FLAGS:
688 Status = STATUS_NOT_IMPLEMENTED;
689 ERR("UOI_FLAGS unimplemented!\n");
690 break;
691
692 case UOI_NAME:
693 if (WinStaObject != NULL)
694 {
695 pvData = WinStaObject->Name.Buffer;
696 nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
697 Status = STATUS_SUCCESS;
698 }
699 else if (DesktopObject != NULL)
700 {
701 pvData = DesktopObject->pDeskInfo->szDesktopName;
702 nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
703 Status = STATUS_SUCCESS;
704 }
705 else
706 Status = STATUS_INVALID_PARAMETER;
707 break;
708
709 case UOI_TYPE:
710 if (WinStaObject != NULL)
711 {
712 pvData = L"WindowStation";
713 nDataSize = sizeof(L"WindowStation");
714 Status = STATUS_SUCCESS;
715 }
716 else if (DesktopObject != NULL)
717 {
718 pvData = L"Desktop";
719 nDataSize = sizeof(L"Desktop");
720 Status = STATUS_SUCCESS;
721 }
722 else
723 Status = STATUS_INVALID_PARAMETER;
724 break;
725
726 case UOI_USER_SID:
727 Status = STATUS_NOT_IMPLEMENTED;
728 ERR("UOI_USER_SID unimplemented!\n");
729 break;
730
731 default:
732 Status = STATUS_INVALID_PARAMETER;
733 break;
734 }
735
736 Exit:
737 if (Status == STATUS_SUCCESS && nLength < nDataSize)
738 Status = STATUS_BUFFER_TOO_SMALL;
739
740 _SEH2_TRY
741 {
742 if (nLengthNeeded)
743 *nLengthNeeded = nDataSize;
744
745 /* try to copy data to caller */
746 if (Status == STATUS_SUCCESS)
747 {
748 TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
749 RtlCopyMemory(pvInformation, pvData, nDataSize);
750 }
751 }
752 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
753 {
754 Status = _SEH2_GetExceptionCode();
755 }
756 _SEH2_END;
757
758 /* release objects */
759 if (WinStaObject != NULL)
760 ObDereferenceObject(WinStaObject);
761 if (DesktopObject != NULL)
762 ObDereferenceObject(DesktopObject);
763
764 if (!NT_SUCCESS(Status))
765 {
766 SetLastNtError(Status);
767 return FALSE;
768 }
769
770 return TRUE;
771 }
772
773 /*
774 * NtUserSetObjectInformation
775 *
776 * The NtUserSetObjectInformation function sets information about a
777 * window station or desktop object.
778 *
779 * Parameters
780 * hObj
781 * Handle to the window station or desktop object for which to set
782 * object information. This value can be a handle of type HDESK or
783 * HWINSTA.
784 *
785 * nIndex
786 * Specifies the object information to be set.
787 *
788 * pvInfo
789 * Pointer to a buffer containing the object information.
790 *
791 * nLength
792 * Specifies the size, in bytes, of the information contained in the
793 * buffer pointed to by pvInfo.
794 *
795 * Return Value
796 * If the function succeeds, the return value is nonzero. If the function
797 * fails the return value is zero.
798 *
799 * Status
800 * @unimplemented
801 */
802
803 BOOL
804 APIENTRY
805 NtUserSetObjectInformation(
806 HANDLE hObject,
807 DWORD nIndex,
808 PVOID pvInformation,
809 DWORD nLength)
810 {
811 /* FIXME: ZwQueryObject */
812 /* FIXME: ZwSetInformationObject */
813 SetLastNtError(STATUS_UNSUCCESSFUL);
814 return FALSE;
815 }
816
817
818
819
820 HWINSTA FASTCALL
821 UserGetProcessWindowStation(VOID)
822 {
823 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
824
825 return ppi->hwinsta;
826 }
827
828
829 /*
830 * NtUserGetProcessWindowStation
831 *
832 * Returns a handle to the current process window station.
833 *
834 * Return Value
835 * If the function succeeds, the return value is handle to the window
836 * station assigned to the current process. If the function fails, the
837 * return value is NULL.
838 *
839 * Status
840 * @implemented
841 */
842
843 HWINSTA APIENTRY
844 NtUserGetProcessWindowStation(VOID)
845 {
846 return UserGetProcessWindowStation();
847 }
848
849 BOOL FASTCALL
850 UserSetProcessWindowStation(HWINSTA hWindowStation)
851 {
852 PPROCESSINFO ppi;
853 NTSTATUS Status;
854 HWINSTA hwinstaOld;
855 PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
856
857 ppi = PsGetCurrentProcessWin32Process();
858
859 /* Reference the new window station */
860 if(hWindowStation !=NULL)
861 {
862 Status = IntValidateWindowStationHandle( hWindowStation,
863 KernelMode,
864 0,
865 &NewWinSta);
866 if (!NT_SUCCESS(Status))
867 {
868 TRACE("Validation of window station handle (%p) failed\n",
869 hWindowStation);
870 SetLastNtError(Status);
871 return FALSE;
872 }
873 }
874
875 OldWinSta = ppi->prpwinsta;
876 hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
877
878 /* Dereference the previous window station */
879 if(OldWinSta != NULL)
880 {
881 ObDereferenceObject(OldWinSta);
882 }
883
884 /* Check if we have a stale handle (it should happen for console apps) */
885 if(hwinstaOld != ppi->hwinsta)
886 {
887 ObCloseHandle(hwinstaOld, UserMode);
888 }
889
890 /*
891 * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
892 */
893
894 PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
895
896 ppi->prpwinsta = NewWinSta;
897 ppi->hwinsta = hWindowStation;
898
899 return TRUE;
900 }
901
902 /*
903 * NtUserSetProcessWindowStation
904 *
905 * Assigns a window station to the current process.
906 *
907 * Parameters
908 * hWinSta
909 * Handle to the window station.
910 *
911 * Return Value
912 * Status
913 *
914 * Status
915 * @implemented
916 */
917
918 BOOL APIENTRY
919 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
920 {
921 BOOL ret;
922
923 UserEnterExclusive();
924
925 ret = UserSetProcessWindowStation(hWindowStation);
926
927 UserLeave();
928
929 return ret;
930 }
931
932 /*
933 * NtUserLockWindowStation
934 *
935 * Locks switching desktops. Only the logon application is allowed to call this function.
936 *
937 * Status
938 * @implemented
939 */
940
941 BOOL APIENTRY
942 NtUserLockWindowStation(HWINSTA hWindowStation)
943 {
944 PWINSTATION_OBJECT Object;
945 NTSTATUS Status;
946
947 TRACE("About to set process window station with handle (%p)\n",
948 hWindowStation);
949
950 if(PsGetCurrentProcessWin32Process() != LogonProcess)
951 {
952 ERR("Unauthorized process attempted to lock the window station!\n");
953 EngSetLastError(ERROR_ACCESS_DENIED);
954 return FALSE;
955 }
956
957 Status = IntValidateWindowStationHandle(
958 hWindowStation,
959 KernelMode,
960 0,
961 &Object);
962 if (!NT_SUCCESS(Status))
963 {
964 TRACE("Validation of window station handle (%p) failed\n",
965 hWindowStation);
966 SetLastNtError(Status);
967 return FALSE;
968 }
969
970 Object->Flags |= WSS_LOCKED;
971
972 ObDereferenceObject(Object);
973 return TRUE;
974 }
975
976 /*
977 * NtUserUnlockWindowStation
978 *
979 * Unlocks switching desktops. Only the logon application is allowed to call this function.
980 *
981 * Status
982 * @implemented
983 */
984
985 BOOL APIENTRY
986 NtUserUnlockWindowStation(HWINSTA hWindowStation)
987 {
988 PWINSTATION_OBJECT Object;
989 NTSTATUS Status;
990 BOOL Ret;
991
992 TRACE("About to set process window station with handle (%p)\n",
993 hWindowStation);
994
995 if(PsGetCurrentProcessWin32Process() != LogonProcess)
996 {
997 ERR("Unauthorized process attempted to unlock the window station!\n");
998 EngSetLastError(ERROR_ACCESS_DENIED);
999 return FALSE;
1000 }
1001
1002 Status = IntValidateWindowStationHandle(
1003 hWindowStation,
1004 KernelMode,
1005 0,
1006 &Object);
1007 if (!NT_SUCCESS(Status))
1008 {
1009 TRACE("Validation of window station handle (%p) failed\n",
1010 hWindowStation);
1011 SetLastNtError(Status);
1012 return FALSE;
1013 }
1014
1015 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1016 Object->Flags &= ~WSS_LOCKED;
1017
1018 ObDereferenceObject(Object);
1019 return Ret;
1020 }
1021
1022 static NTSTATUS FASTCALL
1023 BuildWindowStationNameList(
1024 ULONG dwSize,
1025 PVOID lpBuffer,
1026 PULONG pRequiredSize)
1027 {
1028 OBJECT_ATTRIBUTES ObjectAttributes;
1029 NTSTATUS Status;
1030 HANDLE DirectoryHandle;
1031 char InitialBuffer[256], *Buffer;
1032 ULONG Context, ReturnLength, BufferSize;
1033 DWORD EntryCount;
1034 POBJECT_DIRECTORY_INFORMATION DirEntry;
1035 WCHAR NullWchar;
1036
1037 /*
1038 * Try to open the directory.
1039 */
1040 InitializeObjectAttributes(
1041 &ObjectAttributes,
1042 &gustrWindowStationsDir,
1043 OBJ_CASE_INSENSITIVE,
1044 NULL,
1045 NULL);
1046
1047 Status = ZwOpenDirectoryObject(
1048 &DirectoryHandle,
1049 DIRECTORY_QUERY,
1050 &ObjectAttributes);
1051
1052 if (!NT_SUCCESS(Status))
1053 {
1054 return Status;
1055 }
1056
1057 /* First try to query the directory using a fixed-size buffer */
1058 Context = 0;
1059 Buffer = NULL;
1060 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1061 FALSE, TRUE, &Context, &ReturnLength);
1062 if (NT_SUCCESS(Status))
1063 {
1064 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1065 FALSE, &Context, NULL))
1066 {
1067 /* Our fixed-size buffer is large enough */
1068 Buffer = InitialBuffer;
1069 }
1070 }
1071
1072 if (NULL == Buffer)
1073 {
1074 /* Need a larger buffer, check how large exactly */
1075 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1076 &ReturnLength);
1077 if (STATUS_BUFFER_TOO_SMALL == Status)
1078 {
1079 ObDereferenceObject(DirectoryHandle);
1080 return STATUS_NO_MEMORY;
1081 }
1082
1083 BufferSize = ReturnLength;
1084 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1085 if (NULL == Buffer)
1086 {
1087 ObDereferenceObject(DirectoryHandle);
1088 return STATUS_NO_MEMORY;
1089 }
1090
1091 /* We should have a sufficiently large buffer now */
1092 Context = 0;
1093 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1094 FALSE, TRUE, &Context, &ReturnLength);
1095 if (! NT_SUCCESS(Status) ||
1096 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1097 FALSE, &Context, NULL))
1098 {
1099 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1100 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1101 ObDereferenceObject(DirectoryHandle);
1102 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1103 }
1104 }
1105
1106 ZwClose(DirectoryHandle);
1107
1108 /*
1109 * Count the required size of buffer.
1110 */
1111 ReturnLength = sizeof(DWORD);
1112 EntryCount = 0;
1113 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1114 DirEntry++)
1115 {
1116 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1117 EntryCount++;
1118 }
1119 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1120 if (NULL != pRequiredSize)
1121 {
1122 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1123 if (! NT_SUCCESS(Status))
1124 {
1125 if (Buffer != InitialBuffer)
1126 {
1127 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1128 }
1129 return STATUS_BUFFER_TOO_SMALL;
1130 }
1131 }
1132
1133 /*
1134 * Check if the supplied buffer is large enough.
1135 */
1136 if (dwSize < ReturnLength)
1137 {
1138 if (Buffer != InitialBuffer)
1139 {
1140 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1141 }
1142 return STATUS_BUFFER_TOO_SMALL;
1143 }
1144
1145 /*
1146 * Generate the resulting buffer contents.
1147 */
1148 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1149 if (! NT_SUCCESS(Status))
1150 {
1151 if (Buffer != InitialBuffer)
1152 {
1153 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1154 }
1155 return Status;
1156 }
1157 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1158
1159 NullWchar = L'\0';
1160 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1161 DirEntry++)
1162 {
1163 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1164 if (! NT_SUCCESS(Status))
1165 {
1166 if (Buffer != InitialBuffer)
1167 {
1168 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1169 }
1170 return Status;
1171 }
1172 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1173 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1174 if (! NT_SUCCESS(Status))
1175 {
1176 if (Buffer != InitialBuffer)
1177 {
1178 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1179 }
1180 return Status;
1181 }
1182 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1183 }
1184
1185 /*
1186 * Clean up
1187 */
1188 if (Buffer != InitialBuffer)
1189 {
1190 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1191 }
1192
1193 return STATUS_SUCCESS;
1194 }
1195
1196 static NTSTATUS FASTCALL
1197 BuildDesktopNameList(
1198 HWINSTA hWindowStation,
1199 ULONG dwSize,
1200 PVOID lpBuffer,
1201 PULONG pRequiredSize)
1202 {
1203 NTSTATUS Status;
1204 PWINSTATION_OBJECT WindowStation;
1205 PLIST_ENTRY DesktopEntry;
1206 PDESKTOP DesktopObject;
1207 DWORD EntryCount;
1208 ULONG ReturnLength;
1209 WCHAR NullWchar;
1210 UNICODE_STRING DesktopName;
1211
1212 Status = IntValidateWindowStationHandle(hWindowStation,
1213 KernelMode,
1214 0,
1215 &WindowStation);
1216 if (! NT_SUCCESS(Status))
1217 {
1218 return Status;
1219 }
1220
1221 /*
1222 * Count the required size of buffer.
1223 */
1224 ReturnLength = sizeof(DWORD);
1225 EntryCount = 0;
1226 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1227 DesktopEntry != &WindowStation->DesktopListHead;
1228 DesktopEntry = DesktopEntry->Flink)
1229 {
1230 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1231 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1232 ReturnLength += DesktopName.Length + sizeof(WCHAR);
1233 EntryCount++;
1234 }
1235 TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
1236 if (NULL != pRequiredSize)
1237 {
1238 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1239 if (! NT_SUCCESS(Status))
1240 {
1241 ObDereferenceObject(WindowStation);
1242 return STATUS_BUFFER_TOO_SMALL;
1243 }
1244 }
1245
1246 /*
1247 * Check if the supplied buffer is large enough.
1248 */
1249 if (dwSize < ReturnLength)
1250 {
1251 ObDereferenceObject(WindowStation);
1252 return STATUS_BUFFER_TOO_SMALL;
1253 }
1254
1255 /*
1256 * Generate the resulting buffer contents.
1257 */
1258 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1259 if (! NT_SUCCESS(Status))
1260 {
1261 ObDereferenceObject(WindowStation);
1262 return Status;
1263 }
1264 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1265
1266 NullWchar = L'\0';
1267 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1268 DesktopEntry != &WindowStation->DesktopListHead;
1269 DesktopEntry = DesktopEntry->Flink)
1270 {
1271 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1272 RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
1273 Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
1274 if (! NT_SUCCESS(Status))
1275 {
1276 ObDereferenceObject(WindowStation);
1277 return Status;
1278 }
1279 lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
1280 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1281 if (! NT_SUCCESS(Status))
1282 {
1283 ObDereferenceObject(WindowStation);
1284 return Status;
1285 }
1286 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1287 }
1288
1289 /*
1290 * Clean up and return
1291 */
1292 ObDereferenceObject(WindowStation);
1293 return STATUS_SUCCESS;
1294 }
1295
1296 /*
1297 * NtUserBuildNameList
1298 *
1299 * Function used for enumeration of desktops or window stations.
1300 *
1301 * Parameters
1302 * hWinSta
1303 * For enumeration of window stations this parameter must be set to
1304 * zero. Otherwise it's handle for window station.
1305 *
1306 * dwSize
1307 * Size of buffer passed by caller.
1308 *
1309 * lpBuffer
1310 * Buffer passed by caller. If the function succedes, the buffer is
1311 * filled with window station/desktop count (in first DWORD) and
1312 * NULL-terminated window station/desktop names.
1313 *
1314 * pRequiredSize
1315 * If the function suceedes, this is the number of bytes copied.
1316 * Otherwise it's size of buffer needed for function to succeed.
1317 *
1318 * Status
1319 * @implemented
1320 */
1321
1322 NTSTATUS APIENTRY
1323 NtUserBuildNameList(
1324 HWINSTA hWindowStation,
1325 ULONG dwSize,
1326 PVOID lpBuffer,
1327 PULONG pRequiredSize)
1328 {
1329 /* The WindowStation name list and desktop name list are build in completely
1330 different ways. Call the appropriate function */
1331 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1332 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1333 }
1334
1335 /*
1336 * @implemented
1337 */
1338 BOOL APIENTRY
1339 NtUserSetLogonNotifyWindow(HWND hWnd)
1340 {
1341 if(LogonProcess != PsGetCurrentProcessWin32Process())
1342 {
1343 return FALSE;
1344 }
1345
1346 if(!IntIsWindow(hWnd))
1347 {
1348 return FALSE;
1349 }
1350
1351 hwndSAS = hWnd;
1352
1353 return TRUE;
1354 }
1355
1356 BOOL
1357 APIENTRY
1358 NtUserLockWorkStation(VOID)
1359 {
1360 BOOL ret;
1361 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1362
1363 UserEnterExclusive();
1364
1365 if (pti->rpdesk == IntGetActiveDesktop())
1366 {
1367 ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
1368 }
1369 else
1370 {
1371 ret = FALSE;
1372 }
1373
1374 UserLeave();
1375
1376 return ret;
1377 }
1378
1379 /* EOF */