From 261286187f3b48a1fae1156a32d20d83da8f7b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Fri, 20 Aug 2004 22:38:49 +0000 Subject: [PATCH] Implement NtUserBuildNamesList() svn path=/trunk/; revision=10622 --- reactos/subsys/win32k/include/tags.h | 1 + reactos/subsys/win32k/ntuser/winsta.c | 386 ++++++++++++++++++++------ 2 files changed, 297 insertions(+), 90 deletions(-) diff --git a/reactos/subsys/win32k/include/tags.h b/reactos/subsys/win32k/include/tags.h index d57f20738ad..e9054445944 100644 --- a/reactos/subsys/win32k/include/tags.h +++ b/reactos/subsys/win32k/include/tags.h @@ -22,6 +22,7 @@ #define TAG_TIMERTD TAG('T', 'I', 'M', 'T') /* timer thread dereference list */ #define TAG_TIMERBMP TAG('T', 'I', 'M', 'B') /* timers bitmap */ #define TAG_CALLBACK TAG('C', 'B', 'C', 'K') /* callback memory */ +#define TAG_WINSTA TAG('W', 'S', 'T', 'A') /* window station */ /* objects */ #define TAG_BEZIER TAG('B', 'E', 'Z', 'R') /* bezier */ diff --git a/reactos/subsys/win32k/ntuser/winsta.c b/reactos/subsys/win32k/ntuser/winsta.c index 0995a7cf0e4..35d41554e8b 100644 --- a/reactos/subsys/win32k/ntuser/winsta.c +++ b/reactos/subsys/win32k/ntuser/winsta.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: winsta.c,v 1.64 2004/06/20 00:45:37 navaraf Exp $ + * $Id: winsta.c,v 1.65 2004/08/20 22:38:49 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -954,6 +954,295 @@ NtUserSetWindowStationUser( return 0; } +static NTSTATUS FASTCALL +BuildWindowStationNameList( + ULONG dwSize, + PVOID lpBuffer, + PULONG pRequiredSize) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE DirectoryHandle; + UNICODE_STRING DirectoryName; + char InitialBuffer[256], *Buffer; + ULONG Context, ReturnLength, BufferSize; + DWORD EntryCount; + PDIRECTORY_BASIC_INFORMATION DirEntry; + WCHAR NullWchar; + + /* + * Generate name of window station directory + */ + if (!IntGetFullWindowStationName(&DirectoryName, NULL, NULL)) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* + * Try to open the directory. + */ + InitializeObjectAttributes( + &ObjectAttributes, + &DirectoryName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = ZwOpenDirectoryObject( + &DirectoryHandle, + DIRECTORY_QUERY, + &ObjectAttributes); + + ExFreePool(DirectoryName.Buffer); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* First try to query the directory using a fixed-size buffer */ + Context = 0; + Buffer = NULL; + Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer), + FALSE, TRUE, &Context, &ReturnLength); + if (NT_SUCCESS(Status)) + { + if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, + FALSE, &Context, NULL)) + { + /* Our fixed-size buffer is large enough */ + Buffer = InitialBuffer; + } + } + + if (NULL == Buffer) + { + /* Need a larger buffer, check how large exactly */ + Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context, + &ReturnLength); + if (STATUS_BUFFER_TOO_SMALL == Status) + { + BufferSize = ReturnLength; + Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA); + if (NULL == Buffer) + { + ObDereferenceObject(DirectoryHandle); + return STATUS_NO_MEMORY; + } + + /* We should have a sufficiently large buffer now */ + Context = 0; + Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize, + FALSE, TRUE, &Context, &ReturnLength); + if (! NT_SUCCESS(Status) || + STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, + FALSE, &Context, NULL)) + { + /* Something went wrong, maybe someone added a directory entry? Just give up. */ + ExFreePool(Buffer); + ObDereferenceObject(DirectoryHandle); + return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status; + } + } + } + + ZwClose(DirectoryHandle); + + /* + * Count the required size of buffer. + */ + ReturnLength = sizeof(DWORD); + EntryCount = 0; + for (DirEntry = (PDIRECTORY_BASIC_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length; + DirEntry++) + { + ReturnLength += DirEntry->ObjectName.Length + sizeof(WCHAR); + EntryCount++; + } + DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount); + if (NULL != pRequiredSize) + { + Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG)); + if (! NT_SUCCESS(Status)) + { + if (Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + return STATUS_BUFFER_TOO_SMALL; + } + } + + /* + * Check if the supplied buffer is large enough. + */ + if (dwSize < ReturnLength) + { + if (Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + return STATUS_BUFFER_TOO_SMALL; + } + + /* + * Generate the resulting buffer contents. + */ + Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD)); + if (! NT_SUCCESS(Status)) + { + if (Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD)); + + NullWchar = L'\0'; + for (DirEntry = (PDIRECTORY_BASIC_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length; + DirEntry++) + { + Status = MmCopyToCaller(lpBuffer, DirEntry->ObjectName.Buffer, DirEntry->ObjectName.Length); + if (! NT_SUCCESS(Status)) + { + if (Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->ObjectName.Length); + Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR)); + if (! NT_SUCCESS(Status)) + { + if (Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR)); + } + + /* + * Clean up + */ + if (NULL != Buffer && Buffer != InitialBuffer) + { + ExFreePool(Buffer); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS FASTCALL +BuildDesktopNameList( + HWINSTA hWindowStation, + ULONG dwSize, + PVOID lpBuffer, + PULONG pRequiredSize) +{ + NTSTATUS Status; + PWINSTATION_OBJECT WindowStation; + KIRQL OldLevel; + PLIST_ENTRY DesktopEntry; + PDESKTOP_OBJECT DesktopObject; + DWORD EntryCount; + ULONG ReturnLength; + WCHAR NullWchar; + + Status = IntValidateWindowStationHandle(hWindowStation, + KernelMode, + 0, + &WindowStation); + if (! NT_SUCCESS(Status)) + { + return Status; + } + + KeAcquireSpinLock(&WindowStation->Lock, &OldLevel); + + /* + * Count the required size of buffer. + */ + ReturnLength = sizeof(DWORD); + EntryCount = 0; + for (DesktopEntry = WindowStation->DesktopListHead.Flink; + DesktopEntry != &WindowStation->DesktopListHead; + DesktopEntry = DesktopEntry->Flink) + { + DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP_OBJECT, ListEntry); + ReturnLength += DesktopObject->Name.Length + sizeof(WCHAR); + EntryCount++; + } + DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount); + if (NULL != pRequiredSize) + { + Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG)); + if (! NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + return STATUS_BUFFER_TOO_SMALL; + } + } + + /* + * Check if the supplied buffer is large enough. + */ + if (dwSize < ReturnLength) + { + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + return STATUS_BUFFER_TOO_SMALL; + } + + /* + * Generate the resulting buffer contents. + */ + Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD)); + if (! NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD)); + + NullWchar = L'\0'; + for (DesktopEntry = WindowStation->DesktopListHead.Flink; + DesktopEntry != &WindowStation->DesktopListHead; + DesktopEntry = DesktopEntry->Flink) + { + DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP_OBJECT, ListEntry); + Status = MmCopyToCaller(lpBuffer, DesktopObject->Name.Buffer, DesktopObject->Name.Length); + if (! NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + DesktopObject->Name.Length); + Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR)); + if (! NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + return Status; + } + lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR)); + } + + /* + * Clean up + */ + KeReleaseSpinLock(&WindowStation->Lock, OldLevel); + ObDereferenceObject(WindowStation); + + return STATUS_SUCCESS; +} + /* * NtUserBuildNameList * @@ -977,103 +1266,20 @@ NtUserSetWindowStationUser( * Otherwise it's size of buffer needed for function to succeed. * * Status - * @unimplemented + * @implemented */ NTSTATUS STDCALL NtUserBuildNameList( - HWINSTA hWinSta, + HWINSTA hWindowStation, ULONG dwSize, PVOID lpBuffer, PULONG pRequiredSize) { -#if 0 - NTSTATUS Status; - HANDLE DirectoryHandle; - ULONG EntryCount = 0; - UNICODE_STRING DirectoryNameW; - PWCHAR BufferChar; - PDIRECTORY_OBJECT DirObj = NULL; - PLIST_ENTRY CurrentEntry = NULL; - POBJECT_HEADER CurrentObject = NULL; - - /* - * Generate full window station name - */ - - /* FIXME: Correct this for desktop */ - if (!IntGetFullWindowStationName(&DirectoryNameW, NULL, NULL)) - { - SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); - return 0; - } - - /* - * Try to open the directory. - */ - - Status = ObReferenceObjectByName(&DirectoryNameW, 0, NULL, DIRECTORY_QUERY, - ObDirectoryType, UserMode, (PVOID*)&DirObj, NULL); - if (!NT_SUCCESS(Status)) - { - ExFreePool(DirectoryNameW.Buffer); - return Status; - } - - /* - * Count the required size of buffer. - */ - - *pRequiredSize = sizeof(DWORD); - for (CurrentEntry = DirObj->head.Flink; CurrentEntry != &DirObj->head; - CurrentEntry = CurrentEntry->Flink) - { - CurrentObject = CONTAINING_RECORD(CurrentEntry, OBJECT_HEADER, Entry); - *pRequiredSize += CurrentObject->Name.Length + sizeof(UNICODE_NULL); - ++EntryCount; - } - - DPRINT1("Required size: %d Entry count: %d\n", *pRequiredSize, EntryCount); - - /* - * Check if the supplied buffer is large enought. - */ - - if (*pRequiredSize > dwSize) - { - ExFreePool(DirectoryNameW.Buffer); - ObDereferenceObject(DirectoryHandle); - return STATUS_BUFFER_TOO_SMALL; - } - - /* - * Generate the resulting buffer contents. - */ - - *((DWORD *)lpBuffer) = EntryCount; - BufferChar = (PWCHAR)((INT_PTR)lpBuffer + 4); - for (CurrentEntry = DirObj->head.Flink; CurrentEntry != &DirObj->head; - CurrentEntry = CurrentEntry->Flink) - { - CurrentObject = CONTAINING_RECORD(CurrentEntry, OBJECT_HEADER, Entry); - wcscpy(BufferChar, CurrentObject->Name.Buffer); - DPRINT1("Name: %s\n", BufferChar); - BufferChar += (CurrentObject->Name.Length / sizeof(WCHAR)) + 1; - } - - /* - * Free any resource. - */ - - ExFreePool(DirectoryNameW.Buffer); - ObDereferenceObject(DirectoryHandle); - - return STATUS_SUCCESS; -#else - UNIMPLEMENTED - - return STATUS_NOT_IMPLEMENTED; -#endif + /* The WindowStation name list and desktop name list are build in completely + different ways. Call the appropriate function */ + return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) : + BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize); } /* EOF */