[COMCTL32] Improve failure cases.
[reactos.git] / dll / win32 / comctl32 / imagelist.c
index dbbb494..c7c780b 100644 (file)
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * NOTE
- *
- * This code was audited for completeness against the documented features
- * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
- *
- * Unless otherwise noted, we believe this code to be complete, as per
- * the specification mentioned above.
- * If you discover missing features, or bugs, please note them below.
- *
  *  TODO:
  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
- *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
+ *    - Add support for ILS_GLOW, ILS_SHADOW
  *    - Thread-safe locking
  */
 
-#include "comctl32.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include <commoncontrols.h>
-#include <wine/exception.h>
+#define COBJMACROS
+
+#include "winerror.h"
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h"
+#include "comctl32.h"
+#include "commoncontrols.h"
+#include "wine/debug.h"
+#include "wine/exception.h"
+#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
 
 #define MAX_OVERLAYIMAGE 15
 
+#ifdef __REACTOS__
+//The big bad reactos image list hack!
+BOOL is_valid2(HIMAGELIST himl);
+INT WINAPI Internal_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon);
+BOOL WINAPI Internal_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp);
+COLORREF WINAPI Internal_SetBkColor (HIMAGELIST himl, COLORREF clrBk);
+BOOL WINAPI Internal_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay);
+
+#define ImageList_Add Internal_Add
+#define ImageList_ReplaceIcon Internal_ReplaceIcon
+#define ImageList_SetOverlayImage Internal_SetOverlayImage
+#define ImageList_Replace Internal_Replace
+#define ImageList_AddMasked Internal_AddMasked
+#define ImageList_Remove Internal_Remove
+#define ImageList_GetIcon Internal_GetIcon
+#define ImageList_GetImageInfo Internal_GetImageInfo
+#define ImageList_Copy Internal_Copy
+#define ImageList_Merge Internal_Merge
+#define ImageList_Duplicate Internal_Duplicate
+#define ImageList_GetIconSize Internal_GetIconSize
+#define ImageList_SetIconSize Internal_SetIconSize
+#define ImageList_GetImageCount Internal_GetImageCount
+#define ImageList_SetImageCount Internal_SetImageCount
+#define ImageList_SetBkColor Internal_SetBkColor
+#define ImageList_GetBkColor Internal_GetBkColor
+#define ImageList_BeginDrag Internal_BeginDrag
+#define ImageList_DrawIndirect Internal_DrawIndirect
+#endif
+
 struct _IMAGELIST
 {
     IImageList2 IImageList2_iface;         /* 00: IImageList vtable */
@@ -67,11 +101,15 @@ struct _IMAGELIST
     INT         nOvlIdx[MAX_OVERLAYIMAGE]; /* 38: overlay images index */
 
     /* not yet found out */
+    #ifdef __REACTOS__
+    ULONG   usMagic;
+    #endif
     HBRUSH  hbrBlend25;
     HBRUSH  hbrBlend50;
     INT     cInitial;
     UINT    uBitsPixel;
     char   *has_alpha;
+    BOOL    color_table_set;
 
     LONG        ref;                       /* reference count */
 };
@@ -260,7 +298,7 @@ static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
     SelectObject( hdc, hbmImage );
     mask_width = (bm.bmWidth + 31) / 32 * 4;
 
-    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    if (!(info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     info->bmiHeader.biWidth = bm.bmWidth;
     info->bmiHeader.biHeight = -height;
@@ -272,17 +310,17 @@ static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
     info->bmiHeader.biYPelsPerMeter = 0;
     info->bmiHeader.biClrUsed = 0;
     info->bmiHeader.biClrImportant = 0;
-    if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+    if (!(bits = heap_alloc( info->bmiHeader.biSizeImage ))) goto done;
     if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
 
     if (hbmMask)
     {
-        if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
+        if (!(mask_info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
             goto done;
         mask_info->bmiHeader = info->bmiHeader;
         mask_info->bmiHeader.biBitCount = 1;
         mask_info->bmiHeader.biSizeImage = mask_width * height;
-        if (!(mask_bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
+        if (!(mask_bits = heap_alloc_zero( mask_info->bmiHeader.biSizeImage )))
             goto done;
         if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
     }
@@ -291,13 +329,16 @@ static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
     ret = TRUE;
 
 done:
-    HeapFree( GetProcessHeap(), 0, info );
-    HeapFree( GetProcessHeap(), 0, mask_info );
-    HeapFree( GetProcessHeap(), 0, bits );
-    HeapFree( GetProcessHeap(), 0, mask_bits );
+    heap_free( info );
+    heap_free( mask_info );
+    heap_free( bits );
+    heap_free( mask_bits );
     return ret;
 }
 
+UINT WINAPI
+ImageList_SetColorTable(HIMAGELIST himl, UINT uStartIndex, UINT cEntries, const RGBQUAD *prgb);
+
 /*************************************************************************
  * IMAGELIST_InternalExpandBitmaps [Internal]
  *
@@ -374,7 +415,7 @@ IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
         if (new_alpha) himl->has_alpha = new_alpha;
         else
         {
-            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
+            heap_free( himl->has_alpha );
             himl->has_alpha = NULL;
         }
     }
@@ -420,7 +461,8 @@ ImageList_Add (HIMAGELIST himl,     HBITMAP hbmImage, HBITMAP hbmMask)
 
     nImageCount = bmp.bmWidth / himl->cx;
 
-    TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
+    TRACE("%p has %d images (%d x %d) bpp %d\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight,
+          bmp.bmBitsPixel);
 
     IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
 
@@ -438,6 +480,14 @@ ImageList_Add (HIMAGELIST himl,    HBITMAP hbmImage, HBITMAP hbmMask)
         SelectObject(hdcTemp, hbmMask);
     }
 
+    if (himl->uBitsPixel <= 8 && bmp.bmBitsPixel <= 8 &&
+        !himl->color_table_set && himl->cCurImage == 0)
+    {
+        RGBQUAD colors[256];
+        UINT num = GetDIBColorTable( hdcBitmap, 0, 1 << bmp.bmBitsPixel, colors );
+        if (num) ImageList_SetColorTable( himl, 0, num, colors );
+    }
+
     for (i=0; i<nImageCount; i++)
     {
         imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
@@ -586,6 +636,7 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
                     INT dxHotspot, INT dyHotspot)
 {
     INT cx, cy;
+    POINT src, dst;
 
     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
          dxHotspot, dyHotspot);
@@ -593,8 +644,11 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
     if (!is_valid(himlTrack))
        return FALSE;
 
+    if (iTrack >= himlTrack->cCurImage)
+        return FALSE;
+
     if (InternalDrag.himl)
-        ImageList_EndDrag ();
+        return FALSE;
 
     cx = himlTrack->cx;
     cy = himlTrack->cy;
@@ -609,10 +663,12 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
     InternalDrag.dyHotspot = dyHotspot;
 
     /* copy image */
-    BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
-
-    /* copy mask */
-    BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
+    imagelist_point_from_index(InternalDrag.himl, 0, &dst);
+    imagelist_point_from_index(himlTrack, iTrack, &src);
+    BitBlt(InternalDrag.himl->hdcImage, dst.x, dst.y, cx, cy, himlTrack->hdcImage, src.x, src.y,
+            SRCCOPY);
+    BitBlt(InternalDrag.himl->hdcMask, dst.x, dst.y, cx, cy, himlTrack->hdcMask, src.x, src.y,
+            SRCCOPY);
 
     InternalDrag.himl->cCurImage = 1;
 
@@ -757,7 +813,8 @@ ImageList_Create (INT cx, INT cy, UINT flags,
 
     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
 
-    if (cx <= 0 || cy <= 0) return NULL;
+    if (cx < 0 || cy < 0) return NULL;
+    if (!((flags&ILC_COLORDDB) == ILC_COLORDDB) && (cx == 0 || cy == 0)) return NULL;
 
     /* Create the IImageList interface for the image list */
     if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
@@ -780,6 +837,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
     himl->cGrow     = cGrow;
     himl->clrFg     = CLR_DEFAULT;
     himl->clrBk     = CLR_NONE;
+    himl->color_table_set = FALSE;
 
     /* initialize overlay mask indices */
     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
@@ -828,7 +886,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
         himl->hbmMask = 0;
 
     if (ilc == ILC_COLOR32)
-        himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
+        himl->has_alpha = heap_alloc_zero( himl->cMaxImage );
     else
         himl->has_alpha = NULL;
 
@@ -910,11 +968,7 @@ ImageList_DragEnter (HWND hwndLock, INT x, INT y)
     InternalDrag.y = y;
 
     /* draw the drag image and save the background */
-    if (!ImageList_DragShowNolock(TRUE)) {
-       return FALSE;
-    }
-
-    return TRUE;
+    return ImageList_DragShowNolock(TRUE);
 }
 
 
@@ -1226,8 +1280,11 @@ ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
     return ImageList_DrawIndirect (&imldp);
 }
 
-
+#ifdef __REACTOS__
+static BOOL alpha_blend_image( HIMAGELIST himl, HDC srce_dc, HDC dest_dc, int dest_x, int dest_y,
+#else
 static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+#endif
                                int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
                                UINT style, COLORREF blend_col )
 {
@@ -1240,7 +1297,7 @@ static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int des
     int i, j;
 
     if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
-    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    if (!(info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     info->bmiHeader.biWidth = cx;
     info->bmiHeader.biHeight = cy;
@@ -1252,9 +1309,21 @@ static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int des
     info->bmiHeader.biYPelsPerMeter = 0;
     info->bmiHeader.biClrUsed = 0;
     info->bmiHeader.biClrImportant = 0;
+#ifdef __REACTOS__
+    if (!(bmp = CreateDIBSection( srce_dc, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+#else
     if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+#endif
     SelectObject( hdc, bmp );
+#ifdef __REACTOS__
+    if (!BitBlt( hdc, 0, 0, cx, cy, srce_dc, src_x, src_y, SRCCOPY ))
+    {
+        TRACE("BitBlt failed\n");
+        goto done;
+    }
+#else
     BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
+#endif
 
     if (blend_col != CLR_NONE)
     {
@@ -1307,10 +1376,27 @@ static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int des
         info->bmiColors[1].rgbBlue     = 0xff;
         info->bmiColors[1].rgbReserved = 0;
         if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
+        {
+            TRACE("CreateDIBSection failed %i\n", GetLastError());
+            goto done;
+        }
+        if (SelectObject(hdc, mask) == NULL)
+        {
+            TRACE("SelectObject failed %i\n", GetLastError());
+            SelectObject(hdc, bmp);
+            goto done;
+        }
+        if (!BitBlt(hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY))
+        {
+            TRACE("BitBlt failed %i\n", GetLastError());
+            SelectObject(hdc, bmp);
+            goto done;
+        }
+        if (SelectObject(hdc, bmp) == NULL)
+        {
+            TRACE("SelectObject failed %i\n", GetLastError());
             goto done;
-        SelectObject( hdc, mask );
-        BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
-        SelectObject( hdc, bmp );
+        }
         for (i = 0, ptr = bits; i < cy; i++)
             for (j = 0; j < cx; j++, ptr++)
                 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
@@ -1323,10 +1409,80 @@ done:
     DeleteDC( hdc );
     if (bmp) DeleteObject( bmp );
     if (mask) DeleteObject( mask );
-    HeapFree( GetProcessHeap(), 0, info );
+    heap_free( info );
     return ret;
 }
 
+#ifdef __REACTOS__
+HDC saturate_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+                    int src_x, int src_y, int cx, int cy, COLORREF rgbFg)
+{
+    HDC hdc = NULL;
+    HBITMAP bmp = 0;
+    BITMAPINFO *info;
+
+    unsigned int *ptr;
+    void *bits;
+    int i;
+
+    /* create a dc and its device independent bitmap for doing the work,
+       shamelessly copied from the alpha-blending function above */
+    if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = cx;
+    info->bmiHeader.biHeight = cy;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = cx * cy * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(bmp = CreateDIBSection(himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+
+    /* bind both surfaces */
+    if (SelectObject(hdc, bmp) == NULL)
+    {
+        TRACE("SelectObject failed\n");
+        goto done;
+    }
+
+    /* copy into our dc the section that covers just the icon we we're asked for */
+    if (!BitBlt(hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY))
+    {
+        TRACE("BitBlt failed!\n");
+        goto done;
+    }
+
+    /* loop every pixel of the bitmap */
+    for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
+    {
+        COLORREF orig_color = *ptr;
+
+        /* calculate the effective luminance using the constants from here, adapted to the human eye:
+           <http://bobpowell.net/grayscale.aspx> */
+        float mixed_color = (GetRValue(orig_color) * .30 +
+                             GetGValue(orig_color) * .59 +
+                             GetBValue(orig_color) * .11);
+
+        *ptr = RGBA(mixed_color, mixed_color, mixed_color, GetAValue(orig_color));
+    }
+
+done:
+
+    if (bmp)
+        DeleteObject(bmp);
+
+    if (info)
+        HeapFree(GetProcessHeap(), 0, info);
+
+    /* return the handle to our desaturated dc, that will substitute its original counterpart in the next calls */
+    return hdc;
+}
+#endif /* __REACTOS__ */
+
 /*************************************************************************
  * ImageList_DrawIndirect [COMCTL32.@]
  *
@@ -1354,6 +1510,9 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
     HBRUSH hOldBrush;
     POINT pt;
     BOOL has_alpha;
+#ifdef __REACTOS__
+    HDC hdcSaturated = NULL;
+#endif
 
     if (!pimldp || !(himl = pimldp->himl)) return FALSE;
     if (!is_valid(himl)) return FALSE;
@@ -1403,6 +1562,27 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
     oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
     oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
 
+#ifdef __REACTOS__
+    /*
+     * If the ILS_SATURATE bit is enabled we should multiply the
+     * RGB colors of the original image by the contents of rgbFg.
+     */
+    if (fState & ILS_SATURATE)
+    {
+        hdcSaturated = saturate_image(himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+                                      pt.x, pt.y, cx, cy, pimldp->rgbFg);
+
+        if (hdcSaturated != NULL)
+        {
+            hImageListDC = hdcSaturated;
+            /* shitty way of getting subroutines to blit at the right place (top left corner),
+               as our modified imagelist only contains a single image for performance reasons */
+            pt.x = 0;
+            pt.y = 0;
+        }
+    }
+#endif
+
     has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
     if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
     {
@@ -1423,7 +1603,11 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
 
         if (bIsTransparent)
         {
+#ifdef __REACTOS__
+            bResult = alpha_blend_image( himl, hImageListDC, pimldp->hdcDst, pimldp->x, pimldp->y,
+#else
             bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+#endif
                                          pt.x, pt.y, cx, cy, func, fStyle, blend_col );
             goto end;
         }
@@ -1433,7 +1617,11 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
 
         hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
+#ifdef __REACTOS__
+        alpha_blend_image( himl, hImageListDC, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
+#else
         alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
+#endif
         DeleteObject (SelectObject (hImageDC, hOldBrush));
         bResult = BitBlt( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
         goto end;
@@ -1527,7 +1715,9 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
        }
     }
 
+#ifndef __REACTOS__
     if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
+#endif
     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
 
@@ -1555,6 +1745,10 @@ end:
     SetTextColor(hImageDC, oldImageFg);
     SelectObject(hImageDC, hOldImageBmp);
 cleanup:
+#ifdef __REACTOS__
+    if (hdcSaturated)
+        DeleteDC(hdcSaturated);
+#endif
     DeleteObject(hBlendMaskBmp);
     DeleteObject(hImageBmp);
     DeleteDC(hImageDC);
@@ -1713,8 +1907,13 @@ DWORD WINAPI
 ImageList_GetFlags(HIMAGELIST himl)
 {
     TRACE("%p\n", himl);
-
+#ifdef __REACTOS__
+    if(!is_valid2(himl))
+        return 0;
+    return himl->flags;
+#else
     return is_valid(himl) ? himl->flags : 0;
+#endif
 }
 
 
@@ -1812,8 +2011,6 @@ ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
 {
     if (!is_valid(himl) || !cx || !cy)
        return FALSE;
-    if ((himl->cx <= 0) || (himl->cy <= 0))
-       return FALSE;
 
     *cx = himl->cx;
     *cy = himl->cy;
@@ -1904,6 +2101,12 @@ ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
 BOOL WINAPI
 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
 {
+#ifdef __REACTOS__
+    IMAGEINFO ImageInfo;
+    if (!ImageList_GetImageInfo(himl, i, &ImageInfo))
+        return FALSE;
+    *lpRect = ImageInfo.rcImage;
+#else
     POINT pt;
 
     if (!is_valid(himl) || (lpRect == NULL))
@@ -1916,7 +2119,7 @@ ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
     lpRect->top    = pt.y;
     lpRect->right  = pt.x + himl->cx;
     lpRect->bottom = pt.y + himl->cy;
-
+#endif
     return TRUE;
 }
 
@@ -1943,11 +2146,11 @@ ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
                                     uType, uFlags);
 
     len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
-    lpbmpW = Alloc(len * sizeof(WCHAR));
+    lpbmpW = heap_alloc(len * sizeof(WCHAR));
     MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
 
     himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
-    Free (lpbmpW);
+    heap_free (lpbmpW);
     return himl;
 }
 
@@ -2009,7 +2212,8 @@ ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
 
         nImageCount = dib.dsBm.bmWidth / cx;
 
-        himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);
+        if (clrMask != CLR_NONE) color |= ILC_MASK;
+        himl = ImageList_Create (cx, dib.dsBm.bmHeight, color, nImageCount, cGrow);
         if (!himl) {
             DeleteObject (handle);
             return NULL;
@@ -2153,7 +2357,7 @@ ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
 
 
 /* helper for ImageList_Read, see comments below */
-static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
+static void *read_bitmap(IStream *pstm, BITMAPINFO *bmi)
 {
     BITMAPFILEHEADER   bmfh;
     int bitsperpixel, palspace;
@@ -2187,12 +2391,12 @@ static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
     if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
         return NULL;
 
-    bits = Alloc(bmi->bmiHeader.biSizeImage);
+    bits = heap_alloc_zero(bmi->bmiHeader.biSizeImage);
     if (!bits) return NULL;
 
     if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
     {
-        Free(bits);
+        heap_free(bits);
         return NULL;
     }
     return bits;
@@ -2229,7 +2433,7 @@ static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
  *
  *     BYTE                    maskbits[imagesize];
  */
-HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
+HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
 {
     char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
     char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
@@ -2304,8 +2508,8 @@ HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
                            0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
                            mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
     }
-    Free( image_bits );
-    Free( mask_bits );
+    heap_free( image_bits );
+    heap_free( mask_bits );
 
     himl->cCurImage = ilHead.cCurImage;
     himl->cMaxImage = ilHead.cMaxImage;
@@ -2369,8 +2573,8 @@ ImageList_Remove (HIMAGELIST himl, INT i)
 
         if (himl->has_alpha)
         {
-            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
-            himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
+            heap_free( himl->has_alpha );
+            himl->has_alpha = heap_alloc_zero( himl->cMaxImage );
         }
 
         hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
@@ -2917,7 +3121,7 @@ ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
         if (new_alpha) himl->has_alpha = new_alpha;
         else
         {
-            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
+            heap_free( himl->has_alpha );
             himl->has_alpha = NULL;
         }
     }
@@ -2963,8 +3167,7 @@ ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
 /* helper for ImageList_Write - write bitmap to pstm
  * currently everything is written as 24 bit RGB, except masks
  */
-static BOOL
-_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
+static BOOL _write_bitmap(HBITMAP hBitmap, IStream *pstm)
 {
     LPBITMAPFILEHEADER bmfh;
     LPBITMAPINFOHEADER bmih;
@@ -2986,7 +3189,7 @@ _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
     offBits = totalSize;
     totalSize += sizeImage;
 
-    data = Alloc(totalSize);
+    data = heap_alloc_zero(totalSize);
     bmfh = (LPBITMAPFILEHEADER)data;
     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
     lpBits = data + offBits;
@@ -3027,7 +3230,7 @@ _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
     result = TRUE;
 
 failed:
-    Free(data);
+    heap_free(data);
 
     return result;
 }
@@ -3050,8 +3253,7 @@ failed:
  *     probably.
  */
 
-BOOL WINAPI
-ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
+BOOL WINAPI ImageList_Write(HIMAGELIST himl, IStream *pstm)
 {
     ILHEAD ilHead;
     int i;
@@ -3120,11 +3322,25 @@ static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
 
        if (himl->uBitsPixel <= ILC_COLOR8)
        {
-            /* retrieve the default color map */
-            HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
-            GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
-            DeleteObject( tmp );
-       }
+            if (!himl->color_table_set)
+            {
+                /* retrieve the default color map */
+                HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
+                GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
+                DeleteObject( tmp );
+                if (ilc == ILC_COLOR4)
+                {
+                    RGBQUAD tmp;
+                    tmp = bmi->bmiColors[7];
+                    bmi->bmiColors[7] = bmi->bmiColors[8];
+                    bmi->bmiColors[8] = tmp;
+                }
+            }
+            else
+            {
+                GetDIBColorTable(himl->hdcImage, 0, 1 << himl->uBitsPixel, bmi->bmiColors);
+            }
+        }
        hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
     }
     else /*if (ilc == ILC_COLORDDB)*/
@@ -3159,6 +3375,12 @@ static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
 UINT WINAPI
 ImageList_SetColorTable(HIMAGELIST himl, UINT uStartIndex, UINT cEntries, const RGBQUAD *prgb)
 {
+#ifdef __REACTOS__
+    if(!is_valid2(himl))
+        return 0;
+#endif
+    TRACE("(%p, %d, %d, %p)\n", himl, uStartIndex, cEntries, prgb);
+    himl->color_table_set = TRUE;
     return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
 }
 
@@ -3249,8 +3471,8 @@ static ULONG WINAPI ImageListImpl_Release(IImageList2 *iface)
         if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
 
         This->IImageList2_iface.lpVtbl = NULL;
-        HeapFree(GetProcessHeap(), 0, This->has_alpha);
-        HeapFree(GetProcessHeap(), 0, This);
+        heap_free(This->has_alpha);
+        heap_free(This);
     }
 
     return ref;
@@ -3383,6 +3605,12 @@ static HRESULT WINAPI ImageListImpl_Copy(IImageList2 *iface, int dst_index,
     if (!unk_src)
         return E_FAIL;
 
+#ifdef __REACTOS__
+    /* Make sure that the second image list uses the same implementation with the first */
+    if (!is_valid2((HIMAGELIST)unk_src))
+        return E_FAIL;
+#endif
+
     /* TODO: Add test for IID_ImageList2 too */
     if (FAILED(IUnknown_QueryInterface(unk_src, &IID_IImageList,
             (void **) &src)))
@@ -3407,6 +3635,12 @@ static HRESULT WINAPI ImageListImpl_Merge(IImageList2 *iface, int i1,
 
     TRACE("(%p)->(%d %p %d %d %d %s %p)\n", iface, i1, punk2, i2, dx, dy, debugstr_guid(riid), ppv);
 
+#ifdef __REACTOS__
+    /* Make sure that the second image list uses the same implementation with the first */
+    if (!is_valid2((HIMAGELIST)punk2))
+        return E_FAIL;
+#endif
+
     /* TODO: Add test for IID_ImageList2 too */
     if (FAILED(IUnknown_QueryInterface(punk2, &IID_IImageList,
             (void **) &iml2)))
@@ -3457,7 +3691,9 @@ static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList2 *iface, int i,
     if (!ImageList_GetImageInfo(imgl, i, &info))
         return E_FAIL;
 
-    return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
+    *prc = info.rcImage;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList2 *iface, int *cx,
@@ -3535,7 +3771,7 @@ static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList2 *iface,
     IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
 {
     IImageList *iml2 = NULL;
-    HRESULT ret;
+    BOOL ret;
 
     if (!punk)
         return E_FAIL;
@@ -3734,7 +3970,12 @@ static BOOL is_valid(HIMAGELIST himl)
     BOOL valid;
     __TRY
     {
+    #ifdef __REACTOS__
+        valid = himl && himl->usMagic == IMAGELIST_MAGIC;
+    #else
         valid = himl && himl->IImageList2_iface.lpVtbl == &ImageListImpl_Vtbl;
+    #endif
+
     }
     __EXCEPT_PAGE_FAULT
     {
@@ -3777,10 +4018,13 @@ static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID ii
 
     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
 
-    This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct _IMAGELIST));
+    This = heap_alloc_zero(sizeof(struct _IMAGELIST));
     if (!This) return E_OUTOFMEMORY;
 
     This->IImageList2_iface.lpVtbl = &ImageListImpl_Vtbl;
+#ifdef __REACTOS__
+    This->usMagic = IMAGELIST_MAGIC;
+#endif
     This->ref = 1;
 
     ret = IImageList2_QueryInterface(&This->IImageList2_iface, iid, ppv);
@@ -3788,3 +4032,311 @@ static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID ii
 
     return ret;
 }
+
+
+
+#ifdef __REACTOS__
+//The big bad reactos image list hack!
+#undef ImageList_Add
+#undef ImageList_ReplaceIcon
+#undef ImageList_SetOverlayImage
+#undef ImageList_Replace
+#undef ImageList_AddMasked
+#undef ImageList_Remove
+#undef ImageList_GetIcon
+#undef ImageList_GetImageInfo
+#undef ImageList_Copy
+#undef ImageList_Merge
+#undef ImageList_Duplicate
+#undef ImageList_GetIconSize
+#undef ImageList_SetIconSize
+#undef ImageList_GetImageCount
+#undef ImageList_SetImageCount
+#undef ImageList_SetBkColor
+#undef ImageList_GetBkColor
+#undef ImageList_BeginDrag
+#undef ImageList_DrawIndirect
+
+static inline IImageList2* IImageList2_from_impl(HIMAGELIST himl)
+{
+    if (is_valid(himl))
+    {
+        return &himl->IImageList2_iface;
+    }
+    return NULL;
+}
+
+BOOL is_valid2(HIMAGELIST himl)
+{
+    BOOL valid;
+    __TRY
+    {
+        valid = himl && 
+                himl->IImageList2_iface.lpVtbl == &ImageListImpl_Vtbl && 
+                himl->usMagic == IMAGELIST_MAGIC;
+    }
+    __EXCEPT_PAGE_FAULT
+    {
+        valid = FALSE;
+    }
+    __ENDTRY
+    return valid;
+}
+
+INT WINAPI
+ImageList_Add (HIMAGELIST himl,        HBITMAP hbmImage, HBITMAP hbmMask)
+{
+    int res;
+    HRESULT hr;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return -1;
+
+    hr = piml->lpVtbl->Add(piml, hbmImage, hbmMask, &res);
+    if (FAILED(hr))
+        return -1;
+
+    return res;
+}
+
+INT WINAPI
+ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
+{
+    int res;
+    HRESULT hr;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return -1;
+
+    hr = piml->lpVtbl->ReplaceIcon(piml, nIndex, hIcon, &res);
+    if (FAILED(hr))
+        return -1;
+
+    return res;
+}
+
+BOOL WINAPI
+ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->SetOverlayImage(piml, iImage, iOverlay) == S_OK) ? TRUE : FALSE;
+}
+
+BOOL WINAPI
+ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
+                  HBITMAP hbmMask)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->Replace(piml, i, hbmImage, hbmMask) == S_OK) ? TRUE : FALSE;
+}
+
+INT WINAPI
+ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
+{
+    int res;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    HRESULT hr;
+    if (!piml)
+        return -1;
+
+    hr = piml->lpVtbl->AddMasked(piml, hBitmap, clrMask, &res);
+    if (FAILED(hr))
+        return -1;
+
+    return res;
+}
+
+BOOL WINAPI
+ImageList_Remove (HIMAGELIST himl, INT i)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return -1;
+
+    return (piml->lpVtbl->Remove(piml, i) == S_OK) ? TRUE : FALSE;
+}
+
+HICON WINAPI
+ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
+{
+    HICON res;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    HRESULT hr;
+    if (!piml)
+        return NULL;
+
+    hr = piml->lpVtbl->GetIcon(piml, i, fStyle, &res);
+    if (FAILED(hr))
+        return NULL;
+
+    return res;
+}
+
+BOOL WINAPI
+ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->GetImageInfo(piml, i, pImageInfo) == S_OK) ? TRUE : FALSE;
+}
+
+BOOL WINAPI
+ImageList_Copy (HIMAGELIST himlDst, INT iDst,  HIMAGELIST himlSrc,
+               INT iSrc, UINT uFlags)
+{
+    IImageList2 *pimlDst, *pimlSrc;
+    pimlDst = IImageList2_from_impl(himlDst);
+    pimlSrc = IImageList2_from_impl(himlSrc);
+    if (!pimlDst || !pimlSrc)
+        return FALSE;
+
+    return (pimlDst->lpVtbl->Copy(pimlDst, iDst, (IUnknown*)pimlSrc, iSrc, uFlags) == S_OK) ? TRUE : FALSE;
+}
+
+HIMAGELIST WINAPI
+ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
+                INT dx, INT dy)
+{
+    HRESULT hr;
+    IImageList2 *piml1, *piml2, *pimlMerged;
+    piml1 = IImageList2_from_impl(himl1);
+    piml2 = IImageList2_from_impl(himl2);
+    if (!piml1 || !piml2)
+        return NULL;
+
+    hr = piml1->lpVtbl->Merge(piml1, i1, (IUnknown*)piml2, i2, dx, dy, &IID_IImageList2, (void**)&pimlMerged);
+    if (FAILED(hr))
+        return NULL;
+
+    return (HIMAGELIST)pimlMerged;
+}
+
+HIMAGELIST WINAPI
+ImageList_Duplicate (HIMAGELIST himlSrc)
+{
+    HRESULT hr;
+    IImageList2 *piml, *pimlCloned;
+    piml = IImageList2_from_impl(himlSrc);
+    if (!piml)
+        return FALSE;
+
+    hr = piml->lpVtbl->Clone(piml, &IID_IImageList2, (void**)&pimlCloned);
+    if (FAILED(hr))
+        return NULL;
+
+    return (HIMAGELIST)pimlCloned;
+}
+
+BOOL WINAPI
+ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->GetIconSize(piml, cx, cy) == S_OK) ? TRUE : FALSE;
+}
+
+BOOL WINAPI
+ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->SetIconSize(piml, cx, cy) == S_OK) ? TRUE : FALSE;
+}
+
+INT WINAPI
+ImageList_GetImageCount (HIMAGELIST himl)
+{
+    int res;
+    HRESULT hr;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return 0;
+
+    hr = piml->lpVtbl->GetImageCount(piml, &res);
+    if (FAILED(hr))
+        return 0;
+
+    return res;
+}
+
+BOOL WINAPI
+ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
+{
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->SetImageCount(piml, iImageCount) == S_OK) ? TRUE : FALSE;
+}
+
+COLORREF WINAPI
+ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
+{
+    COLORREF res;
+    HRESULT hr;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return CLR_NONE;
+
+    hr = piml->lpVtbl->SetBkColor(piml, clrBk, &res);
+    if (FAILED(hr))
+        return CLR_NONE;
+
+    return res;
+}
+
+COLORREF WINAPI
+ImageList_GetBkColor (HIMAGELIST himl)
+{
+    COLORREF res;
+    HRESULT hr;
+    IImageList2* piml = IImageList2_from_impl(himl);
+    if (!piml)
+        return CLR_NONE;
+
+    hr = piml->lpVtbl->GetBkColor(piml, &res);
+    if (FAILED(hr))
+        return CLR_NONE;
+
+    return res;
+}
+
+BOOL WINAPI
+ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
+                    INT dxHotspot, INT dyHotspot)
+{
+    IImageList2* piml = IImageList2_from_impl(himlTrack);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->BeginDrag(piml, iTrack, dxHotspot, dyHotspot) == S_OK) ? TRUE : FALSE;
+}
+
+BOOL WINAPI
+ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
+{
+    IImageList2* piml;
+
+    if (!pimldp)
+        return FALSE;
+
+    piml = IImageList2_from_impl(pimldp->himl);
+    if (!piml)
+        return FALSE;
+
+    return (piml->lpVtbl->Draw(piml, pimldp) == S_OK) ? TRUE : FALSE;
+}
+
+#endif