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