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