diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index fea90ac..44a4cc4 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -6,7 +6,7 @@ VPATH     = @srcdir@
 MODULE    = user32.dll
 IMPORTLIB = libuser32.$(IMPLIBEXT)
 IMPORTS   = gdi32 advapi32 kernel32 ntdll
-DELAYIMPORTS = imm32
+DELAYIMPORTS = imm32 winmm
 EXTRALIBS = $(LIBUNICODE)
 
 SPEC_SRCS16 = \
diff --git a/dlls/user/cursoricon.c b/dlls/user/cursoricon.c
index c7d314a..75b733a 100644
--- a/dlls/user/cursoricon.c
+++ b/dlls/user/cursoricon.c
@@ -68,6 +68,7 @@ #include "wine/debug.h"
 #include "wine/list.h"
 #include "wine/server.h"
 #include "user_private.h"
+#include "mmsystem.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
 WINE_DECLARE_DEBUG_CHANNEL(icon);
@@ -1168,6 +1169,175 @@ static BOOL load_cursor_frame( LPBYTE bi
 }
 
 /**********************************************************************
+ *          .ANI cursor support
+ */
+#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;
+
+static void dump_ani_header( const ani_header *header )
+{
+    TRACE("     header size: %ld\n", header->header_size);
+    TRACE("          frames: %ld\n", header->num_frames);
+    TRACE("           steps: %ld\n", header->num_steps);
+    TRACE("           width: %ld\n", header->width);
+    TRACE("          height: %ld\n", header->height);
+    TRACE("             bpp: %ld\n", header->bpp);
+    TRACE("          planes: %ld\n", header->num_planes);
+    TRACE("    display rate: %ld\n", header->display_rate);
+    TRACE("           flags: 0x%08lx\n", header->flags);
+}
+
+static HCURSOR load_ani( const LPBYTE bits, DWORD bits_size, INT width, INT height )
+{
+    int i;
+    WORD max_count = 0;
+    HCURSOR cursor = INVALID_HANDLE_VALUE;
+    CURSORICONFILEDIR *dir = 0;
+    ani_header header = {0};
+    DWORD *frame_seq = 0;
+    cursor_frame_t *frames;
+    unsigned int frame_bits_size = 0;
+    LPBYTE frame_bits;
+    POINT16 hotspot;
+
+    HMMIO hmmio;
+    MMIOINFO mmio_info = {0};
+    MMCKINFO root_chunk, anih_chunk, seq_chunk, icon_list, icon_chunk;
+
+    TRACE("bits %p, bits_size %ld\n", bits, bits_size);
+
+    mmio_info.fccIOProc = FOURCC_MEM;
+    mmio_info.pchBuffer = bits;
+    mmio_info.cchBuffer = bits_size;
+    hmmio = mmioOpenW( NULL, &mmio_info, MMIO_READWRITE );
+    if (!hmmio) return INVALID_HANDLE_VALUE;
+
+    root_chunk.fccType = mmioFOURCC( 'A', 'C', 'O', 'N' );
+    if (mmioDescend( hmmio, &root_chunk, 0, MMIO_FINDRIFF ))
+    {
+        ERR("Failed to get root chunk.\n");
+        goto cleanup;
+    }
+
+    anih_chunk.ckid = mmioFOURCC( 'a', 'n', 'i', 'h' );
+    if (mmioDescend( hmmio, &anih_chunk, &root_chunk, MMIO_FINDCHUNK ))
+    {
+        ERR("Failed to get 'anih' chunk.\n");
+        goto cleanup;
+    }
+    mmioRead( hmmio, (char *)&header, sizeof(header) );
+    mmioAscend( hmmio, &anih_chunk, 0 );
+    dump_ani_header( &header );
+
+    if (header.flags & ANI_FLAG_SEQUENCE)
+    {
+        TRACE("Loading sequence data.\n");
+        seq_chunk.ckid = mmioFOURCC( 's', 'e', 'q', ' ' );
+        if (mmioDescend( hmmio, &seq_chunk, &root_chunk, MMIO_FINDCHUNK ))
+        {
+            ERR("Failed to get 'seq ' chunk\n");
+            goto cleanup;
+        }
+        frame_seq = HeapAlloc( GetProcessHeap(), 0, sizeof(DWORD) * header.num_steps );
+        mmioRead( hmmio, (char *)frame_seq, sizeof(DWORD) * header.num_steps );
+        mmioAscend( hmmio, &seq_chunk, 0 );
+    }
+
+    icon_list.fccType = mmioFOURCC( 'f', 'r', 'a', 'm' );
+    if (mmioDescend( hmmio, &icon_list, &root_chunk, MMIO_FINDLIST ))
+    {
+        ERR("Failed to get icon list\n");
+        goto cleanup;
+    }
+
+    if (mmioDescend( hmmio, &icon_chunk, &icon_list, 0 ))
+    {
+        ERR("Failed to get icon chunk\n");
+        goto cleanup;
+    }
+
+    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;
+        LONG chunk_start = mmioSeek( hmmio, 0, SEEK_CUR );
+
+        mmioSeek( hmmio, 4, SEEK_CUR );   /* Skip magic */
+        mmioRead( hmmio, (char *)&count, 2 );
+
+        /* There's a decent chance the amount of entries will be the same for each icon */
+        if (count > max_count)
+        {
+            HeapFree( GetProcessHeap(), 0, dir );
+            dir = HeapAlloc( GetProcessHeap(), 0, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6 );
+            max_count = count;
+        }
+        mmioSeek( hmmio, chunk_start, SEEK_SET );
+        mmioRead( hmmio, (char *)dir, (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;
+
+        mmioSeek( hmmio, chunk_start+entry->dwDIBOffset, SEEK_SET );
+        mmioRead( hmmio, frame_bits, entry->dwDIBSize );
+
+        load_cursor_frame( frame_bits, entry->dwDIBSize, hotspot, 0x00030000, header.width, header.height, 0, &frames[i] );
+
+        if (mmioDescend( hmmio, &icon_chunk, &icon_list, 0 )) break;
+    }
+    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 );
+
+cleanup:
+    mmioClose( hmmio, 0 );
+    return cursor;
+}
+
+
+/**********************************************************************
  *		CreateIconFromResourceEx (USER32.@)
  *
  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
@@ -1242,6 +1412,11 @@ static HICON CURSORICON_LoadFromFile( LP
     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;
+    else if (!memcmp( bits, "RIFF", 4 ))
+    {
+        hIcon = load_ani( bits, filesize, width, height );
+        goto end;
+    }
 
     dir = (CURSORICONFILEDIR*) bits;
     if ( filesize < sizeof(*dir) )
