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