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