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