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