From 37a4639ee1f25440954ce350746fdbe366c38c85 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Wed, 12 Sep 2001 17:19:13 +0000
Subject: [PATCH] Make sure that functions returning an HWND always return a
 full 32-bit handle.

---
 dlls/user/message.c |  4 +-
 include/win.h       | 13 ++++++-
 windows/clipboard.c | 19 ++++------
 windows/dce.c       | 38 +++++++++----------
 windows/dialog.c    |  5 +++
 windows/focus.c     |  1 +
 windows/input.c     |  2 +-
 windows/win.c       | 90 ++++++++++++++++++++++++++++-----------------
 windows/winpos.c    |  7 +++-
 9 files changed, 108 insertions(+), 71 deletions(-)

diff --git a/dlls/user/message.c b/dlls/user/message.c
index fe8e1b09dd4..57c9c16ac4d 100644
--- a/dlls/user/message.c
+++ b/dlls/user/message.c
@@ -1091,7 +1091,7 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar
         cwp.lParam  = lparam;
         cwp.wParam  = wparam;
         cwp.message = msg;
-        cwp.hwnd    = hwnd;
+        cwp.hwnd    = WIN_GetFullHandle( hwnd );
         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
         else HOOK_CallHooksA( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
         lparam = cwp.lParam;
@@ -1120,7 +1120,7 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar
         cwp.lParam  = lparam;
         cwp.wParam  = wparam;
         cwp.message = msg;
-        cwp.hwnd    = hwnd;
+        cwp.hwnd    = WIN_GetFullHandle( hwnd );
         if (unicode) HOOK_CallHooksW( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
         else HOOK_CallHooksA( WH_CALLWNDPROCRET, HC_ACTION, 1, (LPARAM)&cwp );
     }
diff --git a/include/win.h b/include/win.h
index 2f20cbce5c3..cf56178110c 100644
--- a/include/win.h
+++ b/include/win.h
@@ -85,7 +85,7 @@ extern WND*   WIN_FindWndPtr( HWND hwnd );
 extern WND*   WIN_LockWndPtr(WND *wndPtr);
 extern void   WIN_ReleaseWndPtr(WND *wndPtr);
 extern void   WIN_UpdateWndPtr(WND **oldPtr,WND *newPtr);
-extern HWND WIN_GetFullHandle( HWND hwnd );
+extern HWND WIN_Handle32( HWND16 hwnd16 );
 extern void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter );
 extern void WIN_UnlinkWindow( HWND hwnd );
 extern HWND WIN_FindWinToRepaint( HWND hwnd );
@@ -96,6 +96,17 @@ extern HWND *WIN_ListParents( HWND hwnd );
 extern HWND *WIN_ListChildren( HWND hwnd );
 extern BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly );
 
+inline static HWND WIN_GetFullHandle( HWND hwnd )
+{
+    if (!HIWORD(hwnd) && hwnd) hwnd = WIN_Handle32( LOWORD(hwnd) );
+    return hwnd;
+}
+
+inline static HWND16 WIN_Handle16( HWND hwnd )
+{
+    return LOWORD(hwnd);
+}
+
 extern HWND CARET_GetHwnd(void);
 extern void CARET_GetRect(LPRECT lprc);  /* windows/caret.c */
 
diff --git a/windows/clipboard.c b/windows/clipboard.c
index 9a2d1e36d51..422d71f02d5 100644
--- a/windows/clipboard.c
+++ b/windows/clipboard.c
@@ -12,9 +12,6 @@
  * The internal implementation talks to a "clipboard driver" to fill or
  * expose the cache to the native device. (Currently only the X11 and
  * TTY clipboard  driver are available)
- *
- * TODO: 
- *
  */
 
 #include <stdlib.h>
@@ -31,6 +28,7 @@
 #include "wine/winbase16.h"
 #include "heap.h"
 #include "user.h"
+#include "win.h"
 #include "clipboard.h"
 #include "debugtools.h"
 
@@ -45,10 +43,10 @@ DEFAULT_DEBUG_CHANNEL(clipboard);
 static HANDLE hClipLock   = 0;
 static BOOL bCBHasChanged  = FALSE;
 
-HWND hWndClipWindow = 0;          /* window that last opened clipboard */
-HWND hWndClipOwner  = 0;          /* current clipboard owner */
-HANDLE16 hTaskClipOwner = 0;      /* clipboard owner's task  */
-static HWND hWndViewer     = 0;   /* start of viewers chain */
+static HWND hWndClipWindow;        /* window that last opened clipboard */
+static HWND hWndClipOwner;         /* current clipboard owner */
+static HANDLE16 hTaskClipOwner;    /* clipboard owner's task  */
+static HWND hWndViewer;            /* start of viewers chain */
 
 static WORD LastRegFormat = CF_REGFORMATBASE;
 
@@ -737,7 +735,7 @@ BOOL WINAPI OpenClipboard( HWND hWnd )
         hClipLock = GetCurrentTask();
 
         /* Save current user of the clipboard */
-        hWndClipWindow = hWnd;
+        hWndClipWindow = WIN_GetFullHandle( hWnd );
         bCBHasChanged = FALSE;
         bRet = TRUE;
     }
@@ -1320,7 +1318,7 @@ HWND WINAPI SetClipboardViewer( HWND hWnd )
 
     TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
 
-    hWndViewer = hWnd;
+    hWndViewer = WIN_GetFullHandle( hWnd );
     return hwndPrev;
 }
 
@@ -1368,7 +1366,7 @@ BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
     else
 	WARN("hWndViewer is lost\n");
 
-    if( hWnd == hWndViewer ) hWndViewer = hWndNext;
+    if( hWnd == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
 
     return bRet;
 }
@@ -1474,4 +1472,3 @@ DWORD WINAPI GetClipboardSequenceNumber(VOID)
 	/* FIXME: Use serial numbers */
 	return 0;
 }
-
diff --git a/windows/dce.c b/windows/dce.c
index d20645876cd..2065cb3db94 100644
--- a/windows/dce.c
+++ b/windows/dce.c
@@ -70,7 +70,6 @@ DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
 {
     FARPROC16 hookProc;
     DCE * dce;
-    WND* wnd;
     
     if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(DCE) ))) return NULL;
     if (!(dce->hDC = CreateDCA( "DISPLAY", NULL, NULL, NULL )))
@@ -80,32 +79,31 @@ DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
     }
     if (!defaultDCstate) defaultDCstate = GetDCState16( dce->hDC );
 
-    wnd = WIN_FindWndPtr(hWnd);
-    
     /* store DCE handle in DC hook data field */
 
     hookProc = GetProcAddress16( GetModuleHandle16("USER"), (LPCSTR)362 );
     SetDCHook( dce->hDC, hookProc, (DWORD)dce );
 
-    dce->hwndCurrent = hWnd;
+    dce->hwndCurrent = WIN_GetFullHandle( hWnd );
     dce->hClipRgn    = 0;
-    dce->next        = firstDCE;
-    firstDCE = dce;
 
     if( type != DCE_CACHE_DC ) /* owned or class DC */
     {
 	dce->DCXflags = DCX_DCEBUSY;
 	if( hWnd )
 	{
-	    if( wnd->dwStyle & WS_CLIPCHILDREN ) dce->DCXflags |= DCX_CLIPCHILDREN;
-	    if( wnd->dwStyle & WS_CLIPSIBLINGS ) dce->DCXflags |= DCX_CLIPSIBLINGS;
+            LONG style = GetWindowLongW( hWnd, GWL_STYLE );
+            if (style & WS_CLIPCHILDREN) dce->DCXflags |= DCX_CLIPCHILDREN;
+            if (style & WS_CLIPSIBLINGS) dce->DCXflags |= DCX_CLIPSIBLINGS;
 	}
 	SetHookFlags16(dce->hDC,DCHF_INVALIDATEVISRGN);
     }
     else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY;
-
-    WIN_ReleaseWndPtr(wnd);
     
+    USER_Lock();
+    dce->next = firstDCE;
+    firstDCE = dce;
+    USER_Unlock();
     return dce;
 }
 
@@ -115,7 +113,7 @@ DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
  */
 DCE* DCE_FreeDCE( DCE *dce )
 {
-    DCE **ppDCE;
+    DCE **ppDCE, *ret;
 
     if (!dce) return NULL;
 
@@ -125,6 +123,8 @@ DCE* DCE_FreeDCE( DCE *dce )
 
     while (*ppDCE && (*ppDCE != dce)) ppDCE = &(*ppDCE)->next;
     if (*ppDCE == dce) *ppDCE = dce->next;
+    ret = *ppDCE;
+    USER_Unlock();
 
     SetDCHook(dce->hDC, NULL, 0L);
 
@@ -133,9 +133,7 @@ DCE* DCE_FreeDCE( DCE *dce )
 	DeleteObject(dce->hClipRgn);
     HeapFree( GetProcessHeap(), 0, dce );
 
-    USER_Unlock();
-    
-    return *ppDCE;
+    return ret;
 }
 
 /***********************************************************************
@@ -146,22 +144,21 @@ DCE* DCE_FreeDCE( DCE *dce )
 void DCE_FreeWindowDCE( HWND hwnd )
 {
     DCE *pDCE;
+    WND *pWnd = WIN_FindWndPtr( hwnd );
 
-    USER_Lock();
     pDCE = firstDCE;
+    hwnd = pWnd->hwndSelf;  /* make it a full handle */
 
     while( pDCE )
     {
 	if( pDCE->hwndCurrent == hwnd )
 	{
-            WND *pWnd = WIN_FindWndPtr( hwnd );
 	    if( pDCE == pWnd->dce ) /* owned or Class DCE*/
 	    {
                 if (pWnd->clsStyle & CS_OWNDC)	/* owned DCE*/
 		{
                     pDCE = DCE_FreeDCE( pDCE );
                     pWnd->dce = NULL;
-                    WIN_ReleaseWndPtr( pWnd );
                     continue;
                 }
 		else if( pDCE->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN) )	/* Class DCE*/
@@ -181,8 +178,7 @@ void DCE_FreeWindowDCE( HWND hwnd )
                      * We should change this to WARN when Wine is more stable
                      * (for 1.0?).
                      */
-		    ERR("[%04x] GetDC() without ReleaseDC()!\n", 
-			pWnd->hwndSelf);
+		    ERR("[%08x] GetDC() without ReleaseDC()!\n",hwnd);
 		    DCE_ReleaseDC( pDCE );
 		}
 
@@ -190,12 +186,11 @@ void DCE_FreeWindowDCE( HWND hwnd )
 		pDCE->DCXflags |= DCX_DCEEMPTY;
 		pDCE->hwndCurrent = 0;
 	    }
-            WIN_ReleaseWndPtr( pWnd );
 	}
 	pDCE = pDCE->next;
     }
     
-    USER_Unlock();
+    WIN_ReleaseWndPtr( pWnd );
 }
 
 
@@ -403,6 +398,7 @@ HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
 
     if (!hwnd) hwnd = GetDesktopWindow();
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
+    hwnd = wndPtr->hwndSelf;  /* make it a full handle */
 
     /* fixup flags */
 
diff --git a/windows/dialog.c b/windows/dialog.c
index ca15e7faca4..b9501721e76 100644
--- a/windows/dialog.c
+++ b/windows/dialog.c
@@ -1953,6 +1953,9 @@ HWND WINAPI GetNextDlgGroupItem( HWND hwndDlg, HWND hwndCtrl,
 {
     HWND hwnd, retvalue;
 
+    hwndDlg = WIN_GetFullHandle( hwndDlg );
+    hwndCtrl = WIN_GetFullHandle( hwndCtrl );
+
     if(hwndCtrl)
     {
         /* if the hwndCtrl is the child of the control in the hwndDlg,
@@ -2108,6 +2111,8 @@ static HWND DIALOG_GetNextTabItem( HWND hwndMain, HWND hwndDlg, HWND hwndCtrl, B
 HWND WINAPI GetNextDlgTabItem( HWND hwndDlg, HWND hwndCtrl,
                                    BOOL fPrevious )
 {
+    hwndDlg = WIN_GetFullHandle( hwndDlg );
+    hwndCtrl = WIN_GetFullHandle( hwndCtrl );
     return DIALOG_GetNextTabItem(hwndDlg,hwndDlg,hwndCtrl,fPrevious); 
 }
 
diff --git a/windows/focus.c b/windows/focus.c
index 57582d5cd96..175d39da07e 100644
--- a/windows/focus.c
+++ b/windows/focus.c
@@ -74,6 +74,7 @@ HWND WINAPI SetFocus( HWND hwnd )
         /* Check if we can set the focus to this window */
         WND *wndPtr;
 
+        hwnd = WIN_GetFullHandle( hwnd );
         for (;;)
         {
             HWND parent;
diff --git a/windows/input.c b/windows/input.c
index f371e6161b3..018e669a63a 100644
--- a/windows/input.c
+++ b/windows/input.c
@@ -493,7 +493,7 @@ HWND EVENT_Capture(HWND hwnd, INT16 ht)
         if (wndPtr)
         {
             TRACE_(win)("(0x%04x)\n", hwnd );
-            captureWnd   = hwnd;
+            captureWnd   = wndPtr->hwndSelf;
             captureHT    = ht;
         }
     }
diff --git a/windows/win.c b/windows/win.c
index 6869cda074e..aa6162f0c44 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -147,17 +147,50 @@ static WND *free_window_handle( HWND hwnd )
 
 
 /***********************************************************************
- *           WIN_GetFullHandle
+ *           get_wnd_ptr
  *
- * Get the full 32-bit window handle from a possibly truncated handle.
+ * Return a pointer to the WND structure if local to the process.
+ * If ret value is non-NULL, the user lock is held.
  */
-HWND WIN_GetFullHandle( HWND hwnd )
+static WND *get_wnd_ptr( HWND hwnd )
 {
-    if (!HIWORD(hwnd))
+    WND * ptr;
+
+    if (!hwnd) return NULL;
+
+    USER_Lock();
+    if ((ptr = user_handles[LOWORD(hwnd)]))
+    {
+        if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
+            return ptr;
+    }
+    USER_Unlock();
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           WIN_Handle32
+ *
+ * Convert a 16-bit window handle to a full 32-bit handle.
+ */
+HWND WIN_Handle32( HWND16 hwnd16 )
+{
+    WND *ptr;
+    HWND hwnd = (HWND)hwnd16;
+
+    if (!hwnd || hwnd == HWND_BROADCAST) return hwnd;
+
+    if ((ptr = get_wnd_ptr( hwnd )))
+    {
+        hwnd = ptr->hwndSelf;
+        USER_Unlock();
+    }
+    else  /* may belong to another process */
     {
         SERVER_START_REQ( get_window_info )
         {
-            req->handle = hwnd;
+            req->handle = (user_handle_t)hwnd16;
             if (!SERVER_CALL_ERR()) hwnd = req->full_handle;
         }
         SERVER_END_REQ;
@@ -177,27 +210,19 @@ WND * WIN_FindWndPtr( HWND hwnd )
 
     if (!hwnd) return NULL;
 
-    USER_Lock();
-    if (!(ptr = user_handles[LOWORD(hwnd)]))
+    if ((ptr = get_wnd_ptr( hwnd )))
     {
-        /* check other processes */
-        if (IsWindow( hwnd ))
-        {
-            ERR( "window %04x belongs to other process\n", hwnd );
-            /* DbgBreakPoint(); */
-        }
-        goto error;
+        /* increment destruction monitoring */
+        ptr->irefCount++;
+        return ptr;
     }
-    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();
+    /* check other processes */
+    if (IsWindow( hwnd ))
+    {
+        ERR( "window %04x belongs to other process\n", hwnd );
+        /* DbgBreakPoint(); */
+    }
     SetLastError( ERROR_INVALID_WINDOW_HANDLE );
     return NULL;
 }
@@ -2078,24 +2103,24 @@ BOOL16 WINAPI IsWindow16( HWND16 hwnd )
 BOOL WINAPI IsWindow( HWND hwnd )
 {
     WND *ptr;
-    BOOL ret = FALSE;
+    BOOL ret;
 
     USER_Lock();
     if ((ptr = user_handles[LOWORD(hwnd)]))
     {
         ret = ((ptr->dwMagic == WND_MAGIC) && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf));
+        USER_Unlock();
+        return ret;
     }
     USER_Unlock();
 
-    if (!ret)  /* check other processes */
+    /* check other processes */
+    SERVER_START_REQ( get_window_info )
     {
-        SERVER_START_REQ( get_window_info )
-        {
-            req->handle = hwnd;
-            ret = !SERVER_CALL_ERR();
-        }
-        SERVER_END_REQ;
+        req->handle = hwnd;
+        ret = !SERVER_CALL_ERR();
     }
+    SERVER_END_REQ;
     return ret;
 }
 
@@ -2601,9 +2626,8 @@ HWND WINAPI GetLastActivePopup( HWND hwnd )
     WND *wndPtr =WIN_FindWndPtr(hwnd);
     if (!wndPtr) return hwnd;
     retval = wndPtr->hwndLastActive;
+    if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
     WIN_ReleaseWndPtr(wndPtr);
-    if ((retval != hwnd) && (!IsWindow(retval)))
-       retval = hwnd;
     return retval;
 }
 
diff --git a/windows/winpos.c b/windows/winpos.c
index 8a9be5e2843..843864a587f 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -374,6 +374,7 @@ HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
 
     if (!hwndScope) hwndScope = GetDesktopWindow();
     if (!(wndScope = WIN_FindWndPtr( hwndScope ))) return 0;
+    hwndScope = wndScope->hwndSelf;  /* make it a full handle */
 
     *hittest = HTERROR;
     wndPtr = WIN_LockWndPtr(wndScope->child);
@@ -892,7 +893,7 @@ HWND16 WINAPI GetShellWindow16(void)
 HWND WINAPI SetShellWindow(HWND hwndshell)
 {   WARN("(hWnd=%08x) semi stub\n",hwndshell );
 
-    hGlobalShellWindow = hwndshell;
+    hGlobalShellWindow = WIN_GetFullHandle( hwndshell );
     return hGlobalShellWindow;
 }
 
@@ -1423,6 +1424,9 @@ BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
             hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
     }
 
+    if ((wndPtr = WIN_FindWndPtr(hWnd)))
+        hWnd = wndPtr->hwndSelf;  /* make it a full handle */
+
     /* paranoid checks */
     if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
 	goto CLEANUP_END;
@@ -1430,7 +1434,6 @@ BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
 /*  if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
  *	return 0;
  */
-    wndPtr = WIN_FindWndPtr(hWnd);
     hOldActiveQueue = hActiveQueue;
 
     if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
-- 
GitLab