From 1a66d226eb7cf8fcb050e2b6f20edee009781ae1 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Tue, 28 Aug 2001 18:44:52 +0000
Subject: [PATCH] Added global management of user handles in the server. Very
 preliminary support for shared window handles.

---
 dlls/ttydrv/wnd.c              |   4 +-
 dlls/x11drv/desktop.c          |   1 +
 dlls/x11drv/window.c           |   8 +-
 dlls/x11drv/winpos.c           |   4 +-
 include/win.h                  |   5 +-
 include/wine/server_protocol.h |  70 +++++-
 server/Makefile.in             |   4 +-
 server/protocol.def            |  52 ++++-
 server/queue.c                 |  20 +-
 server/request.h               |  10 +
 server/thread.c                |   2 +
 server/trace.c                 |  69 +++++-
 server/user.c                  | 149 +++++++++++++
 server/user.h                  |  36 ++++
 server/window.c                | 179 ++++++++++++++++
 tools/make_requests            |   1 +
 windows/queue.c                |  24 ---
 windows/win.c                  | 374 +++++++++++++++++++++------------
 18 files changed, 818 insertions(+), 194 deletions(-)
 create mode 100644 server/user.c
 create mode 100644 server/user.h
 create mode 100644 server/window.c

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 <assert.h>
+
+#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;
 
-- 
GitLab