Commit in reactos/subsys/win32k on MAIN
include/tags.h+11.5 -> 1.6
ntuser/winsta.c+280-741.64 -> 1.65
+281-74
2 modified files
Implement NtUserBuildNamesList()

reactos/subsys/win32k/include
tags.h 1.5 -> 1.6
diff -u -r1.5 -r1.6
--- tags.h	23 May 2004 09:36:47 -0000	1.5
+++ tags.h	20 Aug 2004 22:38:49 -0000	1.6
@@ -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 */

reactos/subsys/win32k/ntuser
winsta.c 1.64 -> 1.65
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 */
CVSspam 0.2.8