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