Added window classes in the server, and support for inter-process
GetClassWord/Long (based on a patch by Mike McCormack).
Various fixes to the class instance handling.

diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c
index 8e1542a..aebce24 100644
--- a/dlls/user/user_main.c
+++ b/dlls/user/user_main.c
@@ -128,41 +128,6 @@
 
 
 /***********************************************************************
- *           controls_init
- *
- * Register the classes for the builtin controls
- */
-static void controls_init(void)
-{
-    extern const struct builtin_class_descr BUTTON_builtin_class;
-    extern const struct builtin_class_descr COMBO_builtin_class;
-    extern const struct builtin_class_descr COMBOLBOX_builtin_class;
-    extern const struct builtin_class_descr DIALOG_builtin_class;
-    extern const struct builtin_class_descr DESKTOP_builtin_class;
-    extern const struct builtin_class_descr EDIT_builtin_class;
-    extern const struct builtin_class_descr ICONTITLE_builtin_class;
-    extern const struct builtin_class_descr LISTBOX_builtin_class;
-    extern const struct builtin_class_descr MDICLIENT_builtin_class;
-    extern const struct builtin_class_descr MENU_builtin_class;
-    extern const struct builtin_class_descr SCROLL_builtin_class;
-    extern const struct builtin_class_descr STATIC_builtin_class;
-
-    CLASS_RegisterBuiltinClass( &BUTTON_builtin_class );
-    CLASS_RegisterBuiltinClass( &COMBO_builtin_class );
-    CLASS_RegisterBuiltinClass( &COMBOLBOX_builtin_class );
-    CLASS_RegisterBuiltinClass( &DIALOG_builtin_class );
-    CLASS_RegisterBuiltinClass( &DESKTOP_builtin_class );
-    CLASS_RegisterBuiltinClass( &EDIT_builtin_class );
-    CLASS_RegisterBuiltinClass( &ICONTITLE_builtin_class );
-    CLASS_RegisterBuiltinClass( &LISTBOX_builtin_class );
-    CLASS_RegisterBuiltinClass( &MDICLIENT_builtin_class );
-    CLASS_RegisterBuiltinClass( &MENU_builtin_class );
-    CLASS_RegisterBuiltinClass( &SCROLL_builtin_class );
-    CLASS_RegisterBuiltinClass( &STATIC_builtin_class );
-}
-
-
-/***********************************************************************
  *           palette_init
  *
  * Patch the function pointers in GDI for SelectPalette and RealizePalette
@@ -219,7 +184,7 @@
 /***********************************************************************
  *           USER initialisation routine
  */
-static BOOL process_attach(void)
+static BOOL process_attach( HINSTANCE inst )
 {
     HINSTANCE16 instance;
 
@@ -243,7 +208,7 @@
     palette_init();
 
     /* Initialize built-in window classes */
-    controls_init();
+    CLASS_RegisterBuiltinClasses( inst );
 
     /* Initialize menus */
     if (!MENU_Init()) return FALSE;
@@ -304,7 +269,7 @@
     switch(reason)
     {
     case DLL_PROCESS_ATTACH:
-        ret = process_attach();
+        ret = process_attach( inst );
         break;
     case DLL_THREAD_DETACH:
         thread_detach();
diff --git a/dlls/user/winproc.h b/dlls/user/winproc.h
index 9085df9..883a8fd 100644
--- a/dlls/user/winproc.h
+++ b/dlls/user/winproc.h
@@ -137,13 +137,11 @@
 
 /* Class functions */
 struct tagCLASS;  /* opaque structure */
-struct builtin_class_descr;
 struct tagDCE;
-extern ATOM CLASS_RegisterBuiltinClass( const struct builtin_class_descr *descr );
+extern void CLASS_RegisterBuiltinClasses( HINSTANCE inst );
 extern struct tagCLASS *CLASS_AddWindow( ATOM atom, HINSTANCE inst, WINDOWPROCTYPE type,
                                          INT *winExtra, WNDPROC *winproc,
                                          DWORD *style, struct tagDCE **dce );
-extern void CLASS_RemoveWindow( struct tagCLASS *cls );
 extern void CLASS_FreeModuleClasses( HMODULE16 hModule );
 
 /* Timer functions */
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 40ce933..116be53 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2525,6 +2525,7 @@
     user_handle_t  parent;
     user_handle_t  owner;
     atom_t         atom;
+    void*          instance;
     int            extra;
 };
 struct create_window_reply
@@ -3052,6 +3053,67 @@
 
 
 
+struct create_class_request
+{
+    struct request_header __header;
+    int            local;
+    atom_t         atom;
+    unsigned int   style;
+    void*          instance;
+    int            extra;
+    int            win_extra;
+};
+struct create_class_reply
+{
+    struct reply_header __header;
+};
+
+
+
+struct destroy_class_request
+{
+    struct request_header __header;
+    atom_t         atom;
+    void*          instance;
+};
+struct destroy_class_reply
+{
+    struct reply_header __header;
+};
+
+
+
+struct set_class_info_request
+{
+    struct request_header __header;
+    user_handle_t  window;
+    unsigned int   flags;
+    atom_t         atom;
+    unsigned int   style;
+    int            win_extra;
+    void*          instance;
+    int            extra_offset;
+    size_t         extra_size;
+    unsigned int   extra_value;
+};
+struct set_class_info_reply
+{
+    struct reply_header __header;
+    atom_t         old_atom;
+    unsigned int   old_style;
+    int            old_extra;
+    int            old_win_extra;
+    void*          old_instance;
+    unsigned int   old_extra_value;
+};
+#define SET_CLASS_ATOM      0x0001
+#define SET_CLASS_STYLE     0x0002
+#define SET_CLASS_WINEXTRA  0x0004
+#define SET_CLASS_INSTANCE  0x0008
+#define SET_CLASS_EXTRA     0x0010
+
+
+
 struct set_clipboard_info_request
 {
     struct request_header __header;
@@ -3298,6 +3360,9 @@
     REQ_start_hook_chain,
     REQ_finish_hook_chain,
     REQ_get_next_hook,
+    REQ_create_class,
+    REQ_destroy_class,
+    REQ_set_class_info,
     REQ_set_clipboard_info,
     REQ_open_token,
     REQ_set_global_windows,
@@ -3484,6 +3549,9 @@
     struct start_hook_chain_request start_hook_chain_request;
     struct finish_hook_chain_request finish_hook_chain_request;
     struct get_next_hook_request get_next_hook_request;
+    struct create_class_request create_class_request;
+    struct destroy_class_request destroy_class_request;
+    struct set_class_info_request set_class_info_request;
     struct set_clipboard_info_request set_clipboard_info_request;
     struct open_token_request open_token_request;
     struct set_global_windows_request set_global_windows_request;
@@ -3668,11 +3736,14 @@
     struct start_hook_chain_reply start_hook_chain_reply;
     struct finish_hook_chain_reply finish_hook_chain_reply;
     struct get_next_hook_reply get_next_hook_reply;
+    struct create_class_reply create_class_reply;
+    struct destroy_class_reply destroy_class_reply;
+    struct set_class_info_reply set_class_info_reply;
     struct set_clipboard_info_reply set_clipboard_info_reply;
     struct open_token_reply open_token_reply;
     struct set_global_windows_reply set_global_windows_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 128
+#define SERVER_PROTOCOL_VERSION 129
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/Makefile.in b/server/Makefile.in
index 1955d67..2f4275d 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -9,6 +9,7 @@
 	async.c \
 	atom.c \
 	change.c \
+	class.c \
 	clipboard.c \
 	console.c \
 	context_i386.c \
diff --git a/server/class.c b/server/class.c
new file mode 100644
index 0000000..13d9d5c
--- /dev/null
+++ b/server/class.c
@@ -0,0 +1,204 @@
+/*
+ * Server-side window class management
+ *
+ * Copyright (C) 2002 Mike McCormack
+ * Copyright (C) 2003 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "wine/list.h"
+
+#include "request.h"
+#include "object.h"
+#include "process.h"
+#include "user.h"
+
+struct window_class
+{
+    struct list     entry;           /* entry in process list */
+    struct process *process;         /* process owning the class */
+    int             count;           /* reference count */
+    int             local;           /* local class? */
+    atom_t          atom;            /* class atom */
+    void           *instance;        /* module instance */
+    unsigned int    style;           /* class style */
+    int             win_extra;       /* number of window extra bytes */
+    int             nb_extra_bytes;  /* number of extra bytes */
+    char            extra_bytes[1];  /* extra bytes storage */
+};
+
+static struct window_class *create_class( struct process *process, int extra_bytes, int local )
+{
+    struct window_class *class;
+
+    if (!(class = mem_alloc( sizeof(*class) + extra_bytes - 1 ))) return NULL;
+
+    class->process = (struct process *)grab_object( process );
+    class->count = 0;
+    class->local = local;
+    class->nb_extra_bytes = extra_bytes;
+    memset( class->extra_bytes, 0, extra_bytes );
+    /* other fields are initialized by caller */
+
+    /* local classes have priority so we put them first in the list */
+    if (local) list_add_head( &process->classes, &class->entry );
+    else list_add_tail( &process->classes, &class->entry );
+    return class;
+}
+
+static void destroy_class( struct window_class *class )
+{
+    list_remove( &class->entry );
+    release_object( class->process );
+    free( class );
+}
+
+void destroy_process_classes( struct process *process )
+{
+    struct list *ptr;
+
+    while ((ptr = list_head( &process->classes )))
+    {
+        struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry );
+        destroy_class( class );
+    }
+}
+
+static struct window_class *find_class( struct process *process, atom_t atom, void *instance )
+{
+    struct list *ptr;
+
+    LIST_FOR_EACH( ptr, &process->classes )
+    {
+        struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry );
+        if (class->atom != atom) continue;
+        if (!instance || !class->local || class->instance == instance) return class;
+    }
+    return NULL;
+}
+
+struct window_class *grab_class( struct process *process, atom_t atom, void *instance )
+{
+    struct window_class *class = find_class( process, atom, instance );
+    if (class) class->count++;
+    else set_error( STATUS_INVALID_HANDLE );
+    return class;
+}
+
+void release_class( struct window_class *class )
+{
+    assert( class->count > 0 );
+    class->count--;
+}
+
+atom_t get_class_atom( struct window_class *class )
+{
+    return class->atom;
+}
+
+/* create a window class */
+DECL_HANDLER(create_class)
+{
+    struct window_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 */
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+    if (!grab_global_atom( req->atom )) return;
+
+    if (!(class = create_class( current->process, req->extra, req->local )))
+    {
+        release_global_atom( req->atom );
+        return;
+    }
+    class->atom      = req->atom;
+    class->instance  = req->instance;
+    class->style     = req->style;
+    class->win_extra = req->win_extra;
+}
+
+/* destroy a window class */
+DECL_HANDLER(destroy_class)
+{
+    struct window_class *class = find_class( current->process, req->atom, req->instance );
+
+    if (!class)
+        set_error( STATUS_INVALID_HANDLE );
+    else if (class->count)
+        set_win32_error( ERROR_CLASS_HAS_WINDOWS );
+    else
+        destroy_class( class );
+}
+
+
+/* set some information in a class */
+DECL_HANDLER(set_class_info)
+{
+    struct window_class *class = get_window_class( req->window );
+
+    if (!class) return;
+
+    if (req->extra_size > sizeof(req->extra_value) ||
+        req->extra_offset < -1 ||
+        req->extra_offset > class->nb_extra_bytes - (int)req->extra_size)
+    {
+        set_win32_error( ERROR_INVALID_INDEX );
+        return;
+    }
+    if (req->extra_offset != -1)
+    {
+        memcpy( &reply->old_extra_value, class->extra_bytes + req->extra_offset, req->extra_size );
+    }
+    else if (req->flags & SET_CLASS_EXTRA)
+    {
+        set_win32_error( ERROR_INVALID_INDEX );
+        return;
+    }
+
+    reply->old_atom      = class->atom;
+    reply->old_style     = class->style;
+    reply->old_extra     = class->nb_extra_bytes;
+    reply->old_win_extra = class->win_extra;
+    reply->old_instance  = class->instance;
+
+    if (req->flags & SET_CLASS_ATOM)
+    {
+        if (!grab_global_atom( req->atom )) return;
+        release_global_atom( class->atom );
+        class->atom = req->atom;
+    }
+    if (req->flags & SET_CLASS_STYLE) class->style = req->style;
+    if (req->flags & SET_CLASS_WINEXTRA) class->win_extra = req->win_extra;
+    if (req->flags & SET_CLASS_INSTANCE) class->instance = req->instance;
+    if (req->flags & SET_CLASS_EXTRA) memcpy( class->extra_bytes + req->extra_offset,
+                                              &req->extra_value, req->extra_size );
+}
+
diff --git a/server/process.c b/server/process.c
index fd96614..0927559 100644
--- a/server/process.c
+++ b/server/process.c
@@ -44,6 +44,7 @@
 #include "thread.h"
 #include "request.h"
 #include "console.h"
+#include "user.h"
 
 /* process structure */
 
@@ -283,6 +284,7 @@
     process->group_id        = 0;
     process->token           = create_token();
     list_init( &process->locks );
+    list_init( &process->classes );
 
     gettimeofday( &process->start_time, NULL );
     if ((process->next = first_process) != NULL) process->next->prev = process;
@@ -597,6 +599,7 @@
         if (dll->filename) free( dll->filename );
         free( dll );
     }
+    destroy_process_classes( process );
     set_process_startup_state( process, STARTUP_ABORTED );
     if (process->exe.file) release_object( process->exe.file );
     process->exe.file = NULL;
diff --git a/server/process.h b/server/process.h
index cd759f2..cbf41f9 100644
--- a/server/process.h
+++ b/server/process.h
@@ -68,6 +68,7 @@
     int                  suspend;         /* global process suspend count */
     int                  create_flags;    /* process creation flags */
     struct list          locks;           /* list of file locks owned by the process */
+    struct list          classes;         /* window classes owned by the process */
     struct console_input*console;         /* console input */
     enum startup_state   startup_state;   /* startup state */
     struct startup_info *startup_info;    /* startup info while init is in progress */
diff --git a/server/protocol.def b/server/protocol.def
index c9d4df9..16c6c50 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1780,6 +1780,7 @@
     user_handle_t  parent;      /* parent window */
     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 */
@@ -2129,6 +2130,50 @@
 @END
 
 
+/* Create a window class */
+@REQ(create_class)
+    int            local;          /* is it a local class? */
+    atom_t         atom;           /* class atom */
+    unsigned int   style;          /* class style */
+    void*          instance;       /* module instance */
+    int            extra;          /* number of extra class bytes */
+    int            win_extra;      /* number of window extra bytes */
+@END
+
+
+/* Destroy a window class */
+@REQ(destroy_class)
+    atom_t         atom;           /* class atom */
+    void*          instance;       /* module instance */
+@END
+
+
+/* Set some information in a class */
+@REQ(set_class_info)
+    user_handle_t  window;         /* handle to the window */
+    unsigned int   flags;          /* flags for info to set (see below) */
+    atom_t         atom;           /* class atom */
+    unsigned int   style;          /* class style */
+    int            win_extra;      /* number of window extra bytes */
+    void*          instance;       /* module instance */
+    int            extra_offset;   /* offset to set in extra bytes */
+    size_t         extra_size;     /* size to set in extra bytes */
+    unsigned int   extra_value;    /* value to set in extra bytes */
+@REPLY
+    atom_t         old_atom;       /* previous class atom */
+    unsigned int   old_style;      /* previous class style */
+    int            old_extra;      /* previous number of class extra bytes */
+    int            old_win_extra;  /* previous number of window extra bytes */
+    void*          old_instance;   /* previous module instance */
+    unsigned int   old_extra_value; /* old value in extra bytes */
+@END
+#define SET_CLASS_ATOM      0x0001
+#define SET_CLASS_STYLE     0x0002
+#define SET_CLASS_WINEXTRA  0x0004
+#define SET_CLASS_INSTANCE  0x0008
+#define SET_CLASS_EXTRA     0x0010
+
+
 /* Set/get clipboard information */
 @REQ(set_clipboard_info)
     unsigned int   flags;       /* flags for fields to set (see below) */
diff --git a/server/request.h b/server/request.h
index a0287ad..ec2d5a1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -279,6 +279,9 @@
 DECL_HANDLER(start_hook_chain);
 DECL_HANDLER(finish_hook_chain);
 DECL_HANDLER(get_next_hook);
+DECL_HANDLER(create_class);
+DECL_HANDLER(destroy_class);
+DECL_HANDLER(set_class_info);
 DECL_HANDLER(set_clipboard_info);
 DECL_HANDLER(open_token);
 DECL_HANDLER(set_global_windows);
@@ -464,6 +467,9 @@
     (req_handler)req_start_hook_chain,
     (req_handler)req_finish_hook_chain,
     (req_handler)req_get_next_hook,
+    (req_handler)req_create_class,
+    (req_handler)req_destroy_class,
+    (req_handler)req_set_class_info,
     (req_handler)req_set_clipboard_info,
     (req_handler)req_open_token,
     (req_handler)req_set_global_windows,
diff --git a/server/trace.c b/server/trace.c
index 3405a00..97ec3f5 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2096,6 +2096,7 @@
     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 );
 }
 
@@ -2503,6 +2504,45 @@
     dump_varargs_unicode_str( cur_size );
 }
 
+static void dump_create_class_request( const struct create_class_request *req )
+{
+    fprintf( stderr, " local=%d,", req->local );
+    fprintf( stderr, " atom=%04x,", req->atom );
+    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 );
+}
+
+static void dump_destroy_class_request( const struct destroy_class_request *req )
+{
+    fprintf( stderr, " atom=%04x,", req->atom );
+    fprintf( stderr, " instance=%p", req->instance );
+}
+
+static void dump_set_class_info_request( const struct set_class_info_request *req )
+{
+    fprintf( stderr, " window=%p,", req->window );
+    fprintf( stderr, " flags=%08x,", req->flags );
+    fprintf( stderr, " atom=%04x,", req->atom );
+    fprintf( stderr, " style=%08x,", req->style );
+    fprintf( stderr, " win_extra=%d,", req->win_extra );
+    fprintf( stderr, " instance=%p,", req->instance );
+    fprintf( stderr, " extra_offset=%d,", req->extra_offset );
+    fprintf( stderr, " extra_size=%d,", req->extra_size );
+    fprintf( stderr, " extra_value=%08x", req->extra_value );
+}
+
+static void dump_set_class_info_reply( const struct set_class_info_reply *req )
+{
+    fprintf( stderr, " old_atom=%04x,", req->old_atom );
+    fprintf( stderr, " old_style=%08x,", req->old_style );
+    fprintf( stderr, " old_extra=%d,", req->old_extra );
+    fprintf( stderr, " old_win_extra=%d,", req->old_win_extra );
+    fprintf( stderr, " old_instance=%p,", req->old_instance );
+    fprintf( stderr, " old_extra_value=%08x", req->old_extra_value );
+}
+
 static void dump_set_clipboard_info_request( const struct set_clipboard_info_request *req )
 {
     fprintf( stderr, " flags=%08x,", req->flags );
@@ -2726,6 +2766,9 @@
     (dump_func)dump_start_hook_chain_request,
     (dump_func)dump_finish_hook_chain_request,
     (dump_func)dump_get_next_hook_request,
+    (dump_func)dump_create_class_request,
+    (dump_func)dump_destroy_class_request,
+    (dump_func)dump_set_class_info_request,
     (dump_func)dump_set_clipboard_info_request,
     (dump_func)dump_open_token_request,
     (dump_func)dump_set_global_windows_request,
@@ -2908,6 +2951,9 @@
     (dump_func)dump_start_hook_chain_reply,
     (dump_func)0,
     (dump_func)dump_get_next_hook_reply,
+    (dump_func)0,
+    (dump_func)0,
+    (dump_func)dump_set_class_info_reply,
     (dump_func)dump_set_clipboard_info_reply,
     (dump_func)dump_open_token_reply,
     (dump_func)dump_set_global_windows_reply,
@@ -3090,6 +3136,9 @@
     "start_hook_chain",
     "finish_hook_chain",
     "get_next_hook",
+    "create_class",
+    "destroy_class",
+    "set_class_info",
     "set_clipboard_info",
     "open_token",
     "set_global_windows",
diff --git a/server/user.h b/server/user.h
index a075dd7..8c07b7f 100644
--- a/server/user.h
+++ b/server/user.h
@@ -27,6 +27,7 @@
 struct window;
 struct msg_queue;
 struct hook_table;
+struct window_class;
 
 enum user_object
 {
@@ -72,5 +73,13 @@
 extern struct thread *get_window_thread( user_handle_t handle );
 extern user_handle_t window_from_point( int x, int y );
 extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread );
+extern struct window_class *get_window_class( user_handle_t window );
+
+/* 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 void release_class( struct window_class *class );
+extern atom_t get_class_atom( struct window_class *class );
 
 #endif  /* __WINE_SERVER_USER_H */
diff --git a/server/window.c b/server/window.c
index 6373068..d6a1b6f 100644
--- a/server/window.c
+++ b/server/window.c
@@ -63,6 +63,7 @@
     struct window   *prev;            /* prev window in Z-order */
     user_handle_t    handle;          /* full handle for this window */
     struct thread   *thread;          /* thread owning the window */
+    struct window_class *class;       /* window class */
     atom_t           atom;            /* class atom */
     user_handle_t    last_active;     /* last active popup */
     rectangle_t      window_rect;     /* window rectangle */
@@ -260,6 +261,7 @@
     free_user_handle( win->handle );
     destroy_properties( win );
     unlink_window( win );
+    release_class( win->class );
     if (win->text) free( win->text );
     memset( win, 0x55, sizeof(*win) );
     free( win );
@@ -267,13 +269,23 @@
 
 /* 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,
-                                     int extra_bytes )
+                                     void *instance, int extra_bytes )
 {
-    struct window *win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
-    if (!win) return NULL;
+    struct window *win;
+    struct window_class *class = grab_class( current->process, atom, instance );
+
+    if (!class) return NULL;
+
+    win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
+    if (!win)
+    {
+        release_class( class );
+        return NULL;
+    }
 
     if (!(win->handle = alloc_user_handle( win, USER_WINDOW )))
     {
+        release_class( class );
         free( win );
         return NULL;
     }
@@ -283,6 +295,7 @@
     win->last_child     = NULL;
     win->first_unlinked = NULL;
     win->thread         = current;
+    win->class          = class;
     win->atom           = atom;
     win->last_active    = win->handle;
     win->style          = 0;
@@ -449,6 +462,15 @@
 }
 
 
+/* get the window class of a window */
+struct window_class* get_window_class( user_handle_t window )
+{
+    struct window *win;
+    if (!(win = get_window( window ))) return NULL;
+    return win->class;
+}
+
+
 /* create a window */
 DECL_HANDLER(create_window)
 {
@@ -462,7 +484,7 @@
     {
         if (!top_window)
         {
-            if (!(top_window = create_window( NULL, NULL, req->atom, req->extra ))) return;
+            if (!(top_window = create_window( NULL, NULL, req->atom, req->instance, req->extra ))) return;
             top_window->thread = NULL;  /* no thread owns the desktop */
             top_window->style  = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
         }
@@ -481,7 +503,7 @@
             set_error( STATUS_ACCESS_DENIED );
             return;
         }
-        if (!(win = create_window( parent, owner, req->atom, req->extra ))) return;
+        if (!(win = create_window( parent, owner, req->atom, req->instance, req->extra ))) return;
         reply->handle = win->handle;
     }
 }
@@ -569,7 +591,7 @@
         {
             reply->tid  = get_thread_id( win->thread );
             reply->pid  = get_process_id( win->thread->process );
-            reply->atom = win->atom;
+            reply->atom = get_class_atom( win->class );
         }
     }
 }
@@ -648,7 +670,7 @@
     if (parent)
         for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next)
         {
-            if (req->atom && ptr->atom != req->atom) continue;
+            if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
             total++;
         }
@@ -659,7 +681,7 @@
     {
         for (ptr = parent->first_child; ptr && len; ptr = ptr->next)
         {
-            if (req->atom && ptr->atom != req->atom) continue;
+            if (req->atom && get_class_atom(ptr->class) != req->atom) continue;
             if (req->tid && get_thread_id(ptr->thread) != req->tid) continue;
             *data++ = ptr->handle;
             len -= sizeof(*data);
diff --git a/windows/class.c b/windows/class.c
index 6c9c8ad..cd3261f 100644
--- a/windows/class.c
+++ b/windows/class.c
@@ -1,8 +1,8 @@
 /*
  * Window classes functions
  *
- * Copyright 1993, 1996 Alexandre Julliard
- *           1998 Juergen Schmied (jsch)
+ * Copyright 1993, 1996, 2003 Alexandre Julliard
+ * Copyright 1998 Juergen Schmied (jsch)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,18 +17,12 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * FIXME: In win32 all classes are local. They are registered at
- *	  program start. Processes CANNOT share classes. (Source: some
- *	  win31->NT migration book)
- *
- * FIXME: There seems to be a general problem with hInstance in WINE
- *   classes are getting registered with wrong hInstance.
  */
 
 #include "config.h"
 #include "wine/port.h"
 
+#include <assert.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -46,16 +40,17 @@
 #include "controls.h"
 #include "dce.h"
 #include "winproc.h"
+#include "wine/server.h"
+#include "wine/list.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(class);
 
 typedef struct tagCLASS
 {
-    struct tagCLASS *next;          /* Next class */
-    struct tagCLASS *prev;          /* Prev class */
-    UINT             cWindows;      /* Count of existing windows */
+    struct list      entry;         /* Entry in class list */
     UINT             style;         /* Class style */
+    BOOL             local;         /* Local class? */
     WNDPROC          winprocA;      /* Window procedure (ASCII) */
     WNDPROC          winprocW;      /* Window procedure (Unicode) */
     INT              cbClsExtra;    /* Class extra bytes */
@@ -71,7 +66,10 @@
     ATOM             atomName;      /* Name of the class */
 } CLASS;
 
-static CLASS *firstClass;
+static struct list class_list = LIST_INIT( class_list );
+static HMODULE user32_module;
+
+#define CLASS_OTHER_PROCESS ((CLASS *)1)
 
 /***********************************************************************
  *           get_class_ptr
@@ -83,17 +81,13 @@
     if (ptr)
     {
         if (ptr != WND_OTHER_PROCESS) return ptr->class;
-        if (IsWindow( hwnd )) /* check other processes */
+        if (write_access && IsWindow( hwnd )) /* check other processes */
         {
-            if (write_access)
-            {
-                /* modifying classes in other processes is not allowed */
-                SetLastError( ERROR_ACCESS_DENIED );
-                return NULL;
-            }
-            FIXME( "reading from class of other process window %p\n", hwnd );
-            /* DbgBreakPoint(); */
+            /* modifying classes in other processes is not allowed */
+            SetLastError( ERROR_ACCESS_DENIED );
+            return NULL;
         }
+        return CLASS_OTHER_PROCESS;
     }
     SetLastError( ERROR_INVALID_WINDOW_HANDLE );
     return NULL;
@@ -110,6 +104,51 @@
 
 
 /***********************************************************************
+ *           set_server_info
+ *
+ * Set class info with the wine server.
+ */
+static BOOL set_server_info( HWND hwnd, INT offset, LONG newval )
+{
+    BOOL ret;
+
+    SERVER_START_REQ( set_class_info )
+    {
+        req->window = hwnd;
+        req->extra_offset = -1;
+        switch(offset)
+        {
+        case GCW_ATOM:
+            req->flags = SET_CLASS_ATOM;
+            req->atom = newval;
+        case GCL_STYLE:
+            req->flags = SET_CLASS_STYLE;
+            req->style = newval;
+            break;
+        case GCL_CBWNDEXTRA:
+            req->flags = SET_CLASS_WINEXTRA;
+            req->win_extra = newval;
+            break;
+        case GCL_HMODULE:
+            req->flags = SET_CLASS_INSTANCE;
+            req->instance = (void *)newval;
+            break;
+        default:
+            assert( offset >= 0 );
+            req->flags = SET_CLASS_EXTRA;
+            req->extra_offset = offset;
+            req->extra_size = sizeof(newval);
+            memcpy( &req->extra_value, &newval, sizeof(newval) );
+            break;
+        }
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
  *           CLASS_GetProc
  *
  * Get the class winproc for a given proc type
@@ -256,34 +295,35 @@
  */
 static BOOL CLASS_FreeClass( CLASS *classPtr )
 {
+    BOOL ret;
+
     TRACE("%p\n", classPtr);
 
-    /* Check if we can remove this class */
-
-    if (classPtr->cWindows > 0)
+    SERVER_START_REQ( destroy_class )
     {
-        SetLastError( ERROR_CLASS_HAS_WINDOWS );
-        return FALSE;
+        req->atom = classPtr->atomName;
+        req->instance = classPtr->hInstance;
+        ret = !wine_server_call_err( req );
     }
+    SERVER_END_REQ;
 
-    /* Remove the class from the linked list */
+    if (ret)
+    {
+        list_remove( &classPtr->entry );
 
-    if (classPtr->next) classPtr->next->prev = classPtr->prev;
-    if (classPtr->prev) classPtr->prev->next = classPtr->next;
-    else firstClass = classPtr->next;
+        /* Delete the class */
 
-    /* Delete the class */
-
-    if (classPtr->dce) DCE_FreeDCE( classPtr->dce );
-    if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
-        DeleteObject( classPtr->hbrBackground );
-    GlobalDeleteAtom( classPtr->atomName );
-    WINPROC_FreeProc( classPtr->winprocA, WIN_PROC_CLASS );
-    WINPROC_FreeProc( classPtr->winprocW, WIN_PROC_CLASS );
-    UnMapLS( classPtr->segMenuName );
-    HeapFree( GetProcessHeap(), 0, classPtr->menuName );
-    HeapFree( GetProcessHeap(), 0, classPtr );
-    return TRUE;
+        if (classPtr->dce) DCE_FreeDCE( classPtr->dce );
+        if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
+            DeleteObject( classPtr->hbrBackground );
+        GlobalDeleteAtom( classPtr->atomName );
+        WINPROC_FreeProc( classPtr->winprocA, WIN_PROC_CLASS );
+        WINPROC_FreeProc( classPtr->winprocW, WIN_PROC_CLASS );
+        UnMapLS( classPtr->segMenuName );
+        HeapFree( GetProcessHeap(), 0, classPtr->menuName );
+        HeapFree( GetProcessHeap(), 0, classPtr );
+    }
+    return ret;
 }
 
 
@@ -292,15 +332,16 @@
  */
 void CLASS_FreeModuleClasses( HMODULE16 hModule )
 {
-    CLASS *ptr, *next;
+    struct list *ptr, *next;
 
     TRACE("0x%08x\n", hModule);
 
     USER_Lock();
-    for (ptr = firstClass; ptr; ptr = next)
+    for (ptr = list_head( &class_list ); ptr; ptr = next)
     {
-        next = ptr->next;
-	if (ptr->hInstance == HINSTANCE_32(hModule)) CLASS_FreeClass( ptr );
+        CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
+        next = list_next( &class_list, ptr );
+        if (class->hInstance == HINSTANCE_32(hModule)) CLASS_FreeClass( class );
     }
     USER_Unlock();
 }
@@ -311,69 +352,23 @@
  *
  * Return a pointer to the class.
  * hinstance has been normalized by the caller.
- *
- * NOTES
- *  980805 a local class will be found now if registred with hInst=0
- *  and looed up with a hInst!=0. msmoney does it (jsch)
- *
- *  Local class registered with a USER instance handle are found as if
- *  they were global classes.
  */
 static CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE hinstance )
 {
-    CLASS * class, *tclass = 0, *user_class = 0;
-    HINSTANCE16 hUser = GetModuleHandle16("USER");
+    struct list *ptr;
 
-    TRACE("0x%08x %p\n", atom, hinstance);
-
-    /* First search task-specific classes */
-
-    for (class = firstClass; (class); class = class->next)
+    LIST_FOR_EACH( ptr, &class_list )
     {
-        if (class->style & CS_GLOBALCLASS) continue;
-        if (class->atomName == atom)
+        CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
+        if (class->atomName != atom) continue;
+        if (!hinstance || !class->local || class->hInstance == hinstance)
         {
-            if (hinstance==class->hInstance || hinstance == (HINSTANCE)0xffff)
-            {
-                TRACE("-- found local %p\n", class);
-                return class;
-            }
-            if (class->hInstance == 0) tclass = class;
-            else if(class->hInstance == HINSTANCE_32(hUser))
-            {
-                user_class = class;
-            }
-        }
-    }
-
-    /* Then search global classes */
-
-    for (class = firstClass; (class); class = class->next)
-    {
-        if (!(class->style & CS_GLOBALCLASS)) continue;
-        if (class->atomName == atom)
-        {
-            TRACE("-- found global %p\n", class);
+            TRACE("0x%04x %p -> %p\n", atom, hinstance, class);
             return class;
         }
     }
-
-    /* Check if there was a local class registered with USER */
-    if( user_class )
-    {
-        TRACE("--found local USER class %p\n", user_class);
-        return user_class;
-    }
-
-    /* Then check if there was a local class with hInst=0*/
-    if ( tclass )
-    {
-        WARN("-- found local Class registred with hInst=0\n");
-        return tclass;
-    }
-
-    TRACE("-- not found\n");
-    return 0;
+    TRACE("0x%04x %p -> not found\n", atom, hinstance);
+    return NULL;
 }
 
 
@@ -382,28 +377,15 @@
  *
  * The real RegisterClass() functionality.
  */
-static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance,
+static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance, BOOL local,
                                    DWORD style, INT classExtra, INT winExtra )
 {
     CLASS *classPtr;
+    BOOL ret;
 
     TRACE("atom=0x%x hinst=%p style=0x%lx clExtr=0x%x winExtr=0x%x\n",
           atom, hInstance, style, classExtra, winExtra );
 
-   /* Check if a class with this name already exists */
-    classPtr = CLASS_FindClassByAtom( atom, hInstance );
-    if (classPtr)
-    {
-        /* Class can be created only if it is local and */
-        /* if the class with the same name is global.   */
-
-        if ((style & CS_GLOBALCLASS) || !(classPtr->style & CS_GLOBALCLASS))
-        {
-            SetLastError( ERROR_CLASS_ALREADY_EXISTS );
-            return NULL;
-        }
-    }
-
     /* Fix the extra bytes value */
 
     if (classExtra < 0) classExtra = 0;
@@ -413,11 +395,28 @@
     else if (winExtra > 40)    /* Extra bytes are limited to 40 in Win32 */
         WARN("Win extra bytes %d is > 40\n", winExtra );
 
-    /* Create the class */
-
     classPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLASS) + classExtra );
     if (!classPtr) return NULL;
+
+    SERVER_START_REQ( create_class )
+    {
+        req->local     = local;
+        req->atom      = atom;
+        req->style     = style;
+        req->instance  = hInstance;
+        req->extra     = classExtra;
+        req->win_extra = winExtra;
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    if (!ret)
+    {
+        HeapFree( GetProcessHeap(), 0, classPtr );
+        return NULL;
+    }
+
     classPtr->style       = style;
+    classPtr->local       = local;
     classPtr->cbWndExtra  = winExtra;
     classPtr->cbClsExtra  = classExtra;
     classPtr->hInstance   = hInstance;
@@ -426,50 +425,27 @@
 
     /* Other non-null values must be set by caller */
 
-    if ((classPtr->next = firstClass)) firstClass->prev = classPtr;
-    firstClass = classPtr;
+    if (local) list_add_head( &class_list, &classPtr->entry );
+    else list_add_tail( &class_list, &classPtr->entry );
     return classPtr;
 }
 
 
 /***********************************************************************
- *           CLASS_UnregisterClass
- *
- * The real UnregisterClass() functionality.
- */
-static BOOL CLASS_UnregisterClass( ATOM atom, HINSTANCE hInstance )
-{
-    CLASS *classPtr;
-    BOOL ret = FALSE;
-
-    USER_Lock();
-    if (atom &&
-        (classPtr = CLASS_FindClassByAtom( atom, hInstance )) &&
-        (!hInstance || classPtr->hInstance == hInstance))
-    {
-        ret = CLASS_FreeClass( classPtr );
-    }
-    else SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
-
-    USER_Unlock();
-    return ret;
-}
-
-
-/***********************************************************************
- *           CLASS_RegisterBuiltinClass
+ *           register_builtin
  *
  * Register a builtin control class.
  * This allows having both ASCII and Unicode winprocs for the same class.
  */
-ATOM CLASS_RegisterBuiltinClass( const struct builtin_class_descr *descr )
+static ATOM register_builtin( const struct builtin_class_descr *descr )
 {
     ATOM atom;
     CLASS *classPtr;
 
     if (!(atom = GlobalAddAtomA( descr->name ))) return 0;
 
-    if (!(classPtr = CLASS_RegisterClass( atom, 0, descr->style, 0, descr->extra )))
+    if (!(classPtr = CLASS_RegisterClass( atom, user32_module, FALSE,
+                                          descr->style, 0, descr->extra )))
     {
         GlobalDeleteAtom( atom );
         return 0;
@@ -487,6 +463,40 @@
 
 
 /***********************************************************************
+ *           CLASS_RegisterBuiltinClasses
+ */
+void CLASS_RegisterBuiltinClasses( HMODULE user32 )
+{
+    extern const struct builtin_class_descr BUTTON_builtin_class;
+    extern const struct builtin_class_descr COMBO_builtin_class;
+    extern const struct builtin_class_descr COMBOLBOX_builtin_class;
+    extern const struct builtin_class_descr DIALOG_builtin_class;
+    extern const struct builtin_class_descr DESKTOP_builtin_class;
+    extern const struct builtin_class_descr EDIT_builtin_class;
+    extern const struct builtin_class_descr ICONTITLE_builtin_class;
+    extern const struct builtin_class_descr LISTBOX_builtin_class;
+    extern const struct builtin_class_descr MDICLIENT_builtin_class;
+    extern const struct builtin_class_descr MENU_builtin_class;
+    extern const struct builtin_class_descr SCROLL_builtin_class;
+    extern const struct builtin_class_descr STATIC_builtin_class;
+
+    user32_module = user32;
+    register_builtin( &BUTTON_builtin_class );
+    register_builtin( &COMBO_builtin_class );
+    register_builtin( &COMBOLBOX_builtin_class );
+    register_builtin( &DIALOG_builtin_class );
+    register_builtin( &DESKTOP_builtin_class );
+    register_builtin( &EDIT_builtin_class );
+    register_builtin( &ICONTITLE_builtin_class );
+    register_builtin( &LISTBOX_builtin_class );
+    register_builtin( &MDICLIENT_builtin_class );
+    register_builtin( &MENU_builtin_class );
+    register_builtin( &SCROLL_builtin_class );
+    register_builtin( &STATIC_builtin_class );
+}
+
+
+/***********************************************************************
  *           CLASS_AddWindow
  *
  * Add a new window using this class, and return the necessary
@@ -499,7 +509,6 @@
     if (type == WIN_PROC_16) inst = HINSTANCE_32(GetExePtr(HINSTANCE_16(inst)));
 
     if (!(class = CLASS_FindClassByAtom( atom, inst ))) return NULL;
-    class->cWindows++;
 
     if (type == WIN_PROC_32W)
     {
@@ -517,17 +526,6 @@
 
 
 /***********************************************************************
- *           CLASS_RemoveWindow
- *
- * Remove a window from the class window count.
- */
-void CLASS_RemoveWindow( CLASS *cls )
-{
-    if (cls && cls->cWindows) cls->cWindows--;
-}
-
-
-/***********************************************************************
  *		RegisterClass (USER.57)
  */
 ATOM WINAPI RegisterClass16( const WNDCLASS16 *wc )
@@ -606,11 +604,14 @@
 {
     ATOM atom;
     CLASS *classPtr;
-    HINSTANCE hInstance = HINSTANCE_32(GetExePtr( wc->hInstance ));
+    HINSTANCE hInstance;
+
+    if (!(hInstance = HINSTANCE_32(GetExePtr(wc->hInstance))))
+        hInstance = HINSTANCE_32(GetModuleHandle16(NULL));
 
     if (!(atom = GlobalAddAtomA( MapSL(wc->lpszClassName) ))) return 0;
-    if (!(classPtr = CLASS_RegisterClass( atom, hInstance, wc->style,
-                                          wc->cbClsExtra, wc->cbWndExtra )))
+    if (!(classPtr = CLASS_RegisterClass( atom, hInstance, !(wc->style & CS_GLOBALCLASS),
+                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
     {
         GlobalDeleteAtom( atom );
         return 0;
@@ -640,20 +641,28 @@
 {
     ATOM atom;
     CLASS *classPtr;
+    HINSTANCE instance;
+
+    if (wc->hInstance == user32_module)
+    {
+        /* we can't register a class for user32 */
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return 0;
+    }
+    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
 
     if (!(atom = GlobalAddAtomA( wc->lpszClassName ))) return 0;
 
-    if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
-                                          wc->cbClsExtra, wc->cbWndExtra )))
+    if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
+                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
     {
         GlobalDeleteAtom( atom );
         return 0;
     }
 
     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
-          atom, wc->lpfnWndProc, wc->hInstance,
-          wc->hbrBackground, wc->style, wc->cbClsExtra,
-          wc->cbWndExtra, classPtr );
+          atom, wc->lpfnWndProc, instance, wc->hbrBackground,
+          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
 
     classPtr->hIcon         = wc->hIcon;
     classPtr->hIconSm       = wc->hIconSm;
@@ -672,20 +681,28 @@
 {
     ATOM atom;
     CLASS *classPtr;
+    HINSTANCE instance;
+
+    if (wc->hInstance == user32_module)
+    {
+        /* we can't register a class for user32 */
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return 0;
+    }
+    if (!(instance = wc->hInstance)) instance = GetModuleHandleW( NULL );
 
     if (!(atom = GlobalAddAtomW( wc->lpszClassName ))) return 0;
 
-    if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
-                                          wc->cbClsExtra, wc->cbWndExtra )))
+    if (!(classPtr = CLASS_RegisterClass( atom, instance, !(wc->style & CS_GLOBALCLASS),
+                                          wc->style, wc->cbClsExtra, wc->cbWndExtra )))
     {
         GlobalDeleteAtom( atom );
         return 0;
     }
 
     TRACE("atom=%04x wndproc=%p hinst=%p bg=%p style=%08x clsExt=%d winExt=%d class=%p\n",
-          atom, wc->lpfnWndProc, wc->hInstance,
-          wc->hbrBackground, wc->style, wc->cbClsExtra,
-          wc->cbWndExtra, classPtr );
+          atom, wc->lpfnWndProc, instance, wc->hbrBackground,
+          wc->style, wc->cbClsExtra, wc->cbWndExtra, classPtr );
 
     classPtr->hIcon         = wc->hIcon;
     classPtr->hIconSm       = wc->hIconSm;
@@ -702,17 +719,17 @@
  */
 BOOL16 WINAPI UnregisterClass16( LPCSTR className, HINSTANCE16 hInstance )
 {
+    if (hInstance == GetModuleHandle16("user")) hInstance = 0;
     return UnregisterClassA( className, HINSTANCE_32(GetExePtr( hInstance )) );
 }
 
 /***********************************************************************
  *		UnregisterClassA (USER32.@)
- *
  */
 BOOL WINAPI UnregisterClassA( LPCSTR className, HINSTANCE hInstance )
 {
-    TRACE("%s %p\n",debugstr_a(className), hInstance);
-    return CLASS_UnregisterClass( GlobalFindAtomA( className ), hInstance );
+    ATOM atom = HIWORD(className) ? GlobalFindAtomA( className ) : LOWORD(className);
+    return UnregisterClassW( MAKEINTATOMW(atom), hInstance );
 }
 
 /***********************************************************************
@@ -720,8 +737,22 @@
  */
 BOOL WINAPI UnregisterClassW( LPCWSTR className, HINSTANCE hInstance )
 {
-    TRACE("%s %p\n",debugstr_w(className), hInstance);
-    return CLASS_UnregisterClass( GlobalFindAtomW( className ), hInstance );
+    CLASS *classPtr;
+    BOOL ret = FALSE;
+    ATOM atom = HIWORD(className) ? GlobalFindAtomW( className ) : LOWORD(className);
+
+    TRACE("%s %p %x\n",debugstr_w(className), hInstance, atom);
+
+    if (!hInstance) hInstance = GetModuleHandleW( NULL );
+
+    USER_Lock();
+    if (atom && (classPtr = CLASS_FindClassByAtom( atom, hInstance )))
+    {
+        ret = CLASS_FreeClass( classPtr );
+    }
+    else SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
+    USER_Unlock();
+    return ret;
 }
 
 
@@ -739,6 +770,21 @@
 
     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
 
+    if (class == CLASS_OTHER_PROCESS)
+    {
+        SERVER_START_REQ( set_class_info )
+        {
+            req->window = hwnd;
+            req->flags = 0;
+            req->extra_offset = offset;
+            req->extra_size = sizeof(retvalue);
+            if (!wine_server_call_err( req ))
+                memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
+        }
+        SERVER_END_REQ;
+        return retvalue;
+    }
+
     if (offset <= class->cbClsExtra - sizeof(WORD))
         memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(retvalue) );
     else
@@ -763,17 +809,22 @@
     {
     case GCL_WNDPROC:
         if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
+        if (class == CLASS_OTHER_PROCESS) break;
         ret = (LONG)CLASS_GetProc( class, WIN_PROC_16 );
         release_class_ptr( class );
         return ret;
     case GCL_MENUNAME:
         if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
+        if (class == CLASS_OTHER_PROCESS) break;
         ret = (LONG)CLASS_GetMenuName16( class );
         release_class_ptr( class );
         return ret;
     default:
         return GetClassLongA( hwnd, offset );
     }
+    FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
+    SetLastError( ERROR_INVALID_HANDLE );
+    return 0;
 }
 
 
@@ -789,6 +840,53 @@
 
     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
 
+    if (class == CLASS_OTHER_PROCESS)
+    {
+        SERVER_START_REQ( set_class_info )
+        {
+            req->window = hwnd;
+            req->flags = 0;
+            req->extra_offset = (offset >= 0) ? offset : -1;
+            req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
+            if (!wine_server_call_err( req ))
+            {
+                switch(offset)
+                {
+                case GCL_HBRBACKGROUND:
+                case GCL_HCURSOR:
+                case GCL_HICON:
+                case GCL_HICONSM:
+                case GCL_WNDPROC:
+                case GCL_MENUNAME:
+                    FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
+                    SetLastError( ERROR_INVALID_HANDLE );
+                    break;
+                case GCL_STYLE:
+                    retvalue = reply->old_style;
+                    break;
+                case GCL_CBWNDEXTRA:
+                    retvalue = reply->old_win_extra;
+                    break;
+                case GCL_CBCLSEXTRA:
+                    retvalue = reply->old_extra;
+                    break;
+                case GCL_HMODULE:
+                    retvalue = (LONG)reply->old_instance;
+                    break;
+                case GCW_ATOM:
+                    retvalue = reply->old_atom;
+                    break;
+                default:
+                    if (offset >= 0) memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
+                    else SetLastError( ERROR_INVALID_INDEX );
+                    break;
+                }
+            }
+        }
+        SERVER_END_REQ;
+        return retvalue;
+    }
+
     if (offset >= 0)
     {
         if (offset <= class->cbClsExtra - sizeof(LONG))
@@ -858,6 +956,13 @@
 
     if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
 
+    if (class == CLASS_OTHER_PROCESS)
+    {
+        FIXME( "offset %d not supported on other process window %p\n", offset, hwnd );
+        SetLastError( ERROR_INVALID_HANDLE );
+        return 0;
+    }
+
     if (offset == GCL_WNDPROC)
         retvalue = (LONG)CLASS_GetProc( class, WIN_PROC_32A );
     else  /* GCL_MENUNAME */
@@ -882,14 +987,21 @@
 
     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
 
-    if (offset <= class->cbClsExtra - sizeof(WORD))
+    SERVER_START_REQ( set_class_info )
     {
-        void *ptr = (char *)(class + 1) + offset;
-        memcpy( &retval, ptr, sizeof(retval) );
-        memcpy( ptr, &newval, sizeof(newval) );
+        req->window = hwnd;
+        req->flags = SET_CLASS_EXTRA;
+        req->extra_offset = offset;
+        req->extra_size = sizeof(newval);
+        memcpy( &req->extra_value, &newval, sizeof(newval) );
+        if (!wine_server_call_err( req ))
+        {
+            void *ptr = (char *)(class + 1) + offset;
+            memcpy( &retval, ptr, sizeof(retval) );
+            memcpy( ptr, &newval, sizeof(newval) );
+        }
     }
-    else SetLastError( ERROR_INVALID_INDEX );
-
+    SERVER_END_REQ;
     release_class_ptr( class );
     return retval;
 }
@@ -936,13 +1048,12 @@
 
     if (offset >= 0)
     {
-        if (offset <= class->cbClsExtra - sizeof(LONG))
+        if (set_server_info( hwnd, offset, newval ))
         {
             void *ptr = (char *)(class + 1) + offset;
             memcpy( &retval, ptr, sizeof(retval) );
             memcpy( ptr, &newval, sizeof(newval) );
         }
-        else SetLastError( ERROR_INVALID_INDEX );
     }
     else switch(offset)
     {
@@ -970,18 +1081,22 @@
         class->hIconSm = (HICON)newval;
         break;
     case GCL_STYLE:
+        if (!set_server_info( hwnd, offset, newval )) break;
         retval = (LONG)class->style;
         class->style = newval;
         break;
     case GCL_CBWNDEXTRA:
+        if (!set_server_info( hwnd, offset, newval )) break;
         retval = (LONG)class->cbWndExtra;
         class->cbWndExtra = newval;
         break;
     case GCL_HMODULE:
+        if (!set_server_info( hwnd, offset, newval )) break;
         retval = (LONG)class->hInstance;
         class->hInstance = (HINSTANCE)newval;
         break;
     case GCW_ATOM:
+        if (!set_server_info( hwnd, offset, newval )) break;
         retval = (DWORD)class->atomName;
         class->atomName = newval;
         break;
@@ -1149,20 +1264,21 @@
  */
 BOOL16 WINAPI GetClassInfoEx16( HINSTANCE16 hInst16, SEGPTR name, WNDCLASSEX16 *wc )
 {
-    ATOM atom;
+    ATOM atom = HIWORD(name) ? GlobalFindAtomA( MapSL(name) ) : LOWORD(name);
     CLASS *classPtr;
-    HINSTANCE hInstance = HINSTANCE_32(GetExePtr( hInst16 ));
+    HINSTANCE hInstance;
 
-    TRACE("%p %s %p\n",hInstance,debugstr_a( MapSL(name) ), wc);
+    if (hInst16 == GetModuleHandle16("user")) hInstance = user32_module;
+    else hInstance = HINSTANCE_32(GetExePtr( hInst16 ));
 
-    if (!(atom = GlobalFindAtomA( MapSL(name) )) ||
-        !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
-        (hInstance != classPtr->hInstance)) return FALSE;
+    TRACE("%p %s %x %p\n", hInstance, debugstr_a( MapSL(name) ), atom, wc);
+
+    if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance ))) return FALSE;
     wc->style         = classPtr->style;
     wc->lpfnWndProc   = CLASS_GetProc( classPtr, WIN_PROC_16 );
     wc->cbClsExtra    = (INT16)classPtr->cbClsExtra;
     wc->cbWndExtra    = (INT16)classPtr->cbWndExtra;
-    wc->hInstance     = HINSTANCE_16(classPtr->hInstance);
+    wc->hInstance     = (classPtr->hInstance == user32_module) ? GetModuleHandle16("user") : HINSTANCE_16(classPtr->hInstance);
     wc->hIcon         = HICON_16(classPtr->hIcon);
     wc->hIconSm       = HICON_16(classPtr->hIconSm);
     wc->hCursor       = HCURSOR_16(classPtr->hCursor);
@@ -1179,22 +1295,25 @@
 /***********************************************************************
  *		GetClassInfoExA (USER32.@)
  */
-BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name,
-                                 WNDCLASSEXA *wc )
+BOOL WINAPI GetClassInfoExA( HINSTANCE hInstance, LPCSTR name, WNDCLASSEXA *wc )
 {
-    ATOM atom;
+    ATOM atom = HIWORD(name) ? GlobalFindAtomA( name ) : LOWORD(name);
     CLASS *classPtr;
 
-    TRACE("%p %p %p\n",hInstance, name, wc);
+    TRACE("%p %s %x %p\n", hInstance, debugstr_a(name), atom, wc);
 
-    if (!(atom = GlobalFindAtomA( name )) ||
-        !(classPtr = CLASS_FindClassByAtom( atom, hInstance ))
-	/*|| (hInstance != classPtr->hInstance) */ ) return FALSE;
+    if (!hInstance) hInstance = user32_module;
+
+    if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
+    {
+        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
+        return FALSE;
+    }
     wc->style         = classPtr->style;
     wc->lpfnWndProc   = (WNDPROC)CLASS_GetProc( classPtr, WIN_PROC_32A );
     wc->cbClsExtra    = classPtr->cbClsExtra;
     wc->cbWndExtra    = classPtr->cbWndExtra;
-    wc->hInstance     = classPtr->hInstance;
+    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
     wc->hIcon         = (HICON)classPtr->hIcon;
     wc->hIconSm       = (HICON)classPtr->hIconSm;
     wc->hCursor       = (HCURSOR)classPtr->hCursor;
@@ -1210,22 +1329,25 @@
 /***********************************************************************
  *		GetClassInfoExW (USER32.@)
  */
-BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name,
-                                 WNDCLASSEXW *wc )
+BOOL WINAPI GetClassInfoExW( HINSTANCE hInstance, LPCWSTR name, WNDCLASSEXW *wc )
 {
-    ATOM atom;
+    ATOM atom = HIWORD(name) ? GlobalFindAtomW( name ) : LOWORD(name);
     CLASS *classPtr;
 
-    TRACE("%p %p %p\n",hInstance, name, wc);
+    TRACE("%p %s %x %p\n", hInstance, debugstr_w(name), atom, wc);
 
-    if (!(atom = GlobalFindAtomW( name )) ||
-        !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
-        (hInstance != classPtr->hInstance)) return FALSE;
+    if (!hInstance) hInstance = user32_module;
+
+    if (!atom || !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
+    {
+        SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
+        return FALSE;
+    }
     wc->style         = classPtr->style;
     wc->lpfnWndProc   = (WNDPROC)CLASS_GetProc( classPtr, WIN_PROC_32W );
     wc->cbClsExtra    = classPtr->cbClsExtra;
     wc->cbWndExtra    = classPtr->cbWndExtra;
-    wc->hInstance     = classPtr->hInstance;
+    wc->hInstance     = (hInstance == user32_module) ? 0 : hInstance;
     wc->hIcon         = (HICON)classPtr->hIcon;
     wc->hIconSm       = (HICON)classPtr->hIconSm;
     wc->hCursor       = (HCURSOR)classPtr->hCursor;
diff --git a/windows/win.c b/windows/win.c
index 0c41bda..ce3074d 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -62,23 +62,34 @@
  *
  * Create a window handle with the server.
  */
-static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, unsigned int extra_bytes )
+static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
+                                  HINSTANCE instance, WINDOWPROCTYPE type )
 {
     BOOL res;
-    user_handle_t handle = 0;
     WORD index;
-    WND *win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) );
+    WND *win;
+    DCE *dce;
+    INT extra_bytes;
+    DWORD clsStyle;
+    WNDPROC winproc;
+    struct tagCLASS *class;
+    user_handle_t handle = 0;
 
-    if (!win) return NULL;
+    if (!(class = CLASS_AddWindow( atom, instance, type, &extra_bytes, &winproc, &clsStyle, &dce )))
+        return NULL;
+
+    if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
+        return NULL;
 
     USER_Lock();
 
     SERVER_START_REQ( create_window )
     {
-        req->parent = parent;
-        req->owner  = owner;
-        req->atom   = atom;
-        req->extra  = extra_bytes;
+        req->parent   = parent;
+        req->owner    = owner;
+        req->atom     = atom;
+        req->instance = instance;
+        req->extra    = extra_bytes;
         if ((res = !wine_server_call_err( req ))) handle = reply->handle;
     }
     SERVER_END_REQ;
@@ -92,9 +103,15 @@
     index = LOWORD(handle) - FIRST_USER_HANDLE;
     assert( index < NB_USER_HANDLES );
     user_handles[index] = win;
-    win->hwndSelf = handle;
-    win->dwMagic = WND_MAGIC;
-    win->irefCount = 1;
+    win->hwndSelf   = handle;
+    win->dwMagic    = WND_MAGIC;
+    win->irefCount  = 1;
+    win->class      = class;
+    win->winproc    = winproc;
+    win->dce        = dce;
+    win->clsStyle   = clsStyle;
+    win->cbWndExtra = extra_bytes;
+    memset( win->wExtra, 0, extra_bytes );
     return win;
 }
 
@@ -669,7 +686,6 @@
     DCE_FreeWindowDCE( hwnd );    /* Always do this to catch orphaned DCs */
     USER_Driver.pDestroyWindow( hwnd );
     WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
-    CLASS_RemoveWindow( wndPtr->class );
     wndPtr->class = NULL;
     wndPtr->dwMagic = 0;  /* Mark it as invalid */
     WIN_ReleaseWndPtr( wndPtr );
@@ -705,41 +721,28 @@
  */
 BOOL WIN_CreateDesktopWindow(void)
 {
-    struct tagCLASS *class;
     HWND hwndDesktop;
-    INT wndExtra;
-    DWORD clsStyle;
-    WNDPROC winproc;
-    DCE *dce;
     CREATESTRUCTA cs;
     RECT rect;
 
     TRACE("Creating desktop window\n");
 
-    if (!WINPOS_CreateInternalPosAtom() ||
-        !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
-                                   &wndExtra, &winproc, &clsStyle, &dce )))
-        return FALSE;
+    if (!WINPOS_CreateInternalPosAtom()) return FALSE;
 
-    pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), wndExtra );
+    pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
     if (!pWndDesktop) return FALSE;
     hwndDesktop = pWndDesktop->hwndSelf;
 
     pWndDesktop->tid               = 0;  /* nobody owns the desktop */
     pWndDesktop->parent            = 0;
     pWndDesktop->owner             = 0;
-    pWndDesktop->class             = class;
     pWndDesktop->text              = NULL;
     pWndDesktop->hrgnUpdate        = 0;
-    pWndDesktop->clsStyle          = clsStyle;
-    pWndDesktop->dce               = NULL;
     pWndDesktop->pVScroll          = NULL;
     pWndDesktop->pHScroll          = NULL;
     pWndDesktop->helpContext       = 0;
     pWndDesktop->flags             = 0;
     pWndDesktop->hSysMenu          = 0;
-    pWndDesktop->winproc           = winproc;
-    pWndDesktop->cbWndExtra        = wndExtra;
 
     cs.lpCreateParams = NULL;
     cs.hInstance      = 0;
@@ -970,13 +973,8 @@
 				WINDOWPROCTYPE type )
 {
     INT sw = SW_SHOW;
-    struct tagCLASS *classPtr;
     WND *wndPtr;
     HWND hwnd, parent, owner;
-    INT wndExtra;
-    DWORD clsStyle;
-    WNDPROC winproc;
-    DCE *dce;
     BOOL unicode = (type == WIN_PROC_32W);
 
     TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
@@ -1021,14 +1019,6 @@
         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
     }
 
-    /* Find the window class */
-    if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
-                                      &wndExtra, &winproc, &clsStyle, &dce )))
-    {
-        WARN("Bad class '%s'\n", cs->lpszClass );
-        return 0;
-    }
-
     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
 
     /* Correct the window style - stage 1
@@ -1052,7 +1042,7 @@
 
     /* Create the window structure */
 
-    if (!(wndPtr = create_window_handle( parent, owner, classAtom, wndExtra )))
+    if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
     {
 	TRACE("out of memory\n" );
 	return 0;
@@ -1064,15 +1054,12 @@
     wndPtr->tid            = GetCurrentThreadId();
     wndPtr->owner          = owner;
     wndPtr->parent         = parent;
-    wndPtr->class          = classPtr;
-    wndPtr->winproc        = winproc;
     wndPtr->hInstance      = cs->hInstance;
     wndPtr->text           = NULL;
     wndPtr->hrgnUpdate     = 0;
     wndPtr->hrgnWnd        = 0;
     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
     wndPtr->dwExStyle      = cs->dwExStyle;
-    wndPtr->clsStyle       = clsStyle;
     wndPtr->wIDmenu        = 0;
     wndPtr->helpContext    = 0;
     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
@@ -1080,9 +1067,6 @@
     wndPtr->pHScroll       = NULL;
     wndPtr->userdata       = 0;
     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
-    wndPtr->cbWndExtra     = wndExtra;
-
-    if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
 
     /* Correct the window style - stage 2 */
 
@@ -1109,9 +1093,7 @@
 
     /* Get class or window DC if needed */
 
-    if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
-    else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
-    else wndPtr->dce = NULL;
+    if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
 
     /* Set the window menu */
 
@@ -1248,9 +1230,6 @@
     CREATESTRUCTA cs;
     char buffer[256];
 
-    if(!instance)
-        instance=GetModuleHandleA(NULL);
-
     if(exStyle & WS_EX_MDICHILD)
         return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
 
@@ -1307,9 +1286,6 @@
     CREATESTRUCTW cs;
     WCHAR buffer[256];
 
-    if(!instance)
-        instance=GetModuleHandleW(NULL);
-
     if(exStyle & WS_EX_MDICHILD)
         return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);