diff -urN wine-1.0.orig/dlls/user32/cursoricon.c wine-1.0/dlls/user32/cursoricon.c
--- wine-1.0.orig/dlls/user32/cursoricon.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/user32/cursoricon.c	2008-06-27 15:53:37.000000000 +0200
@@ -5,6 +5,7 @@
  *           1996 Martin Von Loewis
  *           1997 Alex Korobka
  *           1998 Turchanov Sergey
+ *           2007 Henri Verbeet
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,7 +25,9 @@
 /*
  * Theory:
  *
- * Cursors and icons are stored in a global heap block, with the
+ * 32-bit cursors and icons are stored in the server.
+ *
+ * 16-bit cursors and icons are stored in a global heap block, with the
  * following layout:
  *
  * CURSORICONINFO info;
@@ -46,6 +49,8 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "wingdi.h"
@@ -54,6 +59,8 @@
 #include "wine/winuser16.h"
 #include "wine/exception.h"
 #include "wine/debug.h"
+#include "wine/list.h"
+#include "wine/server.h"
 #include "user_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
@@ -126,6 +133,344 @@
 
 static const WORD ICON_HOTSPOT = 0x4242;
 
+/* What is a good table size? */
+#define CURSOR_HASH_SIZE 97
+
+typedef struct {
+    HCURSOR16       cursor16;
+    HCURSOR         cursor32;
+    struct list     entry16;
+    struct list     entry32;
+} cursor_map_entry_t;
+
+static int get_bitmap_width_bytes( int width, int bpp );
+
+static struct list cursor16to32[CURSOR_HASH_SIZE];
+static struct list cursor32to16[CURSOR_HASH_SIZE];
+
+static inline int hash_cursor_handle( DWORD handle )
+{
+    return handle % CURSOR_HASH_SIZE;
+}
+
+static void add_cursor16to32_entry( cursor_map_entry_t *entry )
+{
+    int idx = hash_cursor_handle( entry->cursor16 );
+
+    if (!cursor16to32[idx].next) list_init( &cursor16to32[idx] );
+
+    list_add_head( &cursor16to32[idx], &entry->entry16 );
+}
+
+static void add_cursor32to16_entry( cursor_map_entry_t *entry )
+{
+    int idx = hash_cursor_handle( (DWORD)entry->cursor32 );
+
+    if (!cursor32to16[idx].next) list_init( &cursor32to16[idx] );
+
+    list_add_head( &cursor32to16[idx], &entry->entry32 );
+}
+
+static cursor_map_entry_t *remove_cursor16to32_entry( HCURSOR16 cursor16 )
+{
+    cursor_map_entry_t *entry = NULL;
+    int idx = hash_cursor_handle( cursor16 );
+
+    if (cursor16to32[idx].next)
+    {
+        LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
+            if (entry->cursor16 == cursor16)
+            {
+                list_remove( &entry->entry16 );
+                return entry;
+            }
+    }
+
+    return entry;
+}
+
+static cursor_map_entry_t *remove_cursor32to16_entry( HCURSOR cursor32 )
+{
+    cursor_map_entry_t *entry = NULL;
+    int idx = hash_cursor_handle( (DWORD)cursor32 );
+
+    if (cursor32to16[idx].next)
+    {
+        LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
+            if (entry->cursor32 == cursor32)
+            {
+                list_remove( &entry->entry32 );
+                return entry;
+            }
+    }
+
+    return entry;
+}
+
+/* Ask the server for a cursor */
+static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay )
+{
+    HCURSOR cursor = 0;
+
+    SERVER_START_REQ(create_cursor)
+    {
+        req->num_frames = num_frames;
+        req->delay = delay;
+        if (!wine_server_call_err( req )) cursor = reply->handle;
+    }
+    SERVER_END_REQ;
+
+    return cursor;
+}
+
+/* Tell the server to kill a cursor */
+static HCURSOR16 destroy_cursor( HCURSOR cursor )
+{
+    cursor_map_entry_t *entry;
+    HCURSOR16 cursor16 = 0;
+
+    if (!cursor) return 0;
+
+    SERVER_START_REQ(destroy_cursor)
+    {
+        req->handle = cursor;
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+
+    entry = remove_cursor32to16_entry( cursor );
+    if (entry)
+    {
+        cursor16 = entry->cursor16;
+        remove_cursor16to32_entry( cursor16 );
+        HeapFree( GetProcessHeap(), 0, entry );
+    }
+
+    return GlobalFree16( cursor16 );
+}
+
+/* Upload a cursor frame to the server */
+static void set_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
+{
+    SERVER_START_REQ(set_cursor_frame)
+    {
+        req->handle = cursor;
+        req->frame_idx = frame_idx;
+        req->xhot = frame->xhot;
+        req->yhot = frame->yhot;
+        req->width = frame->width;
+        req->height = frame->height;
+        req->and_width_bytes = frame->and_width_bytes;
+        req->xor_width_bytes = frame->xor_width_bytes;
+        req->planes = frame->planes;
+        req->bpp = frame->bpp;
+        wine_server_add_data( req, frame->bits, (frame->and_width_bytes + frame->xor_width_bytes) * frame->height );
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+}
+
+/* Download a cursor frame from the server */
+static BOOL get_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
+{
+    NTSTATUS res;
+    /* Enough for a 32-bits 32x32 cursor / icon. */
+    unsigned int buffer_size = 4224;
+    unsigned int count = 0;
+
+    do
+    {
+        frame->bits = HeapAlloc(GetProcessHeap(), 0, buffer_size);
+        SERVER_START_REQ(get_cursor_frame)
+        {
+            req->handle = cursor;
+            req->frame_idx = frame_idx;
+            wine_server_set_reply( req, frame->bits, buffer_size);
+            if (!(res = wine_server_call_err( req )))
+            {
+                frame->xhot = reply->xhot;
+                frame->yhot = reply->yhot;
+                frame->width = reply->width;
+                frame->height = reply->height;
+                frame->and_width_bytes = reply->and_width_bytes;
+                frame->xor_width_bytes = reply->xor_width_bytes;
+                frame->planes = reply->planes;
+                frame->bpp = reply->bpp;
+            } else {
+                HeapFree( GetProcessHeap(), 0, frame->bits );
+                buffer_size = (reply->and_width_bytes + reply->xor_width_bytes) * reply->height;
+            }
+        }
+        SERVER_END_REQ;
+    } while (res == STATUS_BUFFER_OVERFLOW && !count++);
+
+    if (!frame->height)
+    {
+        HeapFree( GetProcessHeap(), 0, frame->bits );
+
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/* Retrieve a cursor and all its frames from the server */
+static cursor_t *get_cursor_object( HCURSOR handle )
+{
+    unsigned int i;
+    cursor_t *cursor = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(cursor_t) );
+
+    SERVER_START_REQ(get_cursor_info)
+    {
+        req->handle = handle;
+        if (!wine_server_call_err( req ))
+        {
+            cursor->num_frames = reply->num_frames;
+            cursor->delay = reply->delay;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (!cursor->num_frames)
+    {
+        HeapFree( GetProcessHeap(), 0, cursor );
+        return NULL;
+    }
+
+    cursor->frames = HeapAlloc( GetProcessHeap(), 0, cursor->num_frames * sizeof(cursor_frame_t) );
+    for (i = 0; i < cursor->num_frames; ++i)
+    {
+        if (!get_cursor_frame( handle, i, &cursor->frames[i] ))
+        {
+            unsigned int j;
+
+            for (j = 0; j < i; ++j)
+            {
+                HeapFree( GetProcessHeap(), 0, cursor->frames[j].bits );
+            }
+            HeapFree( GetProcessHeap(), 0, cursor->frames );
+            HeapFree( GetProcessHeap(), 0, cursor );
+
+            return NULL;
+        }
+    }
+
+    return cursor;
+}
+
+static void destroy_cursor_object( cursor_t *cursor )
+{
+    unsigned int i;
+
+    if (!cursor) return;
+
+    for (i = 0; i < cursor->num_frames; ++i)
+    {
+        HeapFree( GetProcessHeap(), 0, cursor->frames[i].bits );
+    }
+    HeapFree( GetProcessHeap(), 0, cursor->frames );
+    HeapFree( GetProcessHeap(), 0, cursor );
+}
+
+/* Lookup the cursor's 16-bit handle. Create one if it doesn't already exist. */
+HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create )
+{
+    cursor_map_entry_t *entry;
+    int idx = hash_cursor_handle( (DWORD)cursor32 );
+
+    if (!cursor32) return 0;
+
+    if (cursor32to16[idx].next)
+    {
+        LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
+            if (entry->cursor32 == cursor32) return entry->cursor16;
+    }
+
+    /* 16-bit cursor handle not found, create one */
+    if (create)
+    {
+        size_t bits_size;
+        HCURSOR16 cursor16;
+        cursor_frame_t frame;
+
+        if (!get_cursor_frame( cursor32, 0, &frame )) return 0;
+
+        entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) );
+        bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height;
+        cursor16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + bits_size );
+        if (cursor16)
+        {
+            CURSORICONINFO *info;
+
+            info = (CURSORICONINFO *)GlobalLock16( cursor16 );
+            info->ptHotSpot.x = frame.xhot;
+            info->ptHotSpot.y = frame.yhot;
+            info->nWidth = frame.width;
+            info->nHeight = frame.height;
+            info->nWidthBytes = frame.xor_width_bytes;
+            info->bPlanes = frame.planes;
+            info->bBitsPerPixel = frame.bpp;
+            CopyMemory( info + 1, frame.bits, bits_size );
+            GlobalUnlock16( cursor16 );
+        }
+        HeapFree( GetProcessHeap(), 0, frame.bits );
+
+        entry->cursor16 = cursor16;
+        entry->cursor32 = cursor32;
+        add_cursor16to32_entry( entry );
+        add_cursor32to16_entry( entry );
+
+        return cursor16;
+    }
+
+    return 0;
+}
+
+HCURSOR get_cursor_handle32( HCURSOR16 cursor16 )
+{
+    cursor_map_entry_t *entry;
+    int idx = hash_cursor_handle( cursor16 );
+
+    if (!cursor16) return 0;
+
+    if (cursor16to32[idx].next)
+    {
+        LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
+            if (entry->cursor16 == cursor16) return entry->cursor32;
+    }
+
+    return 0;
+}
+
+static void update_cursor_32from16( HCURSOR cursor32 )
+{
+    size_t bits_size;
+    HCURSOR16 cursor16;
+    cursor_frame_t frame;
+    CURSORICONINFO *info;
+
+    if (!cursor32) return;
+
+    cursor16 = get_cursor_handle16( cursor32, FALSE );
+    if (!cursor16) return;
+
+    info = (CURSORICONINFO *)GlobalLock16( cursor16 );
+    frame.xhot = info->ptHotSpot.x;
+    frame.yhot = info->ptHotSpot.y;
+    frame.width = info->nWidth;
+    frame.height = info->nHeight;
+    frame.and_width_bytes = get_bitmap_width_bytes( info->nWidth, 1 );
+    frame.xor_width_bytes = info->nWidthBytes;
+    frame.planes = info->bPlanes;
+    frame.bpp = info->bBitsPerPixel;
+    bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height;
+    frame.bits = HeapAlloc( GetProcessHeap(), 0, bits_size );
+    CopyMemory( frame.bits, info + 1, bits_size );
+    GlobalUnlock16( cursor16 );
+
+    set_cursor_frame( cursor32, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+}
 
 /***********************************************************************
  *             map_fileW
@@ -462,7 +807,7 @@
             ICONCACHE *freePtr = *ptr;
             *ptr = freePtr->next;
 
-            GlobalFree16(HICON_16(freePtr->hIcon));
+            destroy_cursor( freePtr->hIcon );
             HeapFree( GetProcessHeap(), 0, freePtr );
             continue;
         }
@@ -660,47 +1005,27 @@
     return &dir->idEntries[n];
 }
 
-/**********************************************************************
- *		CreateIconFromResourceEx (USER32.@)
- *
- * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
- *        with cbSize parameter as well.
- */
-HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
-                                       BOOL bIcon, DWORD dwVersion,
-                                       INT width, INT height,
-                                       UINT cFlag )
+static BOOL load_cursor_frame( LPBYTE bits, UINT cbSize, POINT16 hotspot, DWORD dwVersion,
+                              INT width, INT height, UINT cFlag, cursor_frame_t *frame )
 {
-    HGLOBAL16 hObj;
     static HDC hdcMem;
     int sizeAnd, sizeXor;
     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
     BITMAP bmpXor, bmpAnd;
-    POINT16 hotspot;
     BITMAPINFO *bmi;
     BOOL DoStretch;
     INT size;
 
-    hotspot.x = ICON_HOTSPOT;
-    hotspot.y = ICON_HOTSPOT;
-
-    TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
-                   bits, cbSize, dwVersion, width, height,
-                                  bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
+    TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s\n",
+            bits, cbSize, dwVersion, width, height,
+            (cFlag & LR_MONOCHROME) ? "mono" : "" );
     if (dwVersion == 0x00020000)
     {
         FIXME_(cursor)("\t2.xx resources are not supported\n");
-        return 0;
+        return FALSE;
     }
 
-    if (bIcon)
-        bmi = (BITMAPINFO *)bits;
-    else /* get the hotspot */
-    {
-        POINT16 *pt = (POINT16 *)bits;
-        hotspot = *pt;
-        bmi = (BITMAPINFO *)(pt + 1);
-    }
+    bmi = (BITMAPINFO *)bits;
 
     /* Check bitmap header */
 
@@ -709,7 +1034,7 @@
           bmi->bmiHeader.biCompression != BI_RGB) )
     {
           WARN_(cursor)("\tinvalid resource bitmap header.\n");
-          return 0;
+          return FALSE;
     }
 
     size = bitmap_info_size( bmi, DIB_RGB_COLORS );
@@ -719,6 +1044,13 @@
     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
       (bmi->bmiHeader.biWidth != width);
 
+    /* Scale the hotspot */
+    if (DoStretch && hotspot.x != ICON_HOTSPOT && hotspot.y != ICON_HOTSPOT)
+    {
+        hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
+        hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biWidth / 2);
+    }
+
     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
     if (screen_dc)
     {
@@ -744,14 +1076,7 @@
             /* Create the XOR bitmap */
 
             if (DoStretch) {
-                if(bIcon)
-                {
-                    hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
-                }
-                else
-                {
-                    hXorBits = CreateBitmap(width, height, 1, 1, NULL);
-                }
+                hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
                 if(hXorBits)
                 {
                 HBITMAP hOld;
@@ -772,6 +1097,10 @@
                   hXorBits = CreateBitmap(width, height, 1, 1, NULL);
                   SetDIBits(screen_dc, hXorBits, 0, height,
                      (char*)bmi + size, pInfo, DIB_RGB_COLORS);
+              } else if (bmi->bmiHeader.biBitCount == 32) {
+                  hXorBits = CreateDIBSection(screen_dc, pInfo, DIB_RGB_COLORS, NULL, NULL, 0);
+                  SetDIBits(screen_dc, hXorBits, 0, height,
+                     (char*)bmi + size, pInfo, DIB_RGB_COLORS);
               }
               else
                   hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
@@ -835,40 +1164,313 @@
     if( !hXorBits || !hAndBits )
     {
         WARN_(cursor)("\tunable to create an icon bitmap.\n");
-        return 0;
+        return FALSE;
     }
 
-    /* Now create the CURSORICONINFO structure */
+    /* Setup a cursor frame, send it to the server */
     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
 
-    hObj = GlobalAlloc16( GMEM_MOVEABLE,
-                     sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
-    if (hObj)
-    {
-        CURSORICONINFO *info;
-
-        info = (CURSORICONINFO *)GlobalLock16( hObj );
-        info->ptHotSpot.x   = hotspot.x;
-        info->ptHotSpot.y   = hotspot.y;
-        info->nWidth        = bmpXor.bmWidth;
-        info->nHeight       = bmpXor.bmHeight;
-        info->nWidthBytes   = bmpXor.bmWidthBytes;
-        info->bPlanes       = bmpXor.bmPlanes;
-        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 );
-        GlobalUnlock16( hObj );
-    }
+    frame->xhot              = hotspot.x;
+    frame->yhot              = hotspot.y;
+    frame->width             = bmpXor.bmWidth;
+    frame->height            = bmpXor.bmHeight;
+    frame->and_width_bytes   = bmpAnd.bmWidthBytes;
+    frame->xor_width_bytes   = bmpXor.bmWidthBytes;
+    frame->planes            = bmpXor.bmPlanes;
+    frame->bpp               = bmpXor.bmBitsPixel;
+    frame->bits              = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
+    GetBitmapBits( hAndBits, sizeAnd, frame->bits );
+    GetBitmapBits( hXorBits, sizeXor, frame->bits + sizeAnd );
 
     DeleteObject( hAndBits );
     DeleteObject( hXorBits );
-    return HICON_32(hObj);
+
+    return TRUE;
+}
+
+/**********************************************************************
+ *          .ANI cursor support
+ */
+#define RIFF_FOURCC( c0, c1, c2, c3 ) \
+        ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
+        ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
+
+#define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
+#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
+#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
+#define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
+#define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
+#define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
+
+#define ANI_FLAG_ICON       0x1
+#define ANI_FLAG_SEQUENCE   0x2
+
+typedef struct {
+    DWORD header_size;
+    DWORD num_frames;
+    DWORD num_steps;
+    DWORD width;
+    DWORD height;
+    DWORD bpp;
+    DWORD num_planes;
+    DWORD display_rate;
+    DWORD flags;
+} ani_header;
+
+typedef struct {
+    DWORD           data_size;
+    const unsigned char   *data;
+} riff_chunk_t;
+
+static void dump_ani_header( const ani_header *header )
+{
+    TRACE("     header size: %d\n", header->header_size);
+    TRACE("          frames: %d\n", header->num_frames);
+    TRACE("           steps: %d\n", header->num_steps);
+    TRACE("           width: %d\n", header->width);
+    TRACE("          height: %d\n", header->height);
+    TRACE("             bpp: %d\n", header->bpp);
+    TRACE("          planes: %d\n", header->num_planes);
+    TRACE("    display rate: %d\n", header->display_rate);
+    TRACE("           flags: 0x%08x\n", header->flags);
+}
+
+
+/*
+ * RIFF:
+ * DWORD "RIFF"
+ * DWORD size
+ * DWORD riff_id
+ * BYTE[] data
+ *
+ * LIST:
+ * DWORD "LIST"
+ * DWORD size
+ * DWORD list_id
+ * BYTE[] data
+ *
+ * CHUNK:
+ * DWORD chunk_id
+ * DWORD size
+ * BYTE[] data
+ */
+static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
+{
+    const unsigned char *ptr = parent_chunk->data;
+    const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
+
+    if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
+
+    while (ptr < end)
+    {
+        if ((!chunk_type && *(DWORD *)ptr == chunk_id )
+                || (chunk_type && *(DWORD *)ptr == chunk_type && *((DWORD *)ptr + 2) == chunk_id ))
+        {
+            ptr += sizeof(DWORD);
+            chunk->data_size = *(DWORD *)ptr;
+            ptr += sizeof(DWORD);
+            if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
+            chunk->data = ptr;
+
+            return;
+        }
+
+        ptr += sizeof(DWORD);
+        ptr += *(DWORD *)ptr;
+        ptr += sizeof(DWORD);
+    }
+}
+
+
+/*
+ * .ANI layout:
+ *
+ * RIFF:'ACON'                  RIFF chunk
+ *     |- CHUNK:'anih'          Header
+ *     |- CHUNK:'seq '          Sequence information (optional)
+ *     \- LIST:'fram'           Frame list
+ *            |- CHUNK:icon     Cursor frames
+ *            |- CHUNK:icon
+ *            |- ...
+ *            \- CHUNK:icon
+ */
+static HCURSOR load_ani( const LPBYTE bits, DWORD bits_size, INT width, INT height )
+{
+    int i;
+    WORD max_count = 0;
+    HCURSOR cursor;
+    CURSORICONFILEDIR *dir = 0;
+    ani_header header = {0};
+    DWORD *frame_seq = 0;
+    cursor_frame_t *frames;
+    unsigned int frame_bits_size = 0;
+    LPBYTE frame_bits = 0;
+    POINT16 hotspot;
+
+    riff_chunk_t root_chunk = { bits_size, bits };
+    riff_chunk_t ACON_chunk = {0};
+    riff_chunk_t anih_chunk = {0};
+    riff_chunk_t fram_chunk = {0};
+    const unsigned char *icon_chunk;
+    const unsigned char *icon_data;
+
+    TRACE("bits %p, bits_size %d\n", bits, bits_size);
+
+    if (!bits) return 0;
+
+    riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
+    if (!ACON_chunk.data)
+    {
+        ERR("Failed to get root chunk.\n");
+        return 0;
+    }
+
+    riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
+    if (!anih_chunk.data)
+    {
+        ERR("Failed to get 'anih' chunk.\n");
+        return 0;
+    }
+    memcpy( &header, anih_chunk.data, sizeof(header) );
+    dump_ani_header( &header );
+
+    if (header.flags & ANI_FLAG_SEQUENCE)
+    {
+        riff_chunk_t seq_chunk = {0};
+
+        TRACE("Loading sequence data.\n");
+        riff_find_chunk( ANI_seq__ID, 0, &ACON_chunk, &seq_chunk );
+        if (!seq_chunk.data)
+        {
+            ERR("Failed to get 'seq ' chunk\n");
+            return 0;
+        }
+        frame_seq = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD) * header.num_steps );
+        memcpy( frame_seq, seq_chunk.data, sizeof(DWORD) * header.num_steps );
+    }
+
+    riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
+    if (!fram_chunk.data)
+    {
+        ERR("Failed to get icon list\n");
+        return 0;
+    }
+
+    icon_chunk = fram_chunk.data;
+    icon_data = icon_chunk + (2 * sizeof(DWORD));
+    /* The .ANI stores the display rate in 1/60s, we store the delay between frames in ms */
+    cursor = create_cursor( header.num_steps, (100 * header.display_rate) / 6 );
+    frames = HeapAlloc( GetProcessHeap(), 0, header.num_frames * sizeof(cursor_frame_t) );
+
+    for (i = 0; i < header.num_frames; ++i)
+    {
+        WORD count;
+        CURSORICONFILEDIRENTRY *entry;
+        DWORD chunk_size = *(DWORD *)(icon_chunk + sizeof(DWORD));
+
+        /* Read icon count, skip magic */
+        memcpy( &count, icon_data + sizeof(DWORD), sizeof(WORD) );
+
+        /* There's a decent chance the amount of entries will be the same for each icon */
+        if (count > max_count)
+        {
+            HeapFree( GetProcessHeap(), 0, dir );
+            /* sizeof(CURSORICONFILEDIRENTRY) for each entry, +6 for magic & count */
+            dir = HeapAlloc( GetProcessHeap(), 0, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6 );
+            max_count = count;
+        }
+
+        /* sizeof(CURSORICONFILEDIRENTRY) for each entry, +6 for magic & count */
+        memcpy( dir, icon_data, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6 );
+        entry = CURSORICON_FindBestCursorFile( dir, width, height, 1 );
+
+        if (frame_bits_size < entry->dwDIBSize)
+        {
+            frame_bits_size = entry->dwDIBSize;
+            HeapFree( GetProcessHeap(), 0, frame_bits );
+            frame_bits = HeapAlloc( GetProcessHeap(), 0, frame_bits_size );
+        }
+
+        if (!header.width || !header.height)
+        {
+            header.width = entry->bWidth;
+            header.height = entry->bHeight;
+        }
+
+        hotspot.x = entry->xHotspot;
+        hotspot.y = entry->yHotspot;
+
+        memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
+
+        load_cursor_frame( frame_bits, entry->dwDIBSize, hotspot, 0x00030000, header.width, header.height, 0, &frames[i] );
+
+        /* Advance to the next chunk */
+        icon_chunk += chunk_size + (2 * sizeof(DWORD));
+        icon_data = icon_chunk + (2 * sizeof(DWORD));
+    }
+    HeapFree( GetProcessHeap(), 0, dir );
+
+    /* Set the frames in the correct sequence */
+    for (i = 0; i < header.num_steps; ++i)
+    {
+        int frame_idx = (frame_seq ? frame_seq[i] : i);
+        set_cursor_frame( cursor, i, &frames[frame_idx] );
+    }
+
+    /* Cleanup */
+    for (i = 0; i < header.num_frames; ++i)
+    {
+        HeapFree( GetProcessHeap(), 0, frames[i].bits );
+    }
+    HeapFree( GetProcessHeap(), 0, frame_seq );
+    HeapFree( GetProcessHeap(), 0, frames );
+
+    return cursor;
+}
+
+
+/**********************************************************************
+ *		CreateIconFromResourceEx (USER32.@)
+ *
+ * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
+ *        with cbSize parameter as well.
+ */
+HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
+                                       BOOL bIcon, DWORD dwVersion,
+                                       INT width, INT height,
+                                       UINT cFlag )
+{
+    POINT16 hotspot;
+    HCURSOR cursor = create_cursor( 1, 0 );
+    cursor_frame_t frame = {0};
+
+    if (bIcon)
+    {
+        hotspot.x = ICON_HOTSPOT;
+        hotspot.y = ICON_HOTSPOT;
+    }
+    else
+    {
+        hotspot = *(POINT16 *)bits;
+        bits = (LPBYTE)(((POINT16 *)bits) + 1);
+    }
+
+    if (load_cursor_frame( bits, cbSize, hotspot, dwVersion, width, height, cFlag, &frame ))
+    {
+        set_cursor_frame( cursor, 0, &frame );
+    }
+    else
+    {
+        destroy_cursor( cursor );
+        cursor = 0;
+    }
+
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
+    return cursor;
 }
 
 
@@ -887,9 +1489,11 @@
                              BOOL fCursor, UINT loadflags)
 {
     CURSORICONFILEDIRENTRY *entry;
+    cursor_frame_t frame = {0};
     CURSORICONFILEDIR *dir;
     DWORD filesize = 0;
     HICON hIcon = 0;
+    POINT16 hotspot;
     LPBYTE bits;
 
     TRACE("loading %s\n", debugstr_w( filename ));
@@ -898,10 +1502,15 @@
     if (!bits)
         return hIcon;
 
+    /* If the data contains the magic for an .ICO it's an .ICO,
+     * regardless of what fCursor says. */
+    if (!memcmp( bits, "\x00\x00\x01\x00", 4 )) fCursor = FALSE;
+    /* Same thing for .CUR */
+    else if (!memcmp( bits, "\x00\x00\x02\x00", 4 )) fCursor = TRUE;
     /* Check for .ani. */
-    if (memcmp( bits, "RIFF", 4 ) == 0)
+    else if (!memcmp( bits, "RIFF", 4 ))
     {
-        FIXME("No support for .ani cursors.\n");
+        hIcon = load_ani( bits, filesize, width, height );
         goto end;
     }
 
@@ -926,8 +1535,23 @@
     if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
         goto end;
 
-    hIcon = CreateIconFromResourceEx( &bits[entry->dwDIBOffset], entry->dwDIBSize,
-                                      !fCursor, 0x00030000, width, height, loadflags );
+    if ( fCursor )
+    {
+        hotspot.x = entry->xHotspot;
+        hotspot.y = entry->yHotspot;
+    }
+    else
+    {
+        hotspot.x = ICON_HOTSPOT;
+        hotspot.y = ICON_HOTSPOT;
+    }
+
+    hIcon = create_cursor( 1, 0 );
+    load_cursor_frame( &bits[entry->dwDIBOffset], entry->dwDIBSize, hotspot,
+                               0x00030000, width, height, loadflags, &frame );
+    set_cursor_frame( hIcon, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
 end:
     TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
     UnmapViewOfFile( bits );
@@ -1016,21 +1640,20 @@
  */
 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
 {
-    char *ptrOld, *ptrNew;
-    int size;
-    HICON16 hOld = HICON_16(hIcon);
-    HICON16 hNew;
+    /* Should animated cursors be copyable like this as well? */
+    HCURSOR new_cursor;
+    cursor_frame_t frame;
+
+    if (!hIcon || !get_cursor_frame( hIcon, 0, &frame ))
+    {
+        return 0;
+    }
+
+    new_cursor = create_cursor( 1, 0 );
+    set_cursor_frame( new_cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
 
-    if (!(ptrOld = (char *)GlobalLock16( hOld ))) return 0;
-    if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
-    size = GlobalSize16( hOld );
-    hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
-    FarSetOwner16( hNew, hInst16 );
-    ptrNew = (char *)GlobalLock16( hNew );
-    memcpy( ptrNew, ptrOld, size );
-    GlobalUnlock16( hOld );
-    GlobalUnlock16( hNew );
-    return HICON_32(hNew);
+    return new_cursor;
 }
 
 /*************************************************************************
@@ -1281,25 +1904,31 @@
                                            LPCVOID lpANDbits,
                                            LPCVOID lpXORbits )
 {
-    HGLOBAL16 handle;
-    char *ptr;
+    HCURSOR cursor;
+    cursor_frame_t frame;
     int sizeAnd, sizeXor;
 
-    hInstance = GetExePtr( hInstance );  /* Make it a module handle */
     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
     info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
     sizeXor = info->nHeight * info->nWidthBytes;
     sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
-    if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
-                                  sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
-        return 0;
-    FarSetOwner16( handle, hInstance );
-    ptr = (char *)GlobalLock16( handle );
-    memcpy( ptr, info, sizeof(*info) );
-    memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
-    memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
-    GlobalUnlock16( handle );
-    return handle;
+
+    cursor = create_cursor( 1, 0 );
+    frame.xhot              = info->ptHotSpot.x;
+    frame.yhot              = info->ptHotSpot.y;
+    frame.width             = info->nWidth;
+    frame.height            = info->nHeight;
+    frame.and_width_bytes   = get_bitmap_width_bytes( info->nWidth, 1 );
+    frame.xor_width_bytes   = info->nWidthBytes;
+    frame.planes            = info->bPlanes;
+    frame.bpp               = info->bBitsPerPixel;
+    frame.bits              = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
+    CopyMemory( frame.bits, lpANDbits, sizeAnd );
+    CopyMemory( frame.bits + sizeAnd, lpXORbits, sizeXor );
+    set_cursor_frame( cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
+    return HICON_16(cursor);
 }
 
 
@@ -1368,7 +1997,7 @@
 
     /* Now assume non-shared cursor/icon */
 
-    retv = GlobalFree16( handle );
+    retv = destroy_cursor( HCURSOR_32(handle) );
     return (flags & CID_RESOURCE)? retv : TRUE;
 }
 
@@ -1468,8 +2097,12 @@
     /* 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));
+        cursor_t *cursor;
+
+        update_cursor_32from16( hCursor );
+        cursor = get_cursor_object( hCursor );
+        USER_Driver->pSetCursor( cursor );
+        destroy_cursor_object( cursor );
     }
     return hOldCursor;
 }
@@ -1487,8 +2120,12 @@
     {
         if (++thread_info->cursor_count == 0) /* Show it */
         {
-            USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
-            GlobalUnlock16(HCURSOR_16(thread_info->cursor));
+            cursor_t *cursor;
+
+            update_cursor_32from16( thread_info->cursor );
+            cursor = get_cursor_object( thread_info->cursor );
+            USER_Driver->pSetCursor( cursor );
+            destroy_cursor_object( cursor );
         }
     }
     else
@@ -1790,9 +2427,10 @@
  */
 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
 {
+    HCURSOR cursor;
+    cursor_frame_t frame;
     DIBSECTION bmpXor;
     BITMAP bmpAnd;
-    HICON16 hObj;
     int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
 
     TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
@@ -1821,94 +2459,90 @@
 
     sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
 
-    hObj = GlobalAlloc16( GMEM_MOVEABLE,
-                          sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
-    if (hObj)
-    {
-        CURSORICONINFO *info;
-
-        info = (CURSORICONINFO *)GlobalLock16( hObj );
+    cursor = create_cursor( 1, 0 );
 
-        /* If we are creating an icon, the hotspot is unused */
-        if (iconinfo->fIcon)
-        {
-            info->ptHotSpot.x   = ICON_HOTSPOT;
-            info->ptHotSpot.y   = ICON_HOTSPOT;
-        }
-        else
-        {
-            info->ptHotSpot.x   = iconinfo->xHotspot;
-            info->ptHotSpot.y   = iconinfo->yHotspot;
-        }
+    /* If we are creating an icon, the hotspot is unused */
+    if (iconinfo->fIcon)
+    {
+        frame.xhot              = ICON_HOTSPOT;
+        frame.yhot              = ICON_HOTSPOT;
+    }
+    else
+    {
+        frame.xhot              = iconinfo->xHotspot;
+        frame.yhot              = iconinfo->yHotspot;
+    }
 
-        if (iconinfo->hbmColor)
-        {
-            info->nWidth        = bmpXor.dsBm.bmWidth;
-            info->nHeight       = bmpXor.dsBm.bmHeight;
-            info->nWidthBytes   = bmpXor.dsBm.bmWidthBytes;
-            info->bPlanes       = planes;
-            info->bBitsPerPixel = bpp;
-        }
-        else
-        {
-            info->nWidth        = bmpAnd.bmWidth;
-            info->nHeight       = bmpAnd.bmHeight / 2;
-            info->nWidthBytes   = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
-            info->bPlanes       = 1;
-            info->bBitsPerPixel = 1;
-        }
+    if (iconinfo->hbmColor)
+    {
+        frame.width             = bmpXor.dsBm.bmWidth;
+        frame.height            = bmpXor.dsBm.bmHeight;
+        frame.and_width_bytes   = bmpAnd.bmWidthBytes;
+        frame.xor_width_bytes   = bmpXor.dsBm.bmWidthBytes;
+        frame.planes            = planes;
+        frame.bpp               = bpp;
+    } 
+    else
+    {
+        frame.width             = bmpAnd.bmWidth;
+        frame.height            = bmpAnd.bmHeight / 2;
+        frame.and_width_bytes   = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
+        frame.xor_width_bytes   = 0;
+        frame.planes            = 1;
+        frame.bpp               = 1;
+    }
 
-        /* Transfer the bitmap bits to the CURSORICONINFO structure */
+    frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
 
-        /* Some apps pass a color bitmap as a mask, convert it to b/w */
-        if (bmpAnd.bmBitsPixel == 1)
-        {
-            GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) );
-        }
-        else
-        {
-            HDC hdc, hdc_mem;
-            HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;
+    /* Some apps pass a color bitmap as a mask, convert it to b/w */
+    if (bmpAnd.bmBitsPixel == 1)
+    {
+        GetBitmapBits( iconinfo->hbmMask, sizeAnd, frame.bits );
+    }
+    else
+    {
+        HDC hdc, hdc_mem;
+        HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;
 
-            hdc = GetDC( 0 );
-            hdc_mem = CreateCompatibleDC( hdc );
+        hdc = GetDC( 0 );
+        hdc_mem = CreateCompatibleDC( hdc );
 
-            hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
+        hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
 
-            hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
-            hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );
+        hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
+        hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );
 
-            BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );
+        BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );
 
-            SelectObject( hdc, hbmp_old );
-            SelectObject( hdc_mem, hbmp_mem_old );
+        SelectObject( hdc, hbmp_old );
+        SelectObject( hdc_mem, hbmp_mem_old );
 
-            DeleteDC( hdc_mem );
-            ReleaseDC( 0, hdc );
+        DeleteDC( hdc_mem );
+        ReleaseDC( 0, hdc );
 
-            GetBitmapBits( hbmp_mono, sizeAnd, (char*)(info + 1) );
-            DeleteObject( hbmp_mono );
-        }
+        GetBitmapBits( hbmp_mono, sizeAnd, frame.bits );
+        DeleteObject( hbmp_mono );
+    }
 
         if (iconinfo->hbmColor)
         {
-            char *dst_bits = (char*)(info + 1) + sizeAnd;
+            char *dst_bits = frame.bits + sizeAnd;
 
             if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
                 GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
             else
             {
                 BITMAPINFO bminfo;
-                int dib_width = get_dib_width_bytes( info->nWidth, info->bBitsPerPixel );
-                int bitmap_width = get_bitmap_width_bytes( info->nWidth, info->bBitsPerPixel );
+                int dib_width = get_dib_width_bytes( frame.width, frame.bpp );
+                int bitmap_width = get_bitmap_width_bytes( frame.width, frame.bpp );
 
                 bminfo.bmiHeader.biSize = sizeof(bminfo);
-                bminfo.bmiHeader.biWidth = info->nWidth;
-                bminfo.bmiHeader.biHeight = info->nHeight;
-                bminfo.bmiHeader.biPlanes = info->bPlanes;
-                bminfo.bmiHeader.biBitCount = info->bBitsPerPixel;
+                bminfo.bmiHeader.biWidth = frame.width;
+                bminfo.bmiHeader.biHeight = frame.height;
+                bminfo.bmiHeader.biPlanes = frame.planes;
+                bminfo.bmiHeader.biBitCount = frame.bpp;
                 bminfo.bmiHeader.biCompression = BI_RGB;
-                bminfo.bmiHeader.biSizeImage = info->nHeight * dib_width;
+                bminfo.bmiHeader.biSizeImage = frame.height * dib_width;
                 bminfo.bmiHeader.biXPelsPerMeter = 0;
                 bminfo.bmiHeader.biYPelsPerMeter = 0;
                 bminfo.bmiHeader.biClrUsed = 0;
@@ -1922,23 +2556,24 @@
                 {
                     char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );
 
-                    if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
+                    if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height,
                                                src_bits, &bminfo, DIB_RGB_COLORS ))
                     {
                         int y;
-                        for (y = 0; y < info->nHeight; y++)
+                        for (y = 0; y < frame.height; y++)
                             memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
                     }
                     HeapFree( GetProcessHeap(), 0, src_bits );
                 }
                 else
-                    GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
+                    GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height,
                                dst_bits, &bminfo, DIB_RGB_COLORS );
             }
         }
-        GlobalUnlock16( hObj );
-    }
-    return HICON_32(hObj);
+    set_cursor_frame( cursor, 0, &frame );
+    HeapFree( GetProcessHeap(), 0, frame.bits );
+
+    return cursor;
 }
 
 /******************************************************************************
diff -urN wine-1.0.orig/dlls/user32/display.c wine-1.0/dlls/user32/display.c
--- wine-1.0.orig/dlls/user32/display.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/user32/display.c	2008-06-27 15:53:24.000000000 +0200
@@ -50,7 +50,7 @@
 /***********************************************************************
  *           SetCursor			(DISPLAY.102)
  */
-VOID WINAPI DISPLAY_SetCursor( struct tagCURSORICONINFO *lpCursor )
+VOID WINAPI DISPLAY_SetCursor( const struct cursor_t *lpCursor )
 {
     USER_Driver->pSetCursor(lpCursor);
 }
diff -urN wine-1.0.orig/dlls/user32/driver.c wine-1.0/dlls/user32/driver.c
--- wine-1.0.orig/dlls/user32/driver.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/user32/driver.c	2008-06-27 15:53:24.000000000 +0200
@@ -215,7 +215,7 @@
     return -1;
 }
 
-static void nulldrv_SetCursor( struct tagCURSORICONINFO *info )
+static void nulldrv_SetCursor( const struct cursor_t *cursor )
 {
 }
 
@@ -544,9 +544,9 @@
     return load_driver()->pVkKeyScanEx( ch, layout );
 }
 
-static void loaderdrv_SetCursor( struct tagCURSORICONINFO *info )
+static void loaderdrv_SetCursor( const struct cursor_t *cursor )
 {
-    load_driver()->pSetCursor( info );
+    load_driver()->pSetCursor( cursor );
 }
 
 static BOOL loaderdrv_GetCursorPos( LPPOINT pt )
diff -urN wine-1.0.orig/dlls/user32/user_private.h wine-1.0/dlls/user32/user_private.h
--- wine-1.0.orig/dlls/user32/user_private.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/user32/user_private.h	2008-06-27 15:53:24.000000000 +0200
@@ -99,7 +99,7 @@
     WM_WINE_LAST_DRIVER_MSG = 0x80001fff
 };
 
-struct tagCURSORICONINFO;
+struct cursor_t;
 
 typedef struct tagUSER_DRIVER {
     /* keyboard functions */
@@ -117,7 +117,7 @@
     BOOL   (*pUnloadKeyboardLayout)(HKL);
     SHORT  (*pVkKeyScanEx)(WCHAR, HKL);
     /* mouse functions */
-    void   (*pSetCursor)(struct tagCURSORICONINFO *);
+    void   (*pSetCursor)(const struct cursor_t *);
     BOOL   (*pGetCursorPos)(LPPOINT);
     BOOL   (*pSetCursorPos)(INT,INT);
     BOOL   (*pClipCursor)(LPCRECT);
@@ -302,12 +302,15 @@
 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 cursor32, BOOL create );
+HCURSOR get_cursor_handle32( HCURSOR16 cursor16 );
+
+#define HCURSOR_16(h32)    get_cursor_handle16(h32, TRUE)
+#define HICON_16(h32)      get_cursor_handle16(h32, TRUE)
 #define HINSTANCE_16(h32)  (LOWORD(h32))
 
-#define HCURSOR_32(h16)    ((HCURSOR)(ULONG_PTR)(h16))
-#define HICON_32(h16)      ((HICON)(ULONG_PTR)(h16))
+#define HCURSOR_32(h16)    get_cursor_handle32(h16)
+#define HICON_32(h16)      get_cursor_handle32(h16)
 #define HINSTANCE_32(h16)  ((HINSTANCE)(ULONG_PTR)(h16))
 #define HMODULE_32(h16)    ((HMODULE)(ULONG_PTR)(h16))
 
diff -urN wine-1.0.orig/dlls/user32/wnd16.c wine-1.0/dlls/user32/wnd16.c
--- wine-1.0.orig/dlls/user32/wnd16.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/user32/wnd16.c	2008-06-27 15:53:22.000000000 +0200
@@ -647,7 +647,17 @@
  */
 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 HCURSOR_16((HCURSOR)(LONG_PTR)ret);
+    default:
+        return ret;
+    }
 }
 
 
@@ -656,7 +666,15 @@
  */
 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 HCURSOR_16((HCURSOR)SetClassLongW( WIN_Handle32(hwnd), offset, (LONG_PTR)HCURSOR_32(newval) ));
+    default:
+        return SetClassWord( WIN_Handle32(hwnd), offset, newval );
+    }
 }
 
 
@@ -669,6 +687,10 @@
 
     switch( offset )
     {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return HCURSOR_16((HCURSOR)ret);
     case GCLP_WNDPROC:
         return (LONG_PTR)WINPROC_GetProc16( (WNDPROC)ret, FALSE );
     case GCLP_MENUNAME:
@@ -686,6 +708,10 @@
 {
     switch( offset )
     {
+    case GCLP_HCURSOR:
+    case GCLP_HICON:
+    case GCLP_HICONSM:
+        return HCURSOR_16((HCURSOR)SetClassLongW( WIN_Handle32(hwnd16), offset, (LONG_PTR)HCURSOR_32( newval ) ));
     case GCLP_WNDPROC:
         {
             WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
diff -urN wine-1.0.orig/dlls/winex11.drv/mouse.c wine-1.0/dlls/winex11.drv/mouse.c
--- wine-1.0.orig/dlls/winex11.drv/mouse.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/winex11.drv/mouse.c	2008-06-27 15:53:25.000000000 +0200
@@ -32,6 +32,9 @@
 MAKE_FUNCPTR(XcursorImageCreate);
 MAKE_FUNCPTR(XcursorImageDestroy);
 MAKE_FUNCPTR(XcursorImageLoadCursor);
+MAKE_FUNCPTR(XcursorImagesCreate);
+MAKE_FUNCPTR(XcursorImagesDestroy);
+MAKE_FUNCPTR(XcursorImagesLoadCursor);
 # undef MAKE_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 
@@ -112,6 +115,9 @@
     LOAD_FUNCPTR(XcursorImageCreate);
     LOAD_FUNCPTR(XcursorImageDestroy);
     LOAD_FUNCPTR(XcursorImageLoadCursor);
+    LOAD_FUNCPTR(XcursorImagesCreate);
+    LOAD_FUNCPTR(XcursorImagesDestroy);
+    LOAD_FUNCPTR(XcursorImagesLoadCursor);
 #undef LOAD_FUNCPTR
 #endif /* SONAME_LIBXCURSOR */
 }
@@ -404,29 +410,25 @@
 /***********************************************************************
  *              create_cursor_image
  *
- * Create an XcursorImage from a CURSORICONINFO
+ * Create an XcursorImage from a cursor_frame_t
  */
-static XcursorImage *create_cursor_image( CURSORICONINFO *ptr )
+static XcursorImage *create_cursor_image( cursor_frame_t *frame )
 {
     int x, xmax;
     int y, ymax;
     int and_size;
     unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr;
-    int and_width_bytes, xor_width_bytes;
     XcursorPixel *pixel_ptr;
     XcursorImage *image;
     BOOL alpha_zero = TRUE;
 
-    ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
-    xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
+    ymax = (frame->height > 32) ? 32 : frame->height;
+    xmax = (frame->width > 32) ? 32 : frame->width;
 
-    and_width_bytes = xmax / 8;
-    xor_width_bytes = and_width_bytes * ptr->bBitsPerPixel;
+    and_size = frame->and_width_bytes * frame->height;
+    and_ptr = and_bits = frame->bits;
 
-    and_size = ptr->nWidth * ptr->nHeight / 8;
-    and_ptr = and_bits = (unsigned char *)(ptr + 1);
-
-    xor_ptr = xor_bits = and_ptr + and_size;
+    xor_ptr = xor_bits = frame->bits + and_size;
 
     image = pXcursorImageCreate( xmax, ymax );
     pixel_ptr = image->pixels;
@@ -445,11 +447,11 @@
      *
      * Non-32 bit bitmaps always use the AND mask
      */
-    if(ptr->bBitsPerPixel == 32)
+    if(frame->bpp == 32)
     {
         for (y = 0; alpha_zero && y < ymax; ++y)
         {
-            xor_ptr = xor_bits + (y * xor_width_bytes);
+            xor_ptr = xor_bits + (y * frame->xor_width_bytes);
             for (x = 0; x < xmax; ++x)
             {
                 if (xor_ptr[3] != 0x00)
@@ -478,13 +480,13 @@
      */
     for (y = 0; y < ymax; ++y)
     {
-        and_ptr = and_bits + (y * and_width_bytes);
-        xor_ptr = xor_bits + (y * xor_width_bytes);
+        and_ptr = and_bits + (y * frame->and_width_bytes);
+        xor_ptr = xor_bits + (y * frame->xor_width_bytes);
 
         for (x = 0; x < xmax; ++x)
         {
             /* Xcursor pixel data is in ARGB format, with A in the high byte */
-            switch (ptr->bBitsPerPixel)
+            switch (frame->bpp)
             {
                 case 32:
                     /* BGRA, 8 bits each */
@@ -517,7 +519,7 @@
                     break;
 
                 default:
-                    FIXME("Currently no support for cursors with %d bits per pixel\n", ptr->bBitsPerPixel);
+                    FIXME("Currently no support for cursors with %d bits per pixel\n", frame->bpp);
                     return 0;
             }
 
@@ -548,12 +550,14 @@
  *
  * Use Xcursor to create an X cursor from a Windows one.
  */
-static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr )
+static Cursor create_xcursor_cursor( Display *display, const cursor_t *cursor_object )
 {
+    unsigned int i;
     Cursor cursor;
     XcursorImage *image;
+    XcursorImages *images;
 
-    if (!ptr) /* Create an empty cursor */
+    if (!cursor_object) /* Create an empty cursor */
     {
         image = pXcursorImageCreate( 1, 1 );
         image->xhot = 0;
@@ -565,23 +569,30 @@
         return cursor;
     }
 
-    image = create_cursor_image( ptr );
-    if (!image) return 0;
-
-    /* Make sure hotspot is valid */
-    image->xhot = ptr->ptHotSpot.x;
-    image->yhot = ptr->ptHotSpot.y;
-    if (image->xhot >= image->width ||
-        image->yhot >= image->height)
+    images = pXcursorImagesCreate( cursor_object->num_frames );
+    for (i = 0; i < cursor_object->num_frames; ++i)
     {
-        image->xhot = image->width / 2;
-        image->yhot = image->height / 2;
-    }
+        cursor_frame_t *frame = &cursor_object->frames[i];
+        image = create_cursor_image( frame );
+        if (!image) return 0;
 
-    image->delay = 0;
+        /* Make sure hotspot is valid */
+        image->xhot = frame->xhot;
+        image->yhot = frame->yhot;
+        if (image->xhot >= image->width ||
+            image->yhot >= image->height)
+        {
+            image->xhot = image->width / 2;
+            image->yhot = image->height / 2;
+        }
 
-    cursor = pXcursorImageLoadCursor( display, image );
-    pXcursorImageDestroy( image );
+        image->delay = cursor_object->delay;
+
+        images->images[images->nimage++] = image;
+    }
+
+    cursor = pXcursorImagesLoadCursor( display, images );
+    pXcursorImagesDestroy( images );
 
     return cursor;
 }
@@ -594,7 +605,7 @@
  *
  * Create an X cursor from a Windows one.
  */
-static Cursor create_cursor( Display *display, CURSORICONINFO *ptr )
+static Cursor create_cursor( Display *display, const cursor_t *ptr )
 {
     Pixmap pixmapBits, pixmapMask, pixmapMaskInv = 0, pixmapAll;
     XColor fg, bg;
@@ -621,12 +632,13 @@
     }
     else  /* Create the X cursor from the bits */
     {
+        cursor_frame_t *frame = &ptr->frames[0];
         XImage *image;
         GC gc;
 
         TRACE("Bitmap %dx%d planes=%d bpp=%d bytesperline=%d\n",
-            ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel,
-            ptr->nWidthBytes);
+            frame->width, frame->height, frame->planes, frame->bpp,
+            frame->xor_width_bytes);
 
         /* Create a pixmap and transfer all the bits to it */
 
@@ -639,11 +651,11 @@
          *  the mask and the second is the image.
          */
         if (!(pixmapAll = XCreatePixmap( display, root_window,
-                  ptr->nWidth, ptr->nHeight * 2, 1 )))
+                  frame->width, frame->height * 2, 1 )))
             return 0;
         if (!(image = XCreateImage( display, visual,
-                1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
-                ptr->nHeight * 2, 16, ptr->nWidthBytes/ptr->bBitsPerPixel)))
+                1, ZPixmap, 0, (char *)frame->bits, frame->width,
+                frame->height * 2, 16, frame->xor_width_bytes/frame->bpp)))
         {
             XFreePixmap( display, pixmapAll );
             return 0;
@@ -654,13 +666,13 @@
         image->bitmap_bit_order = MSBFirst;
         image->bitmap_unit = 16;
         _XInitImageFuncPtrs(image);
-        if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
+        if (frame->planes * frame->bpp == 1)
         {
             /* A plain old white on black cursor. */
             fg.red = fg.green = fg.blue = 0xffff;
             bg.red = bg.green = bg.blue = 0x0000;
             XPutImage( display, pixmapAll, gc, image,
-                0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
+                0, 0, 0, 0, frame->width, frame->height * 2 );
         }
         else
         {
@@ -672,11 +684,11 @@
             int     threshold, fgBits, bgBits, bitShifted;
             BYTE    pXorBits[128];   /* Up to 32x32 icons */
 
-            switch (ptr->bBitsPerPixel)
+            switch (frame->bpp)
             {
             case 32:
                 bitMask32 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                       ptr->nWidth * ptr->nHeight / 8 );
+                                       frame->width * frame->height / 8 );
                 /* Fallthrough */
             case 24:
                 rbits = 8;
@@ -692,7 +704,7 @@
                 break;
             default:
                 FIXME("Currently no support for cursors with %d bits per pixel\n",
-                  ptr->bBitsPerPixel);
+                  frame->bpp);
                 XFreePixmap( display, pixmapAll );
                 XFreeGC( display, gc );
                 image->data = NULL;
@@ -700,22 +712,22 @@
                 return 0;
             }
             /* The location of the mask. */
-            theMask = (unsigned char *)(ptr + 1);
+            theMask = frame->bits;
             /* The mask should still be 1 bit per pixel. The color image
              * should immediately follow the mask.
              */
-            theImage = &theMask[ptr->nWidth/8 * ptr->nHeight];
+            theImage = &theMask[frame->width/8 * frame->height];
             rfg = gfg = bfg = rbg = gbg = bbg = 0;
             byteIndex = 0;
             xorIndex = 0;
             fgBits = 0;
             bitShifted = 0x01;
-            xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
-            if (ptr->nWidth > 32) {
+            xmax = (frame->width > 32) ? 32 : frame->width;
+            if (frame->width > 32) {
                 ERR("Got a %dx%d cursor. Cannot handle larger than 32x32.\n",
-                  ptr->nWidth, ptr->nHeight);
+                  frame->width, frame->height);
             }
-            ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
+            ymax = (frame->height > 32) ? 32 : frame->height;
 
             memset(pXorBits, 0, 128);
             for (y=0; y<ymax; y++)
@@ -723,7 +735,7 @@
                 for (x=0; x<xmax; x++)
                 {
                    	red = green = blue = 0;
-                   	switch (ptr->bBitsPerPixel)
+                   	switch (frame->bpp)
                    	{
 			case 32:
 			    theChar = theImage[byteIndex++];
@@ -811,11 +823,11 @@
 
             /* Put the mask. */
             XPutImage( display, pixmapAll, gc, image,
-                   0, 0, 0, 0, ptr->nWidth, ptr->nHeight );
+                   0, 0, 0, 0, frame->width, frame->height );
             XSetFunction( display, gc, GXcopy );
             /* Put the image */
             XCopyArea( display, pixmapBits, pixmapAll, gc,
-                       0, 0, xmax, ymax, 0, ptr->nHeight );
+                       0, 0, xmax, ymax, 0, frame->height );
             XFreePixmap( display, pixmapBits );
         }
         image->data = NULL;
@@ -823,11 +835,11 @@
 
         /* Now create the 2 pixmaps for bits and mask */
 
-        pixmapBits = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
-        if (ptr->bBitsPerPixel != 32)
+        pixmapBits = XCreatePixmap( display, root_window, frame->width, frame->height, 1 );
+        if (frame->bpp != 32)
         {
-            pixmapMaskInv = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
-            pixmapMask = XCreatePixmap( display, root_window, ptr->nWidth, ptr->nHeight, 1 );
+            pixmapMaskInv = XCreatePixmap( display, root_window, frame->width, frame->height, 1 );
+            pixmapMask = XCreatePixmap( display, root_window, frame->width, frame->height, 1 );
 
             /* Make sure everything went OK so far */
             if (pixmapBits && pixmapMask && pixmapMaskInv)
@@ -856,45 +868,45 @@
                  */
                 XSetFunction( display, gc, GXcopy );
                 XCopyArea( display, pixmapAll, pixmapBits, gc,
-                           0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, 0, frame->width, frame->height, 0, 0 );
                 XCopyArea( display, pixmapAll, pixmapMask, gc,
-                           0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, 0, frame->width, frame->height, 0, 0 );
                 XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
-                           0, 0, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, 0, frame->width, frame->height, 0, 0 );
                 XSetFunction( display, gc, GXand );
                 XCopyArea( display, pixmapAll, pixmapMaskInv, gc,
-                           0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, frame->height, frame->width, frame->height, 0, 0 );
                 XSetFunction( display, gc, GXandReverse );
                 XCopyArea( display, pixmapAll, pixmapBits, gc,
-                           0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, frame->height, frame->width, frame->height, 0, 0 );
                 XSetFunction( display, gc, GXorReverse );
                 XCopyArea( display, pixmapAll, pixmapMask, gc,
-                           0, ptr->nHeight, ptr->nWidth, ptr->nHeight, 0, 0 );
+                           0, frame->height, frame->width, frame->height, 0, 0 );
                 /* Additional white */
                 XSetFunction( display, gc, GXor );
                 XCopyArea( display, pixmapMaskInv, pixmapMask, gc,
-                           0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
+                           0, 0, frame->width, frame->height, 1, 1 );
                 XCopyArea( display, pixmapMaskInv, pixmapBits, gc,
-                           0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
+                           0, 0, frame->width, frame->height, 1, 1 );
                 XSetFunction( display, gc, GXcopy );
             }
         }
         else
         {
             pixmapMask = XCreateBitmapFromData( display, root_window,
-                                                bitMask32, ptr->nWidth,
-                                                ptr->nHeight );
+                                                bitMask32, frame->width,
+                                                frame->height );
             HeapFree( GetProcessHeap(), 0, bitMask32 );
         }
 
         /* Make sure hotspot is valid */
-        hotspot.x = ptr->ptHotSpot.x;
-        hotspot.y = ptr->ptHotSpot.y;
-        if (hotspot.x < 0 || hotspot.x >= ptr->nWidth ||
-            hotspot.y < 0 || hotspot.y >= ptr->nHeight)
+        hotspot.x = frame->xhot;
+        hotspot.y = frame->yhot;
+        if (hotspot.x < 0 || hotspot.x >= frame->width ||
+            hotspot.y < 0 || hotspot.y >= frame->height)
         {
-            hotspot.x = ptr->nWidth / 2;
-            hotspot.y = ptr->nHeight / 2;
+            hotspot.x = frame->width / 2;
+            hotspot.y = frame->height / 2;
         }
 
         if (pixmapBits && pixmapMask)
diff -urN wine-1.0.orig/dlls/winex11.drv/x11drv.h wine-1.0/dlls/winex11.drv/x11drv.h
--- wine-1.0.orig/dlls/winex11.drv/x11drv.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/dlls/winex11.drv/x11drv.h	2008-06-27 15:53:24.000000000 +0200
@@ -724,7 +724,7 @@
 extern void X11DRV_ResetSelectionOwner(void);
 extern void X11DRV_SetFocus( HWND hwnd );
 extern Cursor X11DRV_GetCursor( Display *display, struct tagCURSORICONINFO *ptr );
-extern void X11DRV_SetCursor( struct tagCURSORICONINFO *lpCursor );
+struct cursor_t;
 extern BOOL X11DRV_ClipCursor( LPCRECT clip );
 extern void X11DRV_InitKeyboard( Display *display );
 extern void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time,
diff -urN wine-1.0.orig/include/wine/server_protocol.h wine-1.0/include/wine/server_protocol.h
--- wine-1.0.orig/include/wine/server_protocol.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/include/wine/server_protocol.h	2008-06-27 15:53:21.000000000 +0200
@@ -2755,6 +2755,90 @@
 
 
 
+struct create_cursor_request
+{
+    struct request_header __header;
+    unsigned int    num_frames;
+    unsigned short  delay;
+};
+struct create_cursor_reply
+{
+    struct reply_header __header;
+    user_handle_t   handle;
+};
+
+
+
+struct destroy_cursor_request
+{
+    struct request_header __header;
+    user_handle_t   handle;
+};
+struct destroy_cursor_reply
+{
+    struct reply_header __header;
+};
+
+
+
+struct get_cursor_info_request
+{
+    struct request_header __header;
+    user_handle_t   handle;
+};
+struct get_cursor_info_reply
+{
+    struct reply_header __header;
+    unsigned int    num_frames;
+    unsigned short  delay;
+};
+
+
+
+struct get_cursor_frame_request
+{
+    struct request_header __header;
+    user_handle_t   handle;
+    unsigned int    frame_idx;
+};
+struct get_cursor_frame_reply
+{
+    struct reply_header __header;
+    unsigned short  xhot;
+    unsigned short  yhot;
+    unsigned short  width;
+    unsigned short  height;
+    unsigned short  and_width_bytes;
+    unsigned short  xor_width_bytes;
+    unsigned char   planes;
+    unsigned char   bpp;
+    /* VARARG(data,bytes); */
+};
+
+
+
+struct set_cursor_frame_request
+{
+    struct request_header __header;
+    user_handle_t   handle;
+    unsigned int    frame_idx;
+    unsigned short  xhot;
+    unsigned short  yhot;
+    unsigned short  width;
+    unsigned short  height;
+    unsigned short  and_width_bytes;
+    unsigned short  xor_width_bytes;
+    unsigned char   planes;
+    unsigned char   bpp;
+    /* VARARG(data,bytes); */
+};
+struct set_cursor_frame_reply
+{
+    struct reply_header __header;
+};
+
+
+
 struct create_window_request
 {
     struct request_header __header;
@@ -4421,6 +4505,11 @@
     REQ_get_ioctl_result,
     REQ_create_named_pipe,
     REQ_get_named_pipe_info,
+    REQ_create_cursor,
+    REQ_destroy_cursor,
+    REQ_get_cursor_info,
+    REQ_get_cursor_frame,
+    REQ_set_cursor_frame,
     REQ_create_window,
     REQ_destroy_window,
     REQ_get_desktop_window,
@@ -4661,6 +4750,11 @@
     struct get_ioctl_result_request get_ioctl_result_request;
     struct create_named_pipe_request create_named_pipe_request;
     struct get_named_pipe_info_request get_named_pipe_info_request;
+    struct create_cursor_request create_cursor_request;
+    struct destroy_cursor_request destroy_cursor_request;
+    struct get_cursor_info_request get_cursor_info_request;
+    struct get_cursor_frame_request get_cursor_frame_request;
+    struct set_cursor_frame_request set_cursor_frame_request;
     struct create_window_request create_window_request;
     struct destroy_window_request destroy_window_request;
     struct get_desktop_window_request get_desktop_window_request;
@@ -4899,6 +4993,11 @@
     struct get_ioctl_result_reply get_ioctl_result_reply;
     struct create_named_pipe_reply create_named_pipe_reply;
     struct get_named_pipe_info_reply get_named_pipe_info_reply;
+    struct create_cursor_reply create_cursor_reply;
+    struct destroy_cursor_reply destroy_cursor_reply;
+    struct get_cursor_info_reply get_cursor_info_reply;
+    struct get_cursor_frame_reply get_cursor_frame_reply;
+    struct set_cursor_frame_reply set_cursor_frame_reply;
     struct create_window_reply create_window_reply;
     struct destroy_window_reply destroy_window_reply;
     struct get_desktop_window_reply get_desktop_window_reply;
diff -urN wine-1.0.orig/include/wine/winuser16.h wine-1.0/include/wine/winuser16.h
--- wine-1.0.orig/include/wine/winuser16.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/include/wine/winuser16.h	2008-06-27 15:53:23.000000000 +0200
@@ -148,6 +148,25 @@
 
 /* Cursors / Icons */
 
+typedef struct {
+    unsigned short xhot;
+    unsigned short yhot;
+    unsigned short width;
+    unsigned short height;
+    unsigned short and_width_bytes;
+    unsigned short xor_width_bytes;
+    unsigned char planes;
+    unsigned char bpp;
+    /* XOR & AND bitmap bits */
+    unsigned char *bits;
+} cursor_frame_t;
+
+typedef struct cursor_t {
+    unsigned int num_frames;
+    unsigned short delay;
+    cursor_frame_t *frames;
+} cursor_t;
+
 typedef struct tagCURSORICONINFO
 {
     POINT16 ptHotSpot;
diff -urN wine-1.0.orig/server/cursoricon.c wine-1.0/server/cursoricon.c
--- wine-1.0.orig/server/cursoricon.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-1.0/server/cursoricon.c	2008-06-27 15:53:20.000000000 +0200
@@ -0,0 +1,168 @@
+/*
+ * Server-side cursors / icons
+ *
+ * Copyright 2007 Henri Verbeet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "object.h"
+#include "request.h"
+#include "user.h"
+
+typedef struct {
+    unsigned short xhot;
+    unsigned short yhot;
+    unsigned short width;
+    unsigned short height;
+    unsigned short and_width_bytes;
+    unsigned short xor_width_bytes;
+    unsigned char planes;
+    unsigned char bpp;
+    /* bits contains both the AND and XOR bitmap data, in that order */
+    unsigned char *bits;
+} cursor_frame_t;
+
+typedef struct {
+    struct process *process;
+    unsigned int num_frames;
+    unsigned int delay;
+    cursor_frame_t *frames;
+} cursor_t;
+
+void destroy_cursor( cursor_t *cursor )
+{
+    unsigned int i;
+
+    for (i = 0; i < cursor->num_frames; ++i)
+    {
+        free( cursor->frames[i].bits );
+    }
+
+    free( cursor->frames );
+    free( cursor );
+}
+
+/* destroy all cursors belonging to a given process */
+void destroy_process_cursors( struct process *process )
+{
+    user_handle_t handle = 0;
+    cursor_t *cursor;
+
+    while ((cursor = next_user_handle( &handle, USER_CURSOR )))
+    {
+        if (cursor->process != process) continue;
+
+        destroy_cursor( cursor );
+        free_user_handle( handle );
+    }
+}
+
+/* Create a cursor */
+DECL_HANDLER(create_cursor)
+{
+    cursor_t *cursor = mem_alloc( sizeof(cursor_t) );
+    cursor->process = current->process;
+    cursor->num_frames = req->num_frames;
+    cursor->delay = req->delay;
+    cursor->frames = mem_alloc( req->num_frames * sizeof(cursor_frame_t) );
+    memset( cursor->frames, 0, req->num_frames * sizeof(cursor_frame_t) );
+
+    reply->handle = alloc_user_handle( cursor, USER_CURSOR );
+}
+
+/* Destroy a cursor */
+DECL_HANDLER(destroy_cursor)
+{
+    cursor_t *cursor = free_user_handle( req->handle );
+
+    if (cursor) destroy_cursor( cursor );
+}
+
+/* Get cursor info */
+DECL_HANDLER(get_cursor_info)
+{
+    cursor_t *cursor = get_user_object( req->handle, USER_CURSOR );
+
+    if (!cursor) return;
+
+    reply->num_frames = cursor->num_frames;
+    reply->delay = cursor->delay;
+}
+
+/* Get frame info & bitmap bits */
+DECL_HANDLER(get_cursor_frame)
+{
+    unsigned int data_size;
+    unsigned int frame_idx = req->frame_idx;
+    cursor_t *cursor = get_user_object( req->handle, USER_CURSOR );
+    cursor_frame_t *frame;
+
+    if (!cursor || cursor->num_frames < frame_idx)
+    {
+        reply->height = 0;
+        return;
+    }
+
+    frame = &cursor->frames[frame_idx];
+
+    reply->xhot = frame->xhot;
+    reply->yhot = frame->yhot;
+    reply->width = frame->width;
+    reply->height = frame->height;
+    reply->and_width_bytes = frame->and_width_bytes;
+    reply->xor_width_bytes = frame->xor_width_bytes;
+    reply->planes = frame->planes;
+    reply->bpp = frame->bpp;
+
+    data_size = (frame->and_width_bytes + frame->xor_width_bytes) * frame->height;
+    if (data_size > get_reply_max_size())
+    {
+        set_error( STATUS_BUFFER_OVERFLOW );
+        return;
+    }
+
+    set_reply_data( frame->bits, data_size );
+}
+
+/* Set frame info & bitmap bits */
+DECL_HANDLER(set_cursor_frame)
+{
+    size_t data_size = get_req_data_size();
+    unsigned int frame_idx = req->frame_idx;
+    cursor_t *cursor = get_user_object( req->handle, USER_CURSOR );
+    cursor_frame_t *frame;
+
+    if (!cursor || cursor->num_frames < frame_idx || !data_size) return;
+
+    frame = &cursor->frames[frame_idx];
+
+    frame->xhot = req->xhot;
+    frame->yhot = req->yhot;
+    frame->width = req->width;
+    frame->height = req->height;
+    frame->and_width_bytes = req->and_width_bytes;
+    frame->xor_width_bytes = req->xor_width_bytes;
+    frame->planes = req->planes;
+    frame->bpp = req->bpp;
+
+    free( frame->bits );
+    frame->bits = memdup( get_req_data(), data_size );
+}
diff -urN wine-1.0.orig/server/Makefile.in wine-1.0/server/Makefile.in
--- wine-1.0.orig/server/Makefile.in	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/Makefile.in	2008-06-27 15:53:20.000000000 +0200
@@ -19,6 +19,7 @@
 	context_powerpc.c \
 	context_sparc.c \
 	context_x86_64.c \
+	cursoricon.c \
 	debugger.c \
 	device.c \
 	directory.c \
diff -urN wine-1.0.orig/server/process.c wine-1.0/server/process.c
--- wine-1.0.orig/server/process.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/process.c	2008-06-27 15:53:20.000000000 +0200
@@ -657,6 +657,7 @@
         free( dll );
     }
     destroy_process_classes( process );
+    destroy_process_cursors( process );
     remove_process_locks( process );
     set_process_startup_state( process, STARTUP_ABORTED );
     finish_process_tracing( process );
diff -urN wine-1.0.orig/server/protocol.def wine-1.0/server/protocol.def
--- wine-1.0.orig/server/protocol.def	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/protocol.def	2008-06-27 15:53:20.000000000 +0200
@@ -2035,6 +2035,63 @@
 @END
 
 
+/* Create a cursor */
+@REQ(create_cursor)
+    unsigned int    num_frames;
+    unsigned short  delay;
+@REPLY
+    user_handle_t   handle;
+@END
+
+
+/* Destroy a cursor */
+@REQ(destroy_cursor)
+    user_handle_t   handle;
+@END
+
+
+/* Get cursor info */
+@REQ(get_cursor_info)
+    user_handle_t   handle;
+@REPLY
+    unsigned int    num_frames;
+    unsigned short  delay;
+@END
+
+
+/* Get cursor frame */
+@REQ(get_cursor_frame)
+    user_handle_t   handle;
+    unsigned int    frame_idx;
+@REPLY
+    unsigned short  xhot;
+    unsigned short  yhot;
+    unsigned short  width;
+    unsigned short  height;
+    unsigned short  and_width_bytes;
+    unsigned short  xor_width_bytes;
+    unsigned char   planes;
+    unsigned char   bpp;
+    VARARG(data,bytes);
+@END
+
+
+/* Set cursor frame */
+@REQ(set_cursor_frame)
+    user_handle_t   handle;
+    unsigned int    frame_idx;
+    unsigned short  xhot;
+    unsigned short  yhot;
+    unsigned short  width;
+    unsigned short  height;
+    unsigned short  and_width_bytes;
+    unsigned short  xor_width_bytes;
+    unsigned char   planes;
+    unsigned char   bpp;
+    VARARG(data,bytes);
+@END
+
+
 /* Create a window */
 @REQ(create_window)
     user_handle_t  parent;      /* parent window */
diff -urN wine-1.0.orig/server/request.h wine-1.0/server/request.h
--- wine-1.0.orig/server/request.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/request.h	2008-06-27 15:53:21.000000000 +0200
@@ -249,6 +249,11 @@
 DECL_HANDLER(get_ioctl_result);
 DECL_HANDLER(create_named_pipe);
 DECL_HANDLER(get_named_pipe_info);
+DECL_HANDLER(create_cursor);
+DECL_HANDLER(destroy_cursor);
+DECL_HANDLER(get_cursor_info);
+DECL_HANDLER(get_cursor_frame);
+DECL_HANDLER(set_cursor_frame);
 DECL_HANDLER(create_window);
 DECL_HANDLER(destroy_window);
 DECL_HANDLER(get_desktop_window);
@@ -488,6 +493,11 @@
     (req_handler)req_get_ioctl_result,
     (req_handler)req_create_named_pipe,
     (req_handler)req_get_named_pipe_info,
+    (req_handler)req_create_cursor,
+    (req_handler)req_destroy_cursor,
+    (req_handler)req_get_cursor_info,
+    (req_handler)req_get_cursor_frame,
+    (req_handler)req_set_cursor_frame,
     (req_handler)req_create_window,
     (req_handler)req_destroy_window,
     (req_handler)req_get_desktop_window,
diff -urN wine-1.0.orig/server/trace.c wine-1.0/server/trace.c
--- wine-1.0.orig/server/trace.c	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/trace.c	2008-06-27 15:53:21.000000000 +0200
@@ -2544,6 +2544,69 @@
     fprintf( stderr, " insize=%08x", req->insize );
 }
 
+static void dump_create_cursor_request( const struct create_cursor_request *req )
+{
+    fprintf( stderr, " num_frames=%08x,", req->num_frames );
+    fprintf( stderr, " delay=%04x", req->delay );
+}
+
+static void dump_create_cursor_reply( const struct create_cursor_reply *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_destroy_cursor_request( const struct destroy_cursor_request *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_cursor_info_request( const struct get_cursor_info_request *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_cursor_info_reply( const struct get_cursor_info_reply *req )
+{
+    fprintf( stderr, " num_frames=%08x,", req->num_frames );
+    fprintf( stderr, " delay=%04x", req->delay );
+}
+
+static void dump_get_cursor_frame_request( const struct get_cursor_frame_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " frame_idx=%08x", req->frame_idx );
+}
+
+static void dump_get_cursor_frame_reply( const struct get_cursor_frame_reply *req )
+{
+    fprintf( stderr, " xhot=%04x,", req->xhot );
+    fprintf( stderr, " yhot=%04x,", req->yhot );
+    fprintf( stderr, " width=%04x,", req->width );
+    fprintf( stderr, " height=%04x,", req->height );
+    fprintf( stderr, " and_width_bytes=%04x,", req->and_width_bytes );
+    fprintf( stderr, " xor_width_bytes=%04x,", req->xor_width_bytes );
+    fprintf( stderr, " planes=%02x,", req->planes );
+    fprintf( stderr, " bpp=%02x,", req->bpp );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
+static void dump_set_cursor_frame_request( const struct set_cursor_frame_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " frame_idx=%08x,", req->frame_idx );
+    fprintf( stderr, " xhot=%04x,", req->xhot );
+    fprintf( stderr, " yhot=%04x,", req->yhot );
+    fprintf( stderr, " width=%04x,", req->width );
+    fprintf( stderr, " height=%04x,", req->height );
+    fprintf( stderr, " and_width_bytes=%04x,", req->and_width_bytes );
+    fprintf( stderr, " xor_width_bytes=%04x,", req->xor_width_bytes );
+    fprintf( stderr, " planes=%02x,", req->planes );
+    fprintf( stderr, " bpp=%02x,", req->bpp );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
 static void dump_create_window_request( const struct create_window_request *req )
 {
     fprintf( stderr, " parent=%p,", req->parent );
@@ -3921,6 +3984,11 @@
     (dump_func)dump_get_ioctl_result_request,
     (dump_func)dump_create_named_pipe_request,
     (dump_func)dump_get_named_pipe_info_request,
+    (dump_func)dump_create_cursor_request,
+    (dump_func)dump_destroy_cursor_request,
+    (dump_func)dump_get_cursor_info_request,
+    (dump_func)dump_get_cursor_frame_request,
+    (dump_func)dump_set_cursor_frame_request,
     (dump_func)dump_create_window_request,
     (dump_func)dump_destroy_window_request,
     (dump_func)dump_get_desktop_window_request,
@@ -4157,6 +4225,11 @@
     (dump_func)dump_get_ioctl_result_reply,
     (dump_func)dump_create_named_pipe_reply,
     (dump_func)dump_get_named_pipe_info_reply,
+    (dump_func)dump_create_cursor_reply,
+    (dump_func)0,
+    (dump_func)dump_get_cursor_info_reply,
+    (dump_func)dump_get_cursor_frame_reply,
+    (dump_func)0,
     (dump_func)dump_create_window_reply,
     (dump_func)0,
     (dump_func)dump_get_desktop_window_reply,
@@ -4393,6 +4466,11 @@
     "get_ioctl_result",
     "create_named_pipe",
     "get_named_pipe_info",
+    "create_cursor",
+    "destroy_cursor",
+    "get_cursor_info",
+    "get_cursor_frame",
+    "set_cursor_frame",
     "create_window",
     "destroy_window",
     "get_desktop_window",
diff -urN wine-1.0.orig/server/user.h wine-1.0/server/user.h
--- wine-1.0.orig/server/user.h	2008-06-17 16:07:31.000000000 +0200
+++ wine-1.0/server/user.h	2008-06-27 15:53:21.000000000 +0200
@@ -35,7 +35,8 @@
 enum user_object
 {
     USER_WINDOW = 1,
-    USER_HOOK
+    USER_HOOK,
+    USER_CURSOR
 };
 
 #define DESKTOP_ATOM  ((atom_t)32769)
@@ -75,6 +76,10 @@
 
 extern void cleanup_clipboard_thread( struct thread *thread );
 
+/* cursor functions */
+
+extern void destroy_process_cursors( struct process *process );
+
 /* hook functions */
 
 extern void remove_thread_hooks( struct thread *thread );
