Added global management of user handles in the server.
Very preliminary support for shared window handles.

diff --git a/windows/win.c b/windows/win.c
index a8cc9ad..7985360 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 WORD wDragWidth = 4;
 static WORD wDragHeight= 3;
 
+static void *user_handles[65536];
+
 /* thread safeness */
 extern SYSLEVEL USER_SysLevel;  /* FIXME */
 
@@ -70,6 +73,80 @@
 }
 
 /***********************************************************************
+ *           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
  *
  * Return a pointer to the WND structure corresponding to a HWND.
@@ -77,34 +154,35 @@
 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 @@
      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 @@
  *
  * 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 @@
  * 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 @@
                                    &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 @@
     pWndDesktop->userdata          = 0;
     pWndDesktop->winproc           = winproc;
     pWndDesktop->cbWndExtra        = wndExtra;
-    pWndDesktop->irefCount         = 0;
 
     cs.lpCreateParams = NULL;
     cs.hInstance      = 0;
@@ -470,6 +551,7 @@
     if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
 
     pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
+    WIN_ReleaseWndPtr( pWndDesktop );
     return TRUE;
 }
 
@@ -613,15 +695,17 @@
 
     /* 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 @@
 
     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 @@
     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 @@
         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 @@
  */
 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 @@
 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 @@
 
     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 @@
 
     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;