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