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 );
}