From 8382eb01b2f2ed05a0a8131618e8c68e6581ad2d Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Wed, 5 Dec 2007 18:16:42 +0100
Subject: [PATCH] server: Return correct object types in the
 get_directory_entry request.

---
 server/async.c      |  2 +
 server/atom.c       |  1 +
 server/change.c     |  1 +
 server/clipboard.c  |  1 +
 server/completion.c |  9 +++++
 server/console.c    |  3 ++
 server/debugger.c   |  2 +
 server/device.c     | 11 ++++++
 server/directory.c  | 91 +++++++++++++++++++++++++++++++++++++++++----
 server/event.c      |  9 +++++
 server/fd.c         |  4 ++
 server/file.c       |  1 +
 server/handle.c     |  1 +
 server/hook.c       |  1 +
 server/mailslot.c   | 11 ++++++
 server/mapping.c    |  9 +++++
 server/mutex.c      |  9 +++++
 server/named_pipe.c | 12 ++++++
 server/object.c     |  5 +++
 server/object.h     |  5 +++
 server/process.c    |  2 +
 server/queue.c      |  2 +
 server/registry.c   |  1 +
 server/request.c    |  1 +
 server/semaphore.c  |  9 +++++
 server/serial.c     |  1 +
 server/signal.c     |  1 +
 server/snapshot.c   |  1 +
 server/sock.c       |  1 +
 server/symlink.c    |  9 +++++
 server/thread.c     |  2 +
 server/timer.c      |  9 +++++
 server/token.c      |  1 +
 server/winstation.c | 18 +++++++++
 34 files changed, 239 insertions(+), 7 deletions(-)

diff --git a/server/async.c b/server/async.c
index acf61d8b551..9ca239c8465 100644
--- a/server/async.c
+++ b/server/async.c
@@ -52,6 +52,7 @@ static const struct object_ops async_ops =
 {
     sizeof(struct async),      /* size */
     async_dump,                /* dump */
+    no_get_type,               /* get_type */
     no_add_queue,              /* add_queue */
     NULL,                      /* remove_queue */
     NULL,                      /* signaled */
@@ -81,6 +82,7 @@ static const struct object_ops async_queue_ops =
 {
     sizeof(struct async_queue),      /* size */
     async_queue_dump,                /* dump */
+    no_get_type,                     /* get_type */
     no_add_queue,                    /* add_queue */
     NULL,                            /* remove_queue */
     NULL,                            /* signaled */
diff --git a/server/atom.c b/server/atom.c
index 336e6e362eb..8094188c85a 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -76,6 +76,7 @@ static const struct object_ops atom_table_ops =
 {
     sizeof(struct atom_table),    /* size */
     atom_table_dump,              /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
diff --git a/server/change.c b/server/change.c
index dc449803c2a..590a1cb6b61 100644
--- a/server/change.c
+++ b/server/change.c
@@ -164,6 +164,7 @@ static const struct object_ops dir_ops =
 {
     sizeof(struct dir),       /* size */
     dir_dump,                 /* dump */
+    no_get_type,              /* get_type */
     add_queue,                /* add_queue */
     remove_queue,             /* remove_queue */
     default_fd_signaled,      /* signaled */
diff --git a/server/clipboard.c b/server/clipboard.c
index 44ca7bdfdfb..a90dbc27e58 100644
--- a/server/clipboard.c
+++ b/server/clipboard.c
@@ -52,6 +52,7 @@ static const struct object_ops clipboard_ops =
 {
     sizeof(struct clipboard),     /* size */
     clipboard_dump,               /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
diff --git a/server/completion.c b/server/completion.c
index 96aaacc83e1..41884882d54 100644
--- a/server/completion.c
+++ b/server/completion.c
@@ -52,6 +52,7 @@ struct completion
 };
 
 static void completion_dump( struct object*, int );
+static struct object_type *completion_get_type( struct object *obj );
 static void completion_destroy( struct object * );
 static int  completion_signaled( struct object *obj, struct thread *thread );
 
@@ -59,6 +60,7 @@ static const struct object_ops completion_ops =
 {
     sizeof(struct completion), /* size */
     completion_dump,           /* dump */
+    completion_get_type,       /* get_type */
     add_queue,                 /* add_queue */
     remove_queue,              /* remove_queue */
     completion_signaled,       /* signaled */
@@ -104,6 +106,13 @@ static void completion_dump( struct object *obj, int verbose )
     fprintf( stderr, " (%u packets pending)\n", completion->depth );
 }
 
+static struct object_type *completion_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'C','o','m','p','l','e','t','i','o','n'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int completion_signaled( struct object *obj, struct thread *thread )
 {
     struct completion *completion = (struct completion *)obj;
diff --git a/server/console.c b/server/console.c
index 5f005884672..a5020ac06a0 100644
--- a/server/console.c
+++ b/server/console.c
@@ -76,6 +76,7 @@ static const struct object_ops console_input_ops =
 {
     sizeof(struct console_input),     /* size */
     console_input_dump,               /* dump */
+    no_get_type,                      /* get_type */
     no_add_queue,                     /* add_queue */
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
@@ -107,6 +108,7 @@ static const struct object_ops console_input_events_ops =
 {
     sizeof(struct console_input_events), /* size */
     console_input_events_dump,        /* dump */
+    no_get_type,                      /* get_type */
     add_queue,                        /* add_queue */
     remove_queue,                     /* remove_queue */
     console_input_events_signaled,    /* signaled */
@@ -149,6 +151,7 @@ static const struct object_ops screen_buffer_ops =
 {
     sizeof(struct screen_buffer),     /* size */
     screen_buffer_dump,               /* dump */
+    no_get_type,                      /* get_type */
     no_add_queue,                     /* add_queue */
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
diff --git a/server/debugger.c b/server/debugger.c
index a64a17a7d89..37ddd689c69 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -69,6 +69,7 @@ static const struct object_ops debug_event_ops =
 {
     sizeof(struct debug_event),    /* size */
     debug_event_dump,              /* dump */
+    no_get_type,                   /* get_type */
     add_queue,                     /* add_queue */
     remove_queue,                  /* remove_queue */
     debug_event_signaled,          /* signaled */
@@ -92,6 +93,7 @@ static const struct object_ops debug_ctx_ops =
 {
     sizeof(struct debug_ctx),      /* size */
     debug_ctx_dump,                /* dump */
+    no_get_type,                   /* get_type */
     add_queue,                     /* add_queue */
     remove_queue,                  /* remove_queue */
     debug_ctx_signaled,            /* signaled */
diff --git a/server/device.c b/server/device.c
index d5e5e44222e..abf0ac54170 100644
--- a/server/device.c
+++ b/server/device.c
@@ -58,6 +58,7 @@ static const struct object_ops ioctl_call_ops =
 {
     sizeof(struct ioctl_call),        /* size */
     ioctl_call_dump,                  /* dump */
+    no_get_type,                      /* get_type */
     add_queue,                        /* add_queue */
     remove_queue,                     /* remove_queue */
     ioctl_call_signaled,              /* signaled */
@@ -89,6 +90,7 @@ static const struct object_ops device_manager_ops =
 {
     sizeof(struct device_manager),    /* size */
     device_manager_dump,              /* dump */
+    no_get_type,                      /* get_type */
     add_queue,                        /* add_queue */
     remove_queue,                     /* remove_queue */
     device_manager_signaled,          /* signaled */
@@ -116,6 +118,7 @@ struct device
 };
 
 static void device_dump( struct object *obj, int verbose );
+static struct object_type *device_get_type( struct object *obj );
 static struct fd *device_get_fd( struct object *obj );
 static void device_destroy( struct object *obj );
 static struct object *device_open_file( struct object *obj, unsigned int access,
@@ -128,6 +131,7 @@ static const struct object_ops device_ops =
 {
     sizeof(struct device),            /* size */
     device_dump,                      /* dump */
+    device_get_type,                  /* get_type */
     no_add_queue,                     /* add_queue */
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
@@ -252,6 +256,13 @@ static void device_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *device_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'D','e','v','i','c','e'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct fd *device_get_fd( struct object *obj )
 {
     struct device *device = (struct device *)obj;
diff --git a/server/directory.c b/server/directory.c
index 3e199f0dad0..bf1cd6938c3 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -41,6 +41,35 @@
 
 #define HASH_SIZE 7  /* default hash size */
 
+struct object_type
+{
+    struct object     obj;        /* object header */
+};
+
+static void object_type_dump( struct object *obj, int verbose );
+static struct object_type *object_type_get_type( struct object *obj );
+
+static const struct object_ops object_type_ops =
+{
+    sizeof(struct object_type),   /* size */
+    object_type_dump,             /* dump */
+    object_type_get_type,         /* get_type */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    NULL,                         /* satisfied */
+    no_signal,                    /* signal */
+    no_get_fd,                    /* get_fd */
+    no_map_access,                /* map_access */
+    default_get_sd,               /* get_sd */
+    default_set_sd,               /* set_sd */
+    no_lookup_name,               /* lookup_name */
+    no_open_file,                 /* open_file */
+    no_close_handle,              /* close_handle */
+    no_destroy                    /* destroy */
+};
+
+
 struct directory
 {
     struct object     obj;        /* object header */
@@ -48,6 +77,7 @@ struct directory
 };
 
 static void directory_dump( struct object *obj, int verbose );
+static struct object_type *directory_get_type( struct object *obj );
 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
                                              unsigned int attr );
 static void directory_destroy( struct object *obj );
@@ -56,6 +86,7 @@ static const struct object_ops directory_ops =
 {
     sizeof(struct directory),     /* size */
     directory_dump,               /* dump */
+    directory_get_type,           /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
@@ -72,8 +103,25 @@ static const struct object_ops directory_ops =
 };
 
 static struct directory *root_directory;
+static struct directory *dir_objtype;
 
 
+static void object_type_dump( struct object *obj, int verbose )
+{
+    assert( obj->ops == &object_type_ops );
+
+    fputs( "Object type ", stderr );
+    dump_object_name( obj );
+    fputc( '\n', stderr );
+}
+
+static struct object_type *object_type_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'O','b','j','e','c','t','T','y','p','e'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static void directory_dump( struct object *obj, int verbose )
 {
     assert( obj->ops == &directory_ops );
@@ -83,6 +131,13 @@ static void directory_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *directory_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'D','i','r','e','c','t','o','r','y'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name,
                                              unsigned int attr )
 {
@@ -120,6 +175,8 @@ static struct object *directory_lookup_name( struct object *obj, struct unicode_
             set_error( STATUS_OBJECT_NAME_INVALID );
         else if (p)  /* Path still has backslashes */
             set_error( STATUS_OBJECT_PATH_NOT_FOUND );
+        else
+            clear_error();
     }
     return NULL;
 }
@@ -284,6 +341,22 @@ void *open_object_dir( struct directory *root, const struct unicode_str *name,
     return NULL;
 }
 
+/* retrieve an object type, creating it if needed */
+struct object_type *get_object_type( const struct unicode_str *name )
+{
+    struct object_type *type;
+
+    if ((type = open_object_dir( dir_objtype, name, 0, &object_type_ops )))
+        return type;
+
+    if ((type = create_named_object_dir( dir_objtype, name, 0, &object_type_ops )))
+    {
+        grab_object( type );
+        make_object_static( &type->obj );
+        clear_error();
+    }
+    return type;
+}
 
 /* Global initialization */
 
@@ -296,12 +369,14 @@ void init_directories(void)
     static const WCHAR dir_basenamedW[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s'};
     static const WCHAR dir_named_pipeW[] = {'\\','D','e','v','i','c','e','\\','N','a','m','e','d','P','i','p','e'};
     static const WCHAR dir_mailslotW[] = {'\\','D','e','v','i','c','e','\\','M','a','i','l','S','l','o','t'};
+    static const WCHAR dir_objtypeW[] = {'O','b','j','e','c','t','T','y','p','e','s',};
     static const struct unicode_str dir_global_str = {dir_globalW, sizeof(dir_globalW)};
     static const struct unicode_str dir_driver_str = {dir_driverW, sizeof(dir_driverW)};
     static const struct unicode_str dir_device_str = {dir_deviceW, sizeof(dir_deviceW)};
     static const struct unicode_str dir_basenamed_str = {dir_basenamedW, sizeof(dir_basenamedW)};
     static const struct unicode_str dir_named_pipe_str = {dir_named_pipeW, sizeof(dir_named_pipeW)};
     static const struct unicode_str dir_mailslot_str = {dir_mailslotW, sizeof(dir_mailslotW)};
+    static const struct unicode_str dir_objtype_str = {dir_objtypeW, sizeof(dir_objtypeW)};
 
     /* symlinks */
     static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'};
@@ -327,8 +402,10 @@ void init_directories(void)
     root_directory = create_directory( NULL, NULL, 0, HASH_SIZE );
     dir_driver     = create_directory( root_directory, &dir_driver_str, 0, HASH_SIZE );
     dir_device     = create_directory( root_directory, &dir_device_str, 0, HASH_SIZE );
+    dir_objtype    = create_directory( root_directory, &dir_objtype_str, 0, HASH_SIZE );
     make_object_static( &root_directory->obj );
     make_object_static( &dir_driver->obj );
+    make_object_static( &dir_objtype->obj );
 
     dir_global     = create_directory( NULL, &dir_global_str, 0, HASH_SIZE );
     /* use a larger hash table for this one since it can contain a lot of objects */
@@ -400,20 +477,19 @@ DECL_HANDLER(open_directory)
 /* 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;
+            size_t name_len, type_len = 0;
+            const WCHAR *type_name = NULL;
             const WCHAR *name = get_object_name( obj, &name_len );
-            const WCHAR *type = obj->ops == &directory_ops ? dirW : objectW;
+            struct object_type *type = obj->ops->get_type( obj );
+
+            if (type) type_name = get_object_name( &type->obj, &type_len );
 
-            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 );
@@ -421,11 +497,12 @@ DECL_HANDLER(get_directory_entry)
                 {
                     reply->name_len = name_len;
                     memcpy( ptr, name, name_len );
-                    memcpy( (char *)ptr + name_len, type, type_len );
+                    memcpy( (char *)ptr + name_len, type_name, type_len );
                 }
             }
             else set_error( STATUS_BUFFER_OVERFLOW );
 
+            if (type) release_object( type );
             release_object( obj );
         }
         release_object( dir );
diff --git a/server/event.c b/server/event.c
index 624159b15c4..7a7331de321 100644
--- a/server/event.c
+++ b/server/event.c
@@ -44,6 +44,7 @@ struct event
 };
 
 static void event_dump( struct object *obj, int verbose );
+static struct object_type *event_get_type( struct object *obj );
 static int event_signaled( struct object *obj, struct thread *thread );
 static int event_satisfied( struct object *obj, struct thread *thread );
 static unsigned int event_map_access( struct object *obj, unsigned int access );
@@ -53,6 +54,7 @@ static const struct object_ops event_ops =
 {
     sizeof(struct event),      /* size */
     event_dump,                /* dump */
+    event_get_type,            /* get_type */
     add_queue,                 /* add_queue */
     remove_queue,              /* remove_queue */
     event_signaled,            /* signaled */
@@ -126,6 +128,13 @@ static void event_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *event_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'E','v','e','n','t'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int event_signaled( struct object *obj, struct thread *thread )
 {
     struct event *event = (struct event *)obj;
diff --git a/server/fd.c b/server/fd.c
index 74c09cedf78..efa575d1e31 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -191,6 +191,7 @@ static const struct object_ops fd_ops =
 {
     sizeof(struct fd),        /* size */
     fd_dump,                  /* dump */
+    no_get_type,              /* get_type */
     no_add_queue,             /* add_queue */
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
@@ -227,6 +228,7 @@ static const struct object_ops device_ops =
 {
     sizeof(struct device),    /* size */
     device_dump,              /* dump */
+    no_get_type,              /* get_type */
     no_add_queue,             /* add_queue */
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
@@ -262,6 +264,7 @@ static const struct object_ops inode_ops =
 {
     sizeof(struct inode),     /* size */
     inode_dump,               /* dump */
+    no_get_type,              /* get_type */
     no_add_queue,             /* add_queue */
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
@@ -299,6 +302,7 @@ static const struct object_ops file_lock_ops =
 {
     sizeof(struct file_lock),   /* size */
     file_lock_dump,             /* dump */
+    no_get_type,                /* get_type */
     add_queue,                  /* add_queue */
     remove_queue,               /* remove_queue */
     file_lock_signaled,         /* signaled */
diff --git a/server/file.c b/server/file.c
index ad98d2129bd..5224e85feaa 100644
--- a/server/file.c
+++ b/server/file.c
@@ -81,6 +81,7 @@ static const struct object_ops file_ops =
 {
     sizeof(struct file),          /* size */
     file_dump,                    /* dump */
+    no_get_type,                  /* get_type */
     add_queue,                    /* add_queue */
     remove_queue,                 /* remove_queue */
     default_fd_signaled,          /* signaled */
diff --git a/server/handle.c b/server/handle.c
index 77de2845855..29214d6d013 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -104,6 +104,7 @@ static const struct object_ops handle_table_ops =
 {
     sizeof(struct handle_table),     /* size */
     handle_table_dump,               /* dump */
+    no_get_type,                     /* get_type */
     no_add_queue,                    /* add_queue */
     NULL,                            /* remove_queue */
     NULL,                            /* signaled */
diff --git a/server/hook.c b/server/hook.c
index 19c1ca8eef0..4c168a34df6 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -77,6 +77,7 @@ static const struct object_ops hook_table_ops =
 {
     sizeof(struct hook_table),    /* size */
     hook_table_dump,              /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
diff --git a/server/mailslot.c b/server/mailslot.c
index ee891ffba1a..e223b8373e1 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -74,6 +74,7 @@ static const struct object_ops mailslot_ops =
 {
     sizeof(struct mailslot),   /* size */
     mailslot_dump,             /* dump */
+    no_get_type,               /* get_type */
     add_queue,                 /* add_queue */
     remove_queue,              /* remove_queue */
     default_fd_signaled,       /* signaled */
@@ -124,6 +125,7 @@ static const struct object_ops mail_writer_ops =
 {
     sizeof(struct mail_writer), /* size */
     mail_writer_dump,           /* dump */
+    no_get_type,                /* get_type */
     no_add_queue,               /* add_queue */
     NULL,                       /* remove_queue */
     NULL,                       /* signaled */
@@ -162,6 +164,7 @@ struct mailslot_device
 };
 
 static void mailslot_device_dump( struct object *obj, int verbose );
+static struct object_type *mailslot_device_get_type( struct object *obj );
 static struct fd *mailslot_device_get_fd( struct object *obj );
 static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name,
                                                    unsigned int attr );
@@ -174,6 +177,7 @@ static const struct object_ops mailslot_device_ops =
 {
     sizeof(struct mailslot_device), /* size */
     mailslot_device_dump,           /* dump */
+    mailslot_device_get_type,       /* get_type */
     no_add_queue,                   /* add_queue */
     NULL,                           /* remove_queue */
     NULL,                           /* signaled */
@@ -318,6 +322,13 @@ static void mailslot_device_dump( struct object *obj, int verbose )
     fprintf( stderr, "Mail slot device\n" );
 }
 
+static struct object_type *mailslot_device_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'D','e','v','i','c','e'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct fd *mailslot_device_get_fd( struct object *obj )
 {
     struct mailslot_device *device = (struct mailslot_device *)obj;
diff --git a/server/mapping.c b/server/mapping.c
index 9f062d0b0f5..02b73b19715 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -52,6 +52,7 @@ struct mapping
 };
 
 static void mapping_dump( struct object *obj, int verbose );
+static struct object_type *mapping_get_type( struct object *obj );
 static struct fd *mapping_get_fd( struct object *obj );
 static unsigned int mapping_map_access( struct object *obj, unsigned int access );
 static void mapping_destroy( struct object *obj );
@@ -60,6 +61,7 @@ static const struct object_ops mapping_ops =
 {
     sizeof(struct mapping),      /* size */
     mapping_dump,                /* dump */
+    mapping_get_type,            /* get_type */
     no_add_queue,                /* add_queue */
     NULL,                        /* remove_queue */
     NULL,                        /* signaled */
@@ -360,6 +362,13 @@ static void mapping_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *mapping_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'S','e','c','t','i','o','n'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct fd *mapping_get_fd( struct object *obj )
 {
     struct mapping *mapping = (struct mapping *)obj;
diff --git a/server/mutex.c b/server/mutex.c
index 0193422bc7a..31a529aa3fa 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -46,6 +46,7 @@ struct mutex
 };
 
 static void mutex_dump( struct object *obj, int verbose );
+static struct object_type *mutex_get_type( struct object *obj );
 static int mutex_signaled( struct object *obj, struct thread *thread );
 static int mutex_satisfied( struct object *obj, struct thread *thread );
 static unsigned int mutex_map_access( struct object *obj, unsigned int access );
@@ -56,6 +57,7 @@ static const struct object_ops mutex_ops =
 {
     sizeof(struct mutex),      /* size */
     mutex_dump,                /* dump */
+    mutex_get_type,            /* get_type */
     add_queue,                 /* add_queue */
     remove_queue,              /* remove_queue */
     mutex_signaled,            /* signaled */
@@ -128,6 +130,13 @@ static void mutex_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *mutex_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'M','u','t','a','n','t'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int mutex_signaled( struct object *obj, struct thread *thread )
 {
     struct mutex *mutex = (struct mutex *)obj;
diff --git a/server/named_pipe.c b/server/named_pipe.c
index d277cdcf96a..659d680162d 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -117,6 +117,7 @@ static const struct object_ops named_pipe_ops =
 {
     sizeof(struct named_pipe),    /* size */
     named_pipe_dump,              /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
@@ -145,6 +146,7 @@ static const struct object_ops pipe_server_ops =
 {
     sizeof(struct pipe_server),   /* size */
     pipe_server_dump,             /* dump */
+    no_get_type,                  /* get_type */
     add_queue,                    /* add_queue */
     remove_queue,                 /* remove_queue */
     default_fd_signaled,          /* signaled */
@@ -183,6 +185,7 @@ static const struct object_ops pipe_client_ops =
 {
     sizeof(struct pipe_client),   /* size */
     pipe_client_dump,             /* dump */
+    no_get_type,                  /* get_type */
     add_queue,                    /* add_queue */
     remove_queue,                 /* remove_queue */
     default_fd_signaled,          /* signaled */
@@ -211,6 +214,7 @@ static const struct fd_ops pipe_client_fd_ops =
 };
 
 static void named_pipe_device_dump( struct object *obj, int verbose );
+static struct object_type *named_pipe_device_get_type( struct object *obj );
 static struct fd *named_pipe_device_get_fd( struct object *obj );
 static struct object *named_pipe_device_lookup_name( struct object *obj,
     struct unicode_str *name, unsigned int attr );
@@ -225,6 +229,7 @@ static const struct object_ops named_pipe_device_ops =
 {
     sizeof(struct named_pipe_device), /* size */
     named_pipe_device_dump,           /* dump */
+    named_pipe_device_get_type,       /* get_type */
     no_add_queue,                     /* add_queue */
     NULL,                             /* remove_queue */
     NULL,                             /* signaled */
@@ -428,6 +433,13 @@ static void named_pipe_device_dump( struct object *obj, int verbose )
     fprintf( stderr, "Named pipe device\n" );
 }
 
+static struct object_type *named_pipe_device_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'D','e','v','i','c','e'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct fd *named_pipe_device_get_fd( struct object *obj )
 {
     struct named_pipe_device *device = (struct named_pipe_device *)obj;
diff --git a/server/object.c b/server/object.c
index 7b7a5e3c4de..f08548c2127 100644
--- a/server/object.c
+++ b/server/object.c
@@ -353,6 +353,11 @@ struct namespace *create_namespace( unsigned int hash_size )
 
 /* functions for unimplemented/default object operations */
 
+struct object_type *no_get_type( struct object *obj )
+{
+    return NULL;
+}
+
 int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
 {
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
diff --git a/server/object.h b/server/object.h
index 543b9ba0ad6..0f311388138 100644
--- a/server/object.h
+++ b/server/object.h
@@ -45,6 +45,7 @@ struct async;
 struct async_queue;
 struct winstation;
 struct directory;
+struct object_type;
 
 
 struct unicode_str
@@ -60,6 +61,8 @@ struct object_ops
     size_t size;
     /* dump the object (for debugging) */
     void (*dump)(struct object *,int);
+    /* return the object type */
+    struct object_type *(*get_type)(struct object *);
     /* add a thread to the object wait queue */
     int  (*add_queue)(struct object *,struct wait_queue_entry *);
     /* remove a thread from the object wait queue */
@@ -127,6 +130,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 struct object_type *no_get_type( struct object *obj );
 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 );
@@ -207,6 +211,7 @@ extern void *create_named_object_dir( struct directory *root, const struct unico
                                       unsigned int attr, const struct object_ops *ops );
 extern void *open_object_dir( struct directory *root, const struct unicode_str *name,
                               unsigned int attr, const struct object_ops *ops );
+extern struct object_type *get_object_type( const struct unicode_str *name );
 extern void init_directories(void);
 
 /* symbolic link functions */
diff --git a/server/process.c b/server/process.c
index e276dc49089..26b18631b10 100644
--- a/server/process.c
+++ b/server/process.c
@@ -67,6 +67,7 @@ static const struct object_ops process_ops =
 {
     sizeof(struct process),      /* size */
     process_dump,                /* dump */
+    no_get_type,                 /* get_type */
     add_queue,                   /* add_queue */
     remove_queue,                /* remove_queue */
     process_signaled,            /* signaled */
@@ -116,6 +117,7 @@ static const struct object_ops startup_info_ops =
 {
     sizeof(struct startup_info),   /* size */
     startup_info_dump,             /* dump */
+    no_get_type,                   /* get_type */
     add_queue,                     /* add_queue */
     remove_queue,                  /* remove_queue */
     startup_info_signaled,         /* signaled */
diff --git a/server/queue.c b/server/queue.c
index 320bdb09b1c..d837e84e0e1 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -149,6 +149,7 @@ static const struct object_ops msg_queue_ops =
 {
     sizeof(struct msg_queue),  /* size */
     msg_queue_dump,            /* dump */
+    no_get_type,               /* get_type */
     msg_queue_add_queue,       /* add_queue */
     msg_queue_remove_queue,    /* remove_queue */
     msg_queue_signaled,        /* signaled */
@@ -181,6 +182,7 @@ static const struct object_ops thread_input_ops =
 {
     sizeof(struct thread_input),  /* size */
     thread_input_dump,            /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
diff --git a/server/registry.c b/server/registry.c
index 03828e15f6c..d691e04a65b 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -142,6 +142,7 @@ static const struct object_ops key_ops =
 {
     sizeof(struct key),      /* size */
     key_dump,                /* dump */
+    no_get_type,             /* get_type */
     no_add_queue,            /* add_queue */
     NULL,                    /* remove_queue */
     NULL,                    /* signaled */
diff --git a/server/request.c b/server/request.c
index dbe483a7348..8a2d4fc8d89 100644
--- a/server/request.c
+++ b/server/request.c
@@ -89,6 +89,7 @@ static const struct object_ops master_socket_ops =
 {
     sizeof(struct master_socket),  /* size */
     master_socket_dump,            /* dump */
+    no_get_type,                   /* get_type */
     no_add_queue,                  /* add_queue */
     NULL,                          /* remove_queue */
     NULL,                          /* signaled */
diff --git a/server/semaphore.c b/server/semaphore.c
index 14121709729..0e26125159c 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -44,6 +44,7 @@ struct semaphore
 };
 
 static void semaphore_dump( struct object *obj, int verbose );
+static struct object_type *semaphore_get_type( struct object *obj );
 static int semaphore_signaled( struct object *obj, struct thread *thread );
 static int semaphore_satisfied( struct object *obj, struct thread *thread );
 static unsigned int semaphore_map_access( struct object *obj, unsigned int access );
@@ -53,6 +54,7 @@ static const struct object_ops semaphore_ops =
 {
     sizeof(struct semaphore),      /* size */
     semaphore_dump,                /* dump */
+    semaphore_get_type,            /* get_type */
     add_queue,                     /* add_queue */
     remove_queue,                  /* remove_queue */
     semaphore_signaled,            /* signaled */
@@ -127,6 +129,13 @@ static void semaphore_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *semaphore_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'S','e','m','a','p','h','o','r','e'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int semaphore_signaled( struct object *obj, struct thread *thread )
 {
     struct semaphore *sem = (struct semaphore *)obj;
diff --git a/server/serial.c b/server/serial.c
index 239a9c5eae6..d1b3822f106 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -87,6 +87,7 @@ static const struct object_ops serial_ops =
 {
     sizeof(struct serial),        /* size */
     serial_dump,                  /* dump */
+    no_get_type,                  /* get_type */
     add_queue,                    /* add_queue */
     remove_queue,                 /* remove_queue */
     default_fd_signaled,          /* signaled */
diff --git a/server/signal.c b/server/signal.c
index 912c6c62ca5..5bcd9cbe908 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -63,6 +63,7 @@ static const struct object_ops handler_ops =
 {
     sizeof(struct handler),   /* size */
     handler_dump,             /* dump */
+    no_get_type,              /* get_type */
     no_add_queue,             /* add_queue */
     NULL,                     /* remove_queue */
     NULL,                     /* signaled */
diff --git a/server/snapshot.c b/server/snapshot.c
index 552cc02ace0..57c9fac8c41 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -61,6 +61,7 @@ static const struct object_ops snapshot_ops =
 {
     sizeof(struct snapshot),      /* size */
     snapshot_dump,                /* dump */
+    no_get_type,                  /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
diff --git a/server/sock.c b/server/sock.c
index 66ab0d116f9..f4fe25e9177 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -106,6 +106,7 @@ static const struct object_ops sock_ops =
 {
     sizeof(struct sock),          /* size */
     sock_dump,                    /* dump */
+    no_get_type,                  /* get_type */
     add_queue,                    /* add_queue */
     remove_queue,                 /* remove_queue */
     sock_signaled,                /* signaled */
diff --git a/server/symlink.c b/server/symlink.c
index 183497ce40b..9769c838c3b 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -46,6 +46,7 @@ struct symlink
 };
 
 static void symlink_dump( struct object *obj, int verbose );
+static struct object_type *symlink_get_type( struct object *obj );
 static unsigned int symlink_map_access( struct object *obj, unsigned int access );
 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
                                            unsigned int attr );
@@ -55,6 +56,7 @@ static const struct object_ops symlink_ops =
 {
     sizeof(struct symlink),       /* size */
     symlink_dump,                 /* dump */
+    symlink_get_type,             /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
@@ -82,6 +84,13 @@ static void symlink_dump( struct object *obj, int verbose )
     fprintf( stderr, "\"\n" );
 }
 
+static struct object_type *symlink_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'S','y','m','b','o','l','i','c','L','i','n','k'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name,
                                            unsigned int attr )
 {
diff --git a/server/thread.c b/server/thread.c
index 6eb43eeda02..5725ec1f4d0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -86,6 +86,7 @@ static const struct object_ops thread_apc_ops =
 {
     sizeof(struct thread_apc),  /* size */
     dump_thread_apc,            /* dump */
+    no_get_type,                /* get_type */
     add_queue,                  /* add_queue */
     remove_queue,               /* remove_queue */
     thread_apc_signaled,        /* signaled */
@@ -114,6 +115,7 @@ static const struct object_ops thread_ops =
 {
     sizeof(struct thread),      /* size */
     dump_thread,                /* dump */
+    no_get_type,                /* get_type */
     add_queue,                  /* add_queue */
     remove_queue,               /* remove_queue */
     thread_signaled,            /* signaled */
diff --git a/server/timer.c b/server/timer.c
index fb2a2a8e6ce..5afe6630be6 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -51,6 +51,7 @@ struct timer
 };
 
 static void timer_dump( struct object *obj, int verbose );
+static struct object_type *timer_get_type( struct object *obj );
 static int timer_signaled( struct object *obj, struct thread *thread );
 static int timer_satisfied( struct object *obj, struct thread *thread );
 static unsigned int timer_map_access( struct object *obj, unsigned int access );
@@ -60,6 +61,7 @@ static const struct object_ops timer_ops =
 {
     sizeof(struct timer),      /* size */
     timer_dump,                /* dump */
+    timer_get_type,            /* get_type */
     add_queue,                 /* add_queue */
     remove_queue,              /* remove_queue */
     timer_signaled,            /* signaled */
@@ -185,6 +187,13 @@ static void timer_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *timer_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'T','i','m','e','r'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int timer_signaled( struct object *obj, struct thread *thread )
 {
     struct timer *timer = (struct timer *)obj;
diff --git a/server/token.c b/server/token.c
index 93696d9d8ea..387163b24ab 100644
--- a/server/token.c
+++ b/server/token.c
@@ -122,6 +122,7 @@ static const struct object_ops token_ops =
 {
     sizeof(struct token),      /* size */
     token_dump,                /* dump */
+    no_get_type,               /* get_type */
     no_add_queue,              /* add_queue */
     NULL,                      /* remove_queue */
     NULL,                      /* signaled */
diff --git a/server/winstation.c b/server/winstation.c
index 5e4bfbcee54..3b163a77921 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -44,10 +44,12 @@ static struct list winstation_list = LIST_INIT(winstation_list);
 static struct namespace *winstation_namespace;
 
 static void winstation_dump( struct object *obj, int verbose );
+static struct object_type *winstation_get_type( struct object *obj );
 static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
 static void winstation_destroy( struct object *obj );
 static unsigned int winstation_map_access( struct object *obj, unsigned int access );
 static void desktop_dump( struct object *obj, int verbose );
+static struct object_type *desktop_get_type( struct object *obj );
 static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
 static void desktop_destroy( struct object *obj );
 static unsigned int desktop_map_access( struct object *obj, unsigned int access );
@@ -56,6 +58,7 @@ static const struct object_ops winstation_ops =
 {
     sizeof(struct winstation),    /* size */
     winstation_dump,              /* dump */
+    winstation_get_type,          /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
@@ -76,6 +79,7 @@ static const struct object_ops desktop_ops =
 {
     sizeof(struct desktop),       /* size */
     desktop_dump,                 /* dump */
+    desktop_get_type,             /* get_type */
     no_add_queue,                 /* add_queue */
     NULL,                         /* remove_queue */
     NULL,                         /* signaled */
@@ -133,6 +137,13 @@ static void winstation_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *winstation_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
 {
     return (process->winstation != handle);
@@ -236,6 +247,13 @@ static void desktop_dump( struct object *obj, int verbose )
     fputc( '\n', stderr );
 }
 
+static struct object_type *desktop_get_type( struct object *obj )
+{
+    static const WCHAR name[] = {'D','e','s','k','t','o','p'};
+    static const struct unicode_str str = { name, sizeof(name) };
+    return get_object_type( &str );
+}
+
 static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
 {
     struct thread *thread;
-- 
GitLab