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 );
 }
-
diff --git a/server/protocol.def b/server/protocol.def
index 16c6c50..f6e40eb 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1781,9 +1781,10 @@
     user_handle_t  owner;       /* owner window */
     atom_t         atom;        /* class atom */
     void*          instance;    /* module instance */
-    int            extra;       /* number of extra bytes */
 @REPLY
     user_handle_t  handle;      /* created window */
+    int            extra;       /* number of extra bytes */
+    void*          class_ptr;   /* pointer to class in client address space */
 @END
 
 
@@ -2138,6 +2139,7 @@
     void*          instance;       /* module instance */
     int            extra;          /* number of extra class bytes */
     int            win_extra;      /* number of window extra bytes */
+    void*          client_ptr;     /* pointer to class in client address space */
 @END
 
 
@@ -2145,6 +2147,8 @@
 @REQ(destroy_class)
     atom_t         atom;           /* class atom */
     void*          instance;       /* module instance */
+@REPLY
+    void*          client_ptr;     /* pointer to class in client address space */
 @END
 
 
diff --git a/server/trace.c b/server/trace.c
index 97ec3f5..2069700 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2096,13 +2096,14 @@
     fprintf( stderr, " parent=%p,", req->parent );
     fprintf( stderr, " owner=%p,", req->owner );
     fprintf( stderr, " atom=%04x,", req->atom );
-    fprintf( stderr, " instance=%p,", req->instance );
-    fprintf( stderr, " extra=%d", req->extra );
+    fprintf( stderr, " instance=%p", req->instance );
 }
 
 static void dump_create_window_reply( const struct create_window_reply *req )
 {
-    fprintf( stderr, " handle=%p", req->handle );
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " extra=%d,", req->extra );
+    fprintf( stderr, " class_ptr=%p", req->class_ptr );
 }
 
 static void dump_link_window_request( const struct link_window_request *req )
@@ -2511,7 +2512,8 @@
     fprintf( stderr, " style=%08x,", req->style );
     fprintf( stderr, " instance=%p,", req->instance );
     fprintf( stderr, " extra=%d,", req->extra );
-    fprintf( stderr, " win_extra=%d", req->win_extra );
+    fprintf( stderr, " win_extra=%d,", req->win_extra );
+    fprintf( stderr, " client_ptr=%p", req->client_ptr );
 }
 
 static void dump_destroy_class_request( const struct destroy_class_request *req )
@@ -2520,6 +2522,11 @@
     fprintf( stderr, " instance=%p", req->instance );
 }
 
+static void dump_destroy_class_reply( const struct destroy_class_reply *req )
+{
+    fprintf( stderr, " client_ptr=%p", req->client_ptr );
+}
+
 static void dump_set_class_info_request( const struct set_class_info_request *req )
 {
     fprintf( stderr, " window=%p,", req->window );
@@ -2952,7 +2959,7 @@
     (dump_func)0,
     (dump_func)dump_get_next_hook_reply,
     (dump_func)0,
-    (dump_func)0,
+    (dump_func)dump_destroy_class_reply,
     (dump_func)dump_set_class_info_reply,
     (dump_func)dump_set_clipboard_info_reply,
     (dump_func)dump_open_token_reply,
diff --git a/server/user.h b/server/user.h
index 8c07b7f..62bc80d 100644
--- a/server/user.h
+++ b/server/user.h
@@ -78,8 +78,10 @@
 /* window class functions */
 
 extern void destroy_process_classes( struct process *process );
-extern struct window_class *grab_class( struct process *process, atom_t atom, void *instance );
+extern struct window_class *grab_class( struct process *process, atom_t atom,
+                                        void *instance, int *extra_bytes );
 extern void release_class( struct window_class *class );
 extern atom_t get_class_atom( struct window_class *class );
+extern void *get_class_client_ptr( struct window_class *class );
 
 #endif  /* __WINE_SERVER_USER_H */
diff --git a/server/window.c b/server/window.c
index d6a1b6f..8550de1 100644
--- a/server/window.c
+++ b/server/window.c
@@ -268,11 +268,12 @@
 }
 
 /* create a new window structure (note: the window is not linked in the window tree) */
-static struct window *create_window( struct window *parent, struct window *owner, atom_t atom,
-                                     void *instance, int extra_bytes )
+static struct window *create_window( struct window *parent, struct window *owner,
+                                     atom_t atom, void *instance )
 {
+    int extra_bytes;
     struct window *win;
-    struct window_class *class = grab_class( current->process, atom, instance );
+    struct window_class *class = grab_class( current->process, atom, instance, &extra_bytes );
 
     if (!class) return NULL;
 
@@ -474,25 +475,22 @@
 /* create a window */
 DECL_HANDLER(create_window)
 {
+    struct window *win;
+
     reply->handle = 0;
-    if (req->extra < 0 || req->extra > 4096)  /* don't allow stupid values here */
-    {
-        set_error( STATUS_INVALID_PARAMETER );
-        return;
-    }
     if (!req->parent)  /* return desktop window */
     {
         if (!top_window)
         {
-            if (!(top_window = create_window( NULL, NULL, req->atom, req->instance, req->extra ))) return;
+            if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return;
             top_window->thread = NULL;  /* no thread owns the desktop */
             top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
         }
-        reply->handle = top_window->handle;
+        win = top_window;
     }
     else
     {
-        struct window *win, *parent, *owner = NULL;
+        struct window *parent, *owner = NULL;
 
         if (!(parent = get_window( req->parent ))) return;
         if (req->owner && !(owner = get_window( req->owner ))) return;
@@ -503,9 +501,11 @@
             set_error( STATUS_ACCESS_DENIED );
             return;
         }
-        if (!(win = create_window( parent, owner, req->atom, req->instance, req->extra ))) return;
-        reply->handle = win->handle;
+        if (!(win = create_window( parent, owner, req->atom, req->instance ))) return;
     }
+    reply->handle    = win->handle;
+    reply->extra     = win->nb_extra_bytes;
+    reply->class_ptr = get_class_client_ptr( win->class );
 }