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