diff --git a/dlls/ttydrv/wnd.c b/dlls/ttydrv/wnd.c index ab9b37b81e3..13a01e9cfdc 100644 --- a/dlls/ttydrv/wnd.c +++ b/dlls/ttydrv/wnd.c @@ -555,8 +555,8 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos ) if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter) { - if ( WIN_UnlinkWindow( winpos->hwnd ) ) - WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter ); + HWND parent = GetAncestor( winpos->hwnd, GA_PARENT ); + if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter ); } /* FIXME: actually do something with WVR_VALIDRECTS */ diff --git a/dlls/x11drv/desktop.c b/dlls/x11drv/desktop.c index aaa0f7b22a9..b78da814835 100644 --- a/dlls/x11drv/desktop.c +++ b/dlls/x11drv/desktop.c @@ -55,6 +55,7 @@ static DWORD CALLBACK desktop_thread( LPVOID driver_data ) /* patch the desktop window queue to point to our queue */ win = WIN_FindWndPtr( hwnd ); + win->tid = GetCurrentThreadId(); win->hmemTaskQ = InitThreadInput16( 0, 0 ); X11DRV_register_window( display, hwnd, win->pDriverData ); WIN_ReleaseWndPtr( win ); diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index 1bb66ab2e4c..22e19fba906 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -863,9 +863,9 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode ) (unsigned int)data->whole_window, (unsigned int)data->client_window ); if ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) - WIN_LinkWindow( hwnd, HWND_BOTTOM ); + WIN_LinkWindow( hwnd, wndPtr->parent->hwndSelf, HWND_BOTTOM ); else - WIN_LinkWindow( hwnd, HWND_TOP ); + WIN_LinkWindow( hwnd, wndPtr->parent->hwndSelf, HWND_TOP ); WIN_ReleaseWndPtr( wndPtr ); @@ -997,9 +997,7 @@ HWND X11DRV_SetParent( HWND hwnd, HWND parent ) { struct x11drv_win_data *data = wndPtr->pDriverData; - WIN_UnlinkWindow(wndPtr->hwndSelf); - wndPtr->parent = pWndParent; - WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP); + WIN_LinkWindow( hwnd, parent, HWND_TOP ); if (parent != GetDesktopWindow()) /* a child window */ { diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 0bfbe3f2294..49885f087a4 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -722,8 +722,8 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos ) if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter) { - if ( WIN_UnlinkWindow( winpos->hwnd ) ) - WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter ); + HWND parent = GetAncestor( winpos->hwnd, GA_PARENT ); + if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter ); } /* Reset active DCEs */ diff --git a/include/win.h b/include/win.h index 63fe1ba0494..974ce0cbc65 100644 --- a/include/win.h +++ b/include/win.h @@ -29,6 +29,7 @@ typedef struct tagWND struct tagCLASS *class; /* Window class */ HWINDOWPROC winproc; /* Window procedure */ DWORD dwMagic; /* Magic number (must be WND_MAGIC) */ + DWORD tid; /* Owner thread id */ HWND hwndSelf; /* Handle of this window */ HINSTANCE hInstance; /* Window hInstance (from CreateWindow) */ RECT rectClient; /* Client area rel. to parent client area */ @@ -86,8 +87,8 @@ extern void WIN_ReleaseWndPtr(WND *wndPtr); extern void WIN_UpdateWndPtr(WND **oldPtr,WND *newPtr); extern void WIN_DumpWindow( HWND hwnd ); extern void WIN_WalkWindows( HWND hwnd, int indent ); -extern BOOL WIN_UnlinkWindow( HWND hwnd ); -extern BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter ); +extern void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter ); +extern void WIN_UnlinkWindow( HWND hwnd ); extern HWND WIN_FindWinToRepaint( HWND hwnd ); extern void WIN_DestroyThreadWindows( HWND hwnd ); extern BOOL WIN_CreateDesktopWindow(void); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2065d1dd18f..ebf2d3fd583 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -38,6 +38,7 @@ struct request_max_size #define REQUEST_MAX_VAR_SIZE 1024 typedef int handle_t; +typedef unsigned int user_handle_t; struct debug_event_exception @@ -1340,7 +1341,7 @@ struct send_message_request struct request_header __header; void* id; int type; - handle_t win; + user_handle_t win; unsigned int msg; unsigned int wparam; unsigned int lparam; @@ -1370,11 +1371,11 @@ struct get_message_request { struct request_header __header; int flags; - handle_t get_win; + user_handle_t get_win; unsigned int get_first; unsigned int get_last; int type; - handle_t win; + user_handle_t win; unsigned int msg; unsigned int wparam; unsigned int lparam; @@ -1412,7 +1413,7 @@ struct get_message_reply_request struct cleanup_window_queue_request { struct request_header __header; - handle_t win; + user_handle_t win; }; @@ -1420,7 +1421,7 @@ struct cleanup_window_queue_request struct set_win_timer_request { struct request_header __header; - handle_t win; + user_handle_t win; unsigned int msg; unsigned int id; unsigned int rate; @@ -1432,7 +1433,7 @@ struct set_win_timer_request struct kill_win_timer_request { struct request_header __header; - handle_t win; + user_handle_t win; unsigned int msg; unsigned int id; }; @@ -1549,6 +1550,7 @@ struct disconnect_named_pipe_request handle_t handle; }; + struct get_named_pipe_info_request { struct request_header __header; @@ -1561,6 +1563,50 @@ struct get_named_pipe_info_request +struct create_desktop_window_request +{ + struct request_header __header; + user_handle_t handle; +}; + + + +struct create_window_request +{ + struct request_header __header; + user_handle_t handle; +}; + + + +struct link_window_request +{ + struct request_header __header; + user_handle_t handle; + user_handle_t parent; + user_handle_t previous; +}; + + + +struct destroy_window_request +{ + struct request_header __header; + user_handle_t handle; +}; + + + +struct get_window_info_request +{ + struct request_header __header; + user_handle_t handle; + user_handle_t full_handle; + void* pid; + void* tid; +}; + + enum request { REQ_new_process, @@ -1686,6 +1732,11 @@ enum request REQ_wait_named_pipe, REQ_disconnect_named_pipe, REQ_get_named_pipe_info, + REQ_create_desktop_window, + REQ_create_window, + REQ_link_window, + REQ_destroy_window, + REQ_get_window_info, REQ_NB_REQUESTS }; @@ -1816,8 +1867,13 @@ union generic_request struct wait_named_pipe_request wait_named_pipe; struct disconnect_named_pipe_request disconnect_named_pipe; struct get_named_pipe_info_request get_named_pipe_info; + struct create_desktop_window_request create_desktop_window; + struct create_window_request create_window; + struct link_window_request link_window; + struct destroy_window_request destroy_window; + struct get_window_info_request get_window_info; }; -#define SERVER_PROTOCOL_VERSION 51 +#define SERVER_PROTOCOL_VERSION 52 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/Makefile.in b/server/Makefile.in index b03708b1249..1bcfaaa3752 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -36,7 +36,9 @@ C_SRCS = \ thread.c \ timer.c \ trace.c \ - unicode.c + unicode.c \ + user.c \ + window.c PROGRAMS = wineserver diff --git a/server/protocol.def b/server/protocol.def index d6c6cd33514..c386dd93b0f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -40,6 +40,7 @@ struct request_max_size #define REQUEST_MAX_VAR_SIZE 1024 typedef int handle_t; +typedef unsigned int user_handle_t; /* definitions of the event data depending on the event code */ struct debug_event_exception @@ -1197,7 +1198,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; @REQ(send_message) void* id; /* thread id */ int type; /* message type (see below) */ - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ @@ -1225,12 +1226,12 @@ enum message_type /* Get a message from the current queue */ @REQ(get_message) int flags; /* see below */ - handle_t get_win; /* window handle to get */ + user_handle_t get_win; /* window handle to get */ unsigned int get_first; /* first message code to get */ unsigned int get_last; /* last message code to get */ @REPLY int type; /* message type */ - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ @@ -1263,13 +1264,13 @@ enum message_type /* Cleanup a queue when a window is deleted */ @REQ(cleanup_window_queue) - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ @END /* Set a window timer */ @REQ(set_win_timer) - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message to post */ unsigned int id; /* timer id */ unsigned int rate; /* timer rate in ms */ @@ -1279,7 +1280,7 @@ enum message_type /* Kill a window timer */ @REQ(kill_win_timer) - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message to post */ unsigned int id; /* timer id */ @END @@ -1383,6 +1384,7 @@ enum message_type handle_t handle; @END + @REQ(get_named_pipe_info) handle_t handle; @REPLY @@ -1392,3 +1394,41 @@ enum message_type unsigned int insize; @END + +/* Create the desktop window */ +@REQ(create_desktop_window) +@REPLY + user_handle_t handle; /* handle to the window */ +@END + + +/* Create a window */ +@REQ(create_window) +@REPLY + user_handle_t handle; /* handle to the window */ +@END + + +/* Link a window into the tree */ +@REQ(link_window) + user_handle_t handle; /* handle to the window */ + user_handle_t parent; /* handle to the parent */ + user_handle_t previous; /* previous child in Z-order */ +@REPLY +@END + + +/* Destroy a window */ +@REQ(destroy_window) + user_handle_t handle; /* handle to the window */ +@END + + +/* Get information from a window handle */ +@REQ(get_window_info) + user_handle_t handle; /* handle to the window */ +@REPLY + user_handle_t full_handle; /* full 32-bit handle */ + void* pid; /* process owning the window */ + void* tid; /* thread owning the window */ +@END diff --git a/server/queue.c b/server/queue.c index 238e3a98858..e5753254e31 100644 --- a/server/queue.c +++ b/server/queue.c @@ -16,6 +16,7 @@ #include "thread.h" #include "process.h" #include "request.h" +#include "user.h" enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE }; #define NB_MSG_KINDS (RAW_HW_MESSAGE+1) @@ -40,7 +41,7 @@ struct message struct message *next; /* next message in list */ struct message *prev; /* prev message in list */ enum message_type type; /* message type */ - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message code */ unsigned int wparam; /* parameters */ unsigned int lparam; /* parameters */ @@ -65,7 +66,7 @@ struct timer struct timer *prev; /* prev timer in list */ struct timeval when; /* next expiration */ unsigned int rate; /* timer rate in ms */ - handle_t win; /* window handle */ + user_handle_t win; /* window handle */ unsigned int msg; /* message to post */ unsigned int id; /* timer id */ unsigned int lparam; /* lparam for message */ @@ -550,7 +551,7 @@ static void restart_timer( struct msg_queue *queue, struct timer *timer ) } /* find an expired timer matching the filtering parameters */ -static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win, +static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win, unsigned int get_first, unsigned int get_last, int remove ) { @@ -568,7 +569,8 @@ static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win, } /* kill a timer */ -static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id ) +static int kill_timer( struct msg_queue *queue, user_handle_t win, + unsigned int msg, unsigned int id ) { struct timer *timer; @@ -597,12 +599,15 @@ static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) } /* remove all messages and timers belonging to a certain window */ -static void cleanup_window( struct msg_queue *queue, handle_t win ) +void queue_cleanup_window( struct thread *thread, user_handle_t win ) { + struct msg_queue *queue = thread->queue; struct timer *timer; struct message *msg; int i; + if (!queue) return; + /* remove timers */ timer = queue->first_timer; while (timer) @@ -818,7 +823,8 @@ static void return_message_to_app( struct msg_queue *queue, struct get_message_r } -inline static struct message *find_matching_message( const struct message_list *list, handle_t win, +inline static struct message *find_matching_message( const struct message_list *list, + user_handle_t win, unsigned int first, unsigned int last ) { struct message *msg; @@ -981,7 +987,7 @@ DECL_HANDLER(get_message_reply) /* cleanup a queue when a window is deleted */ DECL_HANDLER(cleanup_window_queue) { - if (current->queue) cleanup_window( current->queue, req->win ); + queue_cleanup_window( current, req->win ); } diff --git a/server/request.h b/server/request.h index 3187fe51c47..97bc21e57b2 100644 --- a/server/request.h +++ b/server/request.h @@ -188,6 +188,11 @@ DECL_HANDLER(connect_named_pipe); DECL_HANDLER(wait_named_pipe); DECL_HANDLER(disconnect_named_pipe); DECL_HANDLER(get_named_pipe_info); +DECL_HANDLER(create_desktop_window); +DECL_HANDLER(create_window); +DECL_HANDLER(link_window); +DECL_HANDLER(destroy_window); +DECL_HANDLER(get_window_info); #ifdef WANT_REQUEST_HANDLERS @@ -317,6 +322,11 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_wait_named_pipe, (req_handler)req_disconnect_named_pipe, (req_handler)req_get_named_pipe_info, + (req_handler)req_create_desktop_window, + (req_handler)req_create_window, + (req_handler)req_link_window, + (req_handler)req_destroy_window, + (req_handler)req_get_window_info, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/thread.c b/server/thread.c index 918c842a18f..0679d9d1296 100644 --- a/server/thread.c +++ b/server/thread.c @@ -27,6 +27,7 @@ #include "process.h" #include "thread.h" #include "request.h" +#include "user.h" /* thread queues */ @@ -179,6 +180,7 @@ static void cleanup_thread( struct thread *thread ) release_object( thread->queue ); thread->queue = NULL; } + destroy_thread_windows( thread ); for (i = 0; i < MAX_INFLIGHT_FDS; i++) { if (thread->inflight[i].client != -1) diff --git a/server/trace.c b/server/trace.c index f44d0ad2179..5dc05bce231 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1459,7 +1459,7 @@ static void dump_send_message_request( const struct send_message_request *req ) { fprintf( stderr, " id=%p,", req->id ); fprintf( stderr, " type=%d,", req->type ); - fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " win=%08x,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " wparam=%08x,", req->wparam ); fprintf( stderr, " lparam=%08x,", req->lparam ); @@ -1475,7 +1475,7 @@ static void dump_send_message_request( const struct send_message_request *req ) static void dump_get_message_request( const struct get_message_request *req ) { fprintf( stderr, " flags=%d,", req->flags ); - fprintf( stderr, " get_win=%d,", req->get_win ); + fprintf( stderr, " get_win=%08x,", req->get_win ); fprintf( stderr, " get_first=%08x,", req->get_first ); fprintf( stderr, " get_last=%08x", req->get_last ); } @@ -1483,7 +1483,7 @@ static void dump_get_message_request( const struct get_message_request *req ) static void dump_get_message_reply( const struct get_message_request *req ) { fprintf( stderr, " type=%d,", req->type ); - fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " win=%08x,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " wparam=%08x,", req->wparam ); fprintf( stderr, " lparam=%08x,", req->lparam ); @@ -1517,12 +1517,12 @@ static void dump_get_message_reply_reply( const struct get_message_reply_request static void dump_cleanup_window_queue_request( const struct cleanup_window_queue_request *req ) { - fprintf( stderr, " win=%d", req->win ); + fprintf( stderr, " win=%08x", req->win ); } static void dump_set_win_timer_request( const struct set_win_timer_request *req ) { - fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " win=%08x,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " id=%08x,", req->id ); fprintf( stderr, " rate=%08x,", req->rate ); @@ -1531,7 +1531,7 @@ static void dump_set_win_timer_request( const struct set_win_timer_request *req static void dump_kill_win_timer_request( const struct kill_win_timer_request *req ) { - fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " win=%08x,", req->win ); fprintf( stderr, " msg=%08x,", req->msg ); fprintf( stderr, " id=%08x", req->id ); } @@ -1652,6 +1652,48 @@ static void dump_get_named_pipe_info_reply( const struct get_named_pipe_info_req fprintf( stderr, " insize=%08x", req->insize ); } +static void dump_create_desktop_window_request( const struct create_desktop_window_request *req ) +{ +} + +static void dump_create_desktop_window_reply( const struct create_desktop_window_request *req ) +{ + fprintf( stderr, " handle=%08x", req->handle ); +} + +static void dump_create_window_request( const struct create_window_request *req ) +{ +} + +static void dump_create_window_reply( const struct create_window_request *req ) +{ + fprintf( stderr, " handle=%08x", req->handle ); +} + +static void dump_link_window_request( const struct link_window_request *req ) +{ + fprintf( stderr, " handle=%08x,", req->handle ); + fprintf( stderr, " parent=%08x,", req->parent ); + fprintf( stderr, " previous=%08x", req->previous ); +} + +static void dump_destroy_window_request( const struct destroy_window_request *req ) +{ + fprintf( stderr, " handle=%08x", req->handle ); +} + +static void dump_get_window_info_request( const struct get_window_info_request *req ) +{ + fprintf( stderr, " handle=%08x", req->handle ); +} + +static void dump_get_window_info_reply( const struct get_window_info_request *req ) +{ + fprintf( stderr, " full_handle=%08x,", req->full_handle ); + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " tid=%p", req->tid ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -1776,6 +1818,11 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_wait_named_pipe_request, (dump_func)dump_disconnect_named_pipe_request, (dump_func)dump_get_named_pipe_info_request, + (dump_func)dump_create_desktop_window_request, + (dump_func)dump_create_window_request, + (dump_func)dump_link_window_request, + (dump_func)dump_destroy_window_request, + (dump_func)dump_get_window_info_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -1902,6 +1949,11 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)0, (dump_func)dump_get_named_pipe_info_reply, + (dump_func)dump_create_desktop_window_reply, + (dump_func)dump_create_window_reply, + (dump_func)0, + (dump_func)0, + (dump_func)dump_get_window_info_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -2028,6 +2080,11 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "wait_named_pipe", "disconnect_named_pipe", "get_named_pipe_info", + "create_desktop_window", + "create_window", + "link_window", + "destroy_window", + "get_window_info", }; /* ### make_requests end ### */ diff --git a/server/user.c b/server/user.c new file mode 100644 index 00000000000..ec0584c4191 --- /dev/null +++ b/server/user.c @@ -0,0 +1,149 @@ +/* + * Server-side USER handles + * + * Copyright (C) 2001 Alexandre Julliard + */ + +#include "thread.h" +#include "user.h" + +struct user_handle +{ + void *ptr; /* pointer to object */ + unsigned short type; /* object type (0 if free) */ + unsigned short generation; /* generation counter */ +}; + +static struct user_handle *handles; +static struct user_handle *freelist; +static int nb_handles; +static int allocated_handles; + +#define FIRST_HANDLE 32 /* handle value for first table entry */ +#define MAX_HANDLES (65536-FIRST_HANDLE) + +static struct user_handle *handle_to_entry( user_handle_t handle ) +{ + int index = (handle & 0xffff) - FIRST_HANDLE; + if (index < 0 || index >= nb_handles) return NULL; + if (!handles[index].type) return NULL; + if ((handle >> 16) && (handle >> 16 != handles[index].generation)) return NULL; + return &handles[index]; +} + +inline static user_handle_t entry_to_handle( struct user_handle *ptr ) +{ + int index = ptr - handles; + return (index + FIRST_HANDLE) + (ptr->generation << 16); +} + +inline static struct user_handle *alloc_user_entry(void) +{ + struct user_handle *handle; + + if (freelist) + { + handle = freelist; + freelist = handle->ptr; + return handle; + } + if (nb_handles >= allocated_handles) /* need to grow the array */ + { + struct user_handle *new_handles; + /* grow array by 50% (but at minimum 32 entries) */ + int growth = max( 32, allocated_handles / 2 ); + int new_size = min( allocated_handles + growth, MAX_HANDLES ); + if (new_size <= allocated_handles) return NULL; + if (!(new_handles = realloc( handles, new_size * sizeof(*handles) ))) + return NULL; + handles = new_handles; + allocated_handles = new_size; + } + handle = &handles[nb_handles++]; + handle->generation = 0; + return handle; +} + +inline static void *free_user_entry( struct user_handle *ptr ) +{ + void *ret; + ret = ptr->ptr; + ptr->ptr = freelist; + ptr->type = 0; + freelist = ptr; + return ret; +} + +/* allocate a user handle for a given object */ +user_handle_t alloc_user_handle( void *ptr, enum user_object type ) +{ + struct user_handle *entry = alloc_user_entry(); + if (!entry) return 0; + entry->ptr = ptr; + entry->type = type; + if (++entry->generation >= 0xffff) entry->generation = 1; + return entry_to_handle( entry ); +} + +/* return a pointer to a user object from its handle */ +void *get_user_object( user_handle_t handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( handle )) || entry->type != type) + { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + return entry->ptr; +} + +/* same as get_user_object plus set the handle to the full 32-bit value */ +void *get_user_object_handle( user_handle_t *handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( *handle )) || entry->type != type) + { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + *handle = entry_to_handle( entry ); + return entry->ptr; +} + +/* free a user handle and return a pointer to the object */ +void *free_user_handle( user_handle_t handle ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( handle ))) + { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + return free_user_entry( entry ); +} + +/* return the next user handle after 'handle' that is of a given type */ +void *next_user_handle( user_handle_t *handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!*handle) entry = handles; + else + { + if (!(entry = handle_to_entry( *handle ))) return NULL; + entry++; /* start from the next one */ + } + while (entry < handles + nb_handles) + { + if (!type || entry->type == type) + { + *handle = entry_to_handle( entry ); + return entry->ptr; + } + entry++; + } + return NULL; +} diff --git a/server/user.h b/server/user.h new file mode 100644 index 00000000000..810d60c1398 --- /dev/null +++ b/server/user.h @@ -0,0 +1,36 @@ +/* + * Wine server USER definitions + * + * Copyright (C) 2001 Alexandre Julliard + */ + +#ifndef __WINE_SERVER_USER_H +#define __WINE_SERVER_USER_H + +#include "wine/server_protocol.h" + +struct thread; +struct window; + +enum user_object +{ + USER_WINDOW = 1 +}; + +/* user handles functions */ + +extern user_handle_t alloc_user_handle( void *ptr, enum user_object type ); +extern void *get_user_object( user_handle_t handle, enum user_object type ); +extern void *get_user_object_handle( user_handle_t *handle, enum user_object type ); +extern void *free_user_handle( user_handle_t handle ); +extern void *next_user_handle( user_handle_t *handle, enum user_object type ); + +/* queue functions */ + +extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); + +/* window functions */ + +extern void destroy_thread_windows( struct thread *thread ); + +#endif /* __WINE_SERVER_USER_H */ diff --git a/server/window.c b/server/window.c new file mode 100644 index 00000000000..f6e853c7a87 --- /dev/null +++ b/server/window.c @@ -0,0 +1,179 @@ +/* + * Server-side window handling + * + * Copyright (C) 2001 Alexandre Julliard + */ + +#include + +#include "object.h" +#include "request.h" +#include "thread.h" +#include "process.h" +#include "user.h" + +struct window +{ + struct window *parent; /* parent window */ + struct window *child; /* first child window */ + struct window *next; /* next window in Z-order */ + struct window *prev; /* prev window in Z-order */ + user_handle_t handle; /* full handle for this window */ + struct thread *thread; /* thread owning the window */ +}; + +static struct window *top_window; /* top-level (desktop) window */ + +/* link a window into the tree (or unlink it if the new parent is NULL) */ +static void link_window( struct window *win, struct window *parent, struct window *previous ) +{ + if (win->parent) /* unlink it from the previous location */ + { + if (win->next) win->next->prev = win->prev; + if (win->prev) win->prev->next = win->next; + else win->parent->child = win->next; + } + if ((win->parent = parent)) + { + if ((win->prev = previous)) + { + if ((win->next = previous->next)) win->next->prev = win; + win->prev->next = win; + } + else + { + if ((win->next = parent->child)) win->next->prev = win; + parent->child = win; + } + } + else win->next = win->prev = NULL; + +} + +/* free a window structure */ +static void free_window( struct window *win ) +{ + assert( win != top_window ); + + while (win->child) free_window( win->child ); + if (win->thread->queue) queue_cleanup_window( win->thread, win->handle ); + free_user_handle( win->handle ); + if (win->parent) link_window( win, NULL, NULL ); + memset( win, 0x55, sizeof(*win) ); + free( win ); +} + +/* create a new window structure */ +static struct window *create_window(void) +{ + struct window *win = mem_alloc( sizeof(*win) ); + if (!win) return NULL; + + if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) + { + free( win ); + return NULL; + } + win->parent = NULL; + win->child = NULL; + win->next = NULL; + win->prev = NULL; + win->thread = current; + return win; +} + +/* destroy all windows belonging to a given thread */ +void destroy_thread_windows( struct thread *thread ) +{ + user_handle_t handle = 0; + struct window *win; + + while ((win = next_user_handle( &handle, USER_WINDOW ))) + { + if (win->thread != thread) continue; + free_window( win ); + } +} + +/* create a window */ +DECL_HANDLER(create_window) +{ + struct window *win; + + req->handle = 0; + if ((win = create_window())) req->handle = win->handle; +} + + +/* create the desktop window */ +DECL_HANDLER(create_desktop_window) +{ + req->handle = 0; + if (!top_window) + { + if (!(top_window = create_window())) return; + top_window->thread = NULL; /* no thread owns the desktop */ + } + req->handle = top_window->handle; +} + + +/* link a window into the tree */ +DECL_HANDLER(link_window) +{ + struct window *win, *parent = NULL, *previous = NULL; + + if (!(win = get_user_object( req->handle, USER_WINDOW ))) return; + if (req->parent && !(parent = get_user_object( req->parent, USER_WINDOW ))) return; + if (parent && req->previous) + { + if (req->previous == 1) /* special case: HWND_BOTTOM */ + { + if ((previous = parent->child)) + { + /* make it the last of the list */ + while (previous->next) previous = previous->next; + } + } + else if (!(previous = get_user_object( req->previous, USER_WINDOW ))) return; + + if (previous && previous->parent != parent) /* previous must be a child of parent */ + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + link_window( win, parent, previous ); +} + + +/* destroy a window */ +DECL_HANDLER(destroy_window) +{ + struct window *win = get_user_object( req->handle, USER_WINDOW ); + if (win) + { + if (win != top_window) free_window( win ); + else set_error( STATUS_ACCESS_DENIED ); + } +} + + +/* Get information from a window handle */ +DECL_HANDLER(get_window_info) +{ + user_handle_t handle = req->handle; + struct window *win = get_user_object_handle( &handle, USER_WINDOW ); + + req->full_handle = 0; + req->tid = req->pid = 0; + if (win) + { + req->full_handle = handle; + if (win->thread) + { + req->tid = get_thread_id( win->thread ); + req->pid = get_process_id( win->thread->process ); + } + } +} diff --git a/tools/make_requests b/tools/make_requests index df02a6f30e6..b882effd2bf 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -16,6 +16,7 @@ "void*" => "%p", "time_t" => "%ld", "handle_t" => "%d", + "user_handle_t" => "%08x", ); my @requests = (); diff --git a/windows/queue.c b/windows/queue.c index d4400ba8797..881baa9e198 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -477,30 +477,6 @@ HTASK16 WINAPI GetWindowTask16( HWND16 hwnd ) return retvalue; } -/*********************************************************************** - * GetWindowThreadProcessId (USER32.@) - */ -DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process ) -{ - DWORD retvalue; - MESSAGEQUEUE *queue; - - WND *wndPtr = WIN_FindWndPtr( hwnd ); - if (!wndPtr) return 0; - - queue = QUEUE_Lock( wndPtr->hmemTaskQ ); - WIN_ReleaseWndPtr(wndPtr); - - if (!queue) return 0; - - if ( process ) *process = (DWORD)queue->teb->pid; - retvalue = (DWORD)queue->teb->tid; - - QUEUE_Unlock( queue ); - return retvalue; -} - - /*********************************************************************** * InitThreadInput (USER.409) */ diff --git a/windows/win.c b/windows/win.c index a8cc9adf674..7985360f32a 100644 --- a/windows/win.c +++ b/windows/win.c @@ -9,6 +9,7 @@ #include "windef.h" #include "wine/winbase16.h" #include "wine/winuser16.h" +#include "wine/server.h" #include "wine/unicode.h" #include "win.h" #include "heap.h" @@ -38,6 +39,8 @@ static HWND hwndSysModal = 0; static WORD wDragWidth = 4; static WORD wDragHeight= 3; +static void *user_handles[65536]; + /* thread safeness */ extern SYSLEVEL USER_SysLevel; /* FIXME */ @@ -69,6 +72,80 @@ void WIN_RestoreWndsLock( int ipreviousLocks ) _EnterSysLevel( &USER_SysLevel ); } +/*********************************************************************** + * create_window_handle + * + * Create a window handle with the server. + */ +static WND *create_window_handle( BOOL desktop, INT size ) +{ + BOOL res; + unsigned int handle = 0; + WND *win = HeapAlloc( GetProcessHeap(), 0, size ); + + if (!win) return NULL; + + USER_Lock(); + + if (desktop) + { + SERVER_START_REQ( create_desktop_window ) + { + if ((res = !SERVER_CALL_ERR())) handle = req->handle; + } + SERVER_END_REQ; + } + else + { + SERVER_START_REQ( create_window ) + { + if ((res = !SERVER_CALL_ERR())) handle = req->handle; + } + SERVER_END_REQ; + } + + if (!res) + { + USER_Unlock(); + HeapFree( GetProcessHeap(), 0, win ); + return NULL; + } + user_handles[LOWORD(handle)] = win; + win->hwndSelf = (HWND)handle; + win->dwMagic = WND_MAGIC; + win->irefCount = 1; + return win; +} + + +/*********************************************************************** + * free_window_handle + * + * Free a window handle. + */ +static WND *free_window_handle( HWND hwnd ) +{ + WND *ptr; + + USER_Lock(); + if ((ptr = user_handles[LOWORD(hwnd)])) + { + SERVER_START_REQ( destroy_window ) + { + req->handle = hwnd; + if (!SERVER_CALL_ERR()) + user_handles[LOWORD(hwnd)] = NULL; + else + ptr = NULL; + } + SERVER_END_REQ; + } + USER_Unlock(); + if (ptr) HeapFree( GetProcessHeap(), 0, ptr ); + return ptr; +} + + /*********************************************************************** * WIN_FindWndPtr * @@ -77,34 +154,35 @@ void WIN_RestoreWndsLock( int ipreviousLocks ) WND * WIN_FindWndPtr( HWND hwnd ) { WND * ptr; - - if (!hwnd || HIWORD(hwnd)) goto error2; - ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd ); - /* Lock all WND structures for thread safeness*/ - USER_Lock(); - /*and increment destruction monitoring*/ - ptr->irefCount++; - if (ptr->dwMagic != WND_MAGIC) goto error; - if (ptr->hwndSelf != hwnd) + if (!hwnd) return NULL; + + USER_Lock(); + if (!(ptr = user_handles[LOWORD(hwnd)])) { - ERR("Can't happen: hwnd %04x self pointer is %04x\n",hwnd, ptr->hwndSelf ); + /* check other processes */ + if (IsWindow( hwnd )) + { + ERR( "window %04x belongs to other process\n", hwnd ); + /* DbgBreakPoint(); */ + } goto error; } - /* returns a locked pointer */ + if (ptr->dwMagic != WND_MAGIC) goto error; + /* verify that handle highword (if any) matches the window */ + if (HIWORD(hwnd) && hwnd != ptr->hwndSelf) goto error; + /*and increment destruction monitoring*/ + ptr->irefCount++; return ptr; + error: /* Unlock all WND structures for thread safeness*/ USER_Unlock(); - /* and decrement destruction monitoring value */ - ptr->irefCount--; - -error2: - if ( hwnd!=0 ) - SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); return NULL; } + /*********************************************************************** * WIN_LockWndPtr * @@ -140,8 +218,7 @@ void WIN_ReleaseWndPtr(WND *wndPtr) if(wndPtr->irefCount == 0 && !wndPtr->dwMagic) { /* Release memory */ - USER_HEAP_FREE( wndPtr->hwndSelf); - wndPtr->hwndSelf = 0; + free_window_handle( wndPtr->hwndSelf ); } else if(wndPtr->irefCount < 0) { @@ -173,27 +250,9 @@ void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr) * * Remove a window from the siblings linked list. */ -BOOL WIN_UnlinkWindow( HWND hwnd ) -{ - WND *wndPtr, **ppWnd; - BOOL ret = FALSE; - - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; - else if(!wndPtr->parent) - { - WIN_ReleaseWndPtr(wndPtr); - return FALSE; - } - - ppWnd = &wndPtr->parent->child; - while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next; - if (*ppWnd) - { - *ppWnd = wndPtr->next; - ret = TRUE; - } - WIN_ReleaseWndPtr(wndPtr); - return ret; +void WIN_UnlinkWindow( HWND hwnd ) +{ + WIN_LinkWindow( hwnd, 0, 0 ); } @@ -203,38 +262,62 @@ BOOL WIN_UnlinkWindow( HWND hwnd ) * Insert a window into the siblings linked list. * The window is inserted after the specified window, which can also * be specified as HWND_TOP or HWND_BOTTOM. + * If parent is 0, window is unlinked from the tree. */ -BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter ) -{ - WND *wndPtr, **ppWnd; +void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter ) +{ + WND *wndPtr, **ppWnd, *parentPtr = NULL; + BOOL ret; - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; - else if(!wndPtr->parent) + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return; + if (parent && !(parentPtr = WIN_FindWndPtr( parent ))) { WIN_ReleaseWndPtr(wndPtr); - return FALSE; + return; } - if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM)) + + SERVER_START_REQ( link_window ) { - ppWnd = &wndPtr->parent->child; /* Point to first sibling hwnd */ - if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */ - while (*ppWnd) ppWnd = &(*ppWnd)->next; + req->handle = hwnd; + req->parent = parent; + req->previous = hwndInsertAfter; + ret = !SERVER_CALL_ERR(); } - else /* Normal case */ + SERVER_END_REQ; + if (!ret) goto done; + + /* first unlink it if it is linked */ + if (wndPtr->parent) { - WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter ); - if (!afterPtr) - { - WIN_ReleaseWndPtr(wndPtr); - return FALSE; - } - ppWnd = &afterPtr->next; - WIN_ReleaseWndPtr(afterPtr); + ppWnd = &wndPtr->parent->child; + while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next; + if (*ppWnd) *ppWnd = wndPtr->next; } - wndPtr->next = *ppWnd; - *ppWnd = wndPtr; - WIN_ReleaseWndPtr(wndPtr); - return TRUE; + + wndPtr->parent = parentPtr; + + if (parentPtr) + { + if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM)) + { + ppWnd = &parentPtr->child; /* Point to first sibling hwnd */ + if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */ + while (*ppWnd) ppWnd = &(*ppWnd)->next; + } + else /* Normal case */ + { + WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter ); + if (!afterPtr) goto done; + ppWnd = &afterPtr->next; + WIN_ReleaseWndPtr(afterPtr); + } + wndPtr->next = *ppWnd; + *ppWnd = wndPtr; + } + + done: + WIN_ReleaseWndPtr( parentPtr ); + WIN_ReleaseWndPtr( wndPtr ); } @@ -416,17 +499,16 @@ BOOL WIN_CreateDesktopWindow(void) &wndExtra, &winproc, &clsStyle, &dce ))) return FALSE; - hwndDesktop = USER_HEAP_ALLOC( sizeof(WND) + wndExtra ); - if (!hwndDesktop) return FALSE; - pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop ); + pWndDesktop = create_window_handle( TRUE, sizeof(WND) + wndExtra ); + if (!pWndDesktop) return FALSE; + hwndDesktop = pWndDesktop->hwndSelf; + pWndDesktop->tid = 0; /* nobody owns the desktop */ pWndDesktop->next = NULL; pWndDesktop->child = NULL; pWndDesktop->parent = NULL; pWndDesktop->owner = 0; pWndDesktop->class = class; - pWndDesktop->dwMagic = WND_MAGIC; - pWndDesktop->hwndSelf = hwndDesktop; pWndDesktop->hInstance = 0; pWndDesktop->rectWindow.left = 0; pWndDesktop->rectWindow.top = 0; @@ -452,7 +534,6 @@ BOOL WIN_CreateDesktopWindow(void) pWndDesktop->userdata = 0; pWndDesktop->winproc = winproc; pWndDesktop->cbWndExtra = wndExtra; - pWndDesktop->irefCount = 0; cs.lpCreateParams = NULL; cs.hInstance = 0; @@ -470,6 +551,7 @@ BOOL WIN_CreateDesktopWindow(void) if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE; pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND; + WIN_ReleaseWndPtr( pWndDesktop ); return TRUE; } @@ -613,15 +695,17 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, /* Create the window structure */ - if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) ))) + if (!(wndPtr = create_window_handle( FALSE, + sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) ))) { TRACE("out of memory\n" ); return 0; } + hwnd = wndPtr->hwndSelf; /* Fill the window structure */ - wndPtr = WIN_LockWndPtr((WND *) USER_HEAP_LIN_ADDR( hwnd )); + wndPtr->tid = GetCurrentThreadId(); wndPtr->next = NULL; wndPtr->child = NULL; @@ -643,8 +727,6 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, wndPtr->class = classPtr; wndPtr->winproc = winproc; - wndPtr->dwMagic = WND_MAGIC; - wndPtr->hwndSelf = hwnd; wndPtr->hInstance = cs->hInstance; wndPtr->text = NULL; wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 ); @@ -664,7 +746,6 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0; wndPtr->cbWndExtra = wndExtra; - wndPtr->irefCount = 1; if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra); @@ -685,7 +766,7 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, if (ret) { TRACE("CBT-hook returned 0\n"); - USER_HEAP_FREE( hwnd ); + free_window_handle( hwnd ); CLASS_RemoveWindow( classPtr ); hwnd = 0; goto end; @@ -1978,14 +2059,64 @@ BOOL16 WINAPI IsWindow16( HWND16 hwnd ) */ BOOL WINAPI IsWindow( HWND hwnd ) { - WND * wndPtr; - BOOL retvalue; - - if(!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; - retvalue = (wndPtr->dwMagic == WND_MAGIC); - WIN_ReleaseWndPtr(wndPtr); - return retvalue; - + WND *ptr; + BOOL ret = FALSE; + + USER_Lock(); + if ((ptr = user_handles[LOWORD(hwnd)])) + { + ret = ((ptr->dwMagic == WND_MAGIC) && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf)); + } + USER_Unlock(); + + if (!ret) /* check other processes */ + { + SERVER_START_REQ( get_window_info ) + { + req->handle = hwnd; + ret = !SERVER_CALL_ERR(); + } + SERVER_END_REQ; + } + return ret; +} + + +/*********************************************************************** + * GetWindowThreadProcessId (USER32.@) + */ +DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process ) +{ + WND *ptr; + DWORD tid = 0; + + USER_Lock(); + if ((ptr = user_handles[LOWORD(hwnd)])) + { + if ((ptr->dwMagic == WND_MAGIC) && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf)) + { + /* got a valid window */ + tid = ptr->tid; + if (process) *process = GetCurrentProcessId(); + } + else SetLastError( ERROR_INVALID_WINDOW_HANDLE); + USER_Unlock(); + return tid; + } + USER_Unlock(); + + /* check other processes */ + SERVER_START_REQ( get_window_info ) + { + req->handle = hwnd; + if (!SERVER_CALL_ERR()) + { + tid = (DWORD)req->tid; + if (process) *process = (DWORD)req->pid; + } + } + SERVER_END_REQ; + return tid; } @@ -2071,11 +2202,13 @@ HWND16 WINAPI SetParent16( HWND16 hwndChild, HWND16 hwndNewParent ) HWND WINAPI SetParent( HWND hwnd, HWND parent ) { WND *wndPtr; - WND *pWndParent; DWORD dwStyle; HWND retvalue; - if (hwnd == GetDesktopWindow()) /* sanity check */ + if (!parent) parent = GetDesktopWindow(); + + /* sanity checks */ + if (hwnd == GetDesktopWindow() || !IsWindow( parent )) { SetLastError( ERROR_INVALID_WINDOW_HANDLE ); return 0; @@ -2088,38 +2221,24 @@ HWND WINAPI SetParent( HWND hwnd, HWND parent ) dwStyle = wndPtr->dwStyle; - if (!parent) parent = GetDesktopWindow(); - - if (!(pWndParent = WIN_FindWndPtr(parent))) - { - WIN_ReleaseWndPtr( wndPtr ); - return 0; - } - /* Windows hides the window first, then shows it again * including the WM_SHOWWINDOW messages and all */ if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE ); retvalue = wndPtr->parent->hwndSelf; /* old parent */ - if (pWndParent != wndPtr->parent) + if (parent != retvalue) { - WIN_UnlinkWindow(wndPtr->hwndSelf); - wndPtr->parent = pWndParent; + WIN_LinkWindow( hwnd, parent, HWND_TOP ); if (parent != GetDesktopWindow()) /* a child window */ { - if( !( wndPtr->dwStyle & WS_CHILD ) ) + if (!(dwStyle & WS_CHILD)) { - if( wndPtr->wIDmenu != 0) - { - DestroyMenu( (HMENU) wndPtr->wIDmenu ); - wndPtr->wIDmenu = 0; - } + HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 ); + if (menu) DestroyMenu( menu ); } } - WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP); } - WIN_ReleaseWndPtr( pWndParent ); WIN_ReleaseWndPtr( wndPtr ); /* SetParent additionally needs to make hwnd the topmost window @@ -2828,45 +2947,36 @@ BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend ) if (!IsIconic( hQueryWnd )) { - WND *ptrWnd, *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd); - - tempRect = ptrQueryWnd->rectClient; - if(ptrQueryWnd->parent) - MapWindowPoints( ptrQueryWnd->parent->hwndSelf, 0, - (LPPOINT)&tempRect, 2 ); + GetClientRect( hQueryWnd, &tempRect ); + MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 ); if (PtInRect( &tempRect, pt)) { + int i; + HWND *list = WIN_ListChildren( hQueryWnd ); + wParam = 0; - for (ptrWnd = WIN_LockWndPtr(ptrQueryWnd->child); ptrWnd ;WIN_UpdateWndPtr(&ptrWnd,ptrWnd->next)) + if (list) { - if( ptrWnd->dwStyle & WS_VISIBLE ) + for (i = 0; list[i]; i++) { - GetWindowRect( ptrWnd->hwndSelf, &tempRect ); - if (PtInRect( &tempRect, pt )) break; + if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE) + { + GetWindowRect( list[i], &tempRect ); + if (PtInRect( &tempRect, pt )) break; + } } + if (list[i]) + { + if (IsWindowEnabled( list[i] )) + bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend ); + } + HeapFree( GetProcessHeap(), 0, list ); } - - if(ptrWnd) - { - TRACE_(msg)("hwnd = %04x, %d %d - %d %d\n", - ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top, - ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom ); - if( !(ptrWnd->dwStyle & WS_DISABLED) ) - bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo, bNoSend); - - WIN_ReleaseWndPtr(ptrWnd); - } - - if(bResult) - { - WIN_ReleaseWndPtr(ptrQueryWnd); - return bResult; - } + if(bResult) return bResult; } else wParam = 1; - WIN_ReleaseWndPtr(ptrQueryWnd); } else wParam = 1;