Store a pointer to the client-side class structure in the server and
return it on create_window and destroy_class.
Only create a single instance of the desktop class for the whole
session.
Added some missing locking in the client-side class management.

diff --git a/server/class.c b/server/class.c
index 13d9d5c..5f034d9 100644
--- a/server/class.c
+++ b/server/class.c
@@ -44,10 +44,15 @@
     void           *instance;        /* module instance */
     unsigned int    style;           /* class style */
     int             win_extra;       /* number of window extra bytes */
+    void           *client_ptr;      /* pointer to class in client address space */
     int             nb_extra_bytes;  /* number of extra bytes */
     char            extra_bytes[1];  /* extra bytes storage */
 };
 
+#define DESKTOP_ATOM  ((atom_t)32769)
+
+static struct window_class *desktop_class;
+
 static struct window_class *create_class( struct process *process, int extra_bytes, int local )
 {
     struct window_class *class;
@@ -67,6 +72,25 @@
     return class;
 }
 
+static struct window_class *create_desktop_class( unsigned int style, int win_extra )
+{
+    struct window_class *class;
+
+    if (!(class = mem_alloc( sizeof(*class) - 1 ))) return NULL;
+
+    class->process        = NULL;
+    class->count          = 0;
+    class->local          = 0;
+    class->nb_extra_bytes = 0;
+    class->atom           = DESKTOP_ATOM;
+    class->instance       = NULL;
+    class->style          = style;
+    class->win_extra      = win_extra;
+    class->client_ptr     = NULL;
+    desktop_class = class;
+    return class;
+}
+
 static void destroy_class( struct window_class *class )
 {
     list_remove( &class->entry );
@@ -95,13 +119,19 @@
         if (class->atom != atom) continue;
         if (!instance || !class->local || class->instance == instance) return class;
     }
+    if (atom == DESKTOP_ATOM) return desktop_class;
     return NULL;
 }
 
-struct window_class *grab_class( struct process *process, atom_t atom, void *instance )
+struct window_class *grab_class( struct process *process, atom_t atom,
+                                 void *instance, int *extra_bytes )
 {
     struct window_class *class = find_class( process, atom, instance );
-    if (class) class->count++;
+    if (class)
+    {
+        class->count++;
+        *extra_bytes = class->win_extra;
+    }
     else set_error( STATUS_INVALID_HANDLE );
     return class;
 }
@@ -117,18 +147,31 @@
     return class->atom;
 }
 
+void *get_class_client_ptr( struct window_class *class )
+{
+    return class->client_ptr;
+}
+
 /* create a window class */
 DECL_HANDLER(create_class)
 {
-    struct window_class *class = find_class( current->process, req->atom, req->instance );
+    struct window_class *class;
 
+    if (!req->local && req->atom == DESKTOP_ATOM)
+    {
+        if (!desktop_class) create_desktop_class( req->style, req->win_extra );
+        return;  /* silently ignore further attempts to create the desktop class */
+    }
+
+    class = find_class( current->process, req->atom, req->instance );
     if (class && !class->local == !req->local)
     {
         set_win32_error( ERROR_CLASS_ALREADY_EXISTS );
         return;
     }
-    if (req->extra < 0 || req->extra > 4096)  /* don't allow stupid values here */
+    if (req->extra < 0 || req->extra > 4096 || req->win_extra < 0 || req->win_extra > 4096)
     {
+        /* don't allow stupid values here */
         set_error( STATUS_INVALID_PARAMETER );
         return;
     }
@@ -139,10 +182,11 @@
         release_global_atom( req->atom );
         return;
     }
-    class->atom      = req->atom;
-    class->instance  = req->instance;
-    class->style     = req->style;
-    class->win_extra = req->win_extra;
+    class->atom       = req->atom;
+    class->instance   = req->instance;
+    class->style      = req->style;
+    class->win_extra  = req->win_extra;
+    class->client_ptr = req->client_ptr;
 }
 
 /* destroy a window class */
@@ -151,11 +195,14 @@
     struct window_class *class = find_class( current->process, req->atom, req->instance );
 
     if (!class)
-        set_error( STATUS_INVALID_HANDLE );
+        set_win32_error( ERROR_CLASS_DOES_NOT_EXIST );
     else if (class->count)
         set_win32_error( ERROR_CLASS_HAS_WINDOWS );
     else
-        destroy_class( class );
+    {
+        reply->client_ptr = class->client_ptr;
+        if (class != desktop_class) destroy_class( class );
+    }
 }
 
 
@@ -166,6 +213,12 @@
 
     if (!class) return;
 
+    if (req->flags && class->process != current->process)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return;
+    }
+
     if (req->extra_size > sizeof(req->extra_value) ||
         req->extra_offset < -1 ||
         req->extra_offset > class->nb_extra_bytes - (int)req->extra_size)
@@ -173,6 +226,11 @@
         set_win32_error( ERROR_INVALID_INDEX );
         return;
     }
+    if ((req->flags & SET_CLASS_WINEXTRA) && (req->win_extra < 0 || req->win_extra > 4096))
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
     if (req->extra_offset != -1)
     {
         memcpy( &reply->old_extra_value, class->extra_bytes + req->extra_offset, req->extra_size );
@@ -201,4 +259,3 @@
     if (req->flags & SET_CLASS_EXTRA) memcpy( class->extra_bytes + req->extra_offset,
                                               &req->extra_value, req->extra_size );
 }
-