From 592f98bcbacb1b31a7cef7a7f8000df59d81b9c3 Mon Sep 17 00:00:00 2001
From: Andrew Riedi <andrewriedi@gmail.com>
Date: Tue, 20 Jan 2009 00:38:49 -0800
Subject: [PATCH] user32: Create 32-bit cursor handles.

Based on a patch by Henri Verbeet.
---
 dlls/user32/cursoricon.c       |  236 +++++++++++++++++++++++++++++++++++-----
 dlls/user32/static.c           |   10 +-
 dlls/user32/tests/cursoricon.c |    2 +-
 dlls/user32/user16.c           |   43 ++++----
 dlls/user32/user_main.c        |    3 +
 dlls/user32/user_private.h     |    8 +-
 dlls/user32/wnd16.c            |   46 ++++++--
 7 files changed, 281 insertions(+), 67 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 478e0c6..3b531f5 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -6,6 +6,7 @@
  *           1997 Alex Korobka
  *           1998 Turchanov Sergey
  *           2007 Henri Verbeet
+ *           2009 Andrew Riedi
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -55,6 +56,8 @@
 #include "wine/winuser16.h"
 #include "wine/exception.h"
 #include "wine/debug.h"
+#include "wine/rbtree.h"
+#include "wine/server.h"
 #include "user_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
@@ -127,6 +130,167 @@ static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 static const WORD ICON_HOTSPOT = 0x4242;
 
+struct cursor_map_entry
+{
+    struct rb_entry     entry;
+    struct rb_entry     entry16;
+    HCURSOR             cursor;
+    HCURSOR16           cursor16;
+    /* Cache the cursor data since most calls to wineserver are unneeded. */
+    CURSORICONINFO     *data;
+};
+
+static struct rb_tree global_cursor_map;
+static struct rb_tree global_cursor_map16;
+
+static int cursor_compare(const void *key, const struct rb_entry *entry)
+{
+    const HCURSOR cursor = (HCURSOR) key;
+    const struct cursor_map_entry *map_entry = RB_ENTRY_VALUE(entry,
+        const struct cursor_map_entry, entry);
+
+    if (cursor < map_entry->cursor)
+        return -1;
+    else if (cursor > map_entry->cursor)
+        return 1;
+
+    return 0;
+}
+
+static int cursor_compare16(const void *key, const struct rb_entry *entry16)
+{
+    const HCURSOR16 cursor16 = (HCURSOR16)(ULONG) key;
+    const struct cursor_map_entry *map_entry = RB_ENTRY_VALUE(entry16,
+        const struct cursor_map_entry, entry16);
+
+    if (cursor16 < map_entry->cursor16)
+        return -1;
+    else if (cursor16 > map_entry->cursor16)
+        return 1;
+
+    return 0;
+}
+
+void CURSORICON_init(void)
+{
+    wine_rb_init(&global_cursor_map, cursor_compare);
+    wine_rb_init(&global_cursor_map16, cursor_compare16);
+}
+
+static void add_cursor_entry(HCURSOR16 cursor16, HCURSOR cursor,
+    CURSORICONINFO *data)
+{
+    struct cursor_map_entry *map_entry;
+
+    map_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct cursor_map_entry));
+    if (map_entry)
+    {
+        map_entry->cursor16 = cursor16;
+        map_entry->cursor = cursor;
+        map_entry->data = data;
+
+        wine_rb_put(&global_cursor_map, cursor, &map_entry->entry);
+        wine_rb_put(&global_cursor_map16, (void *)(ULONG) cursor16,
+            &map_entry->entry16);
+    }
+}
+
+static HCURSOR16 remove_cursor_entry(HCURSOR cursor)
+{
+    HCURSOR16 cursor16 = 0;
+
+    if (cursor)
+    {
+        struct rb_entry *entry = wine_rb_get(&global_cursor_map, cursor);
+        struct cursor_map_entry *map_entry = RB_ENTRY_VALUE(entry,
+            struct cursor_map_entry, entry);
+
+        if (entry)
+        {
+            cursor16 = map_entry->cursor16;
+
+            wine_rb_remove(&global_cursor_map, cursor);
+            wine_rb_remove(&global_cursor_map16, (void *)(ULONG) cursor16);
+
+            HeapFree(GetProcessHeap(), 0, map_entry->data);
+            HeapFree(GetProcessHeap(), 0, map_entry);
+        }
+
+    }
+
+    return cursor16;
+}
+
+HCURSOR16 get_cursor_handle16(HCURSOR cursor)
+{
+    if (cursor)
+    {
+        struct rb_entry *entry = wine_rb_get(&global_cursor_map, cursor);
+        struct cursor_map_entry *map_entry = RB_ENTRY_VALUE(entry,
+            struct cursor_map_entry, entry);
+
+        if (entry)
+            return map_entry->cursor16;
+    }
+
+    return 0;
+}
+
+HCURSOR get_cursor_handle(HCURSOR16 cursor16)
+{
+    if (cursor16)
+    {
+        struct rb_entry *entry16 = wine_rb_get(&global_cursor_map16,
+            (void *)(ULONG) cursor16);
+        struct cursor_map_entry *map_entry = RB_ENTRY_VALUE(entry16,
+            struct cursor_map_entry, entry16);
+
+        if (entry16)
+            return map_entry->cursor;
+    }
+
+    return 0;
+}
+
+static HCURSOR create_cursor(HCURSOR16 cursor16, CURSORICONINFO *cursor_data,
+    data_size_t cursor_size)
+{
+    HCURSOR cursor = 0;
+
+    SERVER_START_REQ(create_cursor)
+    {
+        wine_server_add_data(req, cursor_data, cursor_size);
+
+        if (!wine_server_call_err(req))
+            cursor = (HCURSOR) reply->handle;
+    }
+    SERVER_END_REQ;
+
+    /* FIXME: Make all calls to create_cursor() use HeapAlloc() for the
+     * cursor_data.  Once this is done, NULL can be changed to cursor_data. */
+    add_cursor_entry(cursor16, cursor, NULL);
+
+    return cursor;
+}
+
+static HCURSOR16 destroy_cursor(HCURSOR cursor)
+{
+    HCURSOR16 cursor16;
+
+    if (!cursor)
+        return 0;
+
+    SERVER_START_REQ(destroy_cursor)
+    {
+        req->handle = (user_handle_t) cursor;
+        wine_server_call(req);
+    }
+    SERVER_END_REQ;
+
+    cursor16 = remove_cursor_entry(cursor);
+
+    return GlobalFree16(cursor16);
+}
 
 /***********************************************************************
  *             map_fileW
@@ -463,7 +627,7 @@ void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
             ICONCACHE *freePtr = *ptr;
             *ptr = freePtr->next;
 
-            GlobalFree16(HICON_16(freePtr->hIcon));
+            destroy_cursor(freePtr->hIcon);
             HeapFree( GetProcessHeap(), 0, freePtr );
             continue;
         }
@@ -666,6 +830,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
 					   UINT cFlag )
 {
     HGLOBAL16 hObj;
+    HICON cursor = 0;
     static HDC hdcMem;
     int sizeAnd, sizeXor;
     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
@@ -837,15 +1002,19 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
         info->bBitsPerPixel = bmpXor.bmBitsPixel;
 
         /* Transfer the bitmap bits to the CURSORICONINFO structure */
-
         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
+
+        /* Make 32-bit cursor. */
+        cursor = create_cursor(hObj, info, GlobalSize16(hObj));
+
         GlobalUnlock16( hObj );
     }
 
     DeleteObject( hAndBits );
     DeleteObject( hXorBits );
-    return HICON_32(hObj);
+
+    return cursor;
 }
 
 
@@ -1225,10 +1394,11 @@ static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
  */
 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
 {
-    char *ptrOld, *ptrNew;
+    CURSORICONINFO *ptrOld, *ptrNew;
     int size;
-    HICON16 hOld = HICON_16(hIcon);
+    HICON16 hOld = get_cursor_handle16(hIcon);
     HICON16 hNew;
+    HICON cursor;
 
     if (!(ptrOld = GlobalLock16( hOld ))) return 0;
     if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
@@ -1237,9 +1407,13 @@ static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
     FarSetOwner16( hNew, hInst16 );
     ptrNew = GlobalLock16( hNew );
     memcpy( ptrNew, ptrOld, size );
+
+    cursor = create_cursor(hNew, ptrNew, size);
+
     GlobalUnlock16( hOld );
     GlobalUnlock16( hNew );
-    return HICON_32(hNew);
+
+    return cursor;
 }
 
 /*************************************************************************
@@ -1405,7 +1579,7 @@ HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
     info.bPlanes = 1;
     info.bBitsPerPixel = 1;
 
-    return HICON_32(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
+    return get_cursor_handle(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
 }
 
 
@@ -1491,7 +1665,8 @@ HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
                                            LPCVOID lpXORbits )
 {
     HGLOBAL16 handle;
-    char *ptr;
+    HCURSOR cursor;
+    CURSORICONINFO *ptr;
     int sizeAnd, sizeXor;
 
     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
@@ -1507,8 +1682,10 @@ HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
     memcpy( ptr, info, sizeof(*info) );
     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
+    cursor = create_cursor(handle, ptr, GlobalSize16(handle));
     GlobalUnlock16( handle );
-    return handle;
+
+    return get_cursor_handle16(cursor);
 }
 
 
@@ -1518,7 +1695,7 @@ HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
 {
     TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
-    return HICON_16(CURSORICON_Copy(hInstance, HICON_32(hIcon)));
+    return get_cursor_handle16(CURSORICON_Copy(hInstance, get_cursor_handle(hIcon)));
 }
 
 
@@ -1538,7 +1715,7 @@ HICON WINAPI CopyIcon( HICON hIcon )
 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
 {
     TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
-    return HICON_16(CURSORICON_Copy(hInstance, HCURSOR_32(hCursor)));
+    return get_cursor_handle16(CURSORICON_Copy(hInstance, get_cursor_handle(hCursor)));
 }
 
 /**********************************************************************
@@ -1552,12 +1729,13 @@ HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
 {
     WORD retv;
+    HCURSOR hCursor = get_cursor_handle(handle);
 
     TRACE_(icon)("(%04x, %04x)\n", handle, flags );
 
     /* Check whether destroying active cursor */
 
-    if ( get_user_thread_info()->cursor == HICON_32(handle) )
+    if (get_user_thread_info()->cursor == hCursor)
     {
         WARN_(cursor)("Destroying active cursor!\n" );
         return FALSE;
@@ -1567,7 +1745,7 @@ WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
 
     if ( !(flags & CID_NONSHARED) )
     {
-        INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
+        INT count = CURSORICON_DelSharedIcon(hCursor);
 
         if ( count != -1 )
             return (flags & CID_WIN32)? TRUE : (count == 0);
@@ -1577,7 +1755,7 @@ WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
 
     /* Now assume non-shared cursor/icon */
 
-    retv = GlobalFree16( handle );
+    retv = destroy_cursor(hCursor);
     return (flags & CID_RESOURCE)? retv : TRUE;
 }
 
@@ -1586,7 +1764,7 @@ WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
  */
 BOOL WINAPI DestroyIcon( HICON hIcon )
 {
-    return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
+    return DestroyIcon32(get_cursor_handle16(hIcon), CID_WIN32);
 }
 
 
@@ -1595,7 +1773,7 @@ BOOL WINAPI DestroyIcon( HICON hIcon )
  */
 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
 {
-    return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
+    return DestroyIcon32(get_cursor_handle16(hCursor), CID_WIN32);
 }
 
 
@@ -1611,7 +1789,7 @@ BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
 
     TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
 
-    if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
+    if (!(ptr = GlobalLock16(get_cursor_handle16(hIcon)))) return FALSE;
     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
     hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
                                (char *)(ptr+1) );
@@ -1632,7 +1810,7 @@ BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
     DeleteDC( hMemDC );
     if (hXorBits) DeleteObject( hXorBits );
     if (hAndBits) DeleteObject( hAndBits );
-    GlobalUnlock16(HICON_16(hIcon));
+    GlobalUnlock16(get_cursor_handle16(hIcon));
     SetTextColor( hdc, oldFg );
     SetBkColor( hdc, oldBg );
     return TRUE;
@@ -1677,8 +1855,8 @@ HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
     /* Change the cursor shape only if it is visible */
     if (thread_info->cursor_count >= 0)
     {
-        USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
-        GlobalUnlock16(HCURSOR_16(hCursor));
+        USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(get_cursor_handle16(hCursor)) );
+        GlobalUnlock16(get_cursor_handle16(hCursor));
     }
     return hOldCursor;
 }
@@ -1696,8 +1874,8 @@ INT WINAPI ShowCursor( BOOL bShow )
     {
         if (++thread_info->cursor_count == 0) /* Show it */
         {
-            USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
-            GlobalUnlock16(HCURSOR_16(thread_info->cursor));
+            USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(get_cursor_handle16(thread_info->cursor)));
+            GlobalUnlock16(get_cursor_handle16(thread_info->cursor));
         }
     }
     else
@@ -1861,7 +2039,7 @@ HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
 
     TRACE_(cursor)("hRes=%04x\n",hResource);
 
-    return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
+    return get_cursor_handle16(CreateIconFromResourceEx( bits, 0, TRUE,
                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
 }
 
@@ -1939,7 +2117,7 @@ BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
     CURSORICONINFO *ciconinfo;
     INT height;
 
-    ciconinfo = GlobalLock16(HICON_16(hIcon));
+    ciconinfo = GlobalLock16(get_cursor_handle16(hIcon));
     if (!ciconinfo)
         return FALSE;
 
@@ -1979,7 +2157,7 @@ BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
                                 1, 1, (char *)(ciconinfo + 1));
 
-    GlobalUnlock16(HICON_16(hIcon));
+    GlobalUnlock16(get_cursor_handle16(hIcon));
 
     return TRUE;
 }
@@ -1992,6 +2170,7 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
     DIBSECTION bmpXor;
     BITMAP bmpAnd;
     HICON16 hObj;
+    HCURSOR cursor = 0;
     int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
 
     TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
@@ -2135,9 +2314,10 @@ HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
                                dst_bits, &bminfo, DIB_RGB_COLORS );
             }
         }
+        cursor = create_cursor(hObj, info, GlobalSize16(hObj));
         GlobalUnlock16( hObj );
     }
-    return HICON_32(hObj);
+    return cursor;
 }
 
 /******************************************************************************
@@ -2165,7 +2345,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
                             INT cxWidth, INT cyWidth, UINT istep,
                             HBRUSH hbr, UINT flags )
 {
-    CURSORICONINFO *ptr = GlobalLock16(HICON_16(hIcon));
+    CURSORICONINFO *ptr = GlobalLock16(get_cursor_handle16(hIcon));
     HDC hDC_off = 0, hMemDC;
     BOOL result = FALSE, DoOffscreen;
     HBITMAP hB_off = 0, hOld = 0;
@@ -2276,7 +2456,7 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
     if (hMemDC) DeleteDC( hMemDC );
     if (hDC_off) DeleteDC(hDC_off);
     if (hB_off) DeleteObject(hB_off);
-    GlobalUnlock16(HICON_16(hIcon));
+    GlobalUnlock16(get_cursor_handle16(hIcon));
     return result;
 }
 
diff --git a/dlls/user32/static.c b/dlls/user32/static.c
index 5ee9db4..b243abe 100644
--- a/dlls/user32/static.c
+++ b/dlls/user32/static.c
@@ -151,7 +151,8 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
     CURSORICONINFO * info;
 
     if ((style & SS_TYPEMASK) != SS_ICON) return 0;
-    info = hicon?(CURSORICONINFO *) GlobalLock16(HICON_16(hicon)):NULL;
+    info = hicon ? (CURSORICONINFO *) GlobalLock16(get_cursor_handle16(hicon))
+        : NULL;
     if (hicon && !info) {
         WARN("hicon != 0, but info == 0\n");
         return 0;
@@ -174,7 +175,7 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
                           SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
         }
     }
-    if (info) GlobalUnlock16(HICON_16(hicon));
+    if (info) GlobalUnlock16(get_cursor_handle16(hicon));
     return prevIcon;
 }
 
@@ -805,7 +806,8 @@ static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
     GetClientRect( hwnd, &rc );
     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
     hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
-    info = hIcon ? (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)) : NULL;
+    info = hIcon ? (CURSORICONINFO *) GlobalLock16(get_cursor_handle16(hIcon))
+        : NULL;
     if (!hIcon || !info)
     {
         FillRect(hdc, &rc, hbrush);
@@ -825,7 +827,7 @@ static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
         DrawIconEx( hdc, iconRect.left, iconRect.top, hIcon, iconRect.right - iconRect.left,
                     iconRect.bottom - iconRect.top, 0, NULL, DI_NORMAL );
     }
-    if (info) GlobalUnlock16(HICON_16(hIcon));
+    if (info) GlobalUnlock16(get_cursor_handle16(hIcon));
 }
 
 static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 9475534..733058f 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -76,7 +76,7 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam, LPARA
             SetLastError(0xdeadbeef);
             ret = DestroyCursor((HCURSOR) lParam);
             error = GetLastError();
-            todo_wine ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
+            ok(!ret || broken(ret) /* win9x */, "DestroyCursor on the active cursor succeeded.\n");
             ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
                error == 0xdeadbeef,  /* vista */
                 "Last error: %u\n", error);
diff --git a/dlls/user32/user16.c b/dlls/user32/user16.c
index 85b7212..0890603 100644
--- a/dlls/user32/user16.c
+++ b/dlls/user32/user16.c
@@ -176,7 +176,7 @@ BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
  */
 HCURSOR16 WINAPI SetCursor16(HCURSOR16 hCursor)
 {
-  return HCURSOR_16(SetCursor(HCURSOR_32(hCursor)));
+    return get_cursor_handle16(SetCursor(get_cursor_handle(hCursor)));
 }
 
 
@@ -378,7 +378,7 @@ INT16 WINAPI FrameRect16( HDC16 hdc, const RECT16 *rect16, HBRUSH16 hbrush )
  */
 BOOL16 WINAPI DrawIcon16(HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon)
 {
-  return DrawIcon(HDC_32(hdc), x, y, HICON_32(hIcon));
+    return DrawIcon(HDC_32(hdc), x, y, get_cursor_handle(hIcon));
 }
 
 
@@ -591,7 +591,7 @@ BOOL16 WINAPI WinHelp16( HWND16 hWnd, LPCSTR lpHelpFile, UINT16 wCommand,
  */
 HCURSOR16 WINAPI LoadCursor16(HINSTANCE16 hInstance, LPCSTR name)
 {
-  return HCURSOR_16(LoadCursorA(HINSTANCE_32(hInstance), name));
+    return get_cursor_handle16(LoadCursorA(HINSTANCE_32(hInstance), name));
 }
 
 
@@ -600,7 +600,7 @@ HCURSOR16 WINAPI LoadCursor16(HINSTANCE16 hInstance, LPCSTR name)
  */
 HICON16 WINAPI LoadIcon16(HINSTANCE16 hInstance, LPCSTR name)
 {
-  return HICON_16(LoadIconA(HINSTANCE_32(hInstance), name));
+    return get_cursor_handle16(LoadIconA(HINSTANCE_32(hInstance), name));
 }
 
 /**********************************************************************
@@ -844,7 +844,7 @@ BOOL16 WINAPI ExitWindowsExec16( LPCSTR lpszExe, LPCSTR lpszParams )
  */
 HCURSOR16 WINAPI GetCursor16(void)
 {
-  return HCURSOR_16(GetCursor());
+    return get_cursor_handle16(GetCursor());
 }
 
 
@@ -1241,8 +1241,8 @@ HANDLE16 WINAPI LoadImage16(HINSTANCE16 hinst, LPCSTR name, UINT16 type,
 HICON16 WINAPI CopyImage16(HANDLE16 hnd, UINT16 type, INT16 desiredx,
 			   INT16 desiredy, UINT16 flags)
 {
-  return HICON_16(CopyImage(HANDLE_32(hnd), (UINT)type, (INT)desiredx,
-			    (INT)desiredy, (UINT)flags));
+    return get_cursor_handle16(CopyImage(HANDLE_32(hnd), (UINT) type,
+        (INT) desiredx, (INT) desiredy, (UINT) flags));
 }
 
 /**********************************************************************
@@ -1252,8 +1252,8 @@ BOOL16 WINAPI DrawIconEx16(HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
 			   INT16 cxWidth, INT16 cyWidth, UINT16 istep,
 			   HBRUSH16 hbr, UINT16 flags)
 {
-  return DrawIconEx(HDC_32(hdc), xLeft, yTop, HICON_32(hIcon), cxWidth, cyWidth,
-		    istep, HBRUSH_32(hbr), flags);
+    return DrawIconEx(HDC_32(hdc), xLeft, yTop, get_cursor_handle(hIcon),
+        cxWidth, cyWidth, istep, HBRUSH_32(hbr), flags);
 }
 
 /**********************************************************************
@@ -1261,15 +1261,16 @@ BOOL16 WINAPI DrawIconEx16(HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
  */
 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon, LPICONINFO16 iconinfo)
 {
-  ICONINFO ii32;
-  BOOL16 ret = GetIconInfo(HICON_32(hIcon), &ii32);
+    ICONINFO ii32;
+    BOOL16 ret = GetIconInfo(get_cursor_handle(hIcon), &ii32);
 
-  iconinfo->fIcon = ii32.fIcon;
-  iconinfo->xHotspot = ii32.xHotspot;
-  iconinfo->yHotspot = ii32.yHotspot;
-  iconinfo->hbmMask  = HBITMAP_16(ii32.hbmMask);
-  iconinfo->hbmColor = HBITMAP_16(ii32.hbmColor);
-  return ret;
+    iconinfo->fIcon = ii32.fIcon;
+    iconinfo->xHotspot = ii32.xHotspot;
+    iconinfo->yHotspot = ii32.yHotspot;
+    iconinfo->hbmMask  = HBITMAP_16(ii32.hbmMask);
+    iconinfo->hbmColor = HBITMAP_16(ii32.hbmColor);
+
+    return ret;
 }
 
 
@@ -1511,8 +1512,8 @@ HICON16 WINAPI CreateIconFromResourceEx16(LPBYTE bits, UINT16 cbSize,
 					  INT16 width, INT16 height,
 					  UINT16 cFlag)
 {
-  return HICON_16(CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
-					   width, height, cFlag));
+    return get_cursor_handle16(CreateIconFromResourceEx(bits, cbSize, bIcon,
+        dwVersion, width, height, cFlag));
 }
 
 
@@ -1628,7 +1629,7 @@ DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
         return 0L;
     }
 
-    if(hCursor) hOldCursor = SetCursor(HCURSOR_32(hCursor));
+    if(hCursor) hOldCursor = SetCursor(get_cursor_handle(hCursor));
 
     lpDragInfo->hWnd   = hWnd;
     lpDragInfo->hScope = 0;
@@ -1651,7 +1652,7 @@ DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
 
 	/* update DRAGINFO struct */
 	if( DRAG_QueryUpdate16(WIN_Handle32(hwndScope), spDragInfo) > 0 )
-	    hCurrentCursor = HCURSOR_32(hCursor);
+	    hCurrentCursor = get_cursor_handle(hCursor);
 	else
         {
             hCurrentCursor = hBummer;
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c
index 7b7b885..054ca1b 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -282,6 +282,9 @@ static BOOL process_attach(void)
 
     winstation_init();
 
+    /* Initialize cursor/icon structures. */
+    CURSORICON_init();
+
     /* Initialize system colors and metrics */
     SYSPARAMS_Init();
 
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index f1a6585..23abd82 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -306,12 +306,11 @@ extern void SPY_ExitMessage( INT iFlag, HWND hwnd, UINT msg,
 extern int SPY_Init(void) DECLSPEC_HIDDEN;
 
 /* HANDLE16 <-> HANDLE conversions */
-#define HCURSOR_16(h32)    (LOWORD(h32))
-#define HICON_16(h32)      (LOWORD(h32))
+HCURSOR16 get_cursor_handle16(HCURSOR cursor);
+HCURSOR get_cursor_handle(HCURSOR16 cursor16);
+
 #define HINSTANCE_16(h32)  (LOWORD(h32))
 
-#define HCURSOR_32(h16)    ((HCURSOR)(ULONG_PTR)(h16))
-#define HICON_32(h16)      ((HICON)(ULONG_PTR)(h16))
 #define HINSTANCE_32(h16)  ((HINSTANCE)(ULONG_PTR)(h16))
 #define HMODULE_32(h16)    ((HMODULE)(ULONG_PTR)(h16))
 
@@ -352,6 +351,7 @@ typedef struct
 
 #include "poppack.h"
 
+extern void CURSORICON_init(void) DECLSPEC_HIDDEN;
 extern void CURSORICON_FreeModuleIcons( HMODULE16 hModule ) DECLSPEC_HIDDEN;
 
 #endif /* __WINE_USER_PRIVATE_H */
diff --git a/dlls/user32/wnd16.c b/dlls/user32/wnd16.c
index 1f7b0b0..2b252ce 100644
--- a/dlls/user32/wnd16.c
+++ b/dlls/user32/wnd16.c
@@ -647,7 +647,17 @@ void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
  */
 WORD WINAPI GetClassWord16( HWND16 hwnd, INT16 offset )
 {
-    return GetClassWord( WIN_Handle32(hwnd), offset );
+    WORD ret = GetClassWord( WIN_Handle32(hwnd), offset );
+
+    switch (offset)
+    {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return get_cursor_handle16((HCURSOR)(LONG_PTR) ret);
+    default:
+        return ret;
+    }
 }
 
 
@@ -656,7 +666,16 @@ WORD WINAPI GetClassWord16( HWND16 hwnd, INT16 offset )
  */
 WORD WINAPI SetClassWord16( HWND16 hwnd, INT16 offset, WORD newval )
 {
-    return SetClassWord( WIN_Handle32(hwnd), offset, newval );
+    switch (offset)
+    {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return get_cursor_handle16((HCURSOR) SetClassLongW(WIN_Handle32(hwnd),
+            offset, (LONG_PTR) get_cursor_handle(newval)));
+    default:
+        return SetClassWord( WIN_Handle32(hwnd), offset, newval );
+    }
 }
 
 
@@ -669,6 +688,10 @@ LONG WINAPI GetClassLong16( HWND16 hwnd16, INT16 offset )
 
     switch( offset )
     {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return get_cursor_handle16((HCURSOR) ret);
     case GCLP_WNDPROC:
         return (LONG_PTR)WINPROC_GetProc16( (WNDPROC)ret, FALSE );
     case GCLP_MENUNAME:
@@ -686,6 +709,11 @@ LONG WINAPI SetClassLong16( HWND16 hwnd16, INT16 offset, LONG newval )
 {
     switch( offset )
     {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return get_cursor_handle16((HCURSOR) SetClassLongW(WIN_Handle32(hwnd16),
+            offset, (LONG_PTR) get_cursor_handle(newval)));
     case GCLP_WNDPROC:
         {
             WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
@@ -1386,12 +1414,12 @@ ATOM WINAPI RegisterClassEx16( const WNDCLASSEX16 *wc )
     wc32.cbWndExtra    = wc->cbWndExtra;
     wc32.hInstance     = HINSTANCE_32(GetExePtr(wc->hInstance));
     if (!wc32.hInstance) wc32.hInstance = HINSTANCE_32(GetModuleHandle16(NULL));
-    wc32.hIcon         = HICON_32(wc->hIcon);
-    wc32.hCursor       = HCURSOR_32(wc->hCursor);
+    wc32.hIcon         = get_cursor_handle(wc->hIcon);
+    wc32.hCursor       = get_cursor_handle(wc->hCursor);
     wc32.hbrBackground = HBRUSH_32(wc->hbrBackground);
     wc32.lpszMenuName  = MapSL(wc->lpszMenuName);
     wc32.lpszClassName = MapSL(wc->lpszClassName);
-    wc32.hIconSm       = HICON_32(wc->hIconSm);
+    wc32.hIconSm       = get_cursor_handle(wc->hIconSm);
     return RegisterClassExA( &wc32 );
 }
 
@@ -1420,9 +1448,9 @@ BOOL16 WINAPI GetClassInfoEx16( HINSTANCE16 hInst16, SEGPTR name, WNDCLASSEX16 *
         wc->cbClsExtra    = wc32.cbClsExtra;
         wc->cbWndExtra    = wc32.cbWndExtra;
         wc->hInstance     = (wc32.hInstance == user32_module) ? GetModuleHandle16("user") : HINSTANCE_16(wc32.hInstance);
-        wc->hIcon         = HICON_16(wc32.hIcon);
-        wc->hIconSm       = HICON_16(wc32.hIconSm);
-        wc->hCursor       = HCURSOR_16(wc32.hCursor);
+        wc->hIcon         = get_cursor_handle16(wc32.hIcon);
+        wc->hIconSm       = get_cursor_handle16(wc32.hIconSm);
+        wc->hCursor       = get_cursor_handle16(wc32.hCursor);
         wc->hbrBackground = HBRUSH_16(wc32.hbrBackground);
         wc->lpszClassName = 0;
         wc->lpszMenuName  = MapLS(wc32.lpszMenuName);  /* FIXME: leak */
@@ -1775,7 +1803,7 @@ BOOL16 WINAPI DrawCaptionTemp16( HWND16 hwnd, HDC16 hdc, const RECT16 *rect,
     }
     return DrawCaptionTempA( WIN_Handle32(hwnd), HDC_32(hdc),
 			     rect ? &rect32 : NULL, HFONT_32(hFont),
-			     HICON_32(hIcon), str, uFlags & 0x1f );
+			     get_cursor_handle(hIcon), str, uFlags & 0x1f );
 }
 
 
-- 
1.5.6.3

