Added proper support for storing window parents in the server.
Added a few requests to query the window hierarchy.

diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ebf2d3f..18ecc74 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1563,17 +1563,11 @@
 
 
 
-struct create_desktop_window_request
-{
-    struct request_header __header;
-    user_handle_t  handle;
-};
-
-
-
 struct create_window_request
 {
     struct request_header __header;
+    user_handle_t  parent;
+    user_handle_t  owner;
     user_handle_t  handle;
 };
 
@@ -1607,6 +1601,42 @@
 };
 
 
+
+struct get_window_parents_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+    int            count;
+    /* VARARG(parents,user_handles); */
+};
+
+
+
+struct get_window_children_request
+{
+    struct request_header __header;
+    user_handle_t  parent;
+    int            count;
+    /* VARARG(parents,user_handles); */
+};
+
+
+
+struct get_window_tree_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+    user_handle_t  parent;
+    user_handle_t  owner;
+    user_handle_t  next_sibling;
+    user_handle_t  prev_sibling;
+    user_handle_t  first_sibling;
+    user_handle_t  last_sibling;
+    user_handle_t  first_child;
+    user_handle_t  last_child;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -1732,11 +1762,13 @@
     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_get_window_parents,
+    REQ_get_window_children,
+    REQ_get_window_tree,
     REQ_NB_REQUESTS
 };
 
@@ -1867,13 +1899,15 @@
     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;
+    struct get_window_parents_request get_window_parents;
+    struct get_window_children_request get_window_children;
+    struct get_window_tree_request get_window_tree;
 };
 
-#define SERVER_PROTOCOL_VERSION 52
+#define SERVER_PROTOCOL_VERSION 53
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winuser.h b/include/winuser.h
index a8523eb..d1daa24 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -3602,8 +3602,8 @@
 BOOL        WINAPI GetUserObjectInformationA(HANDLE,INT,LPVOID,DWORD,LPDWORD);
 BOOL        WINAPI GetUserObjectInformationW(HANDLE,INT,LPVOID,DWORD,LPDWORD);
 #define     GetUserObjectInformation WINELIB_NAME_AW(GetUserObjectInformation)
-HWND      WINAPI GetWindow(HWND,WORD);
-HDC       WINAPI GetWindowDC(HWND);
+HWND        WINAPI GetWindow(HWND,UINT);
+HDC         WINAPI GetWindowDC(HWND);
 LONG        WINAPI GetWindowLongA(HWND,INT);
 LONG        WINAPI GetWindowLongW(HWND,INT);
 #define     GetWindowLong WINELIB_NAME_AW(GetWindowLong)
diff --git a/server/protocol.def b/server/protocol.def
index c386dd9..a87287c 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1395,17 +1395,12 @@
 @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)
+    user_handle_t  parent;      /* parent window */
+    user_handle_t  owner;       /* owner window */
 @REPLY
-    user_handle_t  handle;      /* handle to the window */
+    user_handle_t  handle;      /* created window */
 @END
 
 
@@ -1432,3 +1427,36 @@
     void*          pid;         /* process owning the window */
     void*          tid;         /* thread owning the window */
 @END
+
+
+/* Get a list of the window parents, up to the root of the tree */
+@REQ(get_window_parents)
+    user_handle_t  handle;        /* handle to the window */
+@REPLY
+    int            count;         /* total count of parents */
+    VARARG(parents,user_handles); /* parent handles */
+@END
+
+
+/* Get a list of the window children */
+@REQ(get_window_children)
+    user_handle_t  parent;        /* parent window */
+@REPLY
+    int            count;         /* total count of children */
+    VARARG(parents,user_handles); /* children handles */
+@END
+
+
+/* Get window tree information from a window handle */
+@REQ(get_window_tree)
+    user_handle_t  handle;        /* handle to the window */
+@REPLY
+    user_handle_t  parent;        /* parent window */
+    user_handle_t  owner;         /* owner window */
+    user_handle_t  next_sibling;  /* next sibling in Z-order */
+    user_handle_t  prev_sibling;  /* prev sibling in Z-order */
+    user_handle_t  first_sibling; /* first sibling in Z-order */
+    user_handle_t  last_sibling;  /* last sibling in Z-order */
+    user_handle_t  first_child;   /* first child */
+    user_handle_t  last_child;    /* last child */
+@END
diff --git a/server/queue.c b/server/queue.c
index 2cab814..4e0332b 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -833,7 +833,7 @@
     {
         /* check against the filters */
         if (msg->msg == WM_QUIT) break;  /* WM_QUIT is never filtered */
-        if (win && msg->win && msg->win != win) continue;
+        if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) continue;
         if (msg->msg < first) continue;
         if (msg->msg > last) continue;
         break; /* found one */
diff --git a/server/request.h b/server/request.h
index 97bc21e..c4530b5 100644
--- a/server/request.h
+++ b/server/request.h
@@ -188,11 +188,13 @@
 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);
+DECL_HANDLER(get_window_parents);
+DECL_HANDLER(get_window_children);
+DECL_HANDLER(get_window_tree);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -322,11 +324,13 @@
     (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,
+    (req_handler)req_get_window_parents,
+    (req_handler)req_get_window_children,
+    (req_handler)req_get_window_tree,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 5dc05bc..93a4f36 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -119,6 +119,21 @@
     return get_size(req);
 }
 
+static size_t dump_varargs_user_handles( const void *req )
+{
+    const user_handle_t *data = get_data(req);
+    size_t len = get_size(req) / sizeof(*data);
+
+    fputc( '{', stderr );
+    while (len > 0)
+    {
+        fprintf( stderr, "%08x", *data++ );
+        if (--len) fputc( ',', stderr );
+    }
+    fputc( '}', stderr );
+    return get_size(req);
+}
+
 static size_t dump_varargs_bytes( const void *req )
 {
     const unsigned char *data = get_data(req);
@@ -1652,17 +1667,10 @@
     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 )
 {
+    fprintf( stderr, " parent=%08x,", req->parent );
+    fprintf( stderr, " owner=%08x", req->owner );
 }
 
 static void dump_create_window_reply( const struct create_window_request *req )
@@ -1694,6 +1702,47 @@
     fprintf( stderr, " tid=%p", req->tid );
 }
 
+static void dump_get_window_parents_request( const struct get_window_parents_request *req )
+{
+    fprintf( stderr, " handle=%08x", req->handle );
+}
+
+static void dump_get_window_parents_reply( const struct get_window_parents_request *req )
+{
+    fprintf( stderr, " count=%d,", req->count );
+    fprintf( stderr, " parents=" );
+    cur_pos += dump_varargs_user_handles( req );
+}
+
+static void dump_get_window_children_request( const struct get_window_children_request *req )
+{
+    fprintf( stderr, " parent=%08x", req->parent );
+}
+
+static void dump_get_window_children_reply( const struct get_window_children_request *req )
+{
+    fprintf( stderr, " count=%d,", req->count );
+    fprintf( stderr, " parents=" );
+    cur_pos += dump_varargs_user_handles( req );
+}
+
+static void dump_get_window_tree_request( const struct get_window_tree_request *req )
+{
+    fprintf( stderr, " handle=%08x", req->handle );
+}
+
+static void dump_get_window_tree_reply( const struct get_window_tree_request *req )
+{
+    fprintf( stderr, " parent=%08x,", req->parent );
+    fprintf( stderr, " owner=%08x,", req->owner );
+    fprintf( stderr, " next_sibling=%08x,", req->next_sibling );
+    fprintf( stderr, " prev_sibling=%08x,", req->prev_sibling );
+    fprintf( stderr, " first_sibling=%08x,", req->first_sibling );
+    fprintf( stderr, " last_sibling=%08x,", req->last_sibling );
+    fprintf( stderr, " first_child=%08x,", req->first_child );
+    fprintf( stderr, " last_child=%08x", req->last_child );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -1818,11 +1867,13 @@
     (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,
+    (dump_func)dump_get_window_parents_request,
+    (dump_func)dump_get_window_children_request,
+    (dump_func)dump_get_window_tree_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -1949,11 +2000,13 @@
     (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,
+    (dump_func)dump_get_window_parents_reply,
+    (dump_func)dump_get_window_children_reply,
+    (dump_func)dump_get_window_tree_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2080,11 +2133,13 @@
     "wait_named_pipe",
     "disconnect_named_pipe",
     "get_named_pipe_info",
-    "create_desktop_window",
     "create_window",
     "link_window",
     "destroy_window",
     "get_window_info",
+    "get_window_parents",
+    "get_window_children",
+    "get_window_tree",
 };
 
 /* ### make_requests end ### */
diff --git a/server/user.c b/server/user.c
index 88c7fd7..e31fb16 100644
--- a/server/user.c
+++ b/server/user.c
@@ -91,11 +91,7 @@
 {
     struct user_handle *entry;
 
-    if (!(entry = handle_to_entry( handle )) || entry->type != type)
-    {
-        set_error( STATUS_INVALID_HANDLE );
-        return NULL;
-    }
+    if (!(entry = handle_to_entry( handle )) || entry->type != type) return NULL;
     return entry->ptr;
 }
 
@@ -114,11 +110,7 @@
 {
     struct user_handle *entry;
 
-    if (!(entry = handle_to_entry( *handle )) || entry->type != type)
-    {
-        set_error( STATUS_INVALID_HANDLE );
-        return NULL;
-    }
+    if (!(entry = handle_to_entry( *handle )) || entry->type != type) return NULL;
     *handle = entry_to_handle( entry );
     return entry->ptr;
 }
diff --git a/server/user.h b/server/user.h
index 1e33168..d53cc53 100644
--- a/server/user.h
+++ b/server/user.h
@@ -33,5 +33,6 @@
 /* window functions */
 
 extern void destroy_thread_windows( struct thread *thread );
+extern int is_child_window( user_handle_t parent, user_handle_t child );
 
 #endif  /* __WINE_SERVER_USER_H */
diff --git a/server/window.c b/server/window.c
index f6e853c..8bc9155 100644
--- a/server/window.c
+++ b/server/window.c
@@ -14,57 +14,85 @@
 
 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 */
+    struct window   *parent;      /* parent window */
+    struct window   *owner;       /* owner of this window */
+    struct window   *first_child; /* first child window */
+    struct window   *last_child;  /* last 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 */
 
+
+/* retrieve a pointer to a window from its handle */
+inline static struct window *get_window( user_handle_t handle )
+{
+    struct window *ret = get_user_object( handle, USER_WINDOW );
+    if (!ret) set_error( STATUS_INVALID_HANDLE );
+    return ret;
+}
+
 /* 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;
+        else if (win->parent->last_child == win) win->parent->last_child = win->prev;
         if (win->prev) win->prev->next = win->next;
-        else win->parent->child = win->next;
+        else if (win->parent->first_child == win) win->parent->first_child = win->next;
     }
-    if ((win->parent = parent))
+    if (parent)
     {
+        win->parent = parent;
         if ((win->prev = previous))
         {
             if ((win->next = previous->next)) win->next->prev = win;
+            else if (win->parent->last_child == previous) win->parent->last_child = win;
             win->prev->next = win;
         }
         else
         {
-            if ((win->next = parent->child)) win->next->prev = win;
-            parent->child = win;
+            if ((win->next = parent->first_child)) win->next->prev = win;
+            else win->parent->last_child = win;
+            parent->first_child = win;
         }
     }
-    else win->next = win->prev = NULL;
-
+    else
+    {
+        /* don't touch parent; an unlinked window still has a valid parent pointer */
+        win->next = win->prev = NULL;
+    }
 }
 
-/* free a window structure */
-static void free_window( struct window *win )
+/* destroy a window */
+static void destroy_window( struct window *win )
 {
     assert( win != top_window );
 
-    while (win->child) free_window( win->child );
+    /* destroy all children */
+    while (win->first_child) destroy_window( win->first_child );
+
+    /* reset siblings owner */
+    if (win->parent)
+    {
+        struct window *ptr;
+        for (ptr = win->parent->first_child; ptr; ptr = ptr->next)
+            if (ptr->owner == win) ptr->owner = NULL;
+    }
+
     if (win->thread->queue) queue_cleanup_window( win->thread, win->handle );
     free_user_handle( win->handle );
-    if (win->parent) link_window( win, NULL, NULL );
+    link_window( win, NULL, NULL );
     memset( win, 0x55, sizeof(*win) );
     free( win );
 }
 
-/* create a new window structure */
-static struct window *create_window(void)
+/* 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 )
 {
     struct window *win = mem_alloc( sizeof(*win) );
     if (!win) return NULL;
@@ -74,11 +102,13 @@
         free( win );
         return NULL;
     }
-    win->parent = NULL;
-    win->child  = NULL;
-    win->next   = NULL;
-    win->prev   = NULL;
-    win->thread = current;
+    win->parent      = parent;
+    win->owner       = owner;
+    win->first_child = NULL;
+    win->last_child  = NULL;
+    win->next        = NULL;
+    win->prev        = NULL;
+    win->thread      = current;
     return win;
 }
 
@@ -91,30 +121,47 @@
     while ((win = next_user_handle( &handle, USER_WINDOW )))
     {
         if (win->thread != thread) continue;
-        free_window( win );
+        destroy_window( win );
     }
 }
 
+/* check whether child is a descendant of parent */
+int is_child_window( user_handle_t parent, user_handle_t child )
+{
+    struct window *child_ptr = get_user_object( child, USER_WINDOW );
+    struct window *parent_ptr = get_user_object( parent, USER_WINDOW );
+
+    if (!child_ptr || !parent_ptr) return 0;
+    while (child_ptr->parent)
+    {
+        if (child_ptr->parent == parent_ptr) return 1;
+        child_ptr = child_ptr->parent;
+    }
+    return 0;
+}
+
 /* 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 (!req->parent)  /* return desktop window */
     {
-        if (!(top_window = create_window())) return;
-        top_window->thread = NULL;  /* no thread owns the desktop */
+        if (!top_window)
+        {
+            if (!(top_window = create_window( NULL, NULL ))) return;
+            top_window->thread = NULL;  /* no thread owns the desktop */
+        }
+        req->handle = top_window->handle;
     }
-    req->handle = top_window->handle;
+    else
+    {
+        struct window *win, *parent, *owner = NULL;
+
+        if (!(parent = get_window( req->parent ))) return;
+        if (req->owner && !(owner = get_window( req->owner ))) return;
+        if (!(win = create_window( parent, owner ))) return;
+        req->handle = win->handle;
+    }
 }
 
 
@@ -123,19 +170,14 @@
 {
     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 (!(win = get_window( req->handle ))) return;
+    if (req->parent && !(parent = get_window( req->parent ))) 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;
+            previous = parent->last_child;
+        else
+            if (!(previous = get_window( req->previous ))) return;
 
         if (previous && previous->parent != parent)  /* previous must be a child of parent */
         {
@@ -150,26 +192,25 @@
 /* destroy a window */
 DECL_HANDLER(destroy_window)
 {
-    struct window *win = get_user_object( req->handle, USER_WINDOW );
+    struct window *win = get_window( req->handle );
     if (win)
     {
-        if (win != top_window) free_window( win );
+        if (win != top_window) destroy_window( win );
         else set_error( STATUS_ACCESS_DENIED );
     }
 }
 
 
-/* Get information from a window handle */
+/* 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 );
+    struct window *win = get_window( req->handle );
 
     req->full_handle = 0;
     req->tid = req->pid = 0;
     if (win)
     {
-        req->full_handle = handle;
+        req->full_handle = win->handle;
         if (win->thread)
         {
             req->tid = get_thread_id( win->thread );
@@ -177,3 +218,77 @@
         }
     }
 }
+
+
+/* get a list of the window parents, up to the root of the tree */
+DECL_HANDLER(get_window_parents)
+{
+    struct window *ptr, *win = get_window( req->handle );
+    int total = 0;
+    size_t len;
+
+    if (win) for (ptr = win->parent; ptr; ptr = ptr->parent) total++;
+
+    req->count = total;
+    len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
+    set_req_data_size( req, len );
+    if (len)
+    {
+        user_handle_t *data = get_req_data(req);
+        for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data))
+            *data++ = ptr->handle;
+    }
+}
+
+
+/* get a list of the window children */
+DECL_HANDLER(get_window_children)
+{
+    struct window *ptr, *parent = get_window( req->parent );
+    int total = 0;
+    size_t len;
+
+    if (parent)
+        for (ptr = parent->first_child, total = 0; ptr; ptr = ptr->next) total++;
+
+    req->count = total;
+    len = min( get_req_data_size(req), total * sizeof(user_handle_t) );
+    set_req_data_size( req, len );
+    if (len)
+    {
+        user_handle_t *data = get_req_data(req);
+        for (ptr = parent->first_child; ptr && len; ptr = ptr->next, len -= sizeof(*data))
+            *data++ = ptr->handle;
+    }
+}
+
+
+/* get window tree information from a window handle */
+DECL_HANDLER(get_window_tree)
+{
+    struct window *win = get_window( req->handle );
+
+    if (!win) return;
+
+    if (win->parent)
+    {
+        struct window *parent = win->parent;
+        req->parent        = parent->handle;
+        req->owner         = win->owner ? win->owner->handle : 0;
+        req->next_sibling  = win->next ? win->next->handle : 0;
+        req->prev_sibling  = win->prev ? win->prev->handle : 0;
+        req->first_sibling = parent->first_child ? parent->first_child->handle : 0;
+        req->last_sibling  = parent->last_child ? parent->last_child->handle : 0;
+    }
+    else
+    {
+        req->parent        = 0;
+        req->owner         = 0;
+        req->next_sibling  = 0;
+        req->prev_sibling  = 0;
+        req->first_sibling = 0;
+        req->last_sibling  = 0;
+    }
+    req->first_child = win->first_child ? win->first_child->handle : 0;
+    req->last_child  = win->last_child ? win->last_child->handle : 0;
+}
diff --git a/windows/win.c b/windows/win.c
index 2ca2f77..a587cae 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -75,7 +75,7 @@
  *
  * Create a window handle with the server.
  */
-static WND *create_window_handle( BOOL desktop, INT size )
+static WND *create_window_handle( HWND parent, HWND owner, INT size )
 {
     BOOL res;
     user_handle_t handle = 0;
@@ -85,22 +85,13 @@
 
     USER_Lock();
 
-    if (desktop)
+    SERVER_START_REQ( create_window )
     {
-        SERVER_START_REQ( create_desktop_window )
-        {
-            if ((res = !SERVER_CALL_ERR())) handle = req->handle;
-        }
-        SERVER_END_REQ;
+        req->parent = parent;
+        req->owner = owner;
+        if ((res = !SERVER_CALL_ERR())) handle = req->handle;
     }
-    else
-    {
-        SERVER_START_REQ( create_window )
-        {
-            if ((res = !SERVER_CALL_ERR())) handle = req->handle;
-        }
-        SERVER_END_REQ;
-    }
+    SERVER_END_REQ;
 
     if (!res)
     {
@@ -542,7 +533,7 @@
                                    &wndExtra, &winproc, &clsStyle, &dce )))
         return FALSE;
 
-    pWndDesktop = create_window_handle( TRUE, sizeof(WND) + wndExtra );
+    pWndDesktop = create_window_handle( 0, 0, sizeof(WND) + wndExtra );
     if (!pWndDesktop) return FALSE;
     hwndDesktop = pWndDesktop->hwndSelf;
 
@@ -675,7 +666,7 @@
     INT sw = SW_SHOW;
     struct tagCLASS *classPtr;
     WND *wndPtr;
-    HWND hwnd, hwndLinkAfter;
+    HWND hwnd, hwndLinkAfter, parent, owner;
     POINT maxSize, maxPos, minTrack, maxTrack;
     INT wndExtra;
     DWORD clsStyle;
@@ -694,6 +685,8 @@
 
     /* Find the parent window */
 
+    parent = GetDesktopWindow();
+    owner = 0;
     if (cs->hwndParent)
     {
 	/* Make sure parent is valid */
@@ -702,7 +695,11 @@
             WARN("Bad parent %04x\n", cs->hwndParent );
 	    return 0;
 	}
-    } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
+        if (cs->style & WS_CHILD) parent = cs->hwndParent;
+        else owner = GetAncestor( cs->hwndParent, GA_ROOT );
+    }
+    else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
+    {
         WARN("No parent for child window\n" );
         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
     }
@@ -738,7 +735,7 @@
 
     /* Create the window structure */
 
-    if (!(wndPtr = create_window_handle( FALSE,
+    if (!(wndPtr = create_window_handle( parent, owner,
                                          sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
     {
 	TRACE("out of memory\n" );
@@ -751,22 +748,9 @@
     wndPtr->tid   = GetCurrentThreadId();
     wndPtr->next  = NULL;
     wndPtr->child = NULL;
-
-    if ((cs->style & WS_CHILD) && cs->hwndParent)
-    {
-        wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
-        wndPtr->owner  = 0;
-        WIN_ReleaseWndPtr(wndPtr->parent);
-    }
-    else
-    {
-        wndPtr->parent = pWndDesktop;
-        if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
-            wndPtr->owner = 0;
-        else
-            wndPtr->owner = GetAncestor( cs->hwndParent, GA_ROOT );
-    }
-
+    wndPtr->owner = owner;
+    wndPtr->parent = WIN_FindWndPtr( parent );
+    WIN_ReleaseWndPtr(wndPtr->parent);
 
     wndPtr->class          = classPtr;
     wndPtr->winproc        = winproc;
@@ -916,7 +900,7 @@
 
     /* Call WH_SHELL hook */
 
-    if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
+    if (!(wndPtr->dwStyle & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
 
     TRACE("created window %04x\n", hwnd);
@@ -1186,7 +1170,7 @@
     if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
 
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
-    if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
+    if (!(wndPtr->dwStyle & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
     {
         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
         /* FIXME: clean up palette - see "Internals" p.352 */
@@ -1210,20 +1194,19 @@
 
       /* Hide the window */
 
-    if (wndPtr->dwStyle & WS_VISIBLE)
+    ShowWindow( hwnd, SW_HIDE );
+    if (!IsWindow(hwnd))
     {
-        ShowWindow( hwnd, SW_HIDE );
-        if (!IsWindow(hwnd))
-        {
-            retvalue = TRUE;
-            goto end;
-        }
+        retvalue = TRUE;
+        goto end;
     }
 
       /* Recursively destroy owned windows */
 
     if( !(wndPtr->dwStyle & WS_CHILD) )
     {
+        HWND owner;
+
       for (;;)
       {
           int i, got_one = 0;
@@ -1232,19 +1215,17 @@
           {
               for (i = 0; list[i]; i++)
               {
-                  WND *siblingPtr = WIN_FindWndPtr( list[i] );
-                  if (!siblingPtr) continue;
-                  if (siblingPtr->owner == hwnd)
+                  WND *siblingPtr;
+                  if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
+                  if (!(siblingPtr = WIN_FindWndPtr( list[i] ))) continue;
+                  if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
                   {
-                      if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
-                      {
-                          WIN_ReleaseWndPtr( siblingPtr );
-                          DestroyWindow( list[i] );
-                          got_one = 1;
-                          continue;
-                      }
-                      else siblingPtr->owner = 0;
+                      WIN_ReleaseWndPtr( siblingPtr );
+                      DestroyWindow( list[i] );
+                      got_one = 1;
+                      continue;
                   }
+                  else siblingPtr->owner = 0;
                   WIN_ReleaseWndPtr( siblingPtr );
               }
               HeapFree( GetProcessHeap(), 0, list );
@@ -1252,13 +1233,16 @@
           if (!got_one) break;
       }
 
-      WINPOS_ActivateOtherWindow(wndPtr->hwndSelf);
+      WINPOS_ActivateOtherWindow( hwnd );
 
-      if (wndPtr->owner)
+      if ((owner = GetWindow( hwnd, GW_OWNER )))
       {
-          WND *owner = WIN_FindWndPtr( wndPtr->owner );
-          if (owner->hwndLastActive == hwnd) owner->hwndLastActive = wndPtr->owner;
-          WIN_ReleaseWndPtr( owner );
+          WND *ptr = WIN_FindWndPtr( owner );
+          if (ptr)
+          {
+              if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
+              WIN_ReleaseWndPtr( ptr );
+          }
       }
     }
 
@@ -2219,72 +2203,45 @@
 /*******************************************************************
  *		GetWindow (USER32.@)
  */
-HWND WINAPI GetWindow( HWND hwnd, WORD rel )
+HWND WINAPI GetWindow( HWND hwnd, UINT rel )
 {
-    HWND retval;
+    HWND retval = 0;
 
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return 0;
-    hwnd = wndPtr->hwndSelf;  /* make it a full handle */
-
-    switch(rel)
+    if (rel == GW_OWNER)  /* special case: not fully supported in the server yet */
     {
-    case GW_HWNDFIRST:
-	retval = wndPtr->parent ? wndPtr->parent->child->hwndSelf : 0;
-        goto end;
-
-    case GW_HWNDLAST:
-        if (!wndPtr->parent)
-        {
-            retval = 0;  /* Desktop window */
-            goto end;
-        }
-        while (wndPtr->next)
-        {
-            WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
-        }
-        retval = wndPtr->hwndSelf;
-        goto end;
-
-    case GW_HWNDNEXT:
-	retval = wndPtr->next ? wndPtr->next->hwndSelf : 0;
-        goto end;
-
-    case GW_HWNDPREV:
-        if (!wndPtr->parent)
-        {
-            retval = 0;  /* Desktop window */
-            goto end;
-        }
-        WIN_UpdateWndPtr(&wndPtr,wndPtr->parent->child); /* First sibling */
-        if (wndPtr->hwndSelf == hwnd)
-        {
-            retval = 0;  /* First in list */
-            goto end;
-        }
-        while (wndPtr->next)
-        {
-            if (wndPtr->next->hwndSelf == hwnd)
-            {
-                retval = wndPtr->hwndSelf;
-                goto end;
-            }
-            WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
-        }
-        retval = 0;
-        goto end;
-
-    case GW_OWNER:
+        WND *wndPtr = WIN_FindWndPtr( hwnd );
+        if (!wndPtr) return 0;
         retval = wndPtr->owner;
-        goto end;
-
-    case GW_CHILD:
-        retval = wndPtr->child ? wndPtr->child->hwndSelf : 0;
-        goto end;
+        WIN_ReleaseWndPtr( wndPtr );
+        return retval;
     }
-    retval = 0;
-end:
-    WIN_ReleaseWndPtr(wndPtr);
+
+    SERVER_START_REQ( get_window_tree )
+    {
+        req->handle = hwnd;
+        if (!SERVER_CALL_ERR())
+        {
+            switch(rel)
+            {
+            case GW_HWNDFIRST:
+                retval = req->first_sibling;
+                break;
+            case GW_HWNDLAST:
+                retval = req->last_sibling;
+                break;
+            case GW_HWNDNEXT:
+                retval = req->next_sibling;
+                break;
+            case GW_HWNDPREV:
+                retval = req->prev_sibling;
+                break;
+            case GW_CHILD:
+                retval = req->first_child;
+                break;
+            }
+        }
+    }
+    SERVER_END_REQ;
     return retval;
 }
 
@@ -2428,36 +2385,23 @@
  */
 HWND *WIN_ListParents( HWND hwnd )
 {
-    WND *parent, *wndPtr = WIN_FindWndPtr( hwnd );
     HWND *list = NULL;
-    UINT i, count = 0;
 
-    /* First count the windows */
-
-    if (!wndPtr) return NULL;
-
-    parent = wndPtr->parent;
-    while (parent && parent->hwndSelf != GetDesktopWindow())
+    SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
     {
-        count++;
-        parent = parent->parent;
-    }
-
-    if (count)
-    {
-        if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1) )))
+        req->handle = hwnd;
+        if (!SERVER_CALL())
         {
-            parent = wndPtr->parent;
-            for (i = 0; i < count; i++)
+            user_handle_t *data = server_data_ptr(req);
+            int i, count = server_data_size(req) / sizeof(*data);
+            if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
             {
-                list[i] = parent->hwndSelf;
-                parent = parent->parent;
+                for (i = 0; i < count; i++) list[i] = data[i];
+                list[i] = 0;
             }
-            list[i] = 0;
         }
     }
-
-    WIN_ReleaseWndPtr( wndPtr );
+    SERVER_END_VAR_REQ;
     return list;
 }
 
@@ -2470,39 +2414,23 @@
  */
 HWND *WIN_ListChildren( HWND hwnd )
 {
-    WND *pWnd, *wndPtr = WIN_FindWndPtr( hwnd );
-    HWND *list, *phwnd;
-    UINT count = 0;
+    HWND *list = NULL;
 
-    /* First count the windows */
-
-    if (!wndPtr) return NULL;
-
-    pWnd = WIN_LockWndPtr(wndPtr->child);
-    while (pWnd)
+    SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE )
     {
-        count++;
-        WIN_UpdateWndPtr(&pWnd,pWnd->next);
+        req->parent = hwnd;
+        if (!SERVER_CALL())
+        {
+            user_handle_t *data = server_data_ptr(req);
+            int i, count = server_data_size(req) / sizeof(*data);
+            if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
+            {
+                for (i = 0; i < count; i++) list[i] = data[i];
+                list[i] = 0;
+            }
+        }
     }
-
-    if( count )
-    {
-	/* Now build the list of all windows */
-
-	if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1))))
-	{
-	    for (pWnd = WIN_LockWndPtr(wndPtr->child), phwnd = list, count = 0; pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
-	    {
-                *phwnd++ = pWnd->hwndSelf;
-                count++;
-	    }
-            WIN_ReleaseWndPtr(pWnd);
-            *phwnd = 0;
-	}
-	else count = 0;
-    } else list = NULL;
-
-    WIN_ReleaseWndPtr( wndPtr );
+    SERVER_END_VAR_REQ;
     return list;
 }