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