- Fix 2 user32 winstation test failures (patch by Giannis Adamopoulos johnyadams...
[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
541 /* FIXME: Obtain the following information from the registry */
542
543 // CurInfo->WheelScroLines = 3;
544 // CurInfo->WheelScroChars = 3;
545 CurInfo->SwapButtons = FALSE;
546 CurInfo->DblClickSpeed = 500;
547 CurInfo->DblClickWidth = 4;
548 CurInfo->DblClickHeight = 4;
549
550 // CurInfo->MouseSpeed = 10;
551 // CurInfo->CursorAccelerationInfo.FirstThreshold = 6;
552 // CurInfo->CursorAccelerationInfo.SecondThreshold = 10;
553 // CurInfo->CursorAccelerationInfo.Acceleration = 1;
554
555 // CurInfo->MouseHoverTime = 80;
556 // CurInfo->MouseHoverWidth = 4;
557 // CurInfo->MouseHoverHeight = 4;
558
559 // WindowStationObject->ScreenSaverActive = FALSE;
560 // WindowStationObject->ScreenSaverTimeOut = 10;
561 WindowStationObject->SystemCursor = CurInfo;
562
563 /* END FIXME loading from register */
564
565 if (!IntSetupClipboard(WindowStationObject))
566 {
567 DPRINT1("WindowStation: Error Setting up the clipboard!!!\n");
568 }
569
570 if (!IntSetupCurIconHandles(WindowStationObject))
571 {
572 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
573 /* FIXME: Complain more loudly? */
574 ExFreePool(FullWindowStationName.Buffer);
575 }
576
577 DPRINT("Window station successfully created (%wZ)\n", &FullWindowStationName);
578 ExFreePool(FullWindowStationName.Buffer);
579 return WindowStation;
580 }
581
582 /*
583 * NtUserOpenWindowStation
584 *
585 * Opens an existing window station.
586 *
587 * Parameters
588 * lpszWindowStationName
589 * Name of the existing window station.
590 *
591 * dwDesiredAccess
592 * Requested type of access.
593 *
594 * Return Value
595 * If the function succeeds, the return value is the handle to the
596 * specified window station. If the function fails, the return value
597 * is NULL.
598 *
599 * Remarks
600 * The returned handle can be closed with NtUserCloseWindowStation.
601 *
602 * Status
603 * @implemented
604 */
605
606 HWINSTA APIENTRY
607 NtUserOpenWindowStation(
608 PUNICODE_STRING lpszWindowStationName,
609 ACCESS_MASK dwDesiredAccess)
610 {
611 UNICODE_STRING WindowStationName;
612 HWINSTA WindowStation;
613 OBJECT_ATTRIBUTES ObjectAttributes;
614 NTSTATUS Status;
615
616 /*
617 * Generate full window station name
618 */
619
620 if (!IntGetFullWindowStationName(&WindowStationName, lpszWindowStationName,
621 NULL))
622 {
623 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
624 return 0;
625 }
626
627 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName);
628
629 /* Initialize ObjectAttributes for the window station object */
630 InitializeObjectAttributes(
631 &ObjectAttributes,
632 &WindowStationName,
633 OBJ_CASE_INSENSITIVE,
634 NULL,
635 NULL);
636
637 Status = ObOpenObjectByName(
638 &ObjectAttributes,
639 ExWindowStationObjectType,
640 KernelMode,
641 NULL,
642 dwDesiredAccess,
643 NULL,
644 (PVOID*)&WindowStation);
645
646 if (!NT_SUCCESS(Status))
647 {
648 SetLastNtError(Status);
649 ExFreePool(WindowStationName.Buffer);
650 return 0;
651 }
652
653 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName);
654 ExFreePool(WindowStationName.Buffer);
655
656 return WindowStation;
657 }
658
659 /*
660 * NtUserCloseWindowStation
661 *
662 * Closes a window station handle.
663 *
664 * Parameters
665 * hWinSta
666 * Handle to the window station.
667 *
668 * Return Value
669 * Status
670 *
671 * Remarks
672 * The window station handle can be created with NtUserCreateWindowStation
673 * or NtUserOpenWindowStation. Attemps to close a handle to the window
674 * station assigned to the calling process will fail.
675 *
676 * Status
677 * @implemented
678 */
679
680 BOOL
681 APIENTRY
682 NtUserCloseWindowStation(
683 HWINSTA hWinSta)
684 {
685 PWINSTATION_OBJECT Object;
686 NTSTATUS Status;
687
688 DPRINT("About to close window station handle (0x%X)\n", hWinSta);
689
690 if (hWinSta == UserGetProcessWindowStation())
691 {
692 return FALSE;
693 }
694
695 Status = IntValidateWindowStationHandle(
696 hWinSta,
697 KernelMode,
698 0,
699 &Object);
700
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta);
704 return FALSE;
705 }
706
707 #if 0
708 /* FIXME - free the cursor information when actually deleting the object!! */
709 ASSERT(Object->SystemCursor);
710 ExFreePool(Object->SystemCursor);
711 #endif
712
713 ObDereferenceObject(Object);
714
715 DPRINT("Closing window station handle (0x%X)\n", hWinSta);
716
717 Status = ZwClose(hWinSta);
718 if (!NT_SUCCESS(Status))
719 {
720 SetLastNtError(Status);
721 return FALSE;
722 }
723
724 return TRUE;
725 }
726
727 /*
728 * NtUserGetObjectInformation
729 *
730 * The NtUserGetObjectInformation function retrieves information about a
731 * window station or desktop object.
732 *
733 * Parameters
734 * hObj
735 * Handle to the window station or desktop object for which to
736 * return information. This can be a handle of type HDESK or HWINSTA
737 * (for example, a handle returned by NtUserCreateWindowStation,
738 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
739 *
740 * nIndex
741 * Specifies the object information to be retrieved.
742 *
743 * pvInfo
744 * Pointer to a buffer to receive the object information.
745 *
746 * nLength
747 * Specifies the size, in bytes, of the buffer pointed to by the
748 * pvInfo parameter.
749 *
750 * lpnLengthNeeded
751 * Pointer to a variable receiving the number of bytes required to
752 * store the requested information. If this variable's value is
753 * greater than the value of the nLength parameter when the function
754 * returns, the function returns FALSE, and none of the information
755 * is copied to the pvInfo buffer. If the value of the variable pointed
756 * to by lpnLengthNeeded is less than or equal to the value of nLength,
757 * the entire information block is copied.
758 *
759 * Return Value
760 * If the function succeeds, the return value is nonzero. If the function
761 * fails, the return value is zero.
762 *
763 * Status
764 * @unimplemented
765 */
766
767 BOOL APIENTRY
768 NtUserGetObjectInformation(
769 HANDLE hObject,
770 DWORD nIndex,
771 PVOID pvInformation,
772 DWORD nLength,
773 PDWORD nLengthNeeded)
774 {
775 PWINSTATION_OBJECT WinStaObject = NULL;
776 PDESKTOP DesktopObject = NULL;
777 NTSTATUS Status;
778 PVOID pvData = NULL;
779 DWORD nDataSize = 0;
780
781 /* try windowstation */
782 DPRINT("Trying to open window station 0x%x\n", hObject);
783 Status = IntValidateWindowStationHandle(
784 hObject,
785 UserMode,/*ExGetPreviousMode(),*/
786 GENERIC_READ, /* FIXME: is this ok? */
787 &WinStaObject);
788
789
790 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_TYPE_MISMATCH)
791 {
792 DPRINT("Failed: 0x%x\n", Status);
793 SetLastNtError(Status);
794 return FALSE;
795 }
796
797 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
798 {
799 /* try desktop */
800 DPRINT("Trying to open desktop 0x%x\n", hObject);
801 Status = IntValidateDesktopHandle(
802 hObject,
803 UserMode,/*ExGetPreviousMode(),*/
804 GENERIC_READ, /* FIXME: is this ok? */
805 &DesktopObject);
806 if (!NT_SUCCESS(Status))
807 {
808 DPRINT("Failed: 0x%x\n", Status);
809 SetLastNtError(Status);
810 return FALSE;
811 }
812 }
813 DPRINT("WinSta or Desktop opened!!\n");
814
815 /* get data */
816 switch (nIndex)
817 {
818 case UOI_FLAGS:
819 Status = STATUS_NOT_IMPLEMENTED;
820 DPRINT1("UOI_FLAGS unimplemented!\n");
821 break;
822
823 case UOI_NAME:
824 if (WinStaObject != NULL)
825 {
826 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Buffer;
827 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Length + 2;
828 Status = STATUS_SUCCESS;
829 }
830 else if (DesktopObject != NULL)
831 {
832 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer;
833 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + 2;
834 Status = STATUS_SUCCESS;
835 }
836 else
837 Status = STATUS_INVALID_PARAMETER;
838 break;
839
840 case UOI_TYPE:
841 if (WinStaObject != NULL)
842 {
843 pvData = L"WindowStation";
844 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
845 Status = STATUS_SUCCESS;
846 }
847 else if (DesktopObject != NULL)
848 {
849 pvData = L"Desktop";
850 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
851 Status = STATUS_SUCCESS;
852 }
853 else
854 Status = STATUS_INVALID_PARAMETER;
855 break;
856
857 case UOI_USER_SID:
858 Status = STATUS_NOT_IMPLEMENTED;
859 DPRINT1("UOI_USER_SID unimplemented!\n");
860 break;
861
862 default:
863 Status = STATUS_INVALID_PARAMETER;
864 break;
865 }
866
867 /* try to copy data to caller */
868 if (Status == STATUS_SUCCESS)
869 {
870 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength, nDataSize);
871 *nLengthNeeded = nDataSize;
872 if (nLength >= nDataSize)
873 Status = MmCopyToCaller(pvInformation, pvData, nDataSize);
874 else
875 Status = STATUS_BUFFER_TOO_SMALL;
876 }
877
878 /* release objects */
879 if (WinStaObject != NULL)
880 ObDereferenceObject(WinStaObject);
881 if (DesktopObject != NULL)
882 ObDereferenceObject(DesktopObject);
883
884 SetLastNtError(Status);
885 return NT_SUCCESS(Status);
886 }
887
888 /*
889 * NtUserSetObjectInformation
890 *
891 * The NtUserSetObjectInformation function sets information about a
892 * window station or desktop object.
893 *
894 * Parameters
895 * hObj
896 * Handle to the window station or desktop object for which to set
897 * object information. This value can be a handle of type HDESK or
898 * HWINSTA.
899 *
900 * nIndex
901 * Specifies the object information to be set.
902 *
903 * pvInfo
904 * Pointer to a buffer containing the object information.
905 *
906 * nLength
907 * Specifies the size, in bytes, of the information contained in the
908 * buffer pointed to by pvInfo.
909 *
910 * Return Value
911 * If the function succeeds, the return value is nonzero. If the function
912 * fails the return value is zero.
913 *
914 * Status
915 * @unimplemented
916 */
917
918 BOOL
919 APIENTRY
920 NtUserSetObjectInformation(
921 HANDLE hObject,
922 DWORD nIndex,
923 PVOID pvInformation,
924 DWORD nLength)
925 {
926 /* FIXME: ZwQueryObject */
927 /* FIXME: ZwSetInformationObject */
928 SetLastNtError(STATUS_UNSUCCESSFUL);
929 return FALSE;
930 }
931
932
933
934
935 HWINSTA FASTCALL
936 UserGetProcessWindowStation(VOID)
937 {
938 NTSTATUS Status;
939 PTHREADINFO pti;
940 HWINSTA WinSta;
941
942 if(PsGetCurrentProcess() != CsrProcess)
943 {
944 return PsGetCurrentProcess()->Win32WindowStation;
945 }
946 else
947 {
948 DPRINT1("Should use ObFindHandleForObject\n");
949 pti = PsGetCurrentThreadWin32Thread();
950 Status = ObOpenObjectByPointer(pti->Desktop->WindowStation,
951 0,
952 NULL,
953 WINSTA_ALL_ACCESS,
954 ExWindowStationObjectType,
955 UserMode,
956 (PHANDLE) &WinSta);
957 if (! NT_SUCCESS(Status))
958 {
959 SetLastNtError(Status);
960 DPRINT1("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
961 Status);
962 return NULL;
963 }
964 return WinSta;
965 }
966 }
967
968
969 /*
970 * NtUserGetProcessWindowStation
971 *
972 * Returns a handle to the current process window station.
973 *
974 * Return Value
975 * If the function succeeds, the return value is handle to the window
976 * station assigned to the current process. If the function fails, the
977 * return value is NULL.
978 *
979 * Status
980 * @implemented
981 */
982
983 HWINSTA APIENTRY
984 NtUserGetProcessWindowStation(VOID)
985 {
986 return UserGetProcessWindowStation();
987 }
988
989 PWINSTATION_OBJECT FASTCALL
990 IntGetWinStaObj(VOID)
991 {
992 PWINSTATION_OBJECT WinStaObj;
993 PTHREADINFO Win32Thread;
994 PEPROCESS CurrentProcess;
995
996 /*
997 * just a temporary hack, this will be gone soon
998 */
999
1000 Win32Thread = PsGetCurrentThreadWin32Thread();
1001 if(Win32Thread != NULL && Win32Thread->Desktop != NULL)
1002 {
1003 WinStaObj = Win32Thread->Desktop->WindowStation;
1004 ObReferenceObjectByPointer(WinStaObj, KernelMode, ExWindowStationObjectType, 0);
1005 }
1006 else if((CurrentProcess = PsGetCurrentProcess()) != CsrProcess)
1007 {
1008 NTSTATUS Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
1009 KernelMode,
1010 0,
1011 &WinStaObj);
1012 if(!NT_SUCCESS(Status))
1013 {
1014 SetLastNtError(Status);
1015 return NULL;
1016 }
1017 }
1018 else
1019 {
1020 WinStaObj = NULL;
1021 }
1022
1023 return WinStaObj;
1024 }
1025
1026 /*
1027 * NtUserSetProcessWindowStation
1028 *
1029 * Assigns a window station to the current process.
1030 *
1031 * Parameters
1032 * hWinSta
1033 * Handle to the window station.
1034 *
1035 * Return Value
1036 * Status
1037 *
1038 * Status
1039 * @implemented
1040 */
1041
1042 BOOL APIENTRY
1043 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1044 {
1045 HANDLE hOld;
1046 PWINSTATION_OBJECT NewWinSta;
1047 NTSTATUS Status;
1048
1049 DPRINT("About to set process window station with handle (0x%X)\n",
1050 hWindowStation);
1051
1052 if(PsGetCurrentProcess() == CsrProcess)
1053 {
1054 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1055 SetLastWin32Error(ERROR_ACCESS_DENIED);
1056 return FALSE;
1057 }
1058
1059 Status = IntValidateWindowStationHandle(
1060 hWindowStation,
1061 KernelMode,
1062 0,
1063 &NewWinSta);
1064
1065 if (!NT_SUCCESS(Status))
1066 {
1067 DPRINT("Validation of window station handle (0x%X) failed\n",
1068 hWindowStation);
1069 SetLastNtError(Status);
1070 return FALSE;
1071 }
1072
1073 /*
1074 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1075 */
1076
1077 /* FIXME - dereference the old window station, etc... */
1078 hOld = InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
1079
1080 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1081 PsGetCurrentProcess()->Win32WindowStation);
1082
1083 return TRUE;
1084 }
1085
1086 /*
1087 * NtUserLockWindowStation
1088 *
1089 * Locks switching desktops. Only the logon application is allowed to call this function.
1090 *
1091 * Status
1092 * @implemented
1093 */
1094
1095 BOOL APIENTRY
1096 NtUserLockWindowStation(HWINSTA hWindowStation)
1097 {
1098 PWINSTATION_OBJECT Object;
1099 NTSTATUS Status;
1100
1101 DPRINT("About to set process window station with handle (0x%X)\n",
1102 hWindowStation);
1103
1104 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1105 {
1106 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1107 SetLastWin32Error(ERROR_ACCESS_DENIED);
1108 return FALSE;
1109 }
1110
1111 Status = IntValidateWindowStationHandle(
1112 hWindowStation,
1113 KernelMode,
1114 0,
1115 &Object);
1116 if (!NT_SUCCESS(Status))
1117 {
1118 DPRINT("Validation of window station handle (0x%X) failed\n",
1119 hWindowStation);
1120 SetLastNtError(Status);
1121 return FALSE;
1122 }
1123
1124 Object->Flags |= WSS_LOCKED;
1125
1126 ObDereferenceObject(Object);
1127 return TRUE;
1128 }
1129
1130 /*
1131 * NtUserUnlockWindowStation
1132 *
1133 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1134 *
1135 * Status
1136 * @implemented
1137 */
1138
1139 BOOL APIENTRY
1140 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1141 {
1142 PWINSTATION_OBJECT Object;
1143 NTSTATUS Status;
1144 BOOL Ret;
1145
1146 DPRINT("About to set process window station with handle (0x%X)\n",
1147 hWindowStation);
1148
1149 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1150 {
1151 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1152 SetLastWin32Error(ERROR_ACCESS_DENIED);
1153 return FALSE;
1154 }
1155
1156 Status = IntValidateWindowStationHandle(
1157 hWindowStation,
1158 KernelMode,
1159 0,
1160 &Object);
1161 if (!NT_SUCCESS(Status))
1162 {
1163 DPRINT("Validation of window station handle (0x%X) failed\n",
1164 hWindowStation);
1165 SetLastNtError(Status);
1166 return FALSE;
1167 }
1168
1169 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1170 Object->Flags &= ~WSS_LOCKED;
1171
1172 ObDereferenceObject(Object);
1173 return Ret;
1174 }
1175
1176 /*
1177 * NtUserSetWindowStationUser
1178 *
1179 * Status
1180 * @unimplemented
1181 */
1182
1183 DWORD APIENTRY
1184 NtUserSetWindowStationUser(
1185 DWORD Unknown0,
1186 DWORD Unknown1,
1187 DWORD Unknown2,
1188 DWORD Unknown3)
1189 {
1190 UNIMPLEMENTED
1191
1192 return 0;
1193 }
1194
1195 static NTSTATUS FASTCALL
1196 BuildWindowStationNameList(
1197 ULONG dwSize,
1198 PVOID lpBuffer,
1199 PULONG pRequiredSize)
1200 {
1201 OBJECT_ATTRIBUTES ObjectAttributes;
1202 NTSTATUS Status;
1203 HANDLE DirectoryHandle;
1204 UNICODE_STRING DirectoryName;
1205 char InitialBuffer[256], *Buffer;
1206 ULONG Context, ReturnLength, BufferSize;
1207 DWORD EntryCount;
1208 POBJECT_DIRECTORY_INFORMATION DirEntry;
1209 WCHAR NullWchar;
1210
1211 /*
1212 * Generate name of window station directory
1213 */
1214 if (!IntGetFullWindowStationName(&DirectoryName, NULL, NULL))
1215 {
1216 return STATUS_INSUFFICIENT_RESOURCES;
1217 }
1218
1219 /*
1220 * Try to open the directory.
1221 */
1222 InitializeObjectAttributes(
1223 &ObjectAttributes,
1224 &DirectoryName,
1225 OBJ_CASE_INSENSITIVE,
1226 NULL,
1227 NULL);
1228
1229 Status = ZwOpenDirectoryObject(
1230 &DirectoryHandle,
1231 DIRECTORY_QUERY,
1232 &ObjectAttributes);
1233
1234 ExFreePool(DirectoryName.Buffer);
1235
1236 if (!NT_SUCCESS(Status))
1237 {
1238 return Status;
1239 }
1240
1241 /* First try to query the directory using a fixed-size buffer */
1242 Context = 0;
1243 Buffer = NULL;
1244 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1245 FALSE, TRUE, &Context, &ReturnLength);
1246 if (NT_SUCCESS(Status))
1247 {
1248 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1249 FALSE, &Context, NULL))
1250 {
1251 /* Our fixed-size buffer is large enough */
1252 Buffer = InitialBuffer;
1253 }
1254 }
1255
1256 if (NULL == Buffer)
1257 {
1258 /* Need a larger buffer, check how large exactly */
1259 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1260 &ReturnLength);
1261 if (STATUS_BUFFER_TOO_SMALL == Status)
1262 {
1263 BufferSize = ReturnLength;
1264 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1265 if (NULL == Buffer)
1266 {
1267 ObDereferenceObject(DirectoryHandle);
1268 return STATUS_NO_MEMORY;
1269 }
1270
1271 /* We should have a sufficiently large buffer now */
1272 Context = 0;
1273 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1274 FALSE, TRUE, &Context, &ReturnLength);
1275 if (! NT_SUCCESS(Status) ||
1276 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1277 FALSE, &Context, NULL))
1278 {
1279 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1280 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1281 ObDereferenceObject(DirectoryHandle);
1282 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1283 }
1284 }
1285 }
1286
1287 ZwClose(DirectoryHandle);
1288
1289 /*
1290 * Count the required size of buffer.
1291 */
1292 ReturnLength = sizeof(DWORD);
1293 EntryCount = 0;
1294 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1295 DirEntry++)
1296 {
1297 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1298 EntryCount++;
1299 }
1300 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1301 if (NULL != pRequiredSize)
1302 {
1303 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1304 if (! NT_SUCCESS(Status))
1305 {
1306 if (Buffer != InitialBuffer)
1307 {
1308 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1309 }
1310 return STATUS_BUFFER_TOO_SMALL;
1311 }
1312 }
1313
1314 /*
1315 * Check if the supplied buffer is large enough.
1316 */
1317 if (dwSize < ReturnLength)
1318 {
1319 if (Buffer != InitialBuffer)
1320 {
1321 ExFreePoolWithTag(Buffer, TAG_WINSTA);
1322 }
1323 return STATUS_BUFFER_TOO_SMALL;
1324 }
1325
1326 /*
1327 * Generate the resulting buffer contents.
1328 */
1329 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1330 if (! NT_SUCCESS(Status))
1331 {
1332 if (Buffer != InitialBuffer)
1333 {
1334 ExFreePool(Buffer);
1335 }
1336 return Status;
1337 }
1338 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1339
1340 NullWchar = L'\0';
1341 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1342 DirEntry++)
1343 {
1344 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1345 if (! NT_SUCCESS(Status))
1346 {
1347 if (Buffer != InitialBuffer)
1348 {
1349 ExFreePool(Buffer);
1350 }
1351 return Status;
1352 }
1353 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1354 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1355 if (! NT_SUCCESS(Status))
1356 {
1357 if (Buffer != InitialBuffer)
1358 {
1359 ExFreePool(Buffer);
1360 }
1361 return Status;
1362 }
1363 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1364 }
1365
1366 /*
1367 * Clean up
1368 */
1369 if (NULL != Buffer && Buffer != InitialBuffer)
1370 {
1371 ExFreePool(Buffer);
1372 }
1373
1374 return STATUS_SUCCESS;
1375 }
1376
1377 static NTSTATUS FASTCALL
1378 BuildDesktopNameList(
1379 HWINSTA hWindowStation,
1380 ULONG dwSize,
1381 PVOID lpBuffer,
1382 PULONG pRequiredSize)
1383 {
1384 NTSTATUS Status;
1385 PWINSTATION_OBJECT WindowStation;
1386 KIRQL OldLevel;
1387 PLIST_ENTRY DesktopEntry;
1388 PDESKTOP DesktopObject;
1389 DWORD EntryCount;
1390 ULONG ReturnLength;
1391 WCHAR NullWchar;
1392
1393 Status = IntValidateWindowStationHandle(hWindowStation,
1394 KernelMode,
1395 0,
1396 &WindowStation);
1397 if (! NT_SUCCESS(Status))
1398 {
1399 return Status;
1400 }
1401
1402 KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
1403
1404 /*
1405 * Count the required size of buffer.
1406 */
1407 ReturnLength = sizeof(DWORD);
1408 EntryCount = 0;
1409 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1410 DesktopEntry != &WindowStation->DesktopListHead;
1411 DesktopEntry = DesktopEntry->Flink)
1412 {
1413 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1414 ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
1415 EntryCount++;
1416 }
1417 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1418 if (NULL != pRequiredSize)
1419 {
1420 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1421 if (! NT_SUCCESS(Status))
1422 {
1423 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1424 ObDereferenceObject(WindowStation);
1425 return STATUS_BUFFER_TOO_SMALL;
1426 }
1427 }
1428
1429 /*
1430 * Check if the supplied buffer is large enough.
1431 */
1432 if (dwSize < ReturnLength)
1433 {
1434 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1435 ObDereferenceObject(WindowStation);
1436 return STATUS_BUFFER_TOO_SMALL;
1437 }
1438
1439 /*
1440 * Generate the resulting buffer contents.
1441 */
1442 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1443 if (! NT_SUCCESS(Status))
1444 {
1445 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1446 ObDereferenceObject(WindowStation);
1447 return Status;
1448 }
1449 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1450
1451 NullWchar = L'\0';
1452 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1453 DesktopEntry != &WindowStation->DesktopListHead;
1454 DesktopEntry = DesktopEntry->Flink)
1455 {
1456 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1457 Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1458 if (! NT_SUCCESS(Status))
1459 {
1460 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1461 ObDereferenceObject(WindowStation);
1462 return Status;
1463 }
1464 lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1465 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1466 if (! NT_SUCCESS(Status))
1467 {
1468 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1469 ObDereferenceObject(WindowStation);
1470 return Status;
1471 }
1472 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1473 }
1474
1475 /*
1476 * Clean up
1477 */
1478 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1479 ObDereferenceObject(WindowStation);
1480
1481 return STATUS_SUCCESS;
1482 }
1483
1484 /*
1485 * NtUserBuildNameList
1486 *
1487 * Function used for enumeration of desktops or window stations.
1488 *
1489 * Parameters
1490 * hWinSta
1491 * For enumeration of window stations this parameter must be set to
1492 * zero. Otherwise it's handle for window station.
1493 *
1494 * dwSize
1495 * Size of buffer passed by caller.
1496 *
1497 * lpBuffer
1498 * Buffer passed by caller. If the function succedes, the buffer is
1499 * filled with window station/desktop count (in first DWORD) and
1500 * NULL-terminated window station/desktop names.
1501 *
1502 * pRequiredSize
1503 * If the function suceedes, this is the number of bytes copied.
1504 * Otherwise it's size of buffer needed for function to succeed.
1505 *
1506 * Status
1507 * @implemented
1508 */
1509
1510 NTSTATUS APIENTRY
1511 NtUserBuildNameList(
1512 HWINSTA hWindowStation,
1513 ULONG dwSize,
1514 PVOID lpBuffer,
1515 PULONG pRequiredSize)
1516 {
1517 /* The WindowStation name list and desktop name list are build in completely
1518 different ways. Call the appropriate function */
1519 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1520 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1521 }
1522
1523 /* EOF */