server: Implemented EnumWindowStations and EnumDesktops.
diff --git a/server/handle.c b/server/handle.c
index 9b14810..77de284 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -446,6 +446,27 @@
     return 0;
 }
 
+/* enumerate handles of a given type */
+/* this is needed for window stations and desktops */
+obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops,
+                                unsigned int *index )
+{
+    struct handle_table *table = process->handles;
+    unsigned int i;
+    struct handle_entry *entry;
+
+    if (!table) return 0;
+
+    for (i = *index, entry = &table->entries[i]; i <= table->last; i++, entry++)
+    {
+        if (!entry->ptr) continue;
+        if (entry->ptr->ops != ops) continue;
+        *index = i + 1;
+        return index_to_handle(i);
+    }
+    return 0;
+}
+
 /* get/set the handle reserved flags */
 /* return the old flags (or -1 on error) */
 static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags )
diff --git a/server/handle.h b/server/handle.h
index fc34ee7..3809aa3 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -47,6 +47,8 @@
 extern obj_handle_t open_object( const struct namespace *namespace, const struct unicode_str *name,
                                  const struct object_ops *ops, unsigned int access, unsigned int attr );
 extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops );
+extern obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops,
+                                       unsigned int *index );
 extern struct handle_table *alloc_handle_table( struct process *process, int count );
 extern struct handle_table *copy_handle_table( struct process *process, struct process *parent );
 extern unsigned int get_handle_table_count( struct process *process);
diff --git a/server/protocol.def b/server/protocol.def
index ae5f2ac..a63b0cb 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2359,6 +2359,15 @@
 @END
 
 
+/* Enumerate window stations */
+@REQ(enum_winstation)
+    unsigned int index;           /* current index */
+@REPLY
+    unsigned int next;            /* next index */
+    VARARG(name,unicode_str);     /* window station name */
+@END
+
+
 /* Create a desktop */
 @REQ(create_desktop)
     unsigned int flags;           /* desktop flags */
@@ -2401,6 +2410,16 @@
 @END
 
 
+/* Enumerate desktops */
+@REQ(enum_desktop)
+    obj_handle_t winstation;      /* handle to the window station */
+    unsigned int index;           /* current index */
+@REPLY
+    unsigned int next;            /* next index */
+    VARARG(name,unicode_str);     /* window station name */
+@END
+
+
 /* Get/set information about a user object (window station or desktop) */
 @REQ(set_user_object_info)
     obj_handle_t handle;          /* handle to the object */
diff --git a/server/request.h b/server/request.h
index cd53e16..c84c6e9 100644
--- a/server/request.h
+++ b/server/request.h
@@ -278,11 +278,13 @@
 DECL_HANDLER(close_winstation);
 DECL_HANDLER(get_process_winstation);
 DECL_HANDLER(set_process_winstation);
+DECL_HANDLER(enum_winstation);
 DECL_HANDLER(create_desktop);
 DECL_HANDLER(open_desktop);
 DECL_HANDLER(close_desktop);
 DECL_HANDLER(get_thread_desktop);
 DECL_HANDLER(set_thread_desktop);
+DECL_HANDLER(enum_desktop);
 DECL_HANDLER(set_user_object_info);
 DECL_HANDLER(attach_thread_input);
 DECL_HANDLER(get_thread_input);
@@ -512,11 +514,13 @@
     (req_handler)req_close_winstation,
     (req_handler)req_get_process_winstation,
     (req_handler)req_set_process_winstation,
+    (req_handler)req_enum_winstation,
     (req_handler)req_create_desktop,
     (req_handler)req_open_desktop,
     (req_handler)req_close_desktop,
     (req_handler)req_get_thread_desktop,
     (req_handler)req_set_thread_desktop,
+    (req_handler)req_enum_desktop,
     (req_handler)req_set_user_object_info,
     (req_handler)req_attach_thread_input,
     (req_handler)req_get_thread_input,
diff --git a/server/trace.c b/server/trace.c
index 38a2991..da4a0c7 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2911,6 +2911,18 @@
     fprintf( stderr, " handle=%p", req->handle );
 }
 
+static void dump_enum_winstation_request( const struct enum_winstation_request *req )
+{
+    fprintf( stderr, " index=%08x", req->index );
+}
+
+static void dump_enum_winstation_reply( const struct enum_winstation_reply *req )
+{
+    fprintf( stderr, " next=%08x,", req->next );
+    fprintf( stderr, " name=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
 static void dump_create_desktop_request( const struct create_desktop_request *req )
 {
     fprintf( stderr, " flags=%08x,", req->flags );
@@ -2959,6 +2971,19 @@
     fprintf( stderr, " handle=%p", req->handle );
 }
 
+static void dump_enum_desktop_request( const struct enum_desktop_request *req )
+{
+    fprintf( stderr, " winstation=%p,", req->winstation );
+    fprintf( stderr, " index=%08x", req->index );
+}
+
+static void dump_enum_desktop_reply( const struct enum_desktop_reply *req )
+{
+    fprintf( stderr, " next=%08x,", req->next );
+    fprintf( stderr, " name=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
 static void dump_set_user_object_info_request( const struct set_user_object_info_request *req )
 {
     fprintf( stderr, " handle=%p,", req->handle );
@@ -3876,11 +3901,13 @@
     (dump_func)dump_close_winstation_request,
     (dump_func)dump_get_process_winstation_request,
     (dump_func)dump_set_process_winstation_request,
+    (dump_func)dump_enum_winstation_request,
     (dump_func)dump_create_desktop_request,
     (dump_func)dump_open_desktop_request,
     (dump_func)dump_close_desktop_request,
     (dump_func)dump_get_thread_desktop_request,
     (dump_func)dump_set_thread_desktop_request,
+    (dump_func)dump_enum_desktop_request,
     (dump_func)dump_set_user_object_info_request,
     (dump_func)dump_attach_thread_input_request,
     (dump_func)dump_get_thread_input_request,
@@ -4107,11 +4134,13 @@
     (dump_func)0,
     (dump_func)dump_get_process_winstation_reply,
     (dump_func)0,
+    (dump_func)dump_enum_winstation_reply,
     (dump_func)dump_create_desktop_reply,
     (dump_func)dump_open_desktop_reply,
     (dump_func)0,
     (dump_func)dump_get_thread_desktop_reply,
     (dump_func)0,
+    (dump_func)dump_enum_desktop_reply,
     (dump_func)dump_set_user_object_info_reply,
     (dump_func)0,
     (dump_func)dump_get_thread_input_reply,
@@ -4338,11 +4367,13 @@
     "close_winstation",
     "get_process_winstation",
     "set_process_winstation",
+    "enum_winstation",
     "create_desktop",
     "open_desktop",
     "close_desktop",
     "get_thread_desktop",
     "set_thread_desktop",
+    "enum_desktop",
     "set_user_object_info",
     "attach_thread_input",
     "get_thread_input",
diff --git a/server/winstation.c b/server/winstation.c
index 55e72ab..5e4bfbc 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -385,6 +385,20 @@
     clear_error();  /* ignore errors */
 }
 
+/* set the reply data from the object name */
+static void set_reply_data_obj_name( struct object *obj )
+{
+    data_size_t len;
+    const WCHAR *ptr, *name = get_object_name( obj, &len );
+
+    /* if there is a backslash return the part of the name after it */
+    if (name && (ptr = memchrW( name, '\\', len/sizeof(WCHAR) )))
+    {
+        len -= (ptr + 1 - name) * sizeof(WCHAR);
+        name = ptr + 1;
+    }
+    if (name) set_reply_data( name, min( len, get_reply_max_size() ));
+}
 
 /* create a window station */
 DECL_HANDLER(create_winstation)
@@ -590,18 +604,60 @@
         release_object( obj );
         return;
     }
-    if (get_reply_max_size())
-    {
-        data_size_t len;
-        const WCHAR *ptr, *name = get_object_name( obj, &len );
-
-        /* if there is a backslash return the part of the name after it */
-        if (name && (ptr = memchrW( name, '\\', len/sizeof(WCHAR) )))
-        {
-            len -= (ptr + 1 - name) * sizeof(WCHAR);
-            name = ptr + 1;
-        }
-        if (name) set_reply_data( name, min( len, get_reply_max_size() ));
-    }
+    if (get_reply_max_size()) set_reply_data_obj_name( obj );
     release_object( obj );
 }
+
+
+/* enumerate window stations */
+DECL_HANDLER(enum_winstation)
+{
+    unsigned int index = req->index;
+    obj_handle_t handle;
+    struct object *obj;
+
+    while ((handle = enumerate_handles( current->process, &winstation_ops, &index )))
+    {
+        if (!(obj = get_handle_obj( current->process, handle, WINSTA_ENUMERATE, &winstation_ops )))
+            continue;
+        set_reply_data_obj_name( obj );
+        release_object( obj );
+        clear_error();
+        reply->next = index;
+        return;
+    }
+    set_error( STATUS_NO_MORE_ENTRIES );
+}
+
+
+/* enumerate desktops */
+DECL_HANDLER(enum_desktop)
+{
+    struct winstation *winstation;
+    struct desktop *desktop;
+    unsigned int index = req->index;
+    obj_handle_t handle;
+
+    if (!(winstation = (struct winstation *)get_handle_obj( current->process, req->winstation,
+                                                            WINSTA_ENUMDESKTOPS, &winstation_ops )))
+        return;
+
+    while ((handle = enumerate_handles( current->process, &desktop_ops, &index )))
+    {
+        if (!(desktop = get_desktop_obj( current->process, handle, DESKTOP_ENUMERATE )))
+            continue;
+
+        if (desktop->winstation == winstation)
+        {
+            set_reply_data_obj_name( &desktop->obj );
+            release_object( desktop );
+            clear_error();
+            reply->next = index;
+            return;
+        }
+        release_object( desktop );
+    }
+
+    release_object( winstation );
+    set_error( STATUS_NO_MORE_ENTRIES );
+}