server: Partial implementation of NtQueryDirectoryObject.
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index 7cb7f06..bc2ee97 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -406,26 +406,62 @@
  * Read information from a namespace directory.
  * 
  * PARAMS
- *  DirectoryHandle   [I]   Handle to a directory object
- *  Buffer            [O]   Buffer to hold the read data
- *  BufferLength      [I]   Size of the buffer in bytes
- *  ReturnSingleEntry [I]   If TRUE, return a single entry, if FALSE, return as many as fit in the buffer
- *  RestartScan       [I]   If TRUE, start scanning from the start, if FALSE, scan from Context
- *  Context           [I/O] Indicates what point of the directory the scan is at
- *  ReturnLength      [O]   Caller supplied storage for the number of bytes written (or NULL)
+ *  handle        [I]   Handle to a directory object
+ *  buffer        [O]   Buffer to hold the read data
+ *  size          [I]   Size of the buffer in bytes
+ *  single_entry  [I]   If TRUE, return a single entry, if FALSE, return as many as fit in the buffer
+ *  restart       [I]   If TRUE, start scanning from the start, if FALSE, scan from Context
+ *  context       [I/O] Indicates what point of the directory the scan is at
+ *  ret_size      [O]   Caller supplied storage for the number of bytes written (or NULL)
  *
  * RETURNS
  *  Success: ERROR_SUCCESS.
  *  Failure: An NTSTATUS error code.
  */
-NTSTATUS WINAPI NtQueryDirectoryObject(IN HANDLE DirectoryHandle, OUT PDIRECTORY_BASIC_INFORMATION Buffer,
-                                       IN ULONG BufferLength, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan,
-                                       IN OUT PULONG Context, OUT PULONG ReturnLength OPTIONAL)
+NTSTATUS WINAPI NtQueryDirectoryObject(HANDLE handle, PDIRECTORY_BASIC_INFORMATION buffer,
+                                       ULONG size, BOOLEAN single_entry, BOOLEAN restart,
+                                       PULONG context, PULONG ret_size)
 {
-    FIXME("(%p,%p,0x%08x,0x%08x,0x%08x,%p,%p), stub\n", DirectoryHandle, Buffer, BufferLength, ReturnSingleEntry,
-          RestartScan, Context, ReturnLength);
+    NTSTATUS ret;
 
-    return STATUS_NOT_IMPLEMENTED;
+    if (restart) *context = 0;
+
+    if (single_entry)
+    {
+        if (size <= sizeof(*buffer) + 2*sizeof(WCHAR)) return STATUS_BUFFER_OVERFLOW;
+
+        SERVER_START_REQ( get_directory_entry )
+        {
+            req->handle = handle;
+            req->index = *context;
+            wine_server_set_reply( req, buffer + 1, size - sizeof(*buffer) - 2*sizeof(WCHAR) );
+            if (!(ret = wine_server_call( req )))
+            {
+                buffer->ObjectName.Buffer = (WCHAR *)(buffer + 1);
+                buffer->ObjectName.Length = reply->name_len;
+                buffer->ObjectName.MaximumLength = reply->name_len + sizeof(WCHAR);
+                buffer->ObjectTypeName.Buffer = (WCHAR *)(buffer + 1) + reply->name_len/sizeof(WCHAR) + 1;
+                buffer->ObjectTypeName.Length = wine_server_reply_size( reply ) - reply->name_len;
+                buffer->ObjectTypeName.MaximumLength = buffer->ObjectTypeName.Length + sizeof(WCHAR);
+                /* make room for the terminating null */
+                memmove( buffer->ObjectTypeName.Buffer, buffer->ObjectTypeName.Buffer - 1,
+                         buffer->ObjectTypeName.Length );
+                buffer->ObjectName.Buffer[buffer->ObjectName.Length/sizeof(WCHAR)] = 0;
+                buffer->ObjectTypeName.Buffer[buffer->ObjectTypeName.Length/sizeof(WCHAR)] = 0;
+                (*context)++;
+            }
+        }
+        SERVER_END_REQ;
+        if (ret_size)
+            *ret_size = buffer->ObjectName.MaximumLength + buffer->ObjectTypeName.MaximumLength + sizeof(*buffer);
+    }
+    else
+    {
+        FIXME("multiple entries not implemented\n");
+        ret = STATUS_NOT_IMPLEMENTED;
+    }
+
+    return ret;
 }
 
 /*
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 34db89f..fea45f8 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3950,6 +3950,22 @@
 
 
 
+struct get_directory_entry_request
+{
+    struct request_header __header;
+    obj_handle_t   handle;
+    unsigned int   index;
+};
+struct get_directory_entry_reply
+{
+    struct reply_header __header;
+    size_t         name_len;
+    /* VARARG(name,unicode_str,name_len); */
+    /* VARARG(type,unicode_str); */
+};
+
+
+
 struct create_symlink_request
 {
     struct request_header __header;
@@ -4448,6 +4464,7 @@
     REQ_set_mailslot_info,
     REQ_create_directory,
     REQ_open_directory,
+    REQ_get_directory_entry,
     REQ_create_symlink,
     REQ_open_symlink,
     REQ_query_symlink,
@@ -4685,6 +4702,7 @@
     struct set_mailslot_info_request set_mailslot_info_request;
     struct create_directory_request create_directory_request;
     struct open_directory_request open_directory_request;
+    struct get_directory_entry_request get_directory_entry_request;
     struct create_symlink_request create_symlink_request;
     struct open_symlink_request open_symlink_request;
     struct query_symlink_request query_symlink_request;
@@ -4920,6 +4938,7 @@
     struct set_mailslot_info_reply set_mailslot_info_reply;
     struct create_directory_reply create_directory_reply;
     struct open_directory_reply open_directory_reply;
+    struct get_directory_entry_reply get_directory_entry_reply;
     struct create_symlink_reply create_symlink_reply;
     struct open_symlink_reply open_symlink_reply;
     struct query_symlink_reply query_symlink_reply;
@@ -4941,6 +4960,6 @@
     struct add_fd_completion_reply add_fd_completion_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 333
+#define SERVER_PROTOCOL_VERSION 334
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/directory.c b/server/directory.c
index f53ffe5..3e199f0 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -396,3 +396,38 @@
 
     if (root) release_object( root );
 }
+
+/* get a directory entry by index */
+DECL_HANDLER(get_directory_entry)
+{
+    static const WCHAR objectW[] = {'O','b','j','e','c','t',0 };
+    static const WCHAR dirW[] = {'D','i','r','e','c','t','o','r','y',0 };
+
+    struct directory *dir = get_directory_obj( current->process, req->handle, DIRECTORY_QUERY );
+    if (dir)
+    {
+        struct object *obj = find_object_index( dir->entries, req->index );
+        if (obj)
+        {
+            size_t name_len, type_len;
+            const WCHAR *name = get_object_name( obj, &name_len );
+            const WCHAR *type = obj->ops == &directory_ops ? dirW : objectW;
+
+            type_len = strlenW(type) * sizeof(WCHAR);
+            if (name_len + type_len <= get_reply_max_size())
+            {
+                void *ptr = set_reply_data_size( name_len + type_len );
+                if (ptr)
+                {
+                    reply->name_len = name_len;
+                    memcpy( ptr, name, name_len );
+                    memcpy( (char *)ptr + name_len, type, type_len );
+                }
+            }
+            else set_error( STATUS_BUFFER_OVERFLOW );
+
+            release_object( obj );
+        }
+        release_object( dir );
+    }
+}
diff --git a/server/object.c b/server/object.c
index eb21ef1..7b7a5e3 100644
--- a/server/object.c
+++ b/server/object.c
@@ -318,6 +318,24 @@
     return NULL;
 }
 
+/* find an object by its index; the refcount is incremented */
+struct object *find_object_index( const struct namespace *namespace, unsigned int index )
+{
+    unsigned int i;
+
+    /* FIXME: not efficient at all */
+    for (i = 0; i < namespace->hash_size; i++)
+    {
+        const struct object_name *ptr;
+        LIST_FOR_EACH_ENTRY( ptr, &namespace->names[i], const struct object_name, entry )
+        {
+            if (!index--) return grab_object( ptr->obj );
+        }
+    }
+    set_error( STATUS_NO_MORE_ENTRIES );
+    return NULL;
+}
+
 /* allocate a namespace */
 struct namespace *create_namespace( unsigned int hash_size )
 {
diff --git a/server/object.h b/server/object.h
index d1af7f2..543b9ba 100644
--- a/server/object.h
+++ b/server/object.h
@@ -126,6 +126,7 @@
 extern void release_object( void *obj );
 extern struct object *find_object( const struct namespace *namespace, const struct unicode_str *name,
                                    unsigned int attributes );
+extern struct object *find_object_index( const struct namespace *namespace, unsigned int index );
 extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
 extern int no_satisfied( struct object *obj, struct thread *thread );
 extern int no_signal( struct object *obj, unsigned int access );
diff --git a/server/protocol.def b/server/protocol.def
index a63b0cb..aa10f89 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2851,6 +2851,17 @@
 @END
 
 
+/* Get a directory entry by index */
+@REQ(get_directory_entry)
+    obj_handle_t   handle;             /* handle to the directory */
+    unsigned int   index;              /* entry index */
+@REPLY
+    size_t         name_len;           /* length of the entry name in bytes */
+    VARARG(name,unicode_str,name_len); /* entry name */
+    VARARG(type,unicode_str);          /* entry type */
+@END
+
+
 /* Create a symbolic link object */
 @REQ(create_symlink)
     unsigned int   access;        /* access flags */
diff --git a/server/request.h b/server/request.h
index c84c6e9..cc1d3d1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -321,6 +321,7 @@
 DECL_HANDLER(set_mailslot_info);
 DECL_HANDLER(create_directory);
 DECL_HANDLER(open_directory);
+DECL_HANDLER(get_directory_entry);
 DECL_HANDLER(create_symlink);
 DECL_HANDLER(open_symlink);
 DECL_HANDLER(query_symlink);
@@ -557,6 +558,7 @@
     (req_handler)req_set_mailslot_info,
     (req_handler)req_create_directory,
     (req_handler)req_open_directory,
+    (req_handler)req_get_directory_entry,
     (req_handler)req_create_symlink,
     (req_handler)req_open_symlink,
     (req_handler)req_query_symlink,
diff --git a/server/trace.c b/server/trace.c
index da4a0c7..4bcd545 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3500,6 +3500,22 @@
     fprintf( stderr, " handle=%p", req->handle );
 }
 
+static void dump_get_directory_entry_request( const struct get_directory_entry_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " index=%08x", req->index );
+}
+
+static void dump_get_directory_entry_reply( const struct get_directory_entry_reply *req )
+{
+    fprintf( stderr, " name_len=%lu,", (unsigned long)req->name_len );
+    fprintf( stderr, " name=" );
+    dump_varargs_unicode_str( min(cur_size,req->name_len) );
+    fputc( ',', stderr );
+    fprintf( stderr, " type=" );
+    dump_varargs_unicode_str( cur_size );
+}
+
 static void dump_create_symlink_request( const struct create_symlink_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
@@ -3944,6 +3960,7 @@
     (dump_func)dump_set_mailslot_info_request,
     (dump_func)dump_create_directory_request,
     (dump_func)dump_open_directory_request,
+    (dump_func)dump_get_directory_entry_request,
     (dump_func)dump_create_symlink_request,
     (dump_func)dump_open_symlink_request,
     (dump_func)dump_query_symlink_request,
@@ -4177,6 +4194,7 @@
     (dump_func)dump_set_mailslot_info_reply,
     (dump_func)dump_create_directory_reply,
     (dump_func)dump_open_directory_reply,
+    (dump_func)dump_get_directory_entry_reply,
     (dump_func)dump_create_symlink_reply,
     (dump_func)dump_open_symlink_reply,
     (dump_func)dump_query_symlink_reply,
@@ -4410,6 +4428,7 @@
     "set_mailslot_info",
     "create_directory",
     "open_directory",
+    "get_directory_entry",
     "create_symlink",
     "open_symlink",
     "query_symlink",