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