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