Fix focus handling when deleting items, or changing modes.
[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 = himl->hbmMask && ((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     /* If we have an opaque image, draw the background */
1119     if (!bIsTransparent && himl->hbmMask) {
1120         HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1121         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1122         DeleteObject (SelectObject (hImageDC, hOldBrush));
1123     }
1124
1125     /*
1126      * Draw Image over the current background
1127      */
1128     if(fStyle & ILD_MASK) {
1129         if (himl->hbmMask) {
1130             BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1131         } else {
1132             HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1133             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1134             SelectObject(hImageDC, hOldBrush);
1135         }
1136     } else if (himl->hbmMask) {
1137         BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1138         BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1139     } else {
1140         /* the image is opaque, just copy it */
1141         TRACE("    - Image is opaque\n");
1142         BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1143     }
1144   
1145     /* Time for blending, if required */
1146     if (bBlend) {
1147         HBRUSH hBlendBrush, hOldBrush;
1148         COLORREF clrBlend = pimldp->rgbFg;
1149         HDC hBlendMaskDC = hImageListDC;
1150         HBITMAP hOldBitmap;
1151
1152         /* Create the blend Mask */
1153         hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1154         hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1155         hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1156         PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1157         SelectObject(hBlendMaskDC, hOldBrush);
1158
1159         /* Modify the blend mask if an Image Mask exist */
1160         if(himl->hbmMask) {
1161             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1162             BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1163         }
1164         
1165         /* now apply blend to the current image given the BlendMask */
1166         if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1167         else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1168         hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1169         BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1170         DeleteObject(SelectObject(hImageDC, hOldBrush));
1171         SelectObject(hBlendMaskDC, hOldBitmap);
1172     }
1173     
1174     /* Now do the overlay image, if any */ 
1175     nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1176     if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1177         nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1178         if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1179             const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1180             if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1181                 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1182             BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1183         }
1184     }
1185
1186     if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1187     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1188     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1189     if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1190
1191     if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1192     if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1193     if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1194     
1195     /* now copy the image to the screen */
1196     dwRop = SRCCOPY;
1197     if (bIsTransparent && !(fStyle & ILD_MASK)) {
1198         COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1199         COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1200         BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1201         SetBkColor(pimldp->hdcDst, oldDstBk);
1202         SetTextColor(pimldp->hdcDst, oldDstFg);
1203         dwRop = SRCPAINT;
1204     }
1205     if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1206     BitBlt (pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1207
1208     bResult = TRUE;
1209     
1210     /* cleanup the mess */
1211     SetBkColor(hImageDC, oldImageBk);
1212     SetTextColor(hImageDC, oldImageFg);
1213     SelectObject(hImageDC, hOldImageBmp);
1214     SelectObject(hImageListDC, hOldImageListBmp);
1215     if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1216 cleanup:
1217     DeleteObject(hBlendMaskBmp);
1218     DeleteObject(hImageBmp);
1219     DeleteObject(hImageDC);
1220     DeleteObject(hImageListDC);
1221     DeleteObject(hMaskListDC);
1222
1223     return bResult;
1224 }
1225
1226
1227 /*************************************************************************
1228  * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1229  *
1230  * PARAMS
1231  *     himlSrc [I] source image list handle
1232  *
1233  * RETURNS
1234  *     Success: Handle of duplicated image list.
1235  *     Failure: NULL
1236  */
1237
1238 HIMAGELIST WINAPI
1239 ImageList_Duplicate (HIMAGELIST himlSrc)
1240 {
1241     HIMAGELIST himlDst;
1242     HDC hdcSrc, hdcDst;
1243
1244     if (himlSrc == NULL) {
1245         ERR("Invalid image list handle!\n");
1246         return NULL;
1247     }
1248
1249     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1250                                 himlSrc->cInitial, himlSrc->cGrow);
1251
1252     if (himlDst)
1253     {
1254         hdcSrc = CreateCompatibleDC (0);
1255         hdcDst = CreateCompatibleDC (0);
1256         SelectObject (hdcSrc, himlSrc->hbmImage);
1257         SelectObject (hdcDst, himlDst->hbmImage);
1258         BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1259                   hdcSrc, 0, 0, SRCCOPY);
1260
1261         if (himlDst->hbmMask)
1262         {
1263             SelectObject (hdcSrc, himlSrc->hbmMask);
1264             SelectObject (hdcDst, himlDst->hbmMask);
1265             BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1266                       himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1267         }
1268
1269         DeleteDC (hdcDst);
1270         DeleteDC (hdcSrc);
1271
1272         himlDst->cCurImage = himlSrc->cCurImage;
1273         himlDst->cMaxImage = himlSrc->cMaxImage;
1274     }
1275     return himlDst;
1276 }
1277
1278
1279 /*************************************************************************
1280  * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1281  *
1282  * Finishes a drag operation.
1283  *
1284  * PARAMS
1285  *     no Parameters
1286  *
1287  * RETURNS
1288  *     Success: TRUE
1289  *     Failure: FALSE
1290  */
1291
1292 BOOL WINAPI
1293 ImageList_EndDrag (void)
1294 {
1295     /* cleanup the InternalDrag struct */
1296     InternalDrag.hwnd = 0;
1297     ImageList_Destroy (InternalDrag.himl);
1298     InternalDrag.himl = 0;
1299     InternalDrag.x= 0;
1300     InternalDrag.y= 0;
1301     InternalDrag.dxHotspot = 0;
1302     InternalDrag.dyHotspot = 0;
1303     InternalDrag.bShow = FALSE;
1304     DeleteObject(InternalDrag.hbmBg);
1305     InternalDrag.hbmBg = 0;
1306     InternalDrag.bHSPending = FALSE;
1307
1308     return TRUE;
1309 }
1310
1311
1312 /*************************************************************************
1313  * ImageList_GetBkColor [COMCTL32.@]
1314  *
1315  * Returns the background color of an image list.
1316  *
1317  * PARAMS
1318  *     himl [I] Image list handle.
1319  *
1320  * RETURNS
1321  *     Success: background color
1322  *     Failure: CLR_NONE
1323  */
1324
1325 COLORREF WINAPI
1326 ImageList_GetBkColor (HIMAGELIST himl)
1327 {
1328     return himl ? himl->clrBk : CLR_NONE;
1329 }
1330
1331
1332 /*************************************************************************
1333  * ImageList_GetDragImage [COMCTL32.@]
1334  *
1335  * Returns the handle to the internal drag image list.
1336  *
1337  * PARAMS
1338  *     ppt        [O] Pointer to the drag position. Can be NULL.
1339  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1340  *
1341  * RETURNS
1342  *     Success: Handle of the drag image list.
1343  *     Failure: NULL.
1344  */
1345
1346 HIMAGELIST WINAPI
1347 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1348 {
1349     if (InternalDrag.himl) {
1350         if (ppt) {
1351             ppt->x = InternalDrag.x;
1352             ppt->y = InternalDrag.y;
1353         }
1354         if (pptHotspot) {
1355             pptHotspot->x = InternalDrag.dxHotspot;
1356             pptHotspot->y = InternalDrag.dyHotspot;
1357         }
1358         return (InternalDrag.himl);
1359     }
1360
1361     return NULL;
1362 }
1363
1364
1365 /*************************************************************************
1366  * ImageList_GetFlags [COMCTL32.@]
1367  *
1368  * BUGS
1369  *    Stub.
1370  */
1371
1372 DWORD WINAPI
1373 ImageList_GetFlags(HIMAGELIST himl)
1374 {
1375     FIXME("(%p):empty stub\n", himl);
1376     return 0;
1377 }
1378
1379
1380 /*************************************************************************
1381  * ImageList_GetIcon [COMCTL32.@]
1382  *
1383  * Creates an icon from a masked image of an image list.
1384  *
1385  * PARAMS
1386  *     himl  [I] handle to image list
1387  *     i     [I] image index
1388  *     flags [I] drawing style flags
1389  *
1390  * RETURNS
1391  *     Success: icon handle
1392  *     Failure: NULL
1393  */
1394
1395 HICON WINAPI
1396 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1397 {
1398     ICONINFO ii;
1399     HICON hIcon;
1400     HBITMAP hOldDstBitmap;
1401     HDC hdcDst;
1402
1403     if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1404
1405     hdcDst = CreateCompatibleDC(0);
1406
1407     ii.fIcon = TRUE;
1408
1409     /* draw mask*/
1410     ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1411     hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1412     ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1413
1414     /* draw image*/
1415     SelectObject (hdcDst, himl->hbmImage);
1416     ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1417     SelectObject (hdcDst, ii.hbmColor);
1418     ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1419
1420     /*
1421      * CreateIconIndirect requires us to deselect the bitmaps from
1422      * the DCs before calling
1423      */
1424     SelectObject(hdcDst, hOldDstBitmap);
1425
1426     hIcon = CreateIconIndirect (&ii);
1427
1428     DeleteObject (ii.hbmMask);
1429     DeleteObject (ii.hbmColor);
1430     DeleteDC (hdcDst);
1431
1432     return hIcon;
1433 }
1434
1435
1436 /*************************************************************************
1437  * ImageList_GetIconSize [COMCTL32.@]
1438  *
1439  * Retrieves the size of an image in an image list.
1440  *
1441  * PARAMS
1442  *     himl [I] handle to image list
1443  *     cx   [O] pointer to the image width.
1444  *     cy   [O] pointer to the image height.
1445  *
1446  * RETURNS
1447  *     Success: TRUE
1448  *     Failure: FALSE
1449  *
1450  * NOTES
1451  *     All images in an image list have the same size.
1452  */
1453
1454 BOOL WINAPI
1455 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1456 {
1457     if (himl == NULL)
1458         return FALSE;
1459     if ((himl->cx <= 0) || (himl->cy <= 0))
1460         return FALSE;
1461
1462     if (cx)
1463         *cx = himl->cx;
1464     if (cy)
1465         *cy = himl->cy;
1466
1467     return TRUE;
1468 }
1469
1470
1471 /*************************************************************************
1472  * ImageList_GetImageCount [COMCTL32.@]
1473  *
1474  * Returns the number of images in an image list.
1475  *
1476  * PARAMS
1477  *     himl [I] handle to image list
1478  *
1479  * RETURNS
1480  *     Success: Number of images.
1481  *     Failure: 0
1482  */
1483
1484 INT WINAPI
1485 ImageList_GetImageCount (HIMAGELIST himl)
1486 {
1487     if (himl == NULL)
1488         return 0;
1489
1490     return himl->cCurImage;
1491 }
1492
1493
1494 /*************************************************************************
1495  * ImageList_GetImageInfo [COMCTL32.@]
1496  *
1497  * Returns information about an image in an image list.
1498  *
1499  * PARAMS
1500  *     himl       [I] handle to image list
1501  *     i          [I] image index
1502  *     pImageInfo [O] pointer to the image information
1503  *
1504  * RETURNS
1505  *     Success: TRUE
1506  *     Failure: FALSE
1507  */
1508
1509 BOOL WINAPI
1510 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1511 {
1512     if ((himl == NULL) || (pImageInfo == NULL))
1513         return FALSE;
1514     if ((i < 0) || (i >= himl->cCurImage))
1515         return FALSE;
1516
1517     pImageInfo->hbmImage = himl->hbmImage;
1518     pImageInfo->hbmMask  = himl->hbmMask;
1519
1520     pImageInfo->rcImage.top    = 0;
1521     pImageInfo->rcImage.bottom = himl->cy;
1522     pImageInfo->rcImage.left   = i * himl->cx;
1523     pImageInfo->rcImage.right  = (i+1) * himl->cx;
1524
1525     return TRUE;
1526 }
1527
1528
1529 /*************************************************************************
1530  * ImageList_GetImageRect [COMCTL32.@]
1531  *
1532  * Retrieves the rectangle of the specified image in an image list.
1533  *
1534  * PARAMS
1535  *     himl   [I] handle to image list
1536  *     i      [I] image index
1537  *     lpRect [O] pointer to the image rectangle
1538  *
1539  * RETURNS
1540  *    Success: TRUE
1541  *    Failure: FALSE
1542  *
1543  * NOTES
1544  *    This is an UNDOCUMENTED function!!!
1545  */
1546
1547 BOOL WINAPI
1548 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1549 {
1550     if ((himl == NULL) || (lpRect == NULL))
1551         return FALSE;
1552     if ((i < 0) || (i >= himl->cCurImage))
1553         return FALSE;
1554
1555     lpRect->left   = i * himl->cx;
1556     lpRect->top    = 0;
1557     lpRect->right  = lpRect->left + himl->cx;
1558     lpRect->bottom = himl->cy;
1559
1560     return TRUE;
1561 }
1562
1563
1564 /*************************************************************************
1565  * ImageList_LoadImage  [COMCTL32.@]
1566  * ImageList_LoadImageA [COMCTL32.@]
1567  *
1568  * Creates an image list from a bitmap, icon or cursor.
1569  *
1570  * PARAMS
1571  *     hi      [I] instance handle
1572  *     lpbmp   [I] name or id of the image
1573  *     cx      [I] width of each image
1574  *     cGrow   [I] number of images to expand
1575  *     clrMask [I] mask color
1576  *     uType   [I] type of image to load
1577  *     uFlags  [I] loading flags
1578  *
1579  * RETURNS
1580  *     Success: handle to the loaded image list
1581  *     Failure: NULL
1582  *
1583  * SEE
1584  *     LoadImage ()
1585  */
1586
1587 HIMAGELIST WINAPI
1588 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1589                         COLORREF clrMask, UINT uType, UINT uFlags)
1590 {
1591     HIMAGELIST himl = NULL;
1592     HANDLE   handle;
1593     INT      nImageCount;
1594
1595     handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1596     if (!handle) {
1597         ERR("Error loading image!\n");
1598         return NULL;
1599     }
1600
1601     if (uType == IMAGE_BITMAP) {
1602         BITMAP bmp;
1603         GetObjectA (handle, sizeof(BITMAP), &bmp);
1604
1605         /* To match windows behavior, if cx is set to zero and
1606          the flag DI_DEFAULTSIZE is specified, cx becomes the
1607          system metric value for icons. If the flag is not specified
1608          the function sets the size to the height of the bitmap */
1609         if (cx == 0)
1610         {
1611             if (uFlags & DI_DEFAULTSIZE)
1612                 cx = GetSystemMetrics (SM_CXICON);
1613             else
1614                 cx = bmp.bmHeight;
1615         }
1616
1617         nImageCount = bmp.bmWidth / cx;
1618
1619         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1620                                  nImageCount, cGrow);
1621         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1622     }
1623     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1624         ICONINFO ii;
1625         BITMAP bmp;
1626
1627         GetIconInfo (handle, &ii);
1628         GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1629         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1630                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1631         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1632         DeleteObject (ii.hbmColor);
1633         DeleteObject (ii.hbmMask);
1634     }
1635
1636     DeleteObject (handle);
1637
1638     return himl;
1639 }
1640
1641
1642 /*************************************************************************
1643  * ImageList_LoadImageW [COMCTL32.@]
1644  *
1645  * Creates an image list from a bitmap, icon or cursor.
1646  *
1647  * PARAMS
1648  *     hi      [I] instance handle
1649  *     lpbmp   [I] name or id of the image
1650  *     cx      [I] width of each image
1651  *     cGrow   [I] number of images to expand
1652  *     clrMask [I] mask color
1653  *     uType   [I] type of image to load
1654  *     uFlags  [I] loading flags
1655  *
1656  * RETURNS
1657  *     Success: handle to the loaded image list
1658  *     Failure: NULL
1659  *
1660  * SEE
1661  *     LoadImage ()
1662  */
1663
1664 HIMAGELIST WINAPI
1665 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1666                         COLORREF clrMask, UINT uType,   UINT uFlags)
1667 {
1668     HIMAGELIST himl = NULL;
1669     HANDLE   handle;
1670     INT      nImageCount;
1671
1672     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1673     if (!handle) {
1674         ERR("Error loading image!\n");
1675         return NULL;
1676     }
1677
1678     if (uType == IMAGE_BITMAP) {
1679         BITMAP bmp;
1680         GetObjectA (handle, sizeof(BITMAP), &bmp);
1681
1682         /* To match windows behavior, if cx is set to zero and
1683          the flag DI_DEFAULTSIZE is specified, cx becomes the
1684          system metric value for icons. If the flag is not specified
1685          the function sets the size to the height of the bitmap */
1686         if (cx == 0)
1687         {
1688             if (uFlags & DI_DEFAULTSIZE)
1689                 cx = GetSystemMetrics (SM_CXICON);
1690             else
1691                 cx = bmp.bmHeight;
1692         }
1693
1694         nImageCount = bmp.bmWidth / cx;
1695
1696         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1697                                  nImageCount, cGrow);
1698         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1699     }
1700     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1701         ICONINFO ii;
1702         BITMAP bmp;
1703
1704         GetIconInfo (handle, &ii);
1705         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1706         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1707                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1708         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1709         DeleteObject (ii.hbmColor);
1710         DeleteObject (ii.hbmMask);
1711     }
1712
1713     DeleteObject (handle);
1714
1715     return himl;
1716 }
1717
1718
1719 /*************************************************************************
1720  * ImageList_Merge [COMCTL32.@]
1721  *
1722  * Creates a new image list that contains a merged image from the specified
1723  * images of both source image lists.
1724  *
1725  * PARAMS
1726  *     himl1 [I] handle to first image list
1727  *     i1    [I] first image index
1728  *     himl2 [I] handle to second image list
1729  *     i2    [I] second image index
1730  *     dx    [I] X offset of the second image relative to the first.
1731  *     dy    [I] Y offset of the second image relative to the first.
1732  *
1733  * RETURNS
1734  *     Success: handle of the merged image list.
1735  *     Failure: NULL
1736  */
1737
1738 HIMAGELIST WINAPI
1739 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1740                  INT dx, INT dy)
1741 {
1742     HIMAGELIST himlDst = NULL;
1743     HDC      hdcSrcImage, hdcDstImage;
1744     INT      cxDst, cyDst;
1745     INT      xOff1, yOff1, xOff2, yOff2;
1746     INT      nX1, nX2;
1747
1748     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1749            i2, dx, dy);
1750
1751     if ((himl1 == NULL) || (himl2 == NULL))
1752         return NULL;
1753
1754     /* check indices */
1755     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1756         ERR("Index 1 out of range! %d\n", i1);
1757         return NULL;
1758     }
1759
1760     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1761         ERR("Index 2 out of range! %d\n", i2);
1762         return NULL;
1763     }
1764
1765     if (dx > 0) {
1766         cxDst = max (himl1->cx, dx + himl2->cx);
1767         xOff1 = 0;
1768         xOff2 = dx;
1769     }
1770     else if (dx < 0) {
1771         cxDst = max (himl2->cx, himl1->cx - dx);
1772         xOff1 = -dx;
1773         xOff2 = 0;
1774     }
1775     else {
1776         cxDst = max (himl1->cx, himl2->cx);
1777         xOff1 = 0;
1778         xOff2 = 0;
1779     }
1780
1781     if (dy > 0) {
1782         cyDst = max (himl1->cy, dy + himl2->cy);
1783         yOff1 = 0;
1784         yOff2 = dy;
1785     }
1786     else if (dy < 0) {
1787         cyDst = max (himl2->cy, himl1->cy - dy);
1788         yOff1 = -dy;
1789         yOff2 = 0;
1790     }
1791     else {
1792         cyDst = max (himl1->cy, himl2->cy);
1793         yOff1 = 0;
1794         yOff2 = 0;
1795     }
1796
1797     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1798
1799     if (himlDst) {
1800         hdcSrcImage = CreateCompatibleDC (0);
1801         hdcDstImage = CreateCompatibleDC (0);
1802         nX1 = i1 * himl1->cx;
1803         nX2 = i2 * himl2->cx;
1804
1805         /* copy image */
1806         SelectObject (hdcSrcImage, himl1->hbmImage);
1807         SelectObject (hdcDstImage, himlDst->hbmImage);
1808         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1809                   hdcSrcImage, 0, 0, BLACKNESS);
1810         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1811                   hdcSrcImage, nX1, 0, SRCCOPY);
1812
1813         SelectObject (hdcSrcImage, himl2->hbmMask);
1814         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1815                   hdcSrcImage, nX2, 0, SRCAND);
1816
1817         SelectObject (hdcSrcImage, himl2->hbmImage);
1818         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1819                   hdcSrcImage, nX2, 0, SRCPAINT);
1820
1821         /* copy mask */
1822         SelectObject (hdcSrcImage, himl1->hbmMask);
1823         SelectObject (hdcDstImage, himlDst->hbmMask);
1824         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1825                   hdcSrcImage, 0, 0, WHITENESS);
1826         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1827                   hdcSrcImage, nX1, 0, SRCCOPY);
1828
1829         SelectObject (hdcSrcImage, himl2->hbmMask);
1830         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1831                   hdcSrcImage, nX2, 0, SRCAND);
1832
1833         DeleteDC (hdcSrcImage);
1834         DeleteDC (hdcDstImage);
1835         himlDst->cCurImage = 1;
1836     }
1837
1838     return himlDst;
1839 }
1840
1841
1842 /* helper for _read_bitmap currently unused */
1843 #if 0
1844 static int may_use_dibsection(HDC hdc) {
1845     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1846     if (bitspixel>8)
1847         return TRUE;
1848     if (bitspixel<=4)
1849         return FALSE;
1850     return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1851 }
1852 #endif
1853
1854 /* helper for ImageList_Read, see comments below */
1855 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1856     HDC                 xdc = 0;
1857     BITMAPFILEHEADER    bmfh;
1858     BITMAPINFOHEADER    bmih;
1859     int                 bitsperpixel,palspace,longsperline,width,height;
1860     LPBITMAPINFOHEADER  bmihc = NULL;
1861     int                 result = 0;
1862     HBITMAP             hbitmap = 0;
1863     LPBYTE              bits = NULL,nbits = NULL;
1864     int                 nbytesperline,bytesperline;
1865
1866     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
1867         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
1868         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
1869         (bmih.biSize != sizeof(bmih))
1870     )
1871         return 0;
1872
1873     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1874     if (bitsperpixel<=8)
1875         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1876     else
1877         palspace = 0;
1878     width = bmih.biWidth;
1879     height = bmih.biHeight;
1880     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1881     memcpy(bmihc,&bmih,sizeof(bmih));
1882     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
1883     bmihc->biSizeImage  = (longsperline*height)<<2;
1884
1885     /* read the palette right after the end of the bitmapinfoheader */
1886     if (palspace)
1887         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1888             goto ret1;
1889
1890     xdc = GetDC(0);
1891 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1892     if ((bitsperpixel>1) &&
1893         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1894      ) {
1895         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1896         if (!hbitmap)
1897             goto ret1;
1898         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1899             goto ret1;
1900         result = 1;
1901     } else
1902 #endif
1903     {
1904         int i,nwidth,nheight;
1905
1906         nwidth  = width*(height/cy);
1907         nheight = cy;
1908
1909         if (bitsperpixel==1)
1910             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1911         else
1912             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1913
1914         /* Might be a bit excessive memory use here */
1915         bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1916         nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1917         if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1918                 goto ret1;
1919
1920         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1921         /* Do not forget that windows bitmaps are bottom->top */
1922         bytesperline    = longsperline*4;
1923         nbytesperline   = (height/cy)*bytesperline;
1924         for (i=0;i<height;i++) {
1925             memcpy(
1926                 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1927                 bits+bytesperline*(height-1-i),
1928                 bytesperline
1929             );
1930         }
1931         bmihc->biWidth  = nwidth;
1932         bmihc->biHeight = nheight;
1933         if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1934                 goto ret1;
1935         LocalFree((HLOCAL)nbits);
1936         LocalFree((HLOCAL)bits);
1937         result = 1;
1938     }
1939 ret1:
1940     if (xdc)    ReleaseDC(0,xdc);
1941     if (bmihc)  LocalFree((HLOCAL)bmihc);
1942     if (!result) {
1943         if (hbitmap) {
1944             DeleteObject(hbitmap);
1945             hbitmap = 0;
1946         }
1947     }
1948     return hbitmap;
1949 }
1950
1951 /*************************************************************************
1952  * ImageList_Read [COMCTL32.@]
1953  *
1954  * Reads an image list from a stream.
1955  *
1956  * PARAMS
1957  *     pstm [I] pointer to a stream
1958  *
1959  * RETURNS
1960  *     Success: handle to image list
1961  *     Failure: NULL
1962  *
1963  * The format is like this:
1964  *      ILHEAD                  ilheadstruct;
1965  *
1966  * for the color image part:
1967  *      BITMAPFILEHEADER        bmfh;
1968  *      BITMAPINFOHEADER        bmih;
1969  * only if it has a palette:
1970  *      RGBQUAD         rgbs[nr_of_paletted_colors];
1971  *
1972  *      BYTE                    colorbits[imagesize];
1973  *
1974  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1975  *      BITMAPFILEHEADER        bmfh_mask;
1976  *      BITMAPINFOHEADER        bmih_mask;
1977  * only if it has a palette (it usually does not):
1978  *      RGBQUAD         rgbs[nr_of_paletted_colors];
1979  *
1980  *      BYTE                    maskbits[imagesize];
1981  *
1982  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1983  *         _read_bitmap needs to convert them.
1984  */
1985 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1986 {
1987     ILHEAD      ilHead;
1988     HIMAGELIST  himl;
1989     HBITMAP     hbmColor=0,hbmMask=0;
1990     int         i;
1991
1992     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1993         return NULL;
1994     if (ilHead.usMagic != (('L' << 8) | 'I'))
1995         return NULL;
1996     if (ilHead.usVersion != 0x101) /* probably version? */
1997         return NULL;
1998
1999 #if 0
2000     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
2001     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2002     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
2003     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2004     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2005     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2006     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2007     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2008     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2009     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2010 #endif
2011
2012     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2013     if (!hbmColor)
2014         return NULL;
2015     if (ilHead.flags & ILC_MASK) {
2016         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2017         if (!hbmMask) {
2018             DeleteObject(hbmColor);
2019             return NULL;
2020         }
2021     }
2022
2023     himl = ImageList_Create (
2024                     ilHead.cx,
2025                     ilHead.cy,
2026                     ilHead.flags,
2027                     1,          /* initial */
2028                     ilHead.cGrow
2029     );
2030     if (!himl) {
2031         DeleteObject(hbmColor);
2032         DeleteObject(hbmMask);
2033         return NULL;
2034     }
2035     himl->hbmImage = hbmColor;
2036     himl->hbmMask = hbmMask;
2037     himl->cCurImage = ilHead.cCurImage;
2038     himl->cMaxImage = ilHead.cMaxImage;
2039
2040     ImageList_SetBkColor(himl,ilHead.bkcolor);
2041     for (i=0;i<4;i++)
2042         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2043     return himl;
2044 }
2045
2046
2047 /*************************************************************************
2048  * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2049  *
2050  * PARAMS
2051  *     himl [I] image list handle
2052  *     i    [I] image index
2053  *
2054  * RETURNS
2055  *     Success: TRUE
2056  *     Failure: FALSE
2057  */
2058
2059 BOOL WINAPI
2060 ImageList_Remove (HIMAGELIST himl, INT i)
2061 {
2062     HBITMAP hbmNewImage, hbmNewMask;
2063     HDC     hdcSrc, hdcDst;
2064     INT     cxNew, nCount;
2065
2066     TRACE("(himl=%p i=%d)\n", himl, i);
2067
2068     if (himl == NULL) {
2069         ERR("Invalid image list handle!\n");
2070         return FALSE;
2071     }
2072
2073     if ((i < -1) || (i >= himl->cCurImage)) {
2074         ERR("index out of range! %d\n", i);
2075         return FALSE;
2076     }
2077
2078     if (i == -1) {
2079         /* remove all */
2080         if (himl->cCurImage == 0) {
2081             /* remove all on empty ImageList is allowed */
2082             TRACE("remove all on empty ImageList!\n");
2083             return TRUE;
2084         }
2085
2086         himl->cMaxImage = himl->cInitial + himl->cGrow;
2087         himl->cCurImage = 0;
2088         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2089              himl->nOvlIdx[nCount] = -1;
2090
2091         DeleteObject (himl->hbmImage);
2092         himl->hbmImage =
2093             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2094                             1, himl->uBitsPixel, NULL);
2095
2096         if (himl->hbmMask) {
2097             DeleteObject (himl->hbmMask);
2098             himl->hbmMask =
2099                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2100                                 1, 1, NULL);
2101         }
2102     }
2103     else {
2104         /* delete one image */
2105         TRACE("Remove single image! %d\n", i);
2106
2107         /* create new bitmap(s) */
2108         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2109
2110         TRACE(" - Number of images: %d / %d (Old/New)\n",
2111                  himl->cCurImage, himl->cCurImage - 1);
2112         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2113                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2114
2115         hbmNewImage =
2116             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2117
2118         if (himl->hbmMask)
2119             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2120         else
2121             hbmNewMask = 0;  /* Just to keep compiler happy! */
2122
2123         hdcSrc = CreateCompatibleDC (0);
2124         hdcDst = CreateCompatibleDC (0);
2125
2126         /* copy all images and masks prior to the "removed" image */
2127         if (i > 0) {
2128             TRACE("Pre image copy: Copy %d images\n", i);
2129
2130             SelectObject (hdcSrc, himl->hbmImage);
2131             SelectObject (hdcDst, hbmNewImage);
2132             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2133                       hdcSrc, 0, 0, SRCCOPY);
2134
2135             if (himl->hbmMask) {
2136                 SelectObject (hdcSrc, himl->hbmMask);
2137                 SelectObject (hdcDst, hbmNewMask);
2138                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2139                           hdcSrc, 0, 0, SRCCOPY);
2140             }
2141         }
2142
2143         /* copy all images and masks behind the removed image */
2144         if (i < himl->cCurImage - 1) {
2145             TRACE("Post image copy!\n");
2146             SelectObject (hdcSrc, himl->hbmImage);
2147             SelectObject (hdcDst, hbmNewImage);
2148             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2149                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2150
2151             if (himl->hbmMask) {
2152                 SelectObject (hdcSrc, himl->hbmMask);
2153                 SelectObject (hdcDst, hbmNewMask);
2154                 BitBlt (hdcDst, i * himl->cx, 0,
2155                           (himl->cCurImage - i - 1) * himl->cx,
2156                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2157             }
2158         }
2159
2160         DeleteDC (hdcSrc);
2161         DeleteDC (hdcDst);
2162
2163         /* delete old images and insert new ones */
2164         DeleteObject (himl->hbmImage);
2165         himl->hbmImage = hbmNewImage;
2166         if (himl->hbmMask) {
2167             DeleteObject (himl->hbmMask);
2168             himl->hbmMask = hbmNewMask;
2169         }
2170
2171         himl->cCurImage--;
2172         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2173     }
2174
2175     return TRUE;
2176 }
2177
2178
2179 /*************************************************************************
2180  * ImageList_Replace [COMCTL32.@]
2181  *
2182  * Replaces an image in an image list with a new image.
2183  *
2184  * PARAMS
2185  *     himl     [I] handle to image list
2186  *     i        [I] image index
2187  *     hbmImage [I] handle to image bitmap
2188  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2189  *
2190  * RETURNS
2191  *     Success: TRUE
2192  *     Failure: FALSE
2193  */
2194
2195 BOOL WINAPI
2196 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2197                    HBITMAP hbmMask)
2198 {
2199     HDC hdcImageList, hdcImage;
2200     BITMAP bmp;
2201
2202     TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2203
2204     if (himl == NULL) {
2205         ERR("Invalid image list handle!\n");
2206         return FALSE;
2207     }
2208
2209     if ((i >= himl->cMaxImage) || (i < 0)) {
2210         ERR("Invalid image index!\n");
2211         return FALSE;
2212     }
2213
2214     hdcImageList = CreateCompatibleDC (0);
2215     hdcImage = CreateCompatibleDC (0);
2216     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2217
2218     /* Replace Image */
2219     SelectObject (hdcImageList, himl->hbmImage);
2220     SelectObject (hdcImage, hbmImage);
2221
2222     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2223                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2224
2225     if (himl->hbmMask)
2226     {
2227         /* Replace Mask */
2228         SelectObject (hdcImageList, himl->hbmMask);
2229         SelectObject (hdcImage, hbmMask);
2230
2231         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2232                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2233
2234
2235         /* Remove the background from the image
2236         */
2237         SelectObject (hdcImageList, himl->hbmImage);
2238         StretchBlt (hdcImageList,
2239             i*himl->cx, 0, himl->cx, himl->cy,
2240             hdcImage,
2241             0, 0, bmp.bmWidth, bmp.bmHeight,
2242             0x220326); /* NOTSRCAND */
2243     }
2244
2245     DeleteDC (hdcImage);
2246     DeleteDC (hdcImageList);
2247
2248     return TRUE;
2249 }
2250
2251
2252 /*************************************************************************
2253  * ImageList_ReplaceIcon [COMCTL32.@]
2254  *
2255  * Replaces an image in an image list using an icon.
2256  *
2257  * PARAMS
2258  *     himl  [I] handle to image list
2259  *     i     [I] image index
2260  *     hIcon [I] handle to icon
2261  *
2262  * RETURNS
2263  *     Success: index of the replaced image
2264  *     Failure: -1
2265  */
2266
2267 INT WINAPI
2268 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2269 {
2270     HDC     hdcImageList, hdcImage;
2271     INT     nIndex;
2272     HICON   hBestFitIcon;
2273     HBITMAP hbmOldSrc, hbmOldDst;
2274     ICONINFO  ii;
2275     BITMAP  bmp;
2276
2277     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2278
2279     if (himl == NULL)
2280         return -1;
2281     if ((i >= himl->cMaxImage) || (i < -1))
2282         return -1;
2283
2284     hBestFitIcon = CopyImage(
2285         hIcon, IMAGE_ICON,
2286         himl->cx, himl->cy,
2287         LR_COPYFROMRESOURCE);
2288
2289     GetIconInfo (hBestFitIcon, &ii);
2290     if (ii.hbmMask == 0)
2291         ERR("no mask!\n");
2292     if (ii.hbmColor == 0)
2293         ERR("no color!\n");
2294     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2295
2296     if (i == -1) {
2297         if (himl->cCurImage + 1 > himl->cMaxImage)
2298             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2299
2300         nIndex = himl->cCurImage;
2301         himl->cCurImage++;
2302     }
2303     else
2304         nIndex = i;
2305
2306     hdcImageList = CreateCompatibleDC (0);
2307     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2308     if (hdcImageList == 0)
2309         ERR("invalid hdcImageList!\n");
2310
2311     hdcImage = CreateCompatibleDC (0);
2312     TRACE("hdcImage=0x%x!\n", hdcImage);
2313     if (hdcImage == 0)
2314         ERR("invalid hdcImage!\n");
2315
2316     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2317     SetTextColor( hdcImageList, RGB(0,0,0));
2318     SetBkColor( hdcImageList, RGB(255,255,255));
2319     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2320     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2321                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2322
2323     if (himl->hbmMask) {
2324         SelectObject (hdcImageList, himl->hbmMask);
2325         SelectObject (hdcImage, ii.hbmMask);
2326         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2327                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2328     }
2329
2330     SelectObject (hdcImage, hbmOldSrc);
2331     SelectObject (hdcImageList, hbmOldDst);
2332
2333     if(hBestFitIcon)
2334         DestroyIcon(hBestFitIcon);
2335     if (hdcImageList)
2336         DeleteDC (hdcImageList);
2337     if (hdcImage)
2338         DeleteDC (hdcImage);
2339     if (ii.hbmColor)
2340         DeleteObject (ii.hbmColor);
2341     if (ii.hbmMask)
2342         DeleteObject (ii.hbmMask);
2343
2344     return nIndex;
2345 }
2346
2347
2348 /*************************************************************************
2349  * ImageList_SetBkColor [COMCTL32.@]
2350  *
2351  * Sets the background color of an image list.
2352  *
2353  * PARAMS
2354  *     himl  [I] handle to image list
2355  *     clrBk [I] background color
2356  *
2357  * RETURNS
2358  *     Success: previous background color
2359  *     Failure: CLR_NONE
2360  */
2361
2362 COLORREF WINAPI
2363 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2364 {
2365     COLORREF clrOldBk;
2366
2367     if (himl == NULL)
2368         return CLR_NONE;
2369
2370     clrOldBk = himl->clrBk;
2371     himl->clrBk = clrBk;
2372     return clrOldBk;
2373 }
2374
2375
2376 /*************************************************************************
2377  * ImageList_SetDragCursorImage [COMCTL32.@]
2378  *
2379  * Combines the specified image with the current drag image
2380  *
2381  * PARAMS
2382  *     himlDrag  [I] handle to drag image list
2383  *     iDrag     [I] drag image index
2384  *     dxHotspot [I] X position of the hot spot
2385  *     dyHotspot [I] Y position of the hot spot
2386  *
2387  * RETURNS
2388  *     Success: TRUE
2389  *     Failure: FALSE
2390  *
2391  * NOTES
2392  *     When this function is called and the drag image is visible, a
2393  *     short flickering occurs but this matches the Win9x behavior. It is
2394  *     possible to fix the flickering using code like in ImageList_DragMove.
2395  */
2396
2397 BOOL WINAPI
2398 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2399                               INT dxHotspot, INT dyHotspot)
2400 {
2401     HIMAGELIST himlTemp;
2402     INT dx, dy;
2403     BOOL visible;
2404
2405     if (InternalDrag.himl == NULL)
2406         return FALSE;
2407
2408     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2409            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2410
2411     visible = InternalDrag.bShow;
2412
2413     /* Calculate the offset between the origin of the old image and the
2414      * origin of the second image.
2415      * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2416      * hotspot) to the origin of the second image.
2417      * See M$DN for details */
2418     if(InternalDrag.bHSPending) {
2419         dx = 0;
2420         dy = 0;
2421         InternalDrag.bHSPending = FALSE;
2422     } else {
2423         dx = InternalDrag.dxHotspot - dxHotspot;
2424         dy = InternalDrag.dyHotspot - dyHotspot;
2425     }
2426     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2427
2428     if (visible) {
2429         /* hide the drag image */
2430         ImageList_DragShowNolock(FALSE);
2431     }
2432     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2433            (InternalDrag.himl->cy != himlTemp->cy)) {
2434         /* the size of the drag image changed, invalidate the buffer */
2435         DeleteObject(InternalDrag.hbmBg);
2436         InternalDrag.hbmBg = 0;
2437     }
2438
2439     ImageList_Destroy (InternalDrag.himl);
2440     InternalDrag.himl = himlTemp;
2441
2442     /* update the InternalDragOffset, if the origin of the
2443      * DragImage was changed by ImageList_Merge. */
2444     if (dx <= 0)
2445         InternalDrag.dxHotspot = dxHotspot;
2446     if (dy <= 0)
2447         InternalDrag.dyHotspot = dyHotspot;
2448
2449     if (visible) {
2450         /* show the drag image */
2451         ImageList_DragShowNolock(TRUE);
2452     }
2453
2454     return TRUE;
2455 }
2456
2457
2458 /*************************************************************************
2459  * ImageList_SetFilter [COMCTL32.@]
2460  *
2461  * Sets a filter (or does something completely different)!!???
2462  * It removes 12 Bytes from the stack (3 Parameters).
2463  *
2464  * PARAMS
2465  *     himl     [I] SHOULD be a handle to image list
2466  *     i        [I] COULD be an index?
2467  *     dwFilter [I] ???
2468  *
2469  * RETURNS
2470  *     Success: TRUE ???
2471  *     Failure: FALSE ???
2472  *
2473  * BUGS
2474  *     This is an UNDOCUMENTED function!!!!
2475  *     empty stub.
2476  */
2477
2478 BOOL WINAPI
2479 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2480 {
2481     FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2482
2483     return FALSE;
2484 }
2485
2486
2487 /*************************************************************************
2488  * ImageList_SetFlags [COMCTL32.@]
2489  *
2490  * BUGS
2491  *    Stub.
2492  */
2493
2494 DWORD WINAPI
2495 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2496 {
2497     FIXME("(%p %08lx):empty stub\n", himl, flags);
2498     return 0;
2499 }
2500
2501
2502 /*************************************************************************
2503  * ImageList_SetIconSize [COMCTL32.@]
2504  *
2505  * Sets the image size of the bitmap and deletes all images.
2506  *
2507  * PARAMS
2508  *     himl [I] handle to image list
2509  *     cx   [I] image width
2510  *     cy   [I] image height
2511  *
2512  * RETURNS
2513  *     Success: TRUE
2514  *     Failure: FALSE
2515  */
2516
2517 BOOL WINAPI
2518 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2519 {
2520     INT nCount;
2521
2522     if (!himl)
2523         return FALSE;
2524
2525     /* remove all images */
2526     himl->cMaxImage = himl->cInitial + himl->cGrow;
2527     himl->cCurImage = 0;
2528     himl->cx        = cx;
2529     himl->cy        = cy;
2530
2531     /* initialize overlay mask indices */
2532     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2533         himl->nOvlIdx[nCount] = -1;
2534
2535     DeleteObject (himl->hbmImage);
2536     himl->hbmImage =
2537         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2538                         1, himl->uBitsPixel, NULL);
2539
2540     if (himl->hbmMask) {
2541         DeleteObject (himl->hbmMask);
2542         himl->hbmMask =
2543             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2544                             1, 1, NULL);
2545     }
2546
2547     return TRUE;
2548 }
2549
2550
2551 /*************************************************************************
2552  * ImageList_SetImageCount [COMCTL32.@]
2553  *
2554  * Resizes an image list to the specified number of images.
2555  *
2556  * PARAMS
2557  *     himl        [I] handle to image list
2558  *     iImageCount [I] number of images in the image list
2559  *
2560  * RETURNS
2561  *     Success: TRUE
2562  *     Failure: FALSE
2563  */
2564
2565 BOOL WINAPI
2566 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2567 {
2568     HDC     hdcImageList, hdcBitmap;
2569     HBITMAP hbmNewBitmap;
2570     INT     nNewCount, nCopyCount;
2571
2572     TRACE("%p %d\n",himl,iImageCount);
2573
2574     if (!himl)
2575         return FALSE;
2576     if (himl->cCurImage >= iImageCount)
2577         return FALSE;
2578     if (himl->cMaxImage > iImageCount)
2579     {
2580         himl->cCurImage = iImageCount;
2581         return TRUE;
2582     }
2583
2584     nNewCount = iImageCount + himl->cGrow;
2585     nCopyCount = min(himl->cCurImage, iImageCount);
2586
2587     hdcImageList = CreateCompatibleDC (0);
2588     hdcBitmap = CreateCompatibleDC (0);
2589
2590     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2591                                    1, himl->uBitsPixel, NULL);
2592     if (hbmNewBitmap != 0)
2593     {
2594         SelectObject (hdcImageList, himl->hbmImage);
2595         SelectObject (hdcBitmap, hbmNewBitmap);
2596
2597         /* copy images */
2598         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2599                   hdcImageList, 0, 0, SRCCOPY);
2600 #if 0
2601         /* delete 'empty' image space */
2602         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2603         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2604         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2605                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2606 #endif
2607         DeleteObject (himl->hbmImage);
2608         himl->hbmImage = hbmNewBitmap;
2609     }
2610     else
2611         ERR("Could not create new image bitmap !\n");
2612
2613     if (himl->hbmMask)
2614     {
2615         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2616                                        1, 1, NULL);
2617         if (hbmNewBitmap != 0)
2618         {
2619             SelectObject (hdcImageList, himl->hbmMask);
2620             SelectObject (hdcBitmap, hbmNewBitmap);
2621
2622             /* copy images */
2623             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2624                       hdcImageList, 0, 0, SRCCOPY);
2625 #if 0
2626             /* delete 'empty' image space */
2627             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2628             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2629             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2630                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2631 #endif
2632             DeleteObject (himl->hbmMask);
2633             himl->hbmMask = hbmNewBitmap;
2634         }
2635         else
2636             ERR("Could not create new mask bitmap!\n");
2637     }
2638
2639     DeleteDC (hdcImageList);
2640     DeleteDC (hdcBitmap);
2641
2642     /* Update max image count and current image count */
2643     himl->cMaxImage = nNewCount;
2644     himl->cCurImage = iImageCount;
2645
2646     return TRUE;
2647 }
2648
2649
2650 /*************************************************************************
2651  * ImageList_SetOverlayImage [COMCTL32.@]
2652  *
2653  * Assigns an overlay mask index to an existing image in an image list.
2654  *
2655  * PARAMS
2656  *     himl     [I] handle to image list
2657  *     iImage   [I] image index
2658  *     iOverlay [I] overlay mask index
2659  *
2660  * RETURNS
2661  *     Success: TRUE
2662  *     Failure: FALSE
2663  */
2664
2665 BOOL WINAPI
2666 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2667 {
2668     if (!himl)
2669         return FALSE;
2670     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2671         return FALSE;
2672     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2673         return FALSE;
2674     himl->nOvlIdx[iOverlay - 1] = iImage;
2675     return TRUE;
2676 }
2677
2678
2679
2680 /* helper for ImageList_Write - write bitmap to pstm
2681  * currently everything is written as 24 bit RGB, except masks
2682  */
2683 static BOOL
2684 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2685 {
2686     LPBITMAPFILEHEADER bmfh;
2687     LPBITMAPINFOHEADER bmih;
2688     LPBYTE data, lpBits, lpBitsOrg;
2689     BITMAP bm;
2690     INT bitCount, sizeImage, offBits, totalSize;
2691     INT nwidth, nheight, nsizeImage, icount;
2692     HDC xdc;
2693     BOOL result = FALSE;
2694
2695
2696     xdc = GetDC(0);
2697     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2698
2699     /* XXX is this always correct? */
2700     icount = bm.bmWidth / cx;
2701     nwidth = cx << 2;
2702     nheight = cy * ((icount+3)>>2);
2703
2704     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2705     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2706     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2707
2708     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2709     if(bitCount != 24)
2710         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2711     offBits = totalSize;
2712     totalSize += nsizeImage;
2713
2714     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2715     bmfh = (LPBITMAPFILEHEADER)data;
2716     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2717     lpBits = data + offBits;
2718
2719     /* setup BITMAPFILEHEADER */
2720     bmfh->bfType      = (('M' << 8) | 'B');
2721     bmfh->bfSize      = 0;
2722     bmfh->bfReserved1 = 0;
2723     bmfh->bfReserved2 = 0;
2724     bmfh->bfOffBits   = offBits;
2725
2726     /* setup BITMAPINFOHEADER */
2727     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2728     bmih->biWidth         = bm.bmWidth;
2729     bmih->biHeight        = bm.bmHeight;
2730     bmih->biPlanes        = 1;
2731     bmih->biBitCount      = bitCount;
2732     bmih->biCompression   = BI_RGB;
2733     bmih->biSizeImage     = nsizeImage;
2734     bmih->biXPelsPerMeter = 0;
2735     bmih->biYPelsPerMeter = 0;
2736     bmih->biClrUsed       = 0;
2737     bmih->biClrImportant  = 0;
2738
2739     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2740     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2741                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2742         goto failed;
2743     else {
2744         int i;
2745         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2746         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2747
2748         for(i = 0; i < nheight; i++) {
2749             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2750             int noff = (nbpl * (nheight-1-i));
2751             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2752         }
2753     }
2754
2755     bmih->biWidth  = nwidth;
2756     bmih->biHeight = nheight;
2757
2758     if(bitCount == 1) {
2759         /* Hack. */
2760         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2761         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2762         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2763     }
2764
2765     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2766         goto failed;
2767
2768     result = TRUE;
2769
2770     failed:
2771     ReleaseDC(0, xdc);
2772     LocalFree((HLOCAL)lpBitsOrg);
2773
2774     return result;
2775 }
2776
2777
2778 /*************************************************************************
2779  * ImageList_Write [COMCTL32.@]
2780  *
2781  * Writes an image list to a stream.
2782  *
2783  * PARAMS
2784  *     himl [I] handle to image list
2785  *     pstm [O] Pointer to a stream.
2786  *
2787  * RETURNS
2788  *     Success: TRUE
2789  *     Failure: FALSE
2790  *
2791  * BUGS
2792  *     probably.
2793  */
2794
2795 BOOL WINAPI
2796 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2797 {
2798     ILHEAD ilHead;
2799     int i;
2800
2801     if (!himl)
2802         return FALSE;
2803
2804     ilHead.usMagic   = (('L' << 8) | 'I');
2805     ilHead.usVersion = 0x101;
2806     ilHead.cCurImage = himl->cCurImage;
2807     ilHead.cMaxImage = himl->cMaxImage;
2808     ilHead.cGrow     = himl->cGrow;
2809     ilHead.cx        = himl->cx;
2810     ilHead.cy        = himl->cy;
2811     ilHead.bkcolor   = himl->clrBk;
2812     ilHead.flags     = himl->flags;
2813     for(i = 0; i < 4; i++) {
2814         ilHead.ovls[i] = himl->nOvlIdx[i];
2815     }
2816
2817     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2818         return FALSE;
2819
2820     /* write the bitmap */
2821     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2822         return FALSE;
2823
2824     /* write the mask if we have one */
2825     if(himl->flags & ILC_MASK) {
2826         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2827             return FALSE;
2828     }
2829
2830     return TRUE;
2831 }