reactos/subsys/win32k/ntuser
diff -u -r1.64 -r1.65
--- winsta.c 20 Jun 2004 00:45:37 -0000 1.64
+++ winsta.c 20 Aug 2004 22:38:49 -0000 1.65
@@ -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,126 +954,332 @@
return 0;
}
-/*
- * NtUserBuildNameList
- *
- * Function used for enumeration of desktops or window stations.
- *
- * Parameters
- * hWinSta
- * For enumeration of window stations this parameter must be set to
- * zero. Otherwise it's handle for window station.
- *
- * dwSize
- * Size of buffer passed by caller.
- *
- * lpBuffer
- * Buffer passed by caller. If the function succedes, the buffer is
- * filled with window station/desktop count (in first DWORD) and
- * NULL-terminated window station/desktop names.
- *
- * pRequiredSize
- * If the function suceedes, this is the number of bytes copied.
- * Otherwise it's size of buffer needed for function to succeed.
- *
- * Status
- * @unimplemented
- */
-
-NTSTATUS STDCALL
-NtUserBuildNameList(
- HWINSTA hWinSta,
+static NTSTATUS FASTCALL
+BuildWindowStationNameList(
ULONG dwSize,
PVOID lpBuffer,
PULONG pRequiredSize)
{
-#if 0
+ OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE DirectoryHandle;
- ULONG EntryCount = 0;
- UNICODE_STRING DirectoryNameW;
- PWCHAR BufferChar;
- PDIRECTORY_OBJECT DirObj = NULL;
- PLIST_ENTRY CurrentEntry = NULL;
- POBJECT_HEADER CurrentObject = NULL;
+ UNICODE_STRING DirectoryName;
+ char InitialBuffer[256], *Buffer;
+ ULONG Context, ReturnLength, BufferSize;
+ DWORD EntryCount;
+ PDIRECTORY_BASIC_INFORMATION DirEntry;
+ WCHAR NullWchar;
/*
- * Generate full window station name
+ * Generate name of window station directory
*/
-
- /* FIXME: Correct this for desktop */
- if (!IntGetFullWindowStationName(&DirectoryNameW, NULL, NULL))
+ if (!IntGetFullWindowStationName(&DirectoryName, NULL, NULL))
{
- SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
- return 0;
+ 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);
- Status = ObReferenceObjectByName(&DirectoryNameW, 0, NULL, DIRECTORY_QUERY,
- ObDirectoryType, UserMode, (PVOID*)&DirObj, NULL);
if (!NT_SUCCESS(Status))
{
- ExFreePool(DirectoryNameW.Buffer);
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;
+ }
+ }
- *pRequiredSize = sizeof(DWORD);
- for (CurrentEntry = DirObj->head.Flink; CurrentEntry != &DirObj->head;
- CurrentEntry = CurrentEntry->Flink)
+ /*
+ * Check if the supplied buffer is large enough.
+ */
+ if (dwSize < ReturnLength)
{
- CurrentObject = CONTAINING_RECORD(CurrentEntry, OBJECT_HEADER, Entry);
- *pRequiredSize += CurrentObject->Name.Length + sizeof(UNICODE_NULL);
- ++EntryCount;
+ if (Buffer != InitialBuffer)
+ {
+ ExFreePool(Buffer);
+ }
+ return STATUS_BUFFER_TOO_SMALL;
}
- DPRINT1("Required size: %d Entry count: %d\n", *pRequiredSize, EntryCount);
+ /*
+ * 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));
+ }
/*
- * Check if the supplied buffer is large enought.
+ * Clean up
*/
+ if (NULL != Buffer && Buffer != InitialBuffer)
+ {
+ ExFreePool(Buffer);
+ }
- if (*pRequiredSize > dwSize)
+ 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))
{
- ExFreePool(DirectoryNameW.Buffer);
- ObDereferenceObject(DirectoryHandle);
+ 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));
- *((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;
+ 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));
}
/*
- * Free any resource.
+ * Clean up
*/
-
- ExFreePool(DirectoryNameW.Buffer);
- ObDereferenceObject(DirectoryHandle);
+ KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
+ ObDereferenceObject(WindowStation);
return STATUS_SUCCESS;
-#else
- UNIMPLEMENTED
+}
+
+/*
+ * NtUserBuildNameList
+ *
+ * Function used for enumeration of desktops or window stations.
+ *
+ * Parameters
+ * hWinSta
+ * For enumeration of window stations this parameter must be set to
+ * zero. Otherwise it's handle for window station.
+ *
+ * dwSize
+ * Size of buffer passed by caller.
+ *
+ * lpBuffer
+ * Buffer passed by caller. If the function succedes, the buffer is
+ * filled with window station/desktop count (in first DWORD) and
+ * NULL-terminated window station/desktop names.
+ *
+ * pRequiredSize
+ * If the function suceedes, this is the number of bytes copied.
+ * Otherwise it's size of buffer needed for function to succeed.
+ *
+ * Status
+ * @implemented
+ */
- return STATUS_NOT_IMPLEMENTED;
-#endif
+NTSTATUS STDCALL
+NtUserBuildNameList(
+ HWINSTA hWindowStation,
+ ULONG dwSize,
+ PVOID lpBuffer,
+ PULONG pRequiredSize)
+{
+ /* 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 */