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