comctl32: toolbar: The top margin should be computed and saved in CalcToolbar.
[wine] / dlls / comctl32 / imagelist.c
1 /*
2  *  ImageList implementation
3  *
4  *  Copyright 1998 Eric Kohl
5  *  Copyright 2000 Jason Mawdsley
6  *  Copyright 2001, 2004 Michael Stefaniuc
7  *  Copyright 2001 Charles Loep for CodeWeavers
8  *  Copyright 2002 Dimitrie O. Paun
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * NOTE
25  *
26  * This code was audited for completeness against the documented features
27  * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
28  *
29  * Unless otherwise noted, we believe this code to be complete, as per
30  * the specification mentioned above.
31  * If you discover missing features, or bugs, please note them below.
32  *
33  *  TODO:
34  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35  *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
36  *    - Thread-safe locking
37  */
38
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #define COBJMACROS
44
45 #include "winerror.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "objbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "commctrl.h"
52 #include "comctl32.h"
53 #include "imagelist.h"
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
57
58
59 #define MAX_OVERLAYIMAGE 15
60
61 /* internal image list data used for Drag & Drop operations */
62 typedef struct
63 {
64     HWND        hwnd;
65     HIMAGELIST  himl;
66     /* position of the drag image relative to the window */
67     INT         x;
68     INT         y;
69     /* offset of the hotspot relative to the origin of the image */
70     INT         dxHotspot;
71     INT         dyHotspot;
72     /* is the drag image visible */
73     BOOL        bShow;
74     /* saved background */
75     HBITMAP     hbmBg;
76 } INTERNALDRAG;
77
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
79
80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height);
81
82 static inline BOOL is_valid(HIMAGELIST himl)
83 {
84     return himl && himl->magic == IMAGELIST_MAGIC;
85 }
86
87 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
88 {
89     pt->x = index * himl->cx;
90     pt->y = 0;
91 }
92
93 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cy, SIZE *sz )
94 {
95     sz->cx = count * himl->cx;
96     sz->cy = cy;
97 }
98
99 /*************************************************************************
100  * IMAGELIST_InternalExpandBitmaps [Internal]
101  *
102  * Expands the bitmaps of an image list by the given number of images.
103  *
104  * PARAMS
105  *     himl        [I] handle to image list
106  *     nImageCount [I] number of images to add
107  *
108  * RETURNS
109  *     nothing
110  *
111  * NOTES
112  *     This function CANNOT be used to reduce the number of images.
113  */
114 static void
115 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
116 {
117     HDC     hdcBitmap;
118     HBITMAP hbmNewBitmap, hbmNull;
119     INT     nNewCount;
120     SIZE    sz;
121
122     if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
123         && (himl->cy >= cy))
124         return;
125
126     if (cy == 0) cy = himl->cy;
127     nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
128
129     imagelist_get_bitmap_size(himl, nNewCount, cy, &sz);
130
131     TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
132     hdcBitmap = CreateCompatibleDC (0);
133
134     hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cy);
135
136     if (hbmNewBitmap == 0)
137         ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
138
139     if (himl->cCurImage)
140     {
141         hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
142         BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
143                 himl->hdcImage, 0, 0, SRCCOPY);
144         SelectObject (hdcBitmap, hbmNull);
145     }
146     SelectObject (himl->hdcImage, hbmNewBitmap);
147     DeleteObject (himl->hbmImage);
148     himl->hbmImage = hbmNewBitmap;
149
150     if (himl->flags & ILC_MASK)
151     {
152         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
153
154         if (hbmNewBitmap == 0)
155             ERR("creating new mask bitmap!\n");
156
157         if(himl->cCurImage)
158         {
159             hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
160             BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
161                     himl->hdcMask, 0, 0, SRCCOPY);
162             SelectObject (hdcBitmap, hbmNull);
163         }
164         SelectObject (himl->hdcMask, hbmNewBitmap);
165         DeleteObject (himl->hbmMask);
166         himl->hbmMask = hbmNewBitmap;
167     }
168
169     himl->cMaxImage = nNewCount;
170
171     DeleteDC (hdcBitmap);
172 }
173
174
175 /*************************************************************************
176  * ImageList_Add [COMCTL32.@]
177  *
178  * Add an image or images to an image list.
179  *
180  * PARAMS
181  *     himl     [I] handle to image list
182  *     hbmImage [I] handle to image bitmap
183  *     hbmMask  [I] handle to mask bitmap
184  *
185  * RETURNS
186  *     Success: Index of the first new image.
187  *     Failure: -1
188  */
189
190 INT WINAPI
191 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
192 {
193     HDC     hdcBitmap;
194     INT     nFirstIndex, nImageCount;
195     BITMAP  bmp;
196     HBITMAP hOldBitmap;
197     POINT   pt;
198
199     TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
200     if (!is_valid(himl))
201         return -1;
202
203     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
204     nImageCount = bmp.bmWidth / himl->cx;
205
206     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
207
208     imagelist_point_from_index( himl, himl->cCurImage, &pt );
209
210     hdcBitmap = CreateCompatibleDC(0);
211
212     hOldBitmap = SelectObject(hdcBitmap, hbmImage);
213
214     /* Copy result to the imagelist
215     */
216     BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
217         hdcBitmap, 0, 0, SRCCOPY);
218
219     if(himl->hbmMask)
220     {
221         HDC hdcTemp;
222         HBITMAP hOldBitmapTemp;
223
224         hdcTemp   = CreateCompatibleDC(0);
225         hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
226
227         BitBlt (himl->hdcMask,
228             pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
229             hdcTemp,
230             0, 0,
231             SRCCOPY);
232
233         SelectObject(hdcTemp, hOldBitmapTemp);
234         DeleteDC(hdcTemp);
235
236         /* Remove the background from the image
237         */
238         BitBlt (himl->hdcImage,
239             pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
240             himl->hdcMask,
241             pt.x, pt.y,
242             0x220326); /* NOTSRCAND */
243     }
244
245     SelectObject(hdcBitmap, hOldBitmap);
246     DeleteDC(hdcBitmap);
247
248     nFirstIndex = himl->cCurImage;
249     himl->cCurImage += nImageCount;
250
251     return nFirstIndex;
252 }
253
254
255 /*************************************************************************
256  * ImageList_AddIcon [COMCTL32.@]
257  *
258  * Adds an icon to an image list.
259  *
260  * PARAMS
261  *     himl  [I] handle to image list
262  *     hIcon [I] handle to icon
263  *
264  * RETURNS
265  *     Success: index of the new image
266  *     Failure: -1
267  */
268 #undef ImageList_AddIcon
269 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
270 {
271     return ImageList_ReplaceIcon (himl, -1, hIcon);
272 }
273
274
275 /*************************************************************************
276  * ImageList_AddMasked [COMCTL32.@]
277  *
278  * Adds an image or images to an image list and creates a mask from the
279  * specified bitmap using the mask color.
280  *
281  * PARAMS
282  *     himl    [I] handle to image list.
283  *     hBitmap [I] handle to bitmap
284  *     clrMask [I] mask color.
285  *
286  * RETURNS
287  *     Success: Index of the first new image.
288  *     Failure: -1
289  */
290
291 INT WINAPI
292 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
293 {
294     HDC    hdcMask, hdcBitmap;
295     INT    nIndex, nImageCount, nMaskXOffset=0;
296     BITMAP bmp;
297     HBITMAP hOldBitmap;
298     HBITMAP hMaskBitmap=0;
299     COLORREF bkColor;
300     POINT  pt;
301
302     TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
303     if (!is_valid(himl))
304         return -1;
305
306     if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
307         return -1;
308
309     if (himl->cx > 0)
310         nImageCount = bmp.bmWidth / himl->cx;
311     else
312         nImageCount = 0;
313
314     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
315
316     nIndex = himl->cCurImage;
317     himl->cCurImage += nImageCount;
318
319     hdcBitmap = CreateCompatibleDC(0);
320
321
322     hOldBitmap = SelectObject(hdcBitmap, hBitmap);
323     if(himl->hbmMask)
324     {
325         hdcMask = himl->hdcMask;
326         nMaskXOffset = nIndex * himl->cx;
327         imagelist_point_from_index( himl, nIndex, &pt );
328     }
329     else
330     {
331         /*
332             Create a temp Mask so we can remove the background of
333             the Image (Windows does this even if there is no mask)
334         */
335         hdcMask = CreateCompatibleDC(0);
336         hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
337         SelectObject(hdcMask, hMaskBitmap);
338         nMaskXOffset = 0;
339         imagelist_point_from_index( himl, 0, &pt );
340     }
341     /* create monochrome image to the mask bitmap */
342     bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
343         GetPixel (hdcBitmap, 0, 0);
344     SetBkColor (hdcBitmap, bkColor);
345     BitBlt (hdcMask,
346         pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
347         hdcBitmap, 0, 0,
348         SRCCOPY);
349
350     SetBkColor(hdcBitmap, RGB(255,255,255));
351     /*Remove the background from the image
352     */
353     /*
354         WINDOWS BUG ALERT!!!!!!
355         The statement below should not be done in common practice
356         but this is how ImageList_AddMasked works in Windows.
357         It overwrites the original bitmap passed, this was discovered
358         by using the same bitmap to iterate the different styles
359         on windows where it failed (BUT ImageList_Add is OK)
360         This is here in case some apps rely on this bug
361     */
362     BitBlt(hdcBitmap,
363         0, 0, bmp.bmWidth, bmp.bmHeight,
364         hdcMask,
365         nMaskXOffset, 0,
366         0x220326); /* NOTSRCAND */
367     /* Copy result to the imagelist
368     */
369     imagelist_point_from_index( himl, nIndex, &pt );
370     BitBlt (himl->hdcImage,
371         pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
372         hdcBitmap,
373         0, 0,
374         SRCCOPY);
375     /* Clean up
376     */
377     SelectObject(hdcBitmap, hOldBitmap);
378     DeleteDC(hdcBitmap);
379     if(!himl->hbmMask)
380     {
381         DeleteObject(hMaskBitmap);
382         DeleteDC(hdcMask);
383     }
384
385     return nIndex;
386 }
387
388
389 /*************************************************************************
390  * ImageList_BeginDrag [COMCTL32.@]
391  *
392  * Creates a temporary image list that contains one image. It will be used
393  * as a drag image.
394  *
395  * PARAMS
396  *     himlTrack [I] handle to the source image list
397  *     iTrack    [I] index of the drag image in the source image list
398  *     dxHotspot [I] X position of the hot spot of the drag image
399  *     dyHotspot [I] Y position of the hot spot of the drag image
400  *
401  * RETURNS
402  *     Success: TRUE
403  *     Failure: FALSE
404  */
405
406 BOOL WINAPI
407 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
408                      INT dxHotspot, INT dyHotspot)
409 {
410     INT cx, cy;
411
412     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
413           dxHotspot, dyHotspot);
414
415     if (!is_valid(himlTrack))
416         return FALSE;
417
418     if (InternalDrag.himl)
419         ImageList_EndDrag ();
420
421     cx = himlTrack->cx;
422     cy = himlTrack->cy;
423
424     InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
425     if (InternalDrag.himl == NULL) {
426         WARN("Error creating drag image list!\n");
427         return FALSE;
428     }
429
430     InternalDrag.dxHotspot = dxHotspot;
431     InternalDrag.dyHotspot = dyHotspot;
432
433     /* copy image */
434     BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
435
436     /* copy mask */
437     BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
438
439     InternalDrag.himl->cCurImage = 1;
440
441     return TRUE;
442 }
443
444
445 /*************************************************************************
446  * ImageList_Copy [COMCTL32.@]
447  *
448  *  Copies an image of the source image list to an image of the
449  *  destination image list. Images can be copied or swapped.
450  *
451  * PARAMS
452  *     himlDst [I] handle to the destination image list
453  *     iDst    [I] destination image index.
454  *     himlSrc [I] handle to the source image list
455  *     iSrc    [I] source image index
456  *     uFlags  [I] flags for the copy operation
457  *
458  * RETURNS
459  *     Success: TRUE
460  *     Failure: FALSE
461  *
462  * NOTES
463  *     Copying from one image list to another is possible. The original
464  *     implementation just copies or swaps within one image list.
465  *     Could this feature become a bug??? ;-)
466  */
467
468 BOOL WINAPI
469 ImageList_Copy (HIMAGELIST himlDst, INT iDst,   HIMAGELIST himlSrc,
470                 INT iSrc, UINT uFlags)
471 {
472     POINT ptSrc, ptDst;
473
474     TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
475
476     if (!is_valid(himlSrc) || !is_valid(himlDst))
477         return FALSE;
478     if ((iDst < 0) || (iDst >= himlDst->cCurImage))
479         return FALSE;
480     if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
481         return FALSE;
482
483     imagelist_point_from_index( himlDst, iDst, &ptDst );
484     imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
485
486     if (uFlags & ILCF_SWAP) {
487         /* swap */
488         HDC     hdcBmp;
489         HBITMAP hbmTempImage, hbmTempMask;
490
491         hdcBmp = CreateCompatibleDC (0);
492
493         /* create temporary bitmaps */
494         hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
495                                        himlSrc->uBitsPixel, NULL);
496         hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
497                                       1, NULL);
498
499         /* copy (and stretch) destination to temporary bitmaps.(save) */
500         /* image */
501         SelectObject (hdcBmp, hbmTempImage);
502         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
503                       himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
504                       SRCCOPY);
505         /* mask */
506         SelectObject (hdcBmp, hbmTempMask);
507         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
508                       himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
509                       SRCCOPY);
510
511         /* copy (and stretch) source to destination */
512         /* image */
513         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
514                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
515                       SRCCOPY);
516         /* mask */
517         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
518                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
519                       SRCCOPY);
520
521         /* copy (without stretching) temporary bitmaps to source (restore) */
522         /* mask */
523         BitBlt       (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
524                       hdcBmp, 0, 0, SRCCOPY);
525
526         /* image */
527         BitBlt       (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
528                       hdcBmp, 0, 0, SRCCOPY);
529         /* delete temporary bitmaps */
530         DeleteObject (hbmTempMask);
531         DeleteObject (hbmTempImage);
532         DeleteDC(hdcBmp);
533     }
534     else {
535         /* copy image */
536         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
537                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
538                       SRCCOPY);
539
540         /* copy mask */
541         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
542                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
543                       SRCCOPY);
544     }
545
546     return TRUE;
547 }
548
549
550 /*************************************************************************
551  * ImageList_Create [COMCTL32.@]
552  *
553  * Creates a new image list.
554  *
555  * PARAMS
556  *     cx       [I] image height
557  *     cy       [I] image width
558  *     flags    [I] creation flags
559  *     cInitial [I] initial number of images in the image list
560  *     cGrow    [I] number of images by which image list grows
561  *
562  * RETURNS
563  *     Success: Handle to the created image list
564  *     Failure: NULL
565  */
566 HIMAGELIST WINAPI
567 ImageList_Create (INT cx, INT cy, UINT flags,
568                   INT cInitial, INT cGrow)
569 {
570     HIMAGELIST himl;
571     INT      nCount;
572     HBITMAP  hbmTemp;
573     UINT     ilc = (flags & 0xFE);
574     static const WORD aBitBlend25[] =
575         {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
576
577     static const WORD aBitBlend50[] =
578         {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
579
580     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
581
582     himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
583     if (!himl)
584         return NULL;
585
586     cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
587
588     himl->magic     = IMAGELIST_MAGIC;
589     himl->cx        = cx;
590     himl->cy        = cy;
591     himl->flags     = flags;
592     himl->cMaxImage = cInitial + cGrow;
593     himl->cInitial  = cInitial;
594     himl->cGrow     = cGrow;
595     himl->clrFg     = CLR_DEFAULT;
596     himl->clrBk     = CLR_NONE;
597
598     /* initialize overlay mask indices */
599     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
600         himl->nOvlIdx[nCount] = -1;
601
602     /* Create Image & Mask DCs */
603     himl->hdcImage = CreateCompatibleDC (0);
604     if (!himl->hdcImage)
605         goto cleanup;
606     if (himl->flags & ILC_MASK){
607         himl->hdcMask = CreateCompatibleDC(0);
608         if (!himl->hdcMask)
609             goto cleanup;
610     }
611
612     /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
613     if (ilc == ILC_COLOR)
614         ilc = ILC_COLOR4;
615
616     if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
617         himl->uBitsPixel = ilc;
618     else
619         himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
620
621     if (himl->cMaxImage > 0) {
622         himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cy);
623         SelectObject(himl->hdcImage, himl->hbmImage);
624     } else
625         himl->hbmImage = 0;
626
627     if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
628         SIZE sz;
629
630         imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
631         himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
632         if (himl->hbmMask == 0) {
633             ERR("Error creating mask bitmap!\n");
634             goto cleanup;
635         }
636         SelectObject(himl->hdcMask, himl->hbmMask);
637     }
638     else
639         himl->hbmMask = 0;
640
641     /* create blending brushes */
642     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
643     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
644     DeleteObject (hbmTemp);
645
646     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
647     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
648     DeleteObject (hbmTemp);
649
650     TRACE("created imagelist %p\n", himl);
651     return himl;
652
653 cleanup:
654     if (himl) ImageList_Destroy(himl);
655     return NULL;
656 }
657
658
659 /*************************************************************************
660  * ImageList_Destroy [COMCTL32.@]
661  *
662  * Destroys an image list.
663  *
664  * PARAMS
665  *     himl [I] handle to image list
666  *
667  * RETURNS
668  *     Success: TRUE
669  *     Failure: FALSE
670  */
671
672 BOOL WINAPI
673 ImageList_Destroy (HIMAGELIST himl)
674 {
675     if (!is_valid(himl))
676         return FALSE;
677
678     /* delete image bitmaps */
679     if (himl->hbmImage)
680         DeleteObject (himl->hbmImage);
681     if (himl->hbmMask)
682         DeleteObject (himl->hbmMask);
683
684     /* delete image & mask DCs */
685     if (himl->hdcImage)
686         DeleteDC(himl->hdcImage);
687     if (himl->hdcMask)
688         DeleteDC(himl->hdcMask);
689
690     /* delete blending brushes */
691     if (himl->hbrBlend25)
692         DeleteObject (himl->hbrBlend25);
693     if (himl->hbrBlend50)
694         DeleteObject (himl->hbrBlend50);
695
696     ZeroMemory(himl, sizeof(*himl));
697     Free (himl);
698
699     return TRUE;
700 }
701
702
703 /*************************************************************************
704  * ImageList_DragEnter [COMCTL32.@]
705  *
706  * Locks window update and displays the drag image at the given position.
707  *
708  * PARAMS
709  *     hwndLock [I] handle of the window that owns the drag image.
710  *     x        [I] X position of the drag image.
711  *     y        [I] Y position of the drag image.
712  *
713  * RETURNS
714  *     Success: TRUE
715  *     Failure: FALSE
716  *
717  * NOTES
718  *     The position of the drag image is relative to the window, not
719  *     the client area.
720  */
721
722 BOOL WINAPI
723 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
724 {
725     TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
726
727     if (!is_valid(InternalDrag.himl))
728         return FALSE;
729
730     if (hwndLock)
731         InternalDrag.hwnd = hwndLock;
732     else
733         InternalDrag.hwnd = GetDesktopWindow ();
734
735     InternalDrag.x = x;
736     InternalDrag.y = y;
737
738     /* draw the drag image and save the background */
739     if (!ImageList_DragShowNolock(TRUE)) {
740         return FALSE;
741     }
742
743     return TRUE;
744 }
745
746
747 /*************************************************************************
748  * ImageList_DragLeave [COMCTL32.@]
749  *
750  * Unlocks window update and hides the drag image.
751  *
752  * PARAMS
753  *     hwndLock [I] handle of the window that owns the drag image.
754  *
755  * RETURNS
756  *     Success: TRUE
757  *     Failure: FALSE
758  */
759
760 BOOL WINAPI
761 ImageList_DragLeave (HWND hwndLock)
762 {
763     /* As we don't save drag info in the window this can lead to problems if
764        an app does not supply the same window as DragEnter */
765     /* if (hwndLock)
766         InternalDrag.hwnd = hwndLock;
767     else
768         InternalDrag.hwnd = GetDesktopWindow (); */
769     if(!hwndLock)
770         hwndLock = GetDesktopWindow();
771     if(InternalDrag.hwnd != hwndLock)
772         FIXME("DragLeave hWnd != DragEnter hWnd\n");
773
774     ImageList_DragShowNolock (FALSE);
775
776     return TRUE;
777 }
778
779
780 /*************************************************************************
781  * ImageList_InternalDragDraw [Internal]
782  *
783  * Draws the drag image.
784  *
785  * PARAMS
786  *     hdc [I] device context to draw into.
787  *     x   [I] X position of the drag image.
788  *     y   [I] Y position of the drag image.
789  *
790  * RETURNS
791  *     Success: TRUE
792  *     Failure: FALSE
793  *
794  * NOTES
795  *     The position of the drag image is relative to the window, not
796  *     the client area.
797  *
798  */
799
800 static inline void
801 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
802 {
803     IMAGELISTDRAWPARAMS imldp;
804
805     ZeroMemory (&imldp, sizeof(imldp));
806     imldp.cbSize  = sizeof(imldp);
807     imldp.himl    = InternalDrag.himl;
808     imldp.i       = 0;
809     imldp.hdcDst  = hdc,
810     imldp.x       = x;
811     imldp.y       = y;
812     imldp.rgbBk   = CLR_DEFAULT;
813     imldp.rgbFg   = CLR_DEFAULT;
814     imldp.fStyle  = ILD_NORMAL;
815     imldp.fState  = ILS_ALPHA;
816     imldp.Frame   = 128;
817
818     /* FIXME: instead of using the alpha blending, we should
819      * create a 50% mask, and draw it semitransparantly that way */
820     ImageList_DrawIndirect (&imldp);
821 }
822
823 /*************************************************************************
824  * ImageList_DragMove [COMCTL32.@]
825  *
826  * Moves the drag image.
827  *
828  * PARAMS
829  *     x [I] X position of the drag image.
830  *     y [I] Y position of the drag image.
831  *
832  * RETURNS
833  *     Success: TRUE
834  *     Failure: FALSE
835  *
836  * NOTES
837  *     The position of the drag image is relative to the window, not
838  *     the client area.
839  *
840  * BUGS
841  *     The drag image should be drawn semitransparent.
842  */
843
844 BOOL WINAPI
845 ImageList_DragMove (INT x, INT y)
846 {
847     TRACE("(x=%d y=%d)\n", x, y);
848
849     if (!is_valid(InternalDrag.himl))
850         return FALSE;
851
852     /* draw/update the drag image */
853     if (InternalDrag.bShow) {
854         HDC hdcDrag;
855         HDC hdcOffScreen;
856         HDC hdcBg;
857         HBITMAP hbmOffScreen;
858         INT origNewX, origNewY;
859         INT origOldX, origOldY;
860         INT origRegX, origRegY;
861         INT sizeRegX, sizeRegY;
862
863
864         /* calculate the update region */
865         origNewX = x - InternalDrag.dxHotspot;
866         origNewY = y - InternalDrag.dyHotspot;
867         origOldX = InternalDrag.x - InternalDrag.dxHotspot;
868         origOldY = InternalDrag.y - InternalDrag.dyHotspot;
869         origRegX = min(origNewX, origOldX);
870         origRegY = min(origNewY, origOldY);
871         sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
872         sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
873
874         hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
875                           DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
876         hdcOffScreen = CreateCompatibleDC(hdcDrag);
877         hdcBg = CreateCompatibleDC(hdcDrag);
878
879         hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
880         SelectObject(hdcOffScreen, hbmOffScreen);
881         SelectObject(hdcBg, InternalDrag.hbmBg);
882
883         /* get the actual background of the update region */
884         BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
885                origRegX, origRegY, SRCCOPY);
886         /* erase the old image */
887         BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
888                InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
889                SRCCOPY);
890         /* save the background */
891         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
892                hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
893         /* draw the image */
894         ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, 
895                                    origNewY - origRegY);
896         /* draw the update region to the screen */
897         BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
898                hdcOffScreen, 0, 0, SRCCOPY);
899
900         DeleteDC(hdcBg);
901         DeleteDC(hdcOffScreen);
902         DeleteObject(hbmOffScreen);
903         ReleaseDC(InternalDrag.hwnd, hdcDrag);
904     }
905
906     /* update the image position */
907     InternalDrag.x = x;
908     InternalDrag.y = y;
909
910     return TRUE;
911 }
912
913
914 /*************************************************************************
915  * ImageList_DragShowNolock [COMCTL32.@]
916  *
917  * Shows or hides the drag image.
918  *
919  * PARAMS
920  *     bShow [I] TRUE shows the drag image, FALSE hides it.
921  *
922  * RETURNS
923  *     Success: TRUE
924  *     Failure: FALSE
925  *
926  * BUGS
927  *     The drag image should be drawn semitransparent.
928  */
929
930 BOOL WINAPI
931 ImageList_DragShowNolock (BOOL bShow)
932 {
933     HDC hdcDrag;
934     HDC hdcBg;
935     INT x, y;
936
937     if (!is_valid(InternalDrag.himl))
938         return FALSE;
939     
940     TRACE("bShow=0x%X!\n", bShow);
941
942     /* DragImage is already visible/hidden */
943     if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
944         return FALSE;
945     }
946
947     /* position of the origin of the DragImage */
948     x = InternalDrag.x - InternalDrag.dxHotspot;
949     y = InternalDrag.y - InternalDrag.dyHotspot;
950
951     hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
952                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
953     if (!hdcDrag) {
954         return FALSE;
955     }
956
957     hdcBg = CreateCompatibleDC(hdcDrag);
958     if (!InternalDrag.hbmBg) {
959         InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
960                     InternalDrag.himl->cx, InternalDrag.himl->cy);
961     }
962     SelectObject(hdcBg, InternalDrag.hbmBg);
963
964     if (bShow) {
965         /* save the background */
966         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
967                hdcDrag, x, y, SRCCOPY);
968         /* show the image */
969         ImageList_InternalDragDraw(hdcDrag, x, y);
970     } else {
971         /* hide the image */
972         BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
973                hdcBg, 0, 0, SRCCOPY);
974     }
975
976     InternalDrag.bShow = !InternalDrag.bShow;
977
978     DeleteDC(hdcBg);
979     ReleaseDC (InternalDrag.hwnd, hdcDrag);
980     return TRUE;
981 }
982
983
984 /*************************************************************************
985  * ImageList_Draw [COMCTL32.@]
986  *
987  * Draws an image.
988  *
989  * PARAMS
990  *     himl   [I] handle to image list
991  *     i      [I] image index
992  *     hdc    [I] handle to device context
993  *     x      [I] x position
994  *     y      [I] y position
995  *     fStyle [I] drawing flags
996  *
997  * RETURNS
998  *     Success: TRUE
999  *     Failure: FALSE
1000  *
1001  * SEE
1002  *     ImageList_DrawEx.
1003  */
1004
1005 BOOL WINAPI
1006 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1007 {
1008     return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, 
1009                              CLR_DEFAULT, CLR_DEFAULT, fStyle);
1010 }
1011
1012
1013 /*************************************************************************
1014  * ImageList_DrawEx [COMCTL32.@]
1015  *
1016  * Draws an image and allows to use extended drawing features.
1017  *
1018  * PARAMS
1019  *     himl   [I] handle to image list
1020  *     i      [I] image index
1021  *     hdc    [I] handle to device context
1022  *     x      [I] X position
1023  *     y      [I] Y position
1024  *     dx     [I] X offset
1025  *     dy     [I] Y offset
1026  *     rgbBk  [I] background color
1027  *     rgbFg  [I] foreground color
1028  *     fStyle [I] drawing flags
1029  *
1030  * RETURNS
1031  *     Success: TRUE
1032  *     Failure: FALSE
1033  *
1034  * NOTES
1035  *     Calls ImageList_DrawIndirect.
1036  *
1037  * SEE
1038  *     ImageList_DrawIndirect.
1039  */
1040
1041 BOOL WINAPI
1042 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1043                   INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1044                   UINT fStyle)
1045 {
1046     IMAGELISTDRAWPARAMS imldp;
1047
1048     ZeroMemory (&imldp, sizeof(imldp));
1049     imldp.cbSize  = sizeof(imldp);
1050     imldp.himl    = himl;
1051     imldp.i       = i;
1052     imldp.hdcDst  = hdc,
1053     imldp.x       = x;
1054     imldp.y       = y;
1055     imldp.cx      = dx;
1056     imldp.cy      = dy;
1057     imldp.rgbBk   = rgbBk;
1058     imldp.rgbFg   = rgbFg;
1059     imldp.fStyle  = fStyle;
1060
1061     return ImageList_DrawIndirect (&imldp);
1062 }
1063
1064
1065 /*************************************************************************
1066  * ImageList_DrawIndirect [COMCTL32.@]
1067  *
1068  * Draws an image using various parameters specified in pimldp.
1069  *
1070  * PARAMS
1071  *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1072  *
1073  * RETURNS
1074  *     Success: TRUE
1075  *     Failure: FALSE
1076  */
1077
1078 BOOL WINAPI
1079 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1080 {
1081     INT cx, cy, nOvlIdx;
1082     DWORD fState, dwRop;
1083     UINT fStyle;
1084     COLORREF oldImageBk, oldImageFg;
1085     HDC hImageDC, hImageListDC, hMaskListDC;
1086     HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1087     BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1088     HIMAGELIST himl;
1089     POINT pt;
1090
1091     if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1092     if (!is_valid(himl)) return FALSE;
1093     if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1094
1095     imagelist_point_from_index( himl, pimldp->i, &pt );
1096     pt.x += pimldp->xBitmap;
1097     pt.y += pimldp->yBitmap;
1098
1099     fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1100     fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1101     cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1102     cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1103
1104     bIsTransparent = (fStyle & ILD_TRANSPARENT);
1105     if( pimldp->rgbBk == CLR_NONE )
1106         bIsTransparent = TRUE;
1107     if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1108         bIsTransparent = TRUE;
1109     bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1110     bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1111
1112     TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1113           himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1114
1115     /* we will use these DCs to access the images and masks in the ImageList */
1116     hImageListDC = himl->hdcImage;
1117     hMaskListDC  = himl->hdcMask;
1118
1119     /* these will accumulate the image and mask for the image we're drawing */
1120     hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1121     hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1122     hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1123
1124     /* Create a compatible DC. */
1125     if (!hImageListDC || !hImageDC || !hImageBmp ||
1126         (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1127         goto cleanup;
1128     
1129     hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1130   
1131     /*
1132      * To obtain a transparent look, background color should be set
1133      * to white and foreground color to black when blting the
1134      * monochrome mask.
1135      */
1136     oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1137     oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1138
1139     /*
1140      * Draw the initial image
1141      */
1142     if( bMask ) {
1143         if (himl->hbmMask) {
1144             HBRUSH hOldBrush;
1145             hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1146             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1147             BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1148             DeleteObject (SelectObject (hImageDC, hOldBrush));
1149             if( bIsTransparent )
1150             {
1151                 BitBlt ( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1152                 bResult = TRUE;
1153                 goto end;
1154             }
1155         } else {
1156             HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1157             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1158             SelectObject(hImageDC, hOldBrush);
1159         }
1160     } else {
1161         /* blend the image with the needed solid background */
1162         COLORREF colour = RGB(0,0,0);
1163         HBRUSH hOldBrush;
1164
1165         if( !bIsTransparent )
1166         {
1167             colour = pimldp->rgbBk;
1168             if( colour == CLR_DEFAULT )
1169                 colour = himl->clrBk;
1170             if( colour == CLR_NONE )
1171                 colour = GetBkColor(pimldp->hdcDst);
1172         }
1173
1174         hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1175         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1176         BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1177         BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1178         DeleteObject (SelectObject (hImageDC, hOldBrush));
1179     }
1180
1181     /* Time for blending, if required */
1182     if (bBlend) {
1183         HBRUSH hBlendBrush, hOldBrush;
1184         COLORREF clrBlend = pimldp->rgbFg;
1185         HDC hBlendMaskDC = hImageListDC;
1186         HBITMAP hOldBitmap;
1187
1188         /* Create the blend Mask */
1189         hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1190         hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1191         hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1192         PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1193         SelectObject(hBlendMaskDC, hOldBrush);
1194
1195         /* Modify the blend mask if an Image Mask exist */
1196         if(himl->hbmMask) {
1197             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1198             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1199         }
1200         
1201         /* now apply blend to the current image given the BlendMask */
1202         if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1203         else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1204         hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1205         BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1206         DeleteObject(SelectObject(hImageDC, hOldBrush));
1207         SelectObject(hBlendMaskDC, hOldBitmap);
1208     }
1209
1210     /* Now do the overlay image, if any */
1211     nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1212     if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1213         nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1214         if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1215             const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1216             if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1217                 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, pt.x, SRCAND);
1218             BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, pt.y, SRCPAINT);
1219         }
1220     }
1221
1222     if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1223     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1224     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1225     if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1226
1227     if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1228     if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1229     if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1230     
1231     /* now copy the image to the screen */
1232     dwRop = SRCCOPY;
1233     if (himl->hbmMask && bIsTransparent ) {
1234         COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1235         COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1236         BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1237         SetBkColor(pimldp->hdcDst, oldDstBk);
1238         SetTextColor(pimldp->hdcDst, oldDstFg);
1239         dwRop = SRCPAINT;
1240     }
1241     if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1242     BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1243
1244     bResult = TRUE;
1245 end: 
1246     /* cleanup the mess */
1247     SetBkColor(hImageDC, oldImageBk);
1248     SetTextColor(hImageDC, oldImageFg);
1249     SelectObject(hImageDC, hOldImageBmp);
1250 cleanup:
1251     DeleteObject(hBlendMaskBmp);
1252     DeleteObject(hImageBmp);
1253     DeleteDC(hImageDC);
1254
1255     return bResult;
1256 }
1257
1258
1259 /*************************************************************************
1260  * ImageList_Duplicate [COMCTL32.@]
1261  *
1262  * Duplicates an image list.
1263  *
1264  * PARAMS
1265  *     himlSrc [I] source image list handle
1266  *
1267  * RETURNS
1268  *     Success: Handle of duplicated image list.
1269  *     Failure: NULL
1270  */
1271
1272 HIMAGELIST WINAPI
1273 ImageList_Duplicate (HIMAGELIST himlSrc)
1274 {
1275     HIMAGELIST himlDst;
1276
1277     if (!is_valid(himlSrc)) {
1278         ERR("Invalid image list handle!\n");
1279         return NULL;
1280     }
1281
1282     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1283                                 himlSrc->cInitial, himlSrc->cGrow);
1284
1285     if (himlDst)
1286     {
1287         SIZE sz;
1288
1289         imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cy, &sz);
1290         BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1291                 himlSrc->hdcImage, 0, 0, SRCCOPY);
1292
1293         if (himlDst->hbmMask)
1294             BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1295                     himlSrc->hdcMask, 0, 0, SRCCOPY);
1296
1297         himlDst->cCurImage = himlSrc->cCurImage;
1298         himlDst->cMaxImage = himlSrc->cMaxImage;
1299     }
1300     return himlDst;
1301 }
1302
1303
1304 /*************************************************************************
1305  * ImageList_EndDrag [COMCTL32.@]
1306  *
1307  * Finishes a drag operation.
1308  *
1309  * PARAMS
1310  *     no Parameters
1311  *
1312  * RETURNS
1313  *     Success: TRUE
1314  *     Failure: FALSE
1315  */
1316
1317 VOID WINAPI
1318 ImageList_EndDrag (void)
1319 {
1320     /* cleanup the InternalDrag struct */
1321     InternalDrag.hwnd = 0;
1322     ImageList_Destroy (InternalDrag.himl);
1323     InternalDrag.himl = 0;
1324     InternalDrag.x= 0;
1325     InternalDrag.y= 0;
1326     InternalDrag.dxHotspot = 0;
1327     InternalDrag.dyHotspot = 0;
1328     InternalDrag.bShow = FALSE;
1329     DeleteObject(InternalDrag.hbmBg);
1330     InternalDrag.hbmBg = 0;
1331 }
1332
1333
1334 /*************************************************************************
1335  * ImageList_GetBkColor [COMCTL32.@]
1336  *
1337  * Returns the background color of an image list.
1338  *
1339  * PARAMS
1340  *     himl [I] Image list handle.
1341  *
1342  * RETURNS
1343  *     Success: background color
1344  *     Failure: CLR_NONE
1345  */
1346
1347 COLORREF WINAPI
1348 ImageList_GetBkColor (HIMAGELIST himl)
1349 {
1350     return himl ? himl->clrBk : CLR_NONE;
1351 }
1352
1353
1354 /*************************************************************************
1355  * ImageList_GetDragImage [COMCTL32.@]
1356  *
1357  * Returns the handle to the internal drag image list.
1358  *
1359  * PARAMS
1360  *     ppt        [O] Pointer to the drag position. Can be NULL.
1361  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1362  *
1363  * RETURNS
1364  *     Success: Handle of the drag image list.
1365  *     Failure: NULL.
1366  */
1367
1368 HIMAGELIST WINAPI
1369 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1370 {
1371     if (is_valid(InternalDrag.himl)) {
1372         if (ppt) {
1373             ppt->x = InternalDrag.x;
1374             ppt->y = InternalDrag.y;
1375         }
1376         if (pptHotspot) {
1377             pptHotspot->x = InternalDrag.dxHotspot;
1378             pptHotspot->y = InternalDrag.dyHotspot;
1379         }
1380         return (InternalDrag.himl);
1381     }
1382
1383     return NULL;
1384 }
1385
1386
1387 /*************************************************************************
1388  * ImageList_GetFlags [COMCTL32.@]
1389  *
1390  * Gets the flags of the specified image list.
1391  *
1392  * PARAMS
1393  *     himl [I] Handle to image list
1394  *
1395  * RETURNS
1396  *     Image list flags.
1397  *
1398  * BUGS
1399  *    Stub.
1400  */
1401
1402 DWORD WINAPI
1403 ImageList_GetFlags(HIMAGELIST himl)
1404 {
1405     FIXME("(%p):empty stub\n", himl);
1406     return 0;
1407 }
1408
1409
1410 /*************************************************************************
1411  * ImageList_GetIcon [COMCTL32.@]
1412  *
1413  * Creates an icon from a masked image of an image list.
1414  *
1415  * PARAMS
1416  *     himl  [I] handle to image list
1417  *     i     [I] image index
1418  *     flags [I] drawing style flags
1419  *
1420  * RETURNS
1421  *     Success: icon handle
1422  *     Failure: NULL
1423  */
1424
1425 HICON WINAPI
1426 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1427 {
1428     ICONINFO ii;
1429     HICON hIcon;
1430     HBITMAP hOldDstBitmap;
1431     HDC hdcDst;
1432
1433     TRACE("%p %d %d\n", himl, i, fStyle);
1434     if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1435
1436     ii.fIcon = TRUE;
1437     ii.xHotspot = 0;
1438     ii.yHotspot = 0;
1439
1440     /* create colour bitmap */
1441     hdcDst = GetDC(0);
1442     ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1443     ReleaseDC(0, hdcDst);
1444
1445     hdcDst = CreateCompatibleDC(0);
1446
1447     /* draw mask*/
1448     ii.hbmMask  = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1449     hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1450     if (himl->hbmMask) {
1451         BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1452                 himl->hdcMask, i * himl->cx, 0, SRCCOPY);
1453     }
1454     else
1455         PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1456
1457     /* draw image*/
1458     SelectObject (hdcDst, ii.hbmColor);
1459     BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1460             himl->hdcImage, i * himl->cx, 0, SRCCOPY);
1461
1462     /*
1463      * CreateIconIndirect requires us to deselect the bitmaps from
1464      * the DCs before calling
1465      */
1466     SelectObject(hdcDst, hOldDstBitmap);
1467
1468     hIcon = CreateIconIndirect (&ii);
1469
1470     DeleteObject (ii.hbmMask);
1471     DeleteObject (ii.hbmColor);
1472     DeleteDC (hdcDst);
1473
1474     return hIcon;
1475 }
1476
1477
1478 /*************************************************************************
1479  * ImageList_GetIconSize [COMCTL32.@]
1480  *
1481  * Retrieves the size of an image in an image list.
1482  *
1483  * PARAMS
1484  *     himl [I] handle to image list
1485  *     cx   [O] pointer to the image width.
1486  *     cy   [O] pointer to the image height.
1487  *
1488  * RETURNS
1489  *     Success: TRUE
1490  *     Failure: FALSE
1491  *
1492  * NOTES
1493  *     All images in an image list have the same size.
1494  */
1495
1496 BOOL WINAPI
1497 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1498 {
1499     if (!is_valid(himl))
1500         return FALSE;
1501     if ((himl->cx <= 0) || (himl->cy <= 0))
1502         return FALSE;
1503
1504     if (cx)
1505         *cx = himl->cx;
1506     if (cy)
1507         *cy = himl->cy;
1508
1509     return TRUE;
1510 }
1511
1512
1513 /*************************************************************************
1514  * ImageList_GetImageCount [COMCTL32.@]
1515  *
1516  * Returns the number of images in an image list.
1517  *
1518  * PARAMS
1519  *     himl [I] handle to image list
1520  *
1521  * RETURNS
1522  *     Success: Number of images.
1523  *     Failure: 0
1524  */
1525
1526 INT WINAPI
1527 ImageList_GetImageCount (HIMAGELIST himl)
1528 {
1529     if (!is_valid(himl))
1530         return 0;
1531
1532     return himl->cCurImage;
1533 }
1534
1535
1536 /*************************************************************************
1537  * ImageList_GetImageInfo [COMCTL32.@]
1538  *
1539  * Returns information about an image in an image list.
1540  *
1541  * PARAMS
1542  *     himl       [I] handle to image list
1543  *     i          [I] image index
1544  *     pImageInfo [O] pointer to the image information
1545  *
1546  * RETURNS
1547  *     Success: TRUE
1548  *     Failure: FALSE
1549  */
1550
1551 BOOL WINAPI
1552 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1553 {
1554     POINT pt;
1555
1556     if (!is_valid(himl) || (pImageInfo == NULL))
1557         return FALSE;
1558     if ((i < 0) || (i >= himl->cCurImage))
1559         return FALSE;
1560
1561     pImageInfo->hbmImage = himl->hbmImage;
1562     pImageInfo->hbmMask  = himl->hbmMask;
1563
1564     imagelist_point_from_index( himl, i, &pt );
1565     pImageInfo->rcImage.top    = pt.y;
1566     pImageInfo->rcImage.bottom = pt.y + himl->cy;
1567     pImageInfo->rcImage.left   = pt.x;
1568     pImageInfo->rcImage.right  = pt.x + himl->cx;
1569
1570     return TRUE;
1571 }
1572
1573
1574 /*************************************************************************
1575  * ImageList_GetImageRect [COMCTL32.@]
1576  *
1577  * Retrieves the rectangle of the specified image in an image list.
1578  *
1579  * PARAMS
1580  *     himl   [I] handle to image list
1581  *     i      [I] image index
1582  *     lpRect [O] pointer to the image rectangle
1583  *
1584  * RETURNS
1585  *    Success: TRUE
1586  *    Failure: FALSE
1587  *
1588  * NOTES
1589  *    This is an UNDOCUMENTED function!!!
1590  */
1591
1592 BOOL WINAPI
1593 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1594 {
1595     POINT pt;
1596
1597     if (!is_valid(himl) || (lpRect == NULL))
1598         return FALSE;
1599     if ((i < 0) || (i >= himl->cCurImage))
1600         return FALSE;
1601
1602     imagelist_point_from_index( himl, i, &pt );
1603     lpRect->left   = pt.x;
1604     lpRect->top    = pt.y;
1605     lpRect->right  = pt.x + himl->cx;
1606     lpRect->bottom = pt.y + himl->cy;
1607
1608     return TRUE;
1609 }
1610
1611
1612 /*************************************************************************
1613  * ImageList_LoadImage  [COMCTL32.@]
1614  * ImageList_LoadImageA [COMCTL32.@]
1615  *
1616  * Creates an image list from a bitmap, icon or cursor.
1617  *
1618  * See ImageList_LoadImageW.
1619  */
1620
1621 HIMAGELIST WINAPI
1622 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1623                         COLORREF clrMask, UINT uType, UINT uFlags)
1624 {
1625     HIMAGELIST himl;
1626     LPWSTR lpbmpW;
1627     DWORD len;
1628
1629     if (!HIWORD(lpbmp))
1630         return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1631                                     uType, uFlags);
1632
1633     len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1634     lpbmpW = Alloc(len * sizeof(WCHAR));
1635     MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1636
1637     himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1638     Free (lpbmpW);
1639     return himl;
1640 }
1641
1642
1643 /*************************************************************************
1644  * ImageList_LoadImageW [COMCTL32.@]
1645  *
1646  * Creates an image list from a bitmap, icon or cursor.
1647  *
1648  * PARAMS
1649  *     hi      [I] instance handle
1650  *     lpbmp   [I] name or id of the image
1651  *     cx      [I] width of each image
1652  *     cGrow   [I] number of images to expand
1653  *     clrMask [I] mask color
1654  *     uType   [I] type of image to load
1655  *     uFlags  [I] loading flags
1656  *
1657  * RETURNS
1658  *     Success: handle to the loaded image list
1659  *     Failure: NULL
1660  *
1661  * SEE
1662  *     LoadImage ()
1663  */
1664
1665 HIMAGELIST WINAPI
1666 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1667                       COLORREF clrMask, UINT uType, UINT uFlags)
1668 {
1669     HIMAGELIST himl = NULL;
1670     HANDLE   handle;
1671     INT      nImageCount;
1672
1673     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1674     if (!handle) {
1675         ERR("Error loading image!\n");
1676         return NULL;
1677     }
1678
1679     if (uType == IMAGE_BITMAP) {
1680         BITMAP bmp;
1681         GetObjectW (handle, sizeof(BITMAP), &bmp);
1682
1683         /* To match windows behavior, if cx is set to zero and
1684          the flag DI_DEFAULTSIZE is specified, cx becomes the
1685          system metric value for icons. If the flag is not specified
1686          the function sets the size to the height of the bitmap */
1687         if (cx == 0)
1688         {
1689             if (uFlags & DI_DEFAULTSIZE)
1690                 cx = GetSystemMetrics (SM_CXICON);
1691             else
1692                 cx = bmp.bmHeight;
1693         }
1694
1695         nImageCount = bmp.bmWidth / cx;
1696
1697         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1698                                  nImageCount, cGrow);
1699         if (!himl) {
1700             DeleteObject (handle);
1701             return NULL;
1702         }
1703         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1704     }
1705     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1706         ICONINFO ii;
1707         BITMAP bmp;
1708
1709         GetIconInfo (handle, &ii);
1710         GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1711         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1712                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1713         if (!himl) {
1714             DeleteObject (ii.hbmColor);
1715             DeleteObject (ii.hbmMask);
1716             DeleteObject (handle);
1717             return NULL;
1718         }
1719         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1720         DeleteObject (ii.hbmColor);
1721         DeleteObject (ii.hbmMask);
1722     }
1723
1724     DeleteObject (handle);
1725
1726     return himl;
1727 }
1728
1729
1730 /*************************************************************************
1731  * ImageList_Merge [COMCTL32.@]
1732  *
1733  * Create an image list containing a merged image from two image lists.
1734  *
1735  * PARAMS
1736  *     himl1 [I] handle to first image list
1737  *     i1    [I] first image index
1738  *     himl2 [I] handle to second image list
1739  *     i2    [I] second image index
1740  *     dx    [I] X offset of the second image relative to the first.
1741  *     dy    [I] Y offset of the second image relative to the first.
1742  *
1743  * RETURNS
1744  *     Success: The newly created image list. It contains a single image
1745  *              consisting of the second image merged with the first.
1746  *     Failure: NULL, if either himl1 or himl2 are invalid.
1747  *
1748  * NOTES
1749  *   - The returned image list should be deleted by the caller using
1750  *     ImageList_Destroy() when it is no longer required.
1751  *   - If either i1 or i2 are not valid image indices they will be treated
1752  *     as a blank image.
1753  */
1754 HIMAGELIST WINAPI
1755 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1756                  INT dx, INT dy)
1757 {
1758     HIMAGELIST himlDst = NULL;
1759     INT      cxDst, cyDst;
1760     INT      xOff1, yOff1, xOff2, yOff2;
1761     INT      nX1, nX2;
1762
1763     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1764            i2, dx, dy);
1765
1766     if (!is_valid(himl1) || !is_valid(himl2))
1767         return NULL;
1768
1769     if (dx > 0) {
1770         cxDst = max (himl1->cx, dx + himl2->cx);
1771         xOff1 = 0;
1772         xOff2 = dx;
1773     }
1774     else if (dx < 0) {
1775         cxDst = max (himl2->cx, himl1->cx - dx);
1776         xOff1 = -dx;
1777         xOff2 = 0;
1778     }
1779     else {
1780         cxDst = max (himl1->cx, himl2->cx);
1781         xOff1 = 0;
1782         xOff2 = 0;
1783     }
1784
1785     if (dy > 0) {
1786         cyDst = max (himl1->cy, dy + himl2->cy);
1787         yOff1 = 0;
1788         yOff2 = dy;
1789     }
1790     else if (dy < 0) {
1791         cyDst = max (himl2->cy, himl1->cy - dy);
1792         yOff1 = -dy;
1793         yOff2 = 0;
1794     }
1795     else {
1796         cyDst = max (himl1->cy, himl2->cy);
1797         yOff1 = 0;
1798         yOff2 = 0;
1799     }
1800
1801     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1802
1803     if (himlDst)
1804     {
1805         nX1 = i1 * himl1->cx;
1806         nX2 = i2 * himl2->cx;
1807
1808         /* copy image */
1809         BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1810         if (i1 >= 0 && i1 < himl1->cCurImage)
1811             BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1812         if (i2 >= 0 && i2 < himl2->cCurImage)
1813         {
1814             BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1815             BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1816         }
1817
1818         /* copy mask */
1819         BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1820         if (i1 >= 0 && i1 < himl1->cCurImage)
1821             BitBlt (himlDst->hdcMask,  xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask,  nX1, 0, SRCCOPY);
1822         if (i2 >= 0 && i2 < himl2->cCurImage)
1823             BitBlt (himlDst->hdcMask,  xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask,  nX2, 0, SRCAND);
1824
1825         himlDst->cCurImage = 1;
1826     }
1827
1828     return himlDst;
1829 }
1830
1831
1832 /* helper for _read_bitmap currently unused */
1833 #if 0
1834 static int may_use_dibsection(HDC hdc) {
1835     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1836     if (bitspixel>8)
1837         return TRUE;
1838     if (bitspixel<=4)
1839         return FALSE;
1840     return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1841 }
1842 #endif
1843
1844 /* helper for ImageList_Read, see comments below */
1845 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1846     HDC                        xdc = 0, hBitmapDC =0;
1847     BITMAPFILEHEADER    bmfh;
1848     BITMAPINFOHEADER    bmih;
1849     int                 bitsperpixel,palspace,longsperline,width,height;
1850     LPBITMAPINFOHEADER  bmihc = NULL;
1851     int                 result = 0;
1852     HBITMAP            hbitmap = 0, hDIB = 0;
1853     LPBYTE             bits = NULL;
1854
1855     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
1856         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
1857         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
1858         (bmih.biSize != sizeof(bmih))
1859     )
1860         return 0;
1861
1862     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1863     if (bitsperpixel<=8)
1864         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1865     else
1866         palspace = 0;
1867     width = bmih.biWidth;
1868     height = bmih.biHeight;
1869     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1870     if (!bmihc) goto ret1;
1871     memcpy(bmihc,&bmih,sizeof(bmih));
1872     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
1873     bmihc->biSizeImage  = (longsperline*height)<<2;
1874
1875     /* read the palette right after the end of the bitmapinfoheader */
1876     if (palspace)
1877         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1878             goto ret1;
1879
1880     xdc = GetDC(0);
1881 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1882     if ((bitsperpixel>1) &&
1883         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1884      ) {
1885         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1886         if (!hbitmap)
1887             goto ret1;
1888         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1889             goto ret1;
1890         result = 1;
1891     } else
1892 #endif
1893     {
1894        int i,nwidth,nheight,nRows;
1895
1896         nwidth  = width*(height/cy);
1897         nheight = cy;
1898         nRows   = (height/cy);
1899
1900         if (bitsperpixel==1)
1901             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1902         else
1903             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1904
1905        hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1906        if (!hDIB)
1907            goto ret1;
1908        if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1909            goto ret1;
1910
1911         hBitmapDC = CreateCompatibleDC(0);
1912         SelectObject(hBitmapDC, hbitmap);
1913
1914         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1915         /* Do not forget that windows bitmaps are bottom->top */
1916         TRACE("nRows=%d\n", nRows);
1917         for (i=0; i < nRows; i++){
1918             StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1919                 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1920         }
1921         
1922         result = 1;
1923     }
1924 ret1:
1925     if (xdc)    ReleaseDC(0,xdc);
1926     if (bmihc)  LocalFree((HLOCAL)bmihc);
1927     if (hDIB)   DeleteObject(hDIB);
1928     if (hBitmapDC)   DeleteDC(hBitmapDC);
1929     if (!result) {
1930         if (hbitmap) {
1931             DeleteObject(hbitmap);
1932             hbitmap = 0;
1933         }
1934     }
1935     return hbitmap;
1936 }
1937
1938 /*************************************************************************
1939  * ImageList_Read [COMCTL32.@]
1940  *
1941  * Reads an image list from a stream.
1942  *
1943  * PARAMS
1944  *     pstm [I] pointer to a stream
1945  *
1946  * RETURNS
1947  *     Success: handle to image list
1948  *     Failure: NULL
1949  *
1950  * The format is like this:
1951  *      ILHEAD                  ilheadstruct;
1952  *
1953  * for the color image part:
1954  *      BITMAPFILEHEADER        bmfh;
1955  *      BITMAPINFOHEADER        bmih;
1956  * only if it has a palette:
1957  *      RGBQUAD         rgbs[nr_of_paletted_colors];
1958  *
1959  *      BYTE                    colorbits[imagesize];
1960  *
1961  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1962  *      BITMAPFILEHEADER        bmfh_mask;
1963  *      BITMAPINFOHEADER        bmih_mask;
1964  * only if it has a palette (it usually does not):
1965  *      RGBQUAD         rgbs[nr_of_paletted_colors];
1966  *
1967  *      BYTE                    maskbits[imagesize];
1968  *
1969  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1970  *         _read_bitmap needs to convert them.
1971  */
1972 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1973 {
1974     ILHEAD      ilHead;
1975     HIMAGELIST  himl;
1976     HBITMAP     hbmColor=0,hbmMask=0;
1977     int         i;
1978
1979     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1980         return NULL;
1981     if (ilHead.usMagic != (('L' << 8) | 'I'))
1982         return NULL;
1983     if (ilHead.usVersion != 0x101) /* probably version? */
1984         return NULL;
1985
1986 #if 0
1987     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
1988     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1989     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
1990     FIXME("     ilHead.cx = %d\n",ilHead.cx);
1991     FIXME("     ilHead.cy = %d\n",ilHead.cy);
1992     FIXME("     ilHead.flags = %x\n",ilHead.flags);
1993     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1994     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1995     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1996     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1997 #endif
1998
1999     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2000     if (!hbmColor) {
2001         WARN("failed to read bitmap from stream\n");
2002         return NULL;
2003     }
2004     if (ilHead.flags & ILC_MASK) {
2005         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2006         if (!hbmMask) {
2007             DeleteObject(hbmColor);
2008             return NULL;
2009         }
2010     }
2011
2012     himl = ImageList_Create (
2013                     ilHead.cx,
2014                     ilHead.cy,
2015                     ilHead.flags,
2016                     1,          /* initial */
2017                     ilHead.cGrow
2018     );
2019     if (!himl) {
2020         DeleteObject(hbmColor);
2021         DeleteObject(hbmMask);
2022         return NULL;
2023     }
2024     SelectObject(himl->hdcImage, hbmColor);
2025     DeleteObject(himl->hbmImage);
2026     himl->hbmImage = hbmColor;
2027     if (hbmMask){
2028         SelectObject(himl->hdcMask, hbmMask);
2029         DeleteObject(himl->hbmMask);
2030         himl->hbmMask = hbmMask;
2031     }
2032     himl->cCurImage = ilHead.cCurImage;
2033     himl->cMaxImage = ilHead.cMaxImage;
2034
2035     ImageList_SetBkColor(himl,ilHead.bkcolor);
2036     for (i=0;i<4;i++)
2037         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2038     return himl;
2039 }
2040
2041
2042 /*************************************************************************
2043  * ImageList_Remove [COMCTL32.@]
2044  *
2045  * Removes an image from an image list
2046  *
2047  * PARAMS
2048  *     himl [I] image list handle
2049  *     i    [I] image index
2050  *
2051  * RETURNS
2052  *     Success: TRUE
2053  *     Failure: FALSE
2054  */
2055
2056 BOOL WINAPI
2057 ImageList_Remove (HIMAGELIST himl, INT i)
2058 {
2059     HBITMAP hbmNewImage, hbmNewMask;
2060     HDC     hdcBmp;
2061     INT     cxNew, nCount;
2062
2063     TRACE("(himl=%p i=%d)\n", himl, i);
2064
2065     if (!is_valid(himl)) {
2066         ERR("Invalid image list handle!\n");
2067         return FALSE;
2068     }
2069
2070     if ((i < -1) || (i >= himl->cCurImage)) {
2071         TRACE("index out of range! %d\n", i);
2072         return FALSE;
2073     }
2074
2075     if (i == -1) {
2076         /* remove all */
2077         if (himl->cCurImage == 0) {
2078             /* remove all on empty ImageList is allowed */
2079             TRACE("remove all on empty ImageList!\n");
2080             return TRUE;
2081         }
2082
2083         himl->cMaxImage = himl->cInitial + himl->cGrow;
2084         himl->cCurImage = 0;
2085         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2086              himl->nOvlIdx[nCount] = -1;
2087
2088         hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2089         SelectObject (himl->hdcImage, hbmNewImage);
2090         DeleteObject (himl->hbmImage);
2091         himl->hbmImage = hbmNewImage;
2092
2093         if (himl->hbmMask) {
2094             SIZE sz;
2095
2096             imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2097             hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2098             SelectObject (himl->hdcMask, hbmNewMask);
2099             DeleteObject (himl->hbmMask);
2100             himl->hbmMask = hbmNewMask;
2101         }
2102     }
2103     else {
2104         /* delete one image */
2105         TRACE("Remove single image! %d\n", i);
2106
2107         /* create new bitmap(s) */
2108         nCount = (himl->cCurImage + himl->cGrow - 1);
2109         cxNew = nCount * himl->cx;
2110
2111         TRACE(" - Number of images: %d / %d (Old/New)\n",
2112                  himl->cCurImage, himl->cCurImage - 1);
2113         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2114                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2115
2116         hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, nCount, himl->cy);
2117
2118         if (himl->hbmMask)
2119             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2120         else
2121             hbmNewMask = 0;  /* Just to keep compiler happy! */
2122
2123         hdcBmp = CreateCompatibleDC (0);
2124
2125         /* copy all images and masks prior to the "removed" image */
2126         if (i > 0) {
2127             POINT pt;
2128
2129             TRACE("Pre image copy: Copy %d images\n", i);
2130
2131             SelectObject (hdcBmp, hbmNewImage);
2132             imagelist_point_from_index(himl, i, &pt);
2133             BitBlt (hdcBmp, 0, 0, pt.x, pt.y, himl->hdcImage, 0, 0, SRCCOPY);
2134
2135             if (himl->hbmMask) {
2136                 SelectObject (hdcBmp, hbmNewMask);
2137                 BitBlt (hdcBmp, 0, 0, pt.x, pt.y, himl->hdcMask, 0, 0, SRCCOPY);
2138             }
2139         }
2140
2141         /* copy all images and masks behind the removed image */
2142         if (i < himl->cCurImage - 1) {
2143             TRACE("Post image copy!\n");
2144             SelectObject (hdcBmp, hbmNewImage);
2145             BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2146                       himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2147
2148             if (himl->hbmMask) {
2149                 SelectObject (hdcBmp, hbmNewMask);
2150                 BitBlt (hdcBmp, i * himl->cx, 0,
2151                           (himl->cCurImage - i - 1) * himl->cx,
2152                           himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2153             }
2154         }
2155
2156         DeleteDC (hdcBmp);
2157
2158         /* delete old images and insert new ones */
2159         SelectObject (himl->hdcImage, hbmNewImage);
2160         DeleteObject (himl->hbmImage);
2161         himl->hbmImage = hbmNewImage;
2162         if (himl->hbmMask) {
2163             SelectObject (himl->hdcMask, hbmNewMask);
2164             DeleteObject (himl->hbmMask);
2165             himl->hbmMask = hbmNewMask;
2166         }
2167
2168         himl->cCurImage--;
2169         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2170     }
2171
2172     return TRUE;
2173 }
2174
2175
2176 /*************************************************************************
2177  * ImageList_Replace [COMCTL32.@]
2178  *
2179  * Replaces an image in an image list with a new image.
2180  *
2181  * PARAMS
2182  *     himl     [I] handle to image list
2183  *     i        [I] image index
2184  *     hbmImage [I] handle to image bitmap
2185  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2186  *
2187  * RETURNS
2188  *     Success: TRUE
2189  *     Failure: FALSE
2190  */
2191
2192 BOOL WINAPI
2193 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2194                    HBITMAP hbmMask)
2195 {
2196     HDC hdcImage;
2197     BITMAP bmp;
2198     HBITMAP hOldBitmap;
2199     POINT pt;
2200
2201     TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2202
2203     if (!is_valid(himl)) {
2204         ERR("Invalid image list handle!\n");
2205         return FALSE;
2206     }
2207
2208     if ((i >= himl->cMaxImage) || (i < 0)) {
2209         ERR("Invalid image index!\n");
2210         return FALSE;
2211     }
2212
2213     hdcImage = CreateCompatibleDC (0);
2214     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2215
2216     /* Replace Image */
2217     hOldBitmap = SelectObject (hdcImage, hbmImage);
2218
2219     imagelist_point_from_index(himl, i, &pt);
2220     StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2221                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2222
2223     if (himl->hbmMask)
2224     {
2225         HDC hdcTemp;
2226         HBITMAP hOldBitmapTemp;
2227
2228         hdcTemp   = CreateCompatibleDC(0);
2229         hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2230
2231         StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2232                       hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2233         SelectObject(hdcTemp, hOldBitmapTemp);
2234         DeleteDC(hdcTemp);
2235
2236         /* Remove the background from the image
2237         */
2238         BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2239                 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2240     }
2241
2242     SelectObject (hdcImage, hOldBitmap);
2243     DeleteDC (hdcImage);
2244
2245     return TRUE;
2246 }
2247
2248
2249 /*************************************************************************
2250  * ImageList_ReplaceIcon [COMCTL32.@]
2251  *
2252  * Replaces an image in an image list using an icon.
2253  *
2254  * PARAMS
2255  *     himl  [I] handle to image list
2256  *     i     [I] image index
2257  *     hIcon [I] handle to icon
2258  *
2259  * RETURNS
2260  *     Success: index of the replaced image
2261  *     Failure: -1
2262  */
2263
2264 INT WINAPI
2265 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2266 {
2267     HDC     hdcImage;
2268     INT     nIndex;
2269     HICON   hBestFitIcon;
2270     HBITMAP hbmOldSrc;
2271     ICONINFO  ii;
2272     BITMAP  bmp;
2273     BOOL    ret;
2274     POINT   pt;
2275
2276     TRACE("(%p %d %p)\n", himl, i, hIcon);
2277
2278     if (!is_valid(himl)) {
2279         ERR("invalid image list\n");
2280         return -1;
2281     }
2282     if ((i >= himl->cMaxImage) || (i < -1)) {
2283         ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2284         return -1;
2285     }
2286
2287     hBestFitIcon = CopyImage(
2288         hIcon, IMAGE_ICON,
2289         himl->cx, himl->cy,
2290         LR_COPYFROMRESOURCE);
2291     /* the above will fail if the icon wasn't loaded from a resource, so try
2292      * again without LR_COPYFROMRESOURCE flag */
2293     if (!hBestFitIcon)
2294         hBestFitIcon = CopyImage(
2295             hIcon, IMAGE_ICON,
2296             himl->cx, himl->cy,
2297             0);
2298     if (!hBestFitIcon)
2299         return -1;
2300
2301     ret = GetIconInfo (hBestFitIcon, &ii);
2302     if (!ret) {
2303         DestroyIcon(hBestFitIcon);
2304         return -1;
2305     }
2306
2307     if (ii.hbmColor == 0)
2308         ERR("no color!\n");
2309     ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2310     if (!ret) {
2311         ERR("couldn't get mask bitmap info\n");
2312         if (ii.hbmColor)
2313             DeleteObject (ii.hbmColor);
2314         if (ii.hbmMask)
2315             DeleteObject (ii.hbmMask);
2316         DestroyIcon(hBestFitIcon);
2317         return -1;
2318     }
2319
2320     if (i == -1) {
2321         if (himl->cCurImage + 1 > himl->cMaxImage)
2322             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2323
2324         nIndex = himl->cCurImage;
2325         himl->cCurImage++;
2326     }
2327     else
2328         nIndex = i;
2329
2330     hdcImage = CreateCompatibleDC (0);
2331     TRACE("hdcImage=%p\n", hdcImage);
2332     if (hdcImage == 0)
2333         ERR("invalid hdcImage!\n");
2334
2335     SetTextColor(himl->hdcImage, RGB(0,0,0));
2336     SetBkColor  (himl->hdcImage, RGB(255,255,255));
2337     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2338
2339     imagelist_point_from_index(himl, nIndex, &pt);
2340     StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2341                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2342
2343     if (himl->hbmMask) {
2344         SelectObject (hdcImage, ii.hbmMask);
2345         StretchBlt   (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2346                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2347     }
2348
2349     SelectObject (hdcImage, hbmOldSrc);
2350
2351     DestroyIcon(hBestFitIcon);
2352     if (hdcImage)
2353         DeleteDC (hdcImage);
2354     if (ii.hbmColor)
2355         DeleteObject (ii.hbmColor);
2356     if (ii.hbmMask)
2357         DeleteObject (ii.hbmMask);
2358
2359     TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2360     return nIndex;
2361 }
2362
2363
2364 /*************************************************************************
2365  * ImageList_SetBkColor [COMCTL32.@]
2366  *
2367  * Sets the background color of an image list.
2368  *
2369  * PARAMS
2370  *     himl  [I] handle to image list
2371  *     clrBk [I] background color
2372  *
2373  * RETURNS
2374  *     Success: previous background color
2375  *     Failure: CLR_NONE
2376  */
2377
2378 COLORREF WINAPI
2379 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2380 {
2381     COLORREF clrOldBk;
2382
2383     if (!is_valid(himl))
2384         return CLR_NONE;
2385
2386     clrOldBk = himl->clrBk;
2387     himl->clrBk = clrBk;
2388     return clrOldBk;
2389 }
2390
2391
2392 /*************************************************************************
2393  * ImageList_SetDragCursorImage [COMCTL32.@]
2394  *
2395  * Combines the specified image with the current drag image
2396  *
2397  * PARAMS
2398  *     himlDrag  [I] handle to drag image list
2399  *     iDrag     [I] drag image index
2400  *     dxHotspot [I] X position of the hot spot
2401  *     dyHotspot [I] Y position of the hot spot
2402  *
2403  * RETURNS
2404  *     Success: TRUE
2405  *     Failure: FALSE
2406  *
2407  * NOTES
2408  *   - The names dxHotspot, dyHotspot are misleading because they have nothing
2409  *     to do with a hotspot but are only the offset of the origin of the new
2410  *     image relative to the origin of the old image.
2411  *
2412  *   - When this function is called and the drag image is visible, a
2413  *     short flickering occurs but this matches the Win9x behavior. It is
2414  *     possible to fix the flickering using code like in ImageList_DragMove.
2415  */
2416
2417 BOOL WINAPI
2418 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2419                               INT dxHotspot, INT dyHotspot)
2420 {
2421     HIMAGELIST himlTemp;
2422     BOOL visible;
2423
2424     if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2425         return FALSE;
2426
2427     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2428            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2429
2430     visible = InternalDrag.bShow;
2431
2432     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2433                                 dxHotspot, dyHotspot);
2434
2435     if (visible) {
2436         /* hide the drag image */
2437         ImageList_DragShowNolock(FALSE);
2438     }
2439     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2440            (InternalDrag.himl->cy != himlTemp->cy)) {
2441         /* the size of the drag image changed, invalidate the buffer */
2442         DeleteObject(InternalDrag.hbmBg);
2443         InternalDrag.hbmBg = 0;
2444     }
2445
2446     ImageList_Destroy (InternalDrag.himl);
2447     InternalDrag.himl = himlTemp;
2448
2449     if (visible) {
2450         /* show the drag image */
2451         ImageList_DragShowNolock(TRUE);
2452     }
2453
2454     return TRUE;
2455 }
2456
2457
2458 /*************************************************************************
2459  * ImageList_SetFilter [COMCTL32.@]
2460  *
2461  * Sets a filter (or does something completely different)!!???
2462  * It removes 12 Bytes from the stack (3 Parameters).
2463  *
2464  * PARAMS
2465  *     himl     [I] SHOULD be a handle to image list
2466  *     i        [I] COULD be an index?
2467  *     dwFilter [I] ???
2468  *
2469  * RETURNS
2470  *     Success: TRUE ???
2471  *     Failure: FALSE ???
2472  *
2473  * BUGS
2474  *     This is an UNDOCUMENTED function!!!!
2475  *     empty stub.
2476  */
2477
2478 BOOL WINAPI
2479 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2480 {
2481     FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2482
2483     return FALSE;
2484 }
2485
2486
2487 /*************************************************************************
2488  * ImageList_SetFlags [COMCTL32.@]
2489  *
2490  * Sets the image list flags.
2491  *
2492  * PARAMS
2493  *     himl  [I] Handle to image list
2494  *     flags [I] Flags to set
2495  *
2496  * RETURNS
2497  *     Old flags?
2498  *
2499  * BUGS
2500  *    Stub.
2501  */
2502
2503 DWORD WINAPI
2504 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2505 {
2506     FIXME("(%p %08x):empty stub\n", himl, flags);
2507     return 0;
2508 }
2509
2510
2511 /*************************************************************************
2512  * ImageList_SetIconSize [COMCTL32.@]
2513  *
2514  * Sets the image size of the bitmap and deletes all images.
2515  *
2516  * PARAMS
2517  *     himl [I] handle to image list
2518  *     cx   [I] image width
2519  *     cy   [I] image height
2520  *
2521  * RETURNS
2522  *     Success: TRUE
2523  *     Failure: FALSE
2524  */
2525
2526 BOOL WINAPI
2527 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2528 {
2529     INT nCount;
2530     HBITMAP hbmNew;
2531
2532     if (!is_valid(himl))
2533         return FALSE;
2534
2535     /* remove all images */
2536     himl->cMaxImage = himl->cInitial + himl->cGrow;
2537     himl->cCurImage = 0;
2538     himl->cx        = cx;
2539     himl->cy        = cy;
2540
2541     /* initialize overlay mask indices */
2542     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2543         himl->nOvlIdx[nCount] = -1;
2544
2545     hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2546     SelectObject (himl->hdcImage, hbmNew);
2547     DeleteObject (himl->hbmImage);
2548     himl->hbmImage = hbmNew;
2549
2550     if (himl->hbmMask) {
2551         SIZE sz;
2552         imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2553         hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2554         SelectObject (himl->hdcMask, hbmNew);
2555         DeleteObject (himl->hbmMask);
2556         himl->hbmMask = hbmNew;
2557     }
2558
2559     return TRUE;
2560 }
2561
2562
2563 /*************************************************************************
2564  * ImageList_SetImageCount [COMCTL32.@]
2565  *
2566  * Resizes an image list to the specified number of images.
2567  *
2568  * PARAMS
2569  *     himl        [I] handle to image list
2570  *     iImageCount [I] number of images in the image list
2571  *
2572  * RETURNS
2573  *     Success: TRUE
2574  *     Failure: FALSE
2575  */
2576
2577 BOOL WINAPI
2578 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2579 {
2580     HDC     hdcBitmap;
2581     HBITMAP hbmNewBitmap;
2582     INT     nNewCount, nCopyCount;
2583
2584     TRACE("%p %d\n",himl,iImageCount);
2585
2586     if (!is_valid(himl))
2587         return FALSE;
2588     if (iImageCount < 0)
2589         return FALSE;
2590     if (himl->cMaxImage > iImageCount)
2591     {
2592         himl->cCurImage = iImageCount;
2593         /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2594         return TRUE;
2595     }
2596
2597     nNewCount = iImageCount + himl->cGrow;
2598     nCopyCount = min(himl->cCurImage, iImageCount);
2599
2600     hdcBitmap = CreateCompatibleDC (0);
2601
2602     hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cy);
2603
2604     if (hbmNewBitmap != 0)
2605     {
2606         SelectObject (hdcBitmap, hbmNewBitmap);
2607
2608         /* copy images */
2609         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2610                 himl->hdcImage, 0, 0, SRCCOPY);
2611 #if 0
2612         /* delete 'empty' image space */
2613         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2614         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2615         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2616                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2617 #endif
2618         SelectObject (himl->hdcImage, hbmNewBitmap);
2619         DeleteObject (himl->hbmImage);
2620         himl->hbmImage = hbmNewBitmap;
2621     }
2622     else
2623         ERR("Could not create new image bitmap !\n");
2624
2625     if (himl->hbmMask)
2626     {
2627         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2628                                        1, 1, NULL);
2629         if (hbmNewBitmap != 0)
2630         {
2631             SelectObject (hdcBitmap, hbmNewBitmap);
2632
2633             /* copy images */
2634             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2635                     himl->hdcMask, 0, 0, SRCCOPY);
2636 #if 0
2637             /* delete 'empty' image space */
2638             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2639             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2640             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2641                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2642 #endif
2643             SelectObject (himl->hdcMask, hbmNewBitmap);
2644             DeleteObject (himl->hbmMask);
2645             himl->hbmMask = hbmNewBitmap;
2646         }
2647         else
2648             ERR("Could not create new mask bitmap!\n");
2649     }
2650
2651     DeleteDC (hdcBitmap);
2652
2653     /* Update max image count and current image count */
2654     himl->cMaxImage = nNewCount;
2655     himl->cCurImage = iImageCount;
2656
2657     return TRUE;
2658 }
2659
2660
2661 /*************************************************************************
2662  * ImageList_SetOverlayImage [COMCTL32.@]
2663  *
2664  * Assigns an overlay mask index to an existing image in an image list.
2665  *
2666  * PARAMS
2667  *     himl     [I] handle to image list
2668  *     iImage   [I] image index
2669  *     iOverlay [I] overlay mask index
2670  *
2671  * RETURNS
2672  *     Success: TRUE
2673  *     Failure: FALSE
2674  */
2675
2676 BOOL WINAPI
2677 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2678 {
2679     if (!is_valid(himl))
2680         return FALSE;
2681     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2682         return FALSE;
2683     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2684         return FALSE;
2685     himl->nOvlIdx[iOverlay - 1] = iImage;
2686     return TRUE;
2687 }
2688
2689
2690
2691 /* helper for ImageList_Write - write bitmap to pstm
2692  * currently everything is written as 24 bit RGB, except masks
2693  */
2694 static BOOL
2695 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2696 {
2697     LPBITMAPFILEHEADER bmfh;
2698     LPBITMAPINFOHEADER bmih;
2699     LPBYTE data, lpBits, lpBitsOrg;
2700     BITMAP bm;
2701     INT bitCount, sizeImage, offBits, totalSize;
2702     INT nwidth, nheight, nsizeImage, icount;
2703     HDC xdc;
2704     BOOL result = FALSE;
2705
2706
2707     xdc = GetDC(0);
2708     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2709
2710     /* XXX is this always correct? */
2711     icount = bm.bmWidth / cx;
2712     nwidth = cx;
2713     nheight = cy * icount;
2714
2715     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2716     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2717     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2718
2719     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2720     if(bitCount != 24)
2721         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2722     offBits = totalSize;
2723     totalSize += nsizeImage;
2724
2725     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2726     bmfh = (LPBITMAPFILEHEADER)data;
2727     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2728     lpBits = data + offBits;
2729
2730     /* setup BITMAPFILEHEADER */
2731     bmfh->bfType      = (('M' << 8) | 'B');
2732     bmfh->bfSize      = 0;
2733     bmfh->bfReserved1 = 0;
2734     bmfh->bfReserved2 = 0;
2735     bmfh->bfOffBits   = offBits;
2736
2737     /* setup BITMAPINFOHEADER */
2738     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2739     bmih->biWidth         = bm.bmWidth;
2740     bmih->biHeight        = bm.bmHeight;
2741     bmih->biPlanes        = 1;
2742     bmih->biBitCount      = bitCount;
2743     bmih->biCompression   = BI_RGB;
2744     bmih->biSizeImage     = sizeImage;
2745     bmih->biXPelsPerMeter = 0;
2746     bmih->biYPelsPerMeter = 0;
2747     bmih->biClrUsed       = 0;
2748     bmih->biClrImportant  = 0;
2749
2750     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2751     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2752                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2753         goto failed;
2754     else {
2755         int i;
2756         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2757         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2758
2759         for(i = 0; i < nheight; i++) {
2760             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2761             int noff = (nbpl * (nheight-1-i));
2762             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2763         }
2764     }
2765
2766     bmih->biWidth  = nwidth;
2767     bmih->biHeight = nheight;
2768     bmih->biSizeImage = nsizeImage;
2769
2770     if(bitCount == 1) {
2771         /* Hack. */
2772         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2773         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2774         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2775     }
2776
2777     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2778         goto failed;
2779
2780     result = TRUE;
2781
2782     failed:
2783     ReleaseDC(0, xdc);
2784     LocalFree((HLOCAL)lpBitsOrg);
2785     LocalFree((HLOCAL)data);
2786
2787     return result;
2788 }
2789
2790
2791 /*************************************************************************
2792  * ImageList_Write [COMCTL32.@]
2793  *
2794  * Writes an image list to a stream.
2795  *
2796  * PARAMS
2797  *     himl [I] handle to image list
2798  *     pstm [O] Pointer to a stream.
2799  *
2800  * RETURNS
2801  *     Success: TRUE
2802  *     Failure: FALSE
2803  *
2804  * BUGS
2805  *     probably.
2806  */
2807
2808 BOOL WINAPI
2809 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2810 {
2811     ILHEAD ilHead;
2812     int i;
2813
2814     if (!is_valid(himl))
2815         return FALSE;
2816
2817     ilHead.usMagic   = (('L' << 8) | 'I');
2818     ilHead.usVersion = 0x101;
2819     ilHead.cCurImage = himl->cCurImage;
2820     ilHead.cMaxImage = himl->cMaxImage;
2821     ilHead.cGrow     = himl->cGrow;
2822     ilHead.cx        = himl->cx;
2823     ilHead.cy        = himl->cy;
2824     ilHead.bkcolor   = himl->clrBk;
2825     ilHead.flags     = himl->flags;
2826     for(i = 0; i < 4; i++) {
2827         ilHead.ovls[i] = himl->nOvlIdx[i];
2828     }
2829
2830     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2831         return FALSE;
2832
2833     /* write the bitmap */
2834     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2835         return FALSE;
2836
2837     /* write the mask if we have one */
2838     if(himl->flags & ILC_MASK) {
2839         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2840             return FALSE;
2841     }
2842
2843     return TRUE;
2844 }
2845
2846
2847 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height)
2848 {
2849     HBITMAP hbmNewBitmap;
2850     UINT ilc = (himl->flags & 0xFE);
2851     SIZE sz;
2852
2853     imagelist_get_bitmap_size( himl, count, height, &sz );
2854
2855     if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2856     {
2857         VOID* bits;
2858         BITMAPINFO *bmi;
2859
2860         TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2861
2862         if (himl->uBitsPixel <= ILC_COLOR8)
2863         {
2864             LPPALETTEENTRY pal;
2865             ULONG i, colors;
2866             BYTE temp;
2867
2868             colors = 1 << himl->uBitsPixel;
2869             bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2870                             sizeof(PALETTEENTRY) * colors);
2871
2872             pal = (LPPALETTEENTRY)bmi->bmiColors;
2873             GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2874
2875             /* Swap colors returned by GetPaletteEntries so we can use them for
2876              * CreateDIBSection call. */
2877             for (i = 0; i < colors; i++)
2878             {
2879                 temp = pal[i].peBlue;
2880                 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2881                 bmi->bmiColors[i].rgbBlue = temp;
2882             }
2883         }
2884         else
2885         {
2886             bmi = Alloc(sizeof(BITMAPINFOHEADER));
2887         }
2888
2889         bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2890         bmi->bmiHeader.biWidth = sz.cx;
2891         bmi->bmiHeader.biHeight = sz.cy;
2892         bmi->bmiHeader.biPlanes = 1;
2893         bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2894         bmi->bmiHeader.biCompression = BI_RGB;
2895         bmi->bmiHeader.biSizeImage = 0;
2896         bmi->bmiHeader.biXPelsPerMeter = 0;
2897         bmi->bmiHeader.biYPelsPerMeter = 0;
2898         bmi->bmiHeader.biClrUsed = 0;
2899         bmi->bmiHeader.biClrImportant = 0;
2900
2901         hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2902
2903         Free (bmi);
2904     }
2905     else /*if (ilc == ILC_COLORDDB)*/
2906     {
2907         TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2908
2909         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
2910     }
2911     TRACE("returning %p\n", hbmNewBitmap);
2912     return hbmNewBitmap;
2913 }
2914
2915 /*************************************************************************
2916  * ImageList_SetColorTable [COMCTL32.@]
2917  *
2918  * Sets the color table of an image list.
2919  *
2920  * PARAMS
2921  *     himl        [I] Handle to the image list.
2922  *     uStartIndex [I] The first index to set.
2923  *     cEntries    [I] Number of entries to set.
2924  *     prgb        [I] New color information for color table for the image list.
2925  *
2926  * RETURNS
2927  *     Success: Number of entries in the table that were set.
2928  *     Failure: Zero.
2929  *
2930  * SEE
2931  *     ImageList_Create(), SetDIBColorTable()
2932  */
2933
2934 UINT WINAPI
2935 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2936 {
2937     return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
2938 }