Merging r37048, r37051, r37052, r37055 from the-real-msvc 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 STDCALL
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 STDCALL
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 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
298 if (! IntCreatePrimarySurface())
299 {
300 return FALSE;
301 }
302 ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
303 if (NULL == ScreenDeviceContext)
304 {
305 IntDestroyPrimarySurface();
306 return FALSE;
307 }
308 IntGdiSetDCOwnerEx(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC, FALSE);
309
310 /* Setup the cursor */
311 co_IntLoadDefaultCursors();
312
313 hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
314
315 NtGdiSelectFont( hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
316 IntGdiSetDCOwnerEx( hSystemBM, GDI_OBJ_HMGR_PUBLIC, FALSE);
317
318 return TRUE;
319 }
320
321 VOID FASTCALL
322 IntEndDesktopGraphics(VOID)
323 {
324 if (NULL != ScreenDeviceContext)
325 { // No need to allocate a new dcattr.
326 DC_SetOwnership(ScreenDeviceContext, PsGetCurrentProcess());
327 NtGdiDeleteObjectApp(ScreenDeviceContext);
328 ScreenDeviceContext = NULL;
329 }
330 IntHideDesktop(IntGetActiveDesktop());
331 IntDestroyPrimarySurface();
332 }
333
334 HDC FASTCALL
335 IntGetScreenDC(VOID)
336 {
337 return ScreenDeviceContext;
338 }
339
340 /* PUBLIC FUNCTIONS ***********************************************************/
341
342 /*
343 * NtUserCreateWindowStation
344 *
345 * Creates a new window station.
346 *
347 * Parameters
348 * lpszWindowStationName
349 * Pointer to a null-terminated string specifying the name of the
350 * window station to be created. Window station names are
351 * case-insensitive and cannot contain backslash characters (\).
352 * Only members of the Administrators group are allowed to specify a
353 * name.
354 *
355 * dwDesiredAccess
356 * Requested type of access
357 *
358 * lpSecurity
359 * Security descriptor
360 *
361 * Unknown3, Unknown4, Unknown5
362 * Unused
363 *
364 * Return Value
365 * If the function succeeds, the return value is a handle to the newly
366 * created window station. If the specified window station already
367 * exists, the function succeeds and returns a handle to the existing
368 * window station. If the function fails, the return value is NULL.
369 *
370 * Todo
371 * Correct the prototype to match the Windows one (with 7 parameters
372 * on Windows XP).
373 *
374 * Status
375 * @implemented
376 */
377
378 HWINSTA STDCALL
379 NtUserCreateWindowStation(
380 PUNICODE_STRING lpszWindowStationName,
381 ACCESS_MASK dwDesiredAccess,
382 LPSECURITY_ATTRIBUTES lpSecurity,
383 DWORD Unknown3,
384 DWORD Unknown4,
385 DWORD Unknown5,
386 DWORD Unknown6)
387 {
388 PSYSTEM_CURSORINFO CurInfo;
389 UNICODE_STRING WindowStationName;
390 UNICODE_STRING FullWindowStationName;
391 PWINSTATION_OBJECT WindowStationObject;
392 HWINSTA WindowStation;
393 OBJECT_ATTRIBUTES ObjectAttributes;
394 NTSTATUS Status;
395
396 /*
397 * Generate full window station name
398 */
399 Status = ProbeAndCaptureUnicodeString(&WindowStationName,
400 UserMode,
401 lpszWindowStationName);
402 if (!NT_SUCCESS(Status))
403 {
404 DPRINT1("Failed to capture window station name (status 0x%08x)\n",
405 Status);
406 SetLastNtError(Status);
407 return 0;
408 }
409 if (!IntGetFullWindowStationName(&FullWindowStationName,
410 &WindowStationName,
411 NULL))
412 {
413 ReleaseCapturedUnicodeString(&WindowStationName, UserMode);
414 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
415 return 0;
416 }
417
418 /*
419 * Try to open already existing window station
420 */
421
422 DPRINT("Trying to open window station (%wZ)\n", &FullWindowStationName);
423
424 /* Initialize ObjectAttributes for the window station object */
425 InitializeObjectAttributes(
426 &ObjectAttributes,
427 &FullWindowStationName,
428 0,
429 NULL,
430 NULL);
431
432 Status = ObOpenObjectByName(
433 &ObjectAttributes,
434 ExWindowStationObjectType,
435 KernelMode,
436 NULL,
437 dwDesiredAccess,
438 NULL,
439 (PVOID*)&WindowStation);
440
441 if (NT_SUCCESS(Status))
442 {
443 DPRINT("Successfully opened window station (%wZ)\n",
444 FullWindowStationName);
445 ExFreePool(FullWindowStationName.Buffer);
446 ReleaseCapturedUnicodeString(&WindowStationName, UserMode);
447 return (HWINSTA)WindowStation;
448 }
449
450 /*
451 * No existing window station found, try to create new one
452 */
453
454 DPRINT("Creating window station (%wZ)\n", &FullWindowStationName);
455
456 Status = ObCreateObject(
457 KernelMode,
458 ExWindowStationObjectType,
459 &ObjectAttributes,
460 ExGetPreviousMode(),
461 NULL,
462 sizeof(WINSTATION_OBJECT),
463 0,
464 0,
465 (PVOID*)&WindowStationObject);
466
467 if (!NT_SUCCESS(Status))
468 {
469 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName);
470 ExFreePool(FullWindowStationName.Buffer);
471 ReleaseCapturedUnicodeString(&WindowStationName, UserMode);
472 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
473 return 0;
474 }
475
476 KeInitializeSpinLock(&WindowStationObject->Lock);
477
478 InitializeListHead(&WindowStationObject->DesktopListHead);
479
480 WindowStationObject->AtomTable = NULL;
481 Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
482 WindowStationObject->SystemMenuTemplate = (HANDLE)0;
483
484 WindowStationObject->Name = WindowStationName;
485
486 Status = ObInsertObject(
487 (PVOID)WindowStationObject,
488 NULL,
489 STANDARD_RIGHTS_REQUIRED,
490 0,
491 NULL,
492 (PVOID*)&WindowStation);
493
494 if (!NT_SUCCESS(Status))
495 {
496 DPRINT1("Failed creating window station (%wZ)\n", &FullWindowStationName);
497 ExFreePool(FullWindowStationName.Buffer);
498 ExFreePool(WindowStationName.Buffer);
499 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
500 ObDereferenceObject(WindowStationObject);
501 return 0;
502 }
503
504 /*
505 * Initialize the new window station object
506 */
507
508 WindowStationObject->ScreenSaverRunning = FALSE;
509
510 WindowStationObject->FlatMenu = FALSE;
511
512 if(!(CurInfo = ExAllocatePool(PagedPool, sizeof(SYSTEM_CURSORINFO))))
513 {
514 ExFreePool(FullWindowStationName.Buffer);
515 /* FIXME - Delete window station object */
516 ObDereferenceObject(WindowStationObject);
517 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
518 return 0;
519 }
520
521 CurInfo->Enabled = FALSE;
522 CurInfo->ButtonsDown = 0;
523 CurInfo->CursorClipInfo.IsClipped = FALSE;
524 CurInfo->LastBtnDown = 0;
525 CurInfo->CurrentCursorObject = NULL;
526 CurInfo->ShowingCursor = 0;
527
528 /* FIXME: Obtain the following information from the registry */
529
530 CurInfo->WheelScroLines = 3;
531 CurInfo->WheelScroChars = 3;
532 CurInfo->SwapButtons = FALSE;
533 CurInfo->DblClickSpeed = 500;
534 CurInfo->DblClickWidth = 4;
535 CurInfo->DblClickHeight = 4;
536
537 CurInfo->MouseSpeed = 10;
538 CurInfo->CursorAccelerationInfo.FirstThreshold = 6;
539 CurInfo->CursorAccelerationInfo.SecondThreshold = 10;
540 CurInfo->CursorAccelerationInfo.Acceleration = 1;
541
542 CurInfo->MouseHoverTime = 80;
543 CurInfo->MouseHoverWidth = 4;
544 CurInfo->MouseHoverHeight = 4;
545
546 WindowStationObject->ScreenSaverActive = FALSE;
547 WindowStationObject->ScreenSaverTimeOut = 10;
548 WindowStationObject->SystemCursor = CurInfo;
549
550 /* END FIXME loading from register */
551
552 if (!IntSetupClipboard(WindowStationObject))
553 {
554 DPRINT1("WindowStation: Error Setting up the clipboard!!!\n");
555 }
556
557 if (!IntSetupCurIconHandles(WindowStationObject))
558 {
559 DPRINT1("Setting up the Cursor/Icon Handle table failed!\n");
560 /* FIXME: Complain more loudly? */
561 ExFreePool(FullWindowStationName.Buffer);
562 }
563
564 DPRINT("Window station successfully created (%wZ)\n", &FullWindowStationName);
565 ExFreePool(FullWindowStationName.Buffer);
566 return WindowStation;
567 }
568
569 /*
570 * NtUserOpenWindowStation
571 *
572 * Opens an existing window station.
573 *
574 * Parameters
575 * lpszWindowStationName
576 * Name of the existing window station.
577 *
578 * dwDesiredAccess
579 * Requested type of access.
580 *
581 * Return Value
582 * If the function succeeds, the return value is the handle to the
583 * specified window station. If the function fails, the return value
584 * is NULL.
585 *
586 * Remarks
587 * The returned handle can be closed with NtUserCloseWindowStation.
588 *
589 * Status
590 * @implemented
591 */
592
593 HWINSTA STDCALL
594 NtUserOpenWindowStation(
595 PUNICODE_STRING lpszWindowStationName,
596 ACCESS_MASK dwDesiredAccess)
597 {
598 UNICODE_STRING WindowStationName;
599 HWINSTA WindowStation;
600 OBJECT_ATTRIBUTES ObjectAttributes;
601 NTSTATUS Status;
602
603 /*
604 * Generate full window station name
605 */
606
607 if (!IntGetFullWindowStationName(&WindowStationName, lpszWindowStationName,
608 NULL))
609 {
610 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
611 return 0;
612 }
613
614 DPRINT("Trying to open window station (%wZ)\n", &WindowStationName);
615
616 /* Initialize ObjectAttributes for the window station object */
617 InitializeObjectAttributes(
618 &ObjectAttributes,
619 &WindowStationName,
620 0,
621 NULL,
622 NULL);
623
624 Status = ObOpenObjectByName(
625 &ObjectAttributes,
626 ExWindowStationObjectType,
627 UserMode,
628 NULL,
629 dwDesiredAccess,
630 NULL,
631 (PVOID*)&WindowStation);
632
633 if (!NT_SUCCESS(Status))
634 {
635 SetLastNtError(Status);
636 ExFreePool(WindowStationName.Buffer);
637 return 0;
638 }
639
640 DPRINT("Successfully opened window station (%wZ)\n", &WindowStationName);
641 ExFreePool(WindowStationName.Buffer);
642
643 return WindowStation;
644 }
645
646 /*
647 * NtUserCloseWindowStation
648 *
649 * Closes a window station handle.
650 *
651 * Parameters
652 * hWinSta
653 * Handle to the window station.
654 *
655 * Return Value
656 * Status
657 *
658 * Remarks
659 * The window station handle can be created with NtUserCreateWindowStation
660 * or NtUserOpenWindowStation. Attemps to close a handle to the window
661 * station assigned to the calling process will fail.
662 *
663 * Status
664 * @implemented
665 */
666
667 BOOL
668 STDCALL
669 NtUserCloseWindowStation(
670 HWINSTA hWinSta)
671 {
672 PWINSTATION_OBJECT Object;
673 NTSTATUS Status;
674
675 DPRINT("About to close window station handle (0x%X)\n", hWinSta);
676
677 Status = IntValidateWindowStationHandle(
678 hWinSta,
679 KernelMode,
680 0,
681 &Object);
682
683 if (!NT_SUCCESS(Status))
684 {
685 DPRINT("Validation of window station handle (0x%X) failed\n", hWinSta);
686 return FALSE;
687 }
688
689 #if 0
690 /* FIXME - free the cursor information when actually deleting the object!! */
691 ASSERT(Object->SystemCursor);
692 ExFreePool(Object->SystemCursor);
693 #endif
694
695 ObDereferenceObject(Object);
696
697 DPRINT("Closing window station handle (0x%X)\n", hWinSta);
698
699 Status = ZwClose(hWinSta);
700 if (!NT_SUCCESS(Status))
701 {
702 SetLastNtError(Status);
703 return FALSE;
704 }
705
706 return TRUE;
707 }
708
709 /*
710 * NtUserGetObjectInformation
711 *
712 * The NtUserGetObjectInformation function retrieves information about a
713 * window station or desktop object.
714 *
715 * Parameters
716 * hObj
717 * Handle to the window station or desktop object for which to
718 * return information. This can be a handle of type HDESK or HWINSTA
719 * (for example, a handle returned by NtUserCreateWindowStation,
720 * NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
721 *
722 * nIndex
723 * Specifies the object information to be retrieved.
724 *
725 * pvInfo
726 * Pointer to a buffer to receive the object information.
727 *
728 * nLength
729 * Specifies the size, in bytes, of the buffer pointed to by the
730 * pvInfo parameter.
731 *
732 * lpnLengthNeeded
733 * Pointer to a variable receiving the number of bytes required to
734 * store the requested information. If this variable's value is
735 * greater than the value of the nLength parameter when the function
736 * returns, the function returns FALSE, and none of the information
737 * is copied to the pvInfo buffer. If the value of the variable pointed
738 * to by lpnLengthNeeded is less than or equal to the value of nLength,
739 * the entire information block is copied.
740 *
741 * Return Value
742 * If the function succeeds, the return value is nonzero. If the function
743 * fails, the return value is zero.
744 *
745 * Status
746 * @unimplemented
747 */
748
749 BOOL STDCALL
750 NtUserGetObjectInformation(
751 HANDLE hObject,
752 DWORD nIndex,
753 PVOID pvInformation,
754 DWORD nLength,
755 PDWORD nLengthNeeded)
756 {
757 PWINSTATION_OBJECT WinStaObject = NULL;
758 PDESKTOP DesktopObject = NULL;
759 NTSTATUS Status;
760 PVOID pvData = NULL;
761 DWORD nDataSize = 0;
762
763 /* try windowstation */
764 DPRINT("Trying to open window station 0x%x\n", hObject);
765 Status = IntValidateWindowStationHandle(
766 hObject,
767 UserMode,/*ExGetPreviousMode(),*/
768 GENERIC_READ, /* FIXME: is this ok? */
769 &WinStaObject);
770
771
772 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_TYPE_MISMATCH)
773 {
774 DPRINT("Failed: 0x%x\n", Status);
775 SetLastNtError(Status);
776 return FALSE;
777 }
778
779 if (Status == STATUS_OBJECT_TYPE_MISMATCH)
780 {
781 /* try desktop */
782 DPRINT("Trying to open desktop 0x%x\n", hObject);
783 Status = IntValidateDesktopHandle(
784 hObject,
785 UserMode,/*ExGetPreviousMode(),*/
786 GENERIC_READ, /* FIXME: is this ok? */
787 &DesktopObject);
788 if (!NT_SUCCESS(Status))
789 {
790 DPRINT("Failed: 0x%x\n", Status);
791 SetLastNtError(Status);
792 return FALSE;
793 }
794 }
795 DPRINT("WinSta or Desktop opened!!\n");
796
797 /* get data */
798 switch (nIndex)
799 {
800 case UOI_FLAGS:
801 Status = STATUS_NOT_IMPLEMENTED;
802 DPRINT1("UOI_FLAGS unimplemented!\n");
803 break;
804
805 case UOI_NAME:
806 if (WinStaObject != NULL)
807 {
808 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Buffer;
809 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(WinStaObject))->Length + 2;
810 Status = STATUS_SUCCESS;
811 }
812 else if (DesktopObject != NULL)
813 {
814 pvData = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer;
815 nDataSize = ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + 2;
816 Status = STATUS_SUCCESS;
817 }
818 else
819 Status = STATUS_INVALID_PARAMETER;
820 break;
821
822 case UOI_TYPE:
823 if (WinStaObject != NULL)
824 {
825 pvData = L"WindowStation";
826 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
827 Status = STATUS_SUCCESS;
828 }
829 else if (DesktopObject != NULL)
830 {
831 pvData = L"Desktop";
832 nDataSize = (wcslen(pvData) + 1) * sizeof(WCHAR);
833 Status = STATUS_SUCCESS;
834 }
835 else
836 Status = STATUS_INVALID_PARAMETER;
837 break;
838
839 case UOI_USER_SID:
840 Status = STATUS_NOT_IMPLEMENTED;
841 DPRINT1("UOI_USER_SID unimplemented!\n");
842 break;
843
844 default:
845 Status = STATUS_INVALID_PARAMETER;
846 break;
847 }
848
849 /* try to copy data to caller */
850 if (Status == STATUS_SUCCESS)
851 {
852 DPRINT("Trying to copy data to caller (len = %d, len needed = %d)\n", nLength, nDataSize);
853 *nLengthNeeded = nDataSize;
854 if (nLength >= nDataSize)
855 Status = MmCopyToCaller(pvInformation, pvData, nDataSize);
856 else
857 Status = STATUS_BUFFER_TOO_SMALL;
858 }
859
860 /* release objects */
861 if (WinStaObject != NULL)
862 ObDereferenceObject(WinStaObject);
863 if (DesktopObject != NULL)
864 ObDereferenceObject(DesktopObject);
865
866 SetLastNtError(Status);
867 return NT_SUCCESS(Status);
868 }
869
870 /*
871 * NtUserSetObjectInformation
872 *
873 * The NtUserSetObjectInformation function sets information about a
874 * window station or desktop object.
875 *
876 * Parameters
877 * hObj
878 * Handle to the window station or desktop object for which to set
879 * object information. This value can be a handle of type HDESK or
880 * HWINSTA.
881 *
882 * nIndex
883 * Specifies the object information to be set.
884 *
885 * pvInfo
886 * Pointer to a buffer containing the object information.
887 *
888 * nLength
889 * Specifies the size, in bytes, of the information contained in the
890 * buffer pointed to by pvInfo.
891 *
892 * Return Value
893 * If the function succeeds, the return value is nonzero. If the function
894 * fails the return value is zero.
895 *
896 * Status
897 * @unimplemented
898 */
899
900 BOOL
901 STDCALL
902 NtUserSetObjectInformation(
903 HANDLE hObject,
904 DWORD nIndex,
905 PVOID pvInformation,
906 DWORD nLength)
907 {
908 /* FIXME: ZwQueryObject */
909 /* FIXME: ZwSetInformationObject */
910 SetLastNtError(STATUS_UNSUCCESSFUL);
911 return FALSE;
912 }
913
914
915
916
917 HWINSTA FASTCALL
918 UserGetProcessWindowStation(VOID)
919 {
920 NTSTATUS Status;
921 PTHREADINFO pti;
922 HWINSTA WinSta;
923
924 if(PsGetCurrentProcess() != CsrProcess)
925 {
926 return PsGetCurrentProcess()->Win32WindowStation;
927 }
928 else
929 {
930 DPRINT1("Should use ObFindHandleForObject\n");
931 pti = PsGetCurrentThreadWin32Thread();
932 Status = ObOpenObjectByPointer(pti->Desktop->WindowStation,
933 0,
934 NULL,
935 WINSTA_ALL_ACCESS,
936 ExWindowStationObjectType,
937 UserMode,
938 (PHANDLE) &WinSta);
939 if (! NT_SUCCESS(Status))
940 {
941 SetLastNtError(Status);
942 DPRINT1("Unable to open handle for CSRSSs winsta, status 0x%08x\n",
943 Status);
944 return NULL;
945 }
946 return WinSta;
947 }
948 }
949
950
951 /*
952 * NtUserGetProcessWindowStation
953 *
954 * Returns a handle to the current process window station.
955 *
956 * Return Value
957 * If the function succeeds, the return value is handle to the window
958 * station assigned to the current process. If the function fails, the
959 * return value is NULL.
960 *
961 * Status
962 * @implemented
963 */
964
965 HWINSTA STDCALL
966 NtUserGetProcessWindowStation(VOID)
967 {
968 return UserGetProcessWindowStation();
969 }
970
971 PWINSTATION_OBJECT FASTCALL
972 IntGetWinStaObj(VOID)
973 {
974 PWINSTATION_OBJECT WinStaObj;
975 PTHREADINFO Win32Thread;
976 PEPROCESS CurrentProcess;
977
978 /*
979 * just a temporary hack, this will be gone soon
980 */
981
982 Win32Thread = PsGetCurrentThreadWin32Thread();
983 if(Win32Thread != NULL && Win32Thread->Desktop != NULL)
984 {
985 WinStaObj = Win32Thread->Desktop->WindowStation;
986 ObReferenceObjectByPointer(WinStaObj, KernelMode, ExWindowStationObjectType, 0);
987 }
988 else if((CurrentProcess = PsGetCurrentProcess()) != CsrProcess)
989 {
990 NTSTATUS Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
991 KernelMode,
992 0,
993 &WinStaObj);
994 if(!NT_SUCCESS(Status))
995 {
996 SetLastNtError(Status);
997 return NULL;
998 }
999 }
1000 else
1001 {
1002 WinStaObj = NULL;
1003 }
1004
1005 return WinStaObj;
1006 }
1007
1008 /*
1009 * NtUserSetProcessWindowStation
1010 *
1011 * Assigns a window station to the current process.
1012 *
1013 * Parameters
1014 * hWinSta
1015 * Handle to the window station.
1016 *
1017 * Return Value
1018 * Status
1019 *
1020 * Status
1021 * @implemented
1022 */
1023
1024 BOOL STDCALL
1025 NtUserSetProcessWindowStation(HWINSTA hWindowStation)
1026 {
1027 HANDLE hOld;
1028 PWINSTATION_OBJECT NewWinSta;
1029 NTSTATUS Status;
1030
1031 DPRINT("About to set process window station with handle (0x%X)\n",
1032 hWindowStation);
1033
1034 if(PsGetCurrentProcess() == CsrProcess)
1035 {
1036 DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
1037 SetLastWin32Error(ERROR_ACCESS_DENIED);
1038 return FALSE;
1039 }
1040
1041 Status = IntValidateWindowStationHandle(
1042 hWindowStation,
1043 KernelMode,
1044 0,
1045 &NewWinSta);
1046
1047 if (!NT_SUCCESS(Status))
1048 {
1049 DPRINT("Validation of window station handle (0x%X) failed\n",
1050 hWindowStation);
1051 SetLastNtError(Status);
1052 return FALSE;
1053 }
1054
1055 /*
1056 * FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
1057 */
1058
1059 /* FIXME - dereference the old window station, etc... */
1060 hOld = InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
1061
1062 DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
1063 PsGetCurrentProcess()->Win32WindowStation);
1064
1065 return TRUE;
1066 }
1067
1068 /*
1069 * NtUserLockWindowStation
1070 *
1071 * Locks switching desktops. Only the logon application is allowed to call this function.
1072 *
1073 * Status
1074 * @implemented
1075 */
1076
1077 BOOL STDCALL
1078 NtUserLockWindowStation(HWINSTA hWindowStation)
1079 {
1080 PWINSTATION_OBJECT Object;
1081 NTSTATUS Status;
1082
1083 DPRINT("About to set process window station with handle (0x%X)\n",
1084 hWindowStation);
1085
1086 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1087 {
1088 DPRINT1("Unauthorized process attempted to lock the window station!\n");
1089 SetLastWin32Error(ERROR_ACCESS_DENIED);
1090 return FALSE;
1091 }
1092
1093 Status = IntValidateWindowStationHandle(
1094 hWindowStation,
1095 KernelMode,
1096 0,
1097 &Object);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 DPRINT("Validation of window station handle (0x%X) failed\n",
1101 hWindowStation);
1102 SetLastNtError(Status);
1103 return FALSE;
1104 }
1105
1106 Object->Flags |= WSS_LOCKED;
1107
1108 ObDereferenceObject(Object);
1109 return TRUE;
1110 }
1111
1112 /*
1113 * NtUserUnlockWindowStation
1114 *
1115 * Unlocks switching desktops. Only the logon application is allowed to call this function.
1116 *
1117 * Status
1118 * @implemented
1119 */
1120
1121 BOOL STDCALL
1122 NtUserUnlockWindowStation(HWINSTA hWindowStation)
1123 {
1124 PWINSTATION_OBJECT Object;
1125 NTSTATUS Status;
1126 BOOL Ret;
1127
1128 DPRINT("About to set process window station with handle (0x%X)\n",
1129 hWindowStation);
1130
1131 if(PsGetCurrentProcessWin32Process() != LogonProcess)
1132 {
1133 DPRINT1("Unauthorized process attempted to unlock the window station!\n");
1134 SetLastWin32Error(ERROR_ACCESS_DENIED);
1135 return FALSE;
1136 }
1137
1138 Status = IntValidateWindowStationHandle(
1139 hWindowStation,
1140 KernelMode,
1141 0,
1142 &Object);
1143 if (!NT_SUCCESS(Status))
1144 {
1145 DPRINT("Validation of window station handle (0x%X) failed\n",
1146 hWindowStation);
1147 SetLastNtError(Status);
1148 return FALSE;
1149 }
1150
1151 Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
1152 Object->Flags &= ~WSS_LOCKED;
1153
1154 ObDereferenceObject(Object);
1155 return Ret;
1156 }
1157
1158 /*
1159 * NtUserSetWindowStationUser
1160 *
1161 * Status
1162 * @unimplemented
1163 */
1164
1165 DWORD STDCALL
1166 NtUserSetWindowStationUser(
1167 DWORD Unknown0,
1168 DWORD Unknown1,
1169 DWORD Unknown2,
1170 DWORD Unknown3)
1171 {
1172 UNIMPLEMENTED
1173
1174 return 0;
1175 }
1176
1177 static NTSTATUS FASTCALL
1178 BuildWindowStationNameList(
1179 ULONG dwSize,
1180 PVOID lpBuffer,
1181 PULONG pRequiredSize)
1182 {
1183 OBJECT_ATTRIBUTES ObjectAttributes;
1184 NTSTATUS Status;
1185 HANDLE DirectoryHandle;
1186 UNICODE_STRING DirectoryName;
1187 char InitialBuffer[256], *Buffer;
1188 ULONG Context, ReturnLength, BufferSize;
1189 DWORD EntryCount;
1190 POBJECT_DIRECTORY_INFORMATION DirEntry;
1191 WCHAR NullWchar;
1192
1193 /*
1194 * Generate name of window station directory
1195 */
1196 if (!IntGetFullWindowStationName(&DirectoryName, NULL, NULL))
1197 {
1198 return STATUS_INSUFFICIENT_RESOURCES;
1199 }
1200
1201 /*
1202 * Try to open the directory.
1203 */
1204 InitializeObjectAttributes(
1205 &ObjectAttributes,
1206 &DirectoryName,
1207 OBJ_CASE_INSENSITIVE,
1208 NULL,
1209 NULL);
1210
1211 Status = ZwOpenDirectoryObject(
1212 &DirectoryHandle,
1213 DIRECTORY_QUERY,
1214 &ObjectAttributes);
1215
1216 ExFreePool(DirectoryName.Buffer);
1217
1218 if (!NT_SUCCESS(Status))
1219 {
1220 return Status;
1221 }
1222
1223 /* First try to query the directory using a fixed-size buffer */
1224 Context = 0;
1225 Buffer = NULL;
1226 Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
1227 FALSE, TRUE, &Context, &ReturnLength);
1228 if (NT_SUCCESS(Status))
1229 {
1230 if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1231 FALSE, &Context, NULL))
1232 {
1233 /* Our fixed-size buffer is large enough */
1234 Buffer = InitialBuffer;
1235 }
1236 }
1237
1238 if (NULL == Buffer)
1239 {
1240 /* Need a larger buffer, check how large exactly */
1241 Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
1242 &ReturnLength);
1243 if (STATUS_BUFFER_TOO_SMALL == Status)
1244 {
1245 BufferSize = ReturnLength;
1246 Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
1247 if (NULL == Buffer)
1248 {
1249 ObDereferenceObject(DirectoryHandle);
1250 return STATUS_NO_MEMORY;
1251 }
1252
1253 /* We should have a sufficiently large buffer now */
1254 Context = 0;
1255 Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
1256 FALSE, TRUE, &Context, &ReturnLength);
1257 if (! NT_SUCCESS(Status) ||
1258 STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
1259 FALSE, &Context, NULL))
1260 {
1261 /* Something went wrong, maybe someone added a directory entry? Just give up. */
1262 ExFreePool(Buffer);
1263 ObDereferenceObject(DirectoryHandle);
1264 return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
1265 }
1266 }
1267 }
1268
1269 ZwClose(DirectoryHandle);
1270
1271 /*
1272 * Count the required size of buffer.
1273 */
1274 ReturnLength = sizeof(DWORD);
1275 EntryCount = 0;
1276 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1277 DirEntry++)
1278 {
1279 ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
1280 EntryCount++;
1281 }
1282 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1283 if (NULL != pRequiredSize)
1284 {
1285 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1286 if (! NT_SUCCESS(Status))
1287 {
1288 if (Buffer != InitialBuffer)
1289 {
1290 ExFreePool(Buffer);
1291 }
1292 return STATUS_BUFFER_TOO_SMALL;
1293 }
1294 }
1295
1296 /*
1297 * Check if the supplied buffer is large enough.
1298 */
1299 if (dwSize < ReturnLength)
1300 {
1301 if (Buffer != InitialBuffer)
1302 {
1303 ExFreePool(Buffer);
1304 }
1305 return STATUS_BUFFER_TOO_SMALL;
1306 }
1307
1308 /*
1309 * Generate the resulting buffer contents.
1310 */
1311 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1312 if (! NT_SUCCESS(Status))
1313 {
1314 if (Buffer != InitialBuffer)
1315 {
1316 ExFreePool(Buffer);
1317 }
1318 return Status;
1319 }
1320 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1321
1322 NullWchar = L'\0';
1323 for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
1324 DirEntry++)
1325 {
1326 Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
1327 if (! NT_SUCCESS(Status))
1328 {
1329 if (Buffer != InitialBuffer)
1330 {
1331 ExFreePool(Buffer);
1332 }
1333 return Status;
1334 }
1335 lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
1336 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1337 if (! NT_SUCCESS(Status))
1338 {
1339 if (Buffer != InitialBuffer)
1340 {
1341 ExFreePool(Buffer);
1342 }
1343 return Status;
1344 }
1345 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1346 }
1347
1348 /*
1349 * Clean up
1350 */
1351 if (NULL != Buffer && Buffer != InitialBuffer)
1352 {
1353 ExFreePool(Buffer);
1354 }
1355
1356 return STATUS_SUCCESS;
1357 }
1358
1359 static NTSTATUS FASTCALL
1360 BuildDesktopNameList(
1361 HWINSTA hWindowStation,
1362 ULONG dwSize,
1363 PVOID lpBuffer,
1364 PULONG pRequiredSize)
1365 {
1366 NTSTATUS Status;
1367 PWINSTATION_OBJECT WindowStation;
1368 KIRQL OldLevel;
1369 PLIST_ENTRY DesktopEntry;
1370 PDESKTOP DesktopObject;
1371 DWORD EntryCount;
1372 ULONG ReturnLength;
1373 WCHAR NullWchar;
1374
1375 Status = IntValidateWindowStationHandle(hWindowStation,
1376 KernelMode,
1377 0,
1378 &WindowStation);
1379 if (! NT_SUCCESS(Status))
1380 {
1381 return Status;
1382 }
1383
1384 KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
1385
1386 /*
1387 * Count the required size of buffer.
1388 */
1389 ReturnLength = sizeof(DWORD);
1390 EntryCount = 0;
1391 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1392 DesktopEntry != &WindowStation->DesktopListHead;
1393 DesktopEntry = DesktopEntry->Flink)
1394 {
1395 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1396 ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
1397 EntryCount++;
1398 }
1399 DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
1400 if (NULL != pRequiredSize)
1401 {
1402 Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
1403 if (! NT_SUCCESS(Status))
1404 {
1405 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1406 ObDereferenceObject(WindowStation);
1407 return STATUS_BUFFER_TOO_SMALL;
1408 }
1409 }
1410
1411 /*
1412 * Check if the supplied buffer is large enough.
1413 */
1414 if (dwSize < ReturnLength)
1415 {
1416 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1417 ObDereferenceObject(WindowStation);
1418 return STATUS_BUFFER_TOO_SMALL;
1419 }
1420
1421 /*
1422 * Generate the resulting buffer contents.
1423 */
1424 Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
1425 if (! NT_SUCCESS(Status))
1426 {
1427 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1428 ObDereferenceObject(WindowStation);
1429 return Status;
1430 }
1431 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
1432
1433 NullWchar = L'\0';
1434 for (DesktopEntry = WindowStation->DesktopListHead.Flink;
1435 DesktopEntry != &WindowStation->DesktopListHead;
1436 DesktopEntry = DesktopEntry->Flink)
1437 {
1438 DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP, ListEntry);
1439 Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1440 if (! NT_SUCCESS(Status))
1441 {
1442 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1443 ObDereferenceObject(WindowStation);
1444 return Status;
1445 }
1446 lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
1447 Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
1448 if (! NT_SUCCESS(Status))
1449 {
1450 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1451 ObDereferenceObject(WindowStation);
1452 return Status;
1453 }
1454 lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
1455 }
1456
1457 /*
1458 * Clean up
1459 */
1460 KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
1461 ObDereferenceObject(WindowStation);
1462
1463 return STATUS_SUCCESS;
1464 }
1465
1466 /*
1467 * NtUserBuildNameList
1468 *
1469 * Function used for enumeration of desktops or window stations.
1470 *
1471 * Parameters
1472 * hWinSta
1473 * For enumeration of window stations this parameter must be set to
1474 * zero. Otherwise it's handle for window station.
1475 *
1476 * dwSize
1477 * Size of buffer passed by caller.
1478 *
1479 * lpBuffer
1480 * Buffer passed by caller. If the function succedes, the buffer is
1481 * filled with window station/desktop count (in first DWORD) and
1482 * NULL-terminated window station/desktop names.
1483 *
1484 * pRequiredSize
1485 * If the function suceedes, this is the number of bytes copied.
1486 * Otherwise it's size of buffer needed for function to succeed.
1487 *
1488 * Status
1489 * @implemented
1490 */
1491
1492 NTSTATUS STDCALL
1493 NtUserBuildNameList(
1494 HWINSTA hWindowStation,
1495 ULONG dwSize,
1496 PVOID lpBuffer,
1497 PULONG pRequiredSize)
1498 {
1499 /* The WindowStation name list and desktop name list are build in completely
1500 different ways. Call the appropriate function */
1501 return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
1502 BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
1503 }
1504
1505 /* EOF */