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