Fixed a race condition on RPC worker thread creation, and a typo.
[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 believe 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         GetObjectW (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, hBitmapDC =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, hDIB = 0;
1904     LPBYTE             bits = NULL;
1905
1906     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
1907         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
1908         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
1909         (bmih.biSize != sizeof(bmih))
1910     )
1911         return 0;
1912
1913     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1914     if (bitsperpixel<=8)
1915         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1916     else
1917         palspace = 0;
1918     width = bmih.biWidth;
1919     height = bmih.biHeight;
1920     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1921     memcpy(bmihc,&bmih,sizeof(bmih));
1922     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
1923     bmihc->biSizeImage  = (longsperline*height)<<2;
1924
1925     /* read the palette right after the end of the bitmapinfoheader */
1926     if (palspace)
1927         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1928             goto ret1;
1929
1930     xdc = GetDC(0);
1931 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1932     if ((bitsperpixel>1) &&
1933         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1934      ) {
1935         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1936         if (!hbitmap)
1937             goto ret1;
1938         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1939             goto ret1;
1940         result = 1;
1941     } else
1942 #endif
1943     {
1944        int i,nwidth,nheight,nRows;
1945
1946         nwidth  = width*(height/cy);
1947         nheight = cy;
1948         nRows   = (height/cy);
1949
1950         if (bitsperpixel==1)
1951             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1952         else
1953             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1954
1955        hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1956        if (!hDIB)
1957            goto ret1;
1958        if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1959            goto ret1;
1960
1961         hBitmapDC = CreateCompatibleDC(0);
1962         SelectObject(hBitmapDC, hbitmap);
1963
1964         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1965         /* Do not forget that windows bitmaps are bottom->top */
1966         TRACE("nRows=%d\n", nRows);
1967         for (i=0; i < nRows; i++){
1968             StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1969                 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1970         }
1971         
1972         result = 1;
1973     }
1974 ret1:
1975     if (xdc)    ReleaseDC(0,xdc);
1976     if (bmihc)  LocalFree((HLOCAL)bmihc);
1977     if (hDIB)   DeleteObject(hDIB);
1978     if (hBitmapDC)   DeleteDC(hBitmapDC);
1979     if (!result) {
1980         if (hbitmap) {
1981             DeleteObject(hbitmap);
1982             hbitmap = 0;
1983         }
1984     }
1985     return hbitmap;
1986 }
1987
1988 /*************************************************************************
1989  * ImageList_Read [COMCTL32.@]
1990  *
1991  * Reads an image list from a stream.
1992  *
1993  * PARAMS
1994  *     pstm [I] pointer to a stream
1995  *
1996  * RETURNS
1997  *     Success: handle to image list
1998  *     Failure: NULL
1999  *
2000  * The format is like this:
2001  *      ILHEAD                  ilheadstruct;
2002  *
2003  * for the color image part:
2004  *      BITMAPFILEHEADER        bmfh;
2005  *      BITMAPINFOHEADER        bmih;
2006  * only if it has a palette:
2007  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2008  *
2009  *      BYTE                    colorbits[imagesize];
2010  *
2011  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2012  *      BITMAPFILEHEADER        bmfh_mask;
2013  *      BITMAPINFOHEADER        bmih_mask;
2014  * only if it has a palette (it usually does not):
2015  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2016  *
2017  *      BYTE                    maskbits[imagesize];
2018  *
2019  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2020  *         _read_bitmap needs to convert them.
2021  */
2022 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2023 {
2024     ILHEAD      ilHead;
2025     HIMAGELIST  himl;
2026     HBITMAP     hbmColor=0,hbmMask=0;
2027     int         i;
2028
2029     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2030         return NULL;
2031     if (ilHead.usMagic != (('L' << 8) | 'I'))
2032         return NULL;
2033     if (ilHead.usVersion != 0x101) /* probably version? */
2034         return NULL;
2035
2036 #if 0
2037     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
2038     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2039     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
2040     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2041     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2042     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2043     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2044     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2045     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2046     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2047 #endif
2048
2049     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2050     if (!hbmColor)
2051         return NULL;
2052     if (ilHead.flags & ILC_MASK) {
2053         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2054         if (!hbmMask) {
2055             DeleteObject(hbmColor);
2056             return NULL;
2057         }
2058     }
2059
2060     himl = ImageList_Create (
2061                     ilHead.cx,
2062                     ilHead.cy,
2063                     ilHead.flags,
2064                     1,          /* initial */
2065                     ilHead.cGrow
2066     );
2067     if (!himl) {
2068         DeleteObject(hbmColor);
2069         DeleteObject(hbmMask);
2070         return NULL;
2071     }
2072     himl->hbmImage = hbmColor;
2073     himl->hbmMask = hbmMask;
2074     himl->cCurImage = ilHead.cCurImage;
2075     himl->cMaxImage = ilHead.cMaxImage;
2076
2077     ImageList_SetBkColor(himl,ilHead.bkcolor);
2078     for (i=0;i<4;i++)
2079         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2080     return himl;
2081 }
2082
2083
2084 /*************************************************************************
2085  * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2086  *
2087  * PARAMS
2088  *     himl [I] image list handle
2089  *     i    [I] image index
2090  *
2091  * RETURNS
2092  *     Success: TRUE
2093  *     Failure: FALSE
2094  */
2095
2096 BOOL WINAPI
2097 ImageList_Remove (HIMAGELIST himl, INT i)
2098 {
2099     HBITMAP hbmNewImage, hbmNewMask;
2100     HDC     hdcSrc, hdcDst;
2101     INT     cxNew, nCount;
2102
2103     TRACE("(himl=%p i=%d)\n", himl, i);
2104
2105     if (!is_valid(himl)) {
2106         ERR("Invalid image list handle!\n");
2107         return FALSE;
2108     }
2109
2110     if ((i < -1) || (i >= himl->cCurImage)) {
2111         ERR("index out of range! %d\n", i);
2112         return FALSE;
2113     }
2114
2115     if (i == -1) {
2116         /* remove all */
2117         if (himl->cCurImage == 0) {
2118             /* remove all on empty ImageList is allowed */
2119             TRACE("remove all on empty ImageList!\n");
2120             return TRUE;
2121         }
2122
2123         himl->cMaxImage = himl->cInitial + himl->cGrow;
2124         himl->cCurImage = 0;
2125         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2126              himl->nOvlIdx[nCount] = -1;
2127
2128         DeleteObject (himl->hbmImage);
2129         himl->hbmImage =
2130             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2131                             1, himl->uBitsPixel, NULL);
2132
2133         if (himl->hbmMask) {
2134             DeleteObject (himl->hbmMask);
2135             himl->hbmMask =
2136                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2137                                 1, 1, NULL);
2138         }
2139     }
2140     else {
2141         /* delete one image */
2142         TRACE("Remove single image! %d\n", i);
2143
2144         /* create new bitmap(s) */
2145         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2146
2147         TRACE(" - Number of images: %d / %d (Old/New)\n",
2148                  himl->cCurImage, himl->cCurImage - 1);
2149         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2150                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2151
2152         hbmNewImage =
2153             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2154
2155         if (himl->hbmMask)
2156             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2157         else
2158             hbmNewMask = 0;  /* Just to keep compiler happy! */
2159
2160         hdcSrc = CreateCompatibleDC (0);
2161         hdcDst = CreateCompatibleDC (0);
2162
2163         /* copy all images and masks prior to the "removed" image */
2164         if (i > 0) {
2165             TRACE("Pre image copy: Copy %d images\n", i);
2166
2167             SelectObject (hdcSrc, himl->hbmImage);
2168             SelectObject (hdcDst, hbmNewImage);
2169             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2170                       hdcSrc, 0, 0, SRCCOPY);
2171
2172             if (himl->hbmMask) {
2173                 SelectObject (hdcSrc, himl->hbmMask);
2174                 SelectObject (hdcDst, hbmNewMask);
2175                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2176                           hdcSrc, 0, 0, SRCCOPY);
2177             }
2178         }
2179
2180         /* copy all images and masks behind the removed image */
2181         if (i < himl->cCurImage - 1) {
2182             TRACE("Post image copy!\n");
2183             SelectObject (hdcSrc, himl->hbmImage);
2184             SelectObject (hdcDst, hbmNewImage);
2185             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2186                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2187
2188             if (himl->hbmMask) {
2189                 SelectObject (hdcSrc, himl->hbmMask);
2190                 SelectObject (hdcDst, hbmNewMask);
2191                 BitBlt (hdcDst, i * himl->cx, 0,
2192                           (himl->cCurImage - i - 1) * himl->cx,
2193                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2194             }
2195         }
2196
2197         DeleteDC (hdcSrc);
2198         DeleteDC (hdcDst);
2199
2200         /* delete old images and insert new ones */
2201         DeleteObject (himl->hbmImage);
2202         himl->hbmImage = hbmNewImage;
2203         if (himl->hbmMask) {
2204             DeleteObject (himl->hbmMask);
2205             himl->hbmMask = hbmNewMask;
2206         }
2207
2208         himl->cCurImage--;
2209         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2210     }
2211
2212     return TRUE;
2213 }
2214
2215
2216 /*************************************************************************
2217  * ImageList_Replace [COMCTL32.@]
2218  *
2219  * Replaces an image in an image list with a new image.
2220  *
2221  * PARAMS
2222  *     himl     [I] handle to image list
2223  *     i        [I] image index
2224  *     hbmImage [I] handle to image bitmap
2225  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2226  *
2227  * RETURNS
2228  *     Success: TRUE
2229  *     Failure: FALSE
2230  */
2231
2232 BOOL WINAPI
2233 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2234                    HBITMAP hbmMask)
2235 {
2236     HDC hdcImageList, hdcImage;
2237     BITMAP bmp;
2238
2239     TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2240
2241     if (!is_valid(himl)) {
2242         ERR("Invalid image list handle!\n");
2243         return FALSE;
2244     }
2245
2246     if ((i >= himl->cMaxImage) || (i < 0)) {
2247         ERR("Invalid image index!\n");
2248         return FALSE;
2249     }
2250
2251     hdcImageList = CreateCompatibleDC (0);
2252     hdcImage = CreateCompatibleDC (0);
2253     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2254
2255     /* Replace Image */
2256     SelectObject (hdcImageList, himl->hbmImage);
2257     SelectObject (hdcImage, hbmImage);
2258
2259     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2260                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2261
2262     if (himl->hbmMask)
2263     {
2264         /* Replace Mask */
2265         SelectObject (hdcImageList, himl->hbmMask);
2266         SelectObject (hdcImage, hbmMask);
2267
2268         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2269                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2270
2271
2272         /* Remove the background from the image
2273         */
2274         SelectObject (hdcImageList, himl->hbmImage);
2275         StretchBlt (hdcImageList,
2276             i*himl->cx, 0, himl->cx, himl->cy,
2277             hdcImage,
2278             0, 0, bmp.bmWidth, bmp.bmHeight,
2279             0x220326); /* NOTSRCAND */
2280     }
2281
2282     DeleteDC (hdcImage);
2283     DeleteDC (hdcImageList);
2284
2285     return TRUE;
2286 }
2287
2288
2289 /*************************************************************************
2290  * ImageList_ReplaceIcon [COMCTL32.@]
2291  *
2292  * Replaces an image in an image list using an icon.
2293  *
2294  * PARAMS
2295  *     himl  [I] handle to image list
2296  *     i     [I] image index
2297  *     hIcon [I] handle to icon
2298  *
2299  * RETURNS
2300  *     Success: index of the replaced image
2301  *     Failure: -1
2302  */
2303
2304 INT WINAPI
2305 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2306 {
2307     HDC     hdcImageList, hdcImage;
2308     INT     nIndex;
2309     HICON   hBestFitIcon;
2310     HBITMAP hbmOldSrc, hbmOldDst;
2311     ICONINFO  ii;
2312     BITMAP  bmp;
2313
2314     TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2315
2316     if (!is_valid(himl))
2317         return -1;
2318     if ((i >= himl->cMaxImage) || (i < -1))
2319         return -1;
2320
2321     hBestFitIcon = CopyImage(
2322         hIcon, IMAGE_ICON,
2323         himl->cx, himl->cy,
2324         LR_COPYFROMRESOURCE);
2325
2326     GetIconInfo (hBestFitIcon, &ii);
2327     if (ii.hbmMask == 0)
2328         ERR("no mask!\n");
2329     if (ii.hbmColor == 0)
2330         ERR("no color!\n");
2331     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2332
2333     if (i == -1) {
2334         if (himl->cCurImage + 1 > himl->cMaxImage)
2335             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2336
2337         nIndex = himl->cCurImage;
2338         himl->cCurImage++;
2339     }
2340     else
2341         nIndex = i;
2342
2343     hdcImageList = CreateCompatibleDC (0);
2344     TRACE("hdcImageList=%p!\n", hdcImageList);
2345     if (hdcImageList == 0)
2346         ERR("invalid hdcImageList!\n");
2347
2348     hdcImage = CreateCompatibleDC (0);
2349     TRACE("hdcImage=%p!\n", hdcImage);
2350     if (hdcImage == 0)
2351         ERR("invalid hdcImage!\n");
2352
2353     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2354     SetTextColor( hdcImageList, RGB(0,0,0));
2355     SetBkColor( hdcImageList, RGB(255,255,255));
2356     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2357     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2358                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2359
2360     if (himl->hbmMask) {
2361         SelectObject (hdcImageList, himl->hbmMask);
2362         SelectObject (hdcImage, ii.hbmMask);
2363         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2364                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2365     }
2366
2367     SelectObject (hdcImage, hbmOldSrc);
2368     SelectObject (hdcImageList, hbmOldDst);
2369
2370     if(hBestFitIcon)
2371         DestroyIcon(hBestFitIcon);
2372     if (hdcImageList)
2373         DeleteDC (hdcImageList);
2374     if (hdcImage)
2375         DeleteDC (hdcImage);
2376     if (ii.hbmColor)
2377         DeleteObject (ii.hbmColor);
2378     if (ii.hbmMask)
2379         DeleteObject (ii.hbmMask);
2380
2381     return nIndex;
2382 }
2383
2384
2385 /*************************************************************************
2386  * ImageList_SetBkColor [COMCTL32.@]
2387  *
2388  * Sets the background color of an image list.
2389  *
2390  * PARAMS
2391  *     himl  [I] handle to image list
2392  *     clrBk [I] background color
2393  *
2394  * RETURNS
2395  *     Success: previous background color
2396  *     Failure: CLR_NONE
2397  */
2398
2399 COLORREF WINAPI
2400 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2401 {
2402     COLORREF clrOldBk;
2403
2404     if (!is_valid(himl))
2405         return CLR_NONE;
2406
2407     clrOldBk = himl->clrBk;
2408     himl->clrBk = clrBk;
2409     return clrOldBk;
2410 }
2411
2412
2413 /*************************************************************************
2414  * ImageList_SetDragCursorImage [COMCTL32.@]
2415  *
2416  * Combines the specified image with the current drag image
2417  *
2418  * PARAMS
2419  *     himlDrag  [I] handle to drag image list
2420  *     iDrag     [I] drag image index
2421  *     dxHotspot [I] X position of the hot spot
2422  *     dyHotspot [I] Y position of the hot spot
2423  *
2424  * RETURNS
2425  *     Success: TRUE
2426  *     Failure: FALSE
2427  *
2428  * NOTES
2429  *     When this function is called and the drag image is visible, a
2430  *     short flickering occurs but this matches the Win9x behavior. It is
2431  *     possible to fix the flickering using code like in ImageList_DragMove.
2432  */
2433
2434 BOOL WINAPI
2435 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2436                               INT dxHotspot, INT dyHotspot)
2437 {
2438     HIMAGELIST himlTemp;
2439     INT dx, dy;
2440     BOOL visible;
2441
2442     if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2443         return FALSE;
2444
2445     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2446            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2447
2448     visible = InternalDrag.bShow;
2449
2450     /* Calculate the offset between the origin of the old image and the
2451      * origin of the second image.
2452      * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2453      * hotspot) to the origin of the second image.
2454      * See M$DN for details */
2455     if(InternalDrag.bHSPending) {
2456         dx = 0;
2457         dy = 0;
2458         InternalDrag.bHSPending = FALSE;
2459     } else {
2460         dx = InternalDrag.dxHotspot - dxHotspot;
2461         dy = InternalDrag.dyHotspot - dyHotspot;
2462     }
2463     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2464
2465     if (visible) {
2466         /* hide the drag image */
2467         ImageList_DragShowNolock(FALSE);
2468     }
2469     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2470            (InternalDrag.himl->cy != himlTemp->cy)) {
2471         /* the size of the drag image changed, invalidate the buffer */
2472         DeleteObject(InternalDrag.hbmBg);
2473         InternalDrag.hbmBg = 0;
2474     }
2475
2476     ImageList_Destroy (InternalDrag.himl);
2477     InternalDrag.himl = himlTemp;
2478
2479     /* update the InternalDragOffset, if the origin of the
2480      * DragImage was changed by ImageList_Merge. */
2481     if (dx <= 0)
2482         InternalDrag.dxHotspot = dxHotspot;
2483     if (dy <= 0)
2484         InternalDrag.dyHotspot = dyHotspot;
2485
2486     if (visible) {
2487         /* show the drag image */
2488         ImageList_DragShowNolock(TRUE);
2489     }
2490
2491     return TRUE;
2492 }
2493
2494
2495 /*************************************************************************
2496  * ImageList_SetFilter [COMCTL32.@]
2497  *
2498  * Sets a filter (or does something completely different)!!???
2499  * It removes 12 Bytes from the stack (3 Parameters).
2500  *
2501  * PARAMS
2502  *     himl     [I] SHOULD be a handle to image list
2503  *     i        [I] COULD be an index?
2504  *     dwFilter [I] ???
2505  *
2506  * RETURNS
2507  *     Success: TRUE ???
2508  *     Failure: FALSE ???
2509  *
2510  * BUGS
2511  *     This is an UNDOCUMENTED function!!!!
2512  *     empty stub.
2513  */
2514
2515 BOOL WINAPI
2516 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2517 {
2518     FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2519
2520     return FALSE;
2521 }
2522
2523
2524 /*************************************************************************
2525  * ImageList_SetFlags [COMCTL32.@]
2526  *
2527  * BUGS
2528  *    Stub.
2529  */
2530
2531 DWORD WINAPI
2532 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2533 {
2534     FIXME("(%p %08lx):empty stub\n", himl, flags);
2535     return 0;
2536 }
2537
2538
2539 /*************************************************************************
2540  * ImageList_SetIconSize [COMCTL32.@]
2541  *
2542  * Sets the image size of the bitmap and deletes all images.
2543  *
2544  * PARAMS
2545  *     himl [I] handle to image list
2546  *     cx   [I] image width
2547  *     cy   [I] image height
2548  *
2549  * RETURNS
2550  *     Success: TRUE
2551  *     Failure: FALSE
2552  */
2553
2554 BOOL WINAPI
2555 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2556 {
2557     INT nCount;
2558
2559     if (!is_valid(himl))
2560         return FALSE;
2561
2562     /* remove all images */
2563     himl->cMaxImage = himl->cInitial + himl->cGrow;
2564     himl->cCurImage = 0;
2565     himl->cx        = cx;
2566     himl->cy        = cy;
2567
2568     /* initialize overlay mask indices */
2569     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2570         himl->nOvlIdx[nCount] = -1;
2571
2572     DeleteObject (himl->hbmImage);
2573     himl->hbmImage =
2574         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2575                         1, himl->uBitsPixel, NULL);
2576
2577     if (himl->hbmMask) {
2578         DeleteObject (himl->hbmMask);
2579         himl->hbmMask =
2580             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2581                             1, 1, NULL);
2582     }
2583
2584     return TRUE;
2585 }
2586
2587
2588 /*************************************************************************
2589  * ImageList_SetImageCount [COMCTL32.@]
2590  *
2591  * Resizes an image list to the specified number of images.
2592  *
2593  * PARAMS
2594  *     himl        [I] handle to image list
2595  *     iImageCount [I] number of images in the image list
2596  *
2597  * RETURNS
2598  *     Success: TRUE
2599  *     Failure: FALSE
2600  */
2601
2602 BOOL WINAPI
2603 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2604 {
2605     HDC     hdcImageList, hdcBitmap;
2606     HBITMAP hbmNewBitmap;
2607     INT     nNewCount, nCopyCount;
2608
2609     TRACE("%p %d\n",himl,iImageCount);
2610
2611     if (!is_valid(himl))
2612         return FALSE;
2613     if (himl->cCurImage >= iImageCount)
2614         return FALSE;
2615     if (himl->cMaxImage > iImageCount)
2616     {
2617         himl->cCurImage = iImageCount;
2618         return TRUE;
2619     }
2620
2621     nNewCount = iImageCount + himl->cGrow;
2622     nCopyCount = min(himl->cCurImage, iImageCount);
2623
2624     hdcImageList = CreateCompatibleDC (0);
2625     hdcBitmap = CreateCompatibleDC (0);
2626
2627     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2628                                    1, himl->uBitsPixel, NULL);
2629     if (hbmNewBitmap != 0)
2630     {
2631         SelectObject (hdcImageList, himl->hbmImage);
2632         SelectObject (hdcBitmap, hbmNewBitmap);
2633
2634         /* copy images */
2635         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2636                   hdcImageList, 0, 0, SRCCOPY);
2637 #if 0
2638         /* delete 'empty' image space */
2639         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2640         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2641         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2642                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2643 #endif
2644         DeleteObject (himl->hbmImage);
2645         himl->hbmImage = hbmNewBitmap;
2646     }
2647     else
2648         ERR("Could not create new image bitmap !\n");
2649
2650     if (himl->hbmMask)
2651     {
2652         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2653                                        1, 1, NULL);
2654         if (hbmNewBitmap != 0)
2655         {
2656             SelectObject (hdcImageList, himl->hbmMask);
2657             SelectObject (hdcBitmap, hbmNewBitmap);
2658
2659             /* copy images */
2660             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2661                       hdcImageList, 0, 0, SRCCOPY);
2662 #if 0
2663             /* delete 'empty' image space */
2664             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2665             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2666             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2667                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2668 #endif
2669             DeleteObject (himl->hbmMask);
2670             himl->hbmMask = hbmNewBitmap;
2671         }
2672         else
2673             ERR("Could not create new mask bitmap!\n");
2674     }
2675
2676     DeleteDC (hdcImageList);
2677     DeleteDC (hdcBitmap);
2678
2679     /* Update max image count and current image count */
2680     himl->cMaxImage = nNewCount;
2681     himl->cCurImage = iImageCount;
2682
2683     return TRUE;
2684 }
2685
2686
2687 /*************************************************************************
2688  * ImageList_SetOverlayImage [COMCTL32.@]
2689  *
2690  * Assigns an overlay mask index to an existing image in an image list.
2691  *
2692  * PARAMS
2693  *     himl     [I] handle to image list
2694  *     iImage   [I] image index
2695  *     iOverlay [I] overlay mask index
2696  *
2697  * RETURNS
2698  *     Success: TRUE
2699  *     Failure: FALSE
2700  */
2701
2702 BOOL WINAPI
2703 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2704 {
2705     if (!is_valid(himl))
2706         return FALSE;
2707     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2708         return FALSE;
2709     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2710         return FALSE;
2711     himl->nOvlIdx[iOverlay - 1] = iImage;
2712     return TRUE;
2713 }
2714
2715
2716
2717 /* helper for ImageList_Write - write bitmap to pstm
2718  * currently everything is written as 24 bit RGB, except masks
2719  */
2720 static BOOL
2721 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2722 {
2723     LPBITMAPFILEHEADER bmfh;
2724     LPBITMAPINFOHEADER bmih;
2725     LPBYTE data, lpBits, lpBitsOrg;
2726     BITMAP bm;
2727     INT bitCount, sizeImage, offBits, totalSize;
2728     INT nwidth, nheight, nsizeImage, icount;
2729     HDC xdc;
2730     BOOL result = FALSE;
2731
2732
2733     xdc = GetDC(0);
2734     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2735
2736     /* XXX is this always correct? */
2737     icount = bm.bmWidth / cx;
2738     nwidth = cx << 2;
2739     nheight = cy * ((icount+3)>>2);
2740
2741     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2742     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2743     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2744
2745     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2746     if(bitCount != 24)
2747         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2748     offBits = totalSize;
2749     totalSize += nsizeImage;
2750
2751     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2752     bmfh = (LPBITMAPFILEHEADER)data;
2753     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2754     lpBits = data + offBits;
2755
2756     /* setup BITMAPFILEHEADER */
2757     bmfh->bfType      = (('M' << 8) | 'B');
2758     bmfh->bfSize      = 0;
2759     bmfh->bfReserved1 = 0;
2760     bmfh->bfReserved2 = 0;
2761     bmfh->bfOffBits   = offBits;
2762
2763     /* setup BITMAPINFOHEADER */
2764     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2765     bmih->biWidth         = bm.bmWidth;
2766     bmih->biHeight        = bm.bmHeight;
2767     bmih->biPlanes        = 1;
2768     bmih->biBitCount      = bitCount;
2769     bmih->biCompression   = BI_RGB;
2770     bmih->biSizeImage     = nsizeImage;
2771     bmih->biXPelsPerMeter = 0;
2772     bmih->biYPelsPerMeter = 0;
2773     bmih->biClrUsed       = 0;
2774     bmih->biClrImportant  = 0;
2775
2776     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2777     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2778                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2779         goto failed;
2780     else {
2781         int i;
2782         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2783         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2784
2785         for(i = 0; i < nheight; i++) {
2786             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2787             int noff = (nbpl * (nheight-1-i));
2788             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2789         }
2790     }
2791
2792     bmih->biWidth  = nwidth;
2793     bmih->biHeight = nheight;
2794
2795     if(bitCount == 1) {
2796         /* Hack. */
2797         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2798         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2799         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2800     }
2801
2802     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2803         goto failed;
2804
2805     result = TRUE;
2806
2807     failed:
2808     ReleaseDC(0, xdc);
2809     LocalFree((HLOCAL)lpBitsOrg);
2810
2811     return result;
2812 }
2813
2814
2815 /*************************************************************************
2816  * ImageList_Write [COMCTL32.@]
2817  *
2818  * Writes an image list to a stream.
2819  *
2820  * PARAMS
2821  *     himl [I] handle to image list
2822  *     pstm [O] Pointer to a stream.
2823  *
2824  * RETURNS
2825  *     Success: TRUE
2826  *     Failure: FALSE
2827  *
2828  * BUGS
2829  *     probably.
2830  */
2831
2832 BOOL WINAPI
2833 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2834 {
2835     ILHEAD ilHead;
2836     int i;
2837
2838     if (!is_valid(himl))
2839         return FALSE;
2840
2841     ilHead.usMagic   = (('L' << 8) | 'I');
2842     ilHead.usVersion = 0x101;
2843     ilHead.cCurImage = himl->cCurImage;
2844     ilHead.cMaxImage = himl->cMaxImage;
2845     ilHead.cGrow     = himl->cGrow;
2846     ilHead.cx        = himl->cx;
2847     ilHead.cy        = himl->cy;
2848     ilHead.bkcolor   = himl->clrBk;
2849     ilHead.flags     = himl->flags;
2850     for(i = 0; i < 4; i++) {
2851         ilHead.ovls[i] = himl->nOvlIdx[i];
2852     }
2853
2854     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2855         return FALSE;
2856
2857     /* write the bitmap */
2858     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2859         return FALSE;
2860
2861     /* write the mask if we have one */
2862     if(himl->flags & ILC_MASK) {
2863         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2864             return FALSE;
2865     }
2866
2867     return TRUE;
2868 }