Added regedit unit test, a couple minor changes to regedit.
[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.40]
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.41]
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.42]
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.43]
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.44]
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.45]  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->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
972         himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
973                                         1, 1, NULL);
974         if (himl->hbmMask == 0) {
975             ERR("Error creating mask bitmap!\n");
976             if (himl->hbmImage)
977                 DeleteObject (himl->hbmImage);
978             return NULL;
979         }
980     }
981     else
982         himl->hbmMask = 0;
983
984     /* create blending brushes */
985     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
986     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
987     DeleteObject (hbmTemp);
988
989     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
990     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
991     DeleteObject (hbmTemp);
992
993     TRACE("created imagelist %p\n", himl);
994     return himl;
995 }
996
997
998 /*************************************************************************
999  * ImageList_Destroy [COMCTL32.46]
1000  *
1001  * Destroys an image list.
1002  *
1003  * PARAMS
1004  *     himl [I] handle to image list
1005  *
1006  * RETURNS
1007  *     Success: TRUE
1008  *     Failure: FALSE
1009  */
1010
1011 BOOL WINAPI
1012 ImageList_Destroy (HIMAGELIST himl)
1013 {
1014     if (!himl)
1015         return FALSE;
1016
1017     /* delete image bitmaps */
1018     if (himl->hbmImage)
1019         DeleteObject (himl->hbmImage);
1020     if (himl->hbmMask)
1021         DeleteObject (himl->hbmMask);
1022
1023     /* delete blending brushes */
1024     if (himl->hbrBlend25)
1025         DeleteObject (himl->hbrBlend25);
1026     if (himl->hbrBlend50)
1027         DeleteObject (himl->hbrBlend50);
1028
1029     COMCTL32_Free (himl);
1030
1031     return TRUE;
1032 }
1033
1034
1035 /*************************************************************************
1036  * ImageList_DragEnter [COMCTL32.47]
1037  *
1038  * Locks window update and displays the drag image at the given position.
1039  *
1040  * PARAMS
1041  *     hwndLock [I] handle of the window that owns the drag image.
1042  *     x        [I] X position of the drag image.
1043  *     y        [I] Y position of the drag image.
1044  *
1045  * RETURNS
1046  *     Success: TRUE
1047  *     Failure: FALSE
1048  *
1049  * NOTES
1050  *     The position of the drag image is relative to the window, not
1051  *     the client area.
1052  */
1053
1054 BOOL WINAPI
1055 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1056 {
1057     TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1058
1059     if (InternalDrag.himl == NULL)
1060         return FALSE;
1061
1062     if (hwndLock)
1063         InternalDrag.hwnd = hwndLock;
1064     else
1065         InternalDrag.hwnd = GetDesktopWindow ();
1066
1067     InternalDrag.x = x;
1068     InternalDrag.y = y;
1069
1070     /* draw the drag image and save the background */
1071     if (!ImageList_DragShowNolock(TRUE)) {
1072         return FALSE;
1073     }
1074
1075     return TRUE;
1076 }
1077
1078
1079 /*************************************************************************
1080  * ImageList_DragLeave [COMCTL32.48]
1081  *
1082  * Unlocks window update and hides the drag image.
1083  *
1084  * PARAMS
1085  *     hwndLock [I] handle of the window that owns the drag image.
1086  *
1087  * RETURNS
1088  *     Success: TRUE
1089  *     Failure: FALSE
1090  */
1091
1092 BOOL WINAPI
1093 ImageList_DragLeave (HWND hwndLock)
1094 {
1095     /* As we don't save drag info in the window this can lead to problems if
1096        an app does not supply the same window as DragEnter */
1097     /* if (hwndLock)
1098         InternalDrag.hwnd = hwndLock;
1099     else
1100         InternalDrag.hwnd = GetDesktopWindow (); */
1101     if(!hwndLock)
1102         hwndLock = GetDesktopWindow();
1103     if(InternalDrag.hwnd != hwndLock)
1104         FIXME("DragLeave hWnd != DragEnter hWnd\n");
1105
1106     ImageList_DragShowNolock (FALSE);
1107
1108     return TRUE;
1109 }
1110
1111
1112 /*************************************************************************
1113  * ImageList_DragMove [COMCTL32.49]
1114  *
1115  * Moves the drag image.
1116  *
1117  * PARAMS
1118  *     x [I] X position of the drag image.
1119  *     y [I] Y position of the drag image.
1120  *
1121  * RETURNS
1122  *     Success: TRUE
1123  *     Failure: FALSE
1124  *
1125  * NOTES
1126  *     The position of the drag image is relative to the window, not
1127  *     the client area.
1128  *
1129  * BUGS
1130  *     The drag image should be drawn semitransparent.
1131  */
1132
1133 BOOL WINAPI
1134 ImageList_DragMove (INT x, INT y)
1135 {
1136     TRACE("(x=%d y=%d)\n", x, y);
1137
1138     if (!InternalDrag.himl) {
1139         return FALSE;
1140     }
1141
1142     /* draw/update the drag image */
1143     if (InternalDrag.bShow) {
1144         HDC hdcDrag;
1145         HDC hdcOffScreen;
1146         HDC hdcBg;
1147         HBITMAP hbmOffScreen;
1148         INT origNewX, origNewY;
1149         INT origOldX, origOldY;
1150         INT origRegX, origRegY;
1151         INT sizeRegX, sizeRegY;
1152
1153
1154         /* calculate the update region */
1155         origNewX = x - InternalDrag.dxHotspot;
1156         origNewY = y - InternalDrag.dyHotspot;
1157         origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1158         origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1159         origRegX = min(origNewX, origOldX);
1160         origRegY = min(origNewY, origOldY);
1161         sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1162         sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1163
1164         hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1165                           DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1166         hdcOffScreen = CreateCompatibleDC(hdcDrag);
1167         hdcBg = CreateCompatibleDC(hdcDrag);
1168
1169         hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1170         SelectObject(hdcOffScreen, hbmOffScreen);
1171         SelectObject(hdcBg, InternalDrag.hbmBg);
1172
1173         /* get the actual background of the update region */
1174         BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1175                origRegX, origRegY, SRCCOPY);
1176         /* erase the old image */
1177         BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1178                InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1179                SRCCOPY);
1180         /* save the background */
1181         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1182                hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1183         /* draw the image */
1184         /* FIXME: image should be drawn semitransparent */
1185         ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1186                        origNewY - origRegY, ILD_NORMAL);
1187         /* draw the update region to the screen */
1188         BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1189                hdcOffScreen, 0, 0, SRCCOPY);
1190
1191         DeleteDC(hdcBg);
1192         DeleteDC(hdcOffScreen);
1193         DeleteObject(hbmOffScreen);
1194         ReleaseDC(InternalDrag.hwnd, hdcDrag);
1195     }
1196
1197     /* update the image position */
1198     InternalDrag.x = x;
1199     InternalDrag.y = y;
1200
1201     return TRUE;
1202 }
1203
1204
1205 /*************************************************************************
1206  * ImageList_DragShowNolock [COMCTL32.50]
1207  *
1208  * Shows or hides the drag image.
1209  *
1210  * PARAMS
1211  *     bShow [I] TRUE shows the drag image, FALSE hides it.
1212  *
1213  * RETURNS
1214  *     Success: TRUE
1215  *     Failure: FALSE
1216  *
1217  * BUGS
1218  *     The drag image should be drawn semitransparent.
1219  */
1220
1221 BOOL WINAPI
1222 ImageList_DragShowNolock (BOOL bShow)
1223 {
1224     HDC hdcDrag;
1225     HDC hdcBg;
1226     INT x, y;
1227
1228     TRACE("bShow=0x%X!\n", bShow);
1229
1230     /* DragImage is already visible/hidden */
1231     if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1232         return FALSE;
1233     }
1234
1235     /* position of the origin of the DragImage */
1236     x = InternalDrag.x - InternalDrag.dxHotspot;
1237     y = InternalDrag.y - InternalDrag.dyHotspot;
1238
1239     hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1240                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1241     if (!hdcDrag) {
1242         return FALSE;
1243     }
1244
1245     hdcBg = CreateCompatibleDC(hdcDrag);
1246     if (!InternalDrag.hbmBg) {
1247         InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1248                     InternalDrag.himl->cx, InternalDrag.himl->cy);
1249     }
1250     SelectObject(hdcBg, InternalDrag.hbmBg);
1251
1252     if (bShow) {
1253         /* save the background */
1254         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1255                hdcDrag, x, y, SRCCOPY);
1256         /* show the image */
1257         /* FIXME: this should be drawn semitransparent */
1258         ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1259     } else {
1260         /* hide the image */
1261         BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1262                hdcBg, 0, 0, SRCCOPY);
1263     }
1264
1265     InternalDrag.bShow = !InternalDrag.bShow;
1266
1267     DeleteDC(hdcBg);
1268     ReleaseDC (InternalDrag.hwnd, hdcDrag);
1269     return TRUE;
1270 }
1271
1272
1273 /*************************************************************************
1274  * ImageList_Draw [COMCTL32.51] Draws an image.
1275  *
1276  * PARAMS
1277  *     himl   [I] handle to image list
1278  *     i      [I] image index
1279  *     hdc    [I] handle to device context
1280  *     x      [I] x position
1281  *     y      [I] y position
1282  *     fStyle [I] drawing flags
1283  *
1284  * RETURNS
1285  *     Success: TRUE
1286  *     Failure: FALSE
1287  *
1288  * NOTES
1289  *     Calls ImageList_DrawIndirect.
1290  *
1291  * SEE
1292  *     ImageList_DrawIndirect.
1293  */
1294
1295 BOOL WINAPI
1296 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1297                 INT x, INT y, UINT fStyle)
1298 {
1299     IMAGELISTDRAWPARAMS imldp;
1300
1301     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1302     imldp.himl    = himl;
1303     imldp.i       = i;
1304     imldp.hdcDst  = hdc,
1305     imldp.x       = x;
1306     imldp.y       = y;
1307     imldp.cx      = 0;
1308     imldp.cy      = 0;
1309     imldp.xBitmap = 0;
1310     imldp.yBitmap = 0;
1311     imldp.rgbBk   = CLR_DEFAULT;
1312     imldp.rgbFg   = CLR_DEFAULT;
1313     imldp.fStyle  = fStyle;
1314     imldp.dwRop   = 0;
1315
1316     return ImageList_DrawIndirect (&imldp);
1317 }
1318
1319
1320 /*************************************************************************
1321  * ImageList_DrawEx [COMCTL32.52]
1322  *
1323  * Draws an image and allows to use extended drawing features.
1324  *
1325  * PARAMS
1326  *     himl   [I] handle to image list
1327  *     i      [I] image index
1328  *     hdc    [I] handle to device context
1329  *     x      [I] X position
1330  *     y      [I] Y position
1331  *     xOffs  [I] X offset
1332  *     yOffs  [I] Y offset
1333  *     rgbBk  [I] background color
1334  *     rgbFg  [I] foreground color
1335  *     fStyle [I] drawing flags
1336  *
1337  * RETURNS
1338  *     Success: TRUE
1339  *     Failure: FALSE
1340  *
1341  * NOTES
1342  *     Calls ImageList_DrawIndirect.
1343  *
1344  * SEE
1345  *     ImageList_DrawIndirect.
1346  */
1347
1348 BOOL WINAPI
1349 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1350                   INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1351                   UINT fStyle)
1352 {
1353     IMAGELISTDRAWPARAMS imldp;
1354
1355     imldp.cbSize  = sizeof(IMAGELISTDRAWPARAMS);
1356     imldp.himl    = himl;
1357     imldp.i       = i;
1358     imldp.hdcDst  = hdc,
1359     imldp.x       = x;
1360     imldp.y       = y;
1361     imldp.cx      = dx;
1362     imldp.cy      = dy;
1363     imldp.xBitmap = 0;
1364     imldp.yBitmap = 0;
1365     imldp.rgbBk   = rgbBk;
1366     imldp.rgbFg   = rgbFg;
1367     imldp.fStyle  = fStyle;
1368     imldp.dwRop   = 0;
1369
1370     return ImageList_DrawIndirect (&imldp);
1371 }
1372
1373
1374 /*************************************************************************
1375  * ImageList_DrawIndirect [COMCTL32.53]
1376  *
1377  * Draws an image using ...
1378  *
1379  * PARAMS
1380  *     pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1381  *
1382  * RETURNS
1383  *     Success: TRUE
1384  *     Failure: FALSE
1385  */
1386
1387 BOOL WINAPI
1388 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1389 {
1390     INT      cx, cy;
1391     /*
1392         Do some Error Checking
1393     */
1394     if (pimldp == NULL)
1395         return FALSE;
1396     if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1397         return FALSE;
1398     if (pimldp->himl == NULL)
1399         return FALSE;
1400     if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1401         ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1402         return FALSE;
1403     }
1404     /*
1405         Get the Height and Width to display
1406     */
1407     cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1408     cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1409     /*
1410         Draw the image
1411     */
1412     if(pimldp->himl->hbmMask != 0)
1413     {
1414         IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1415     }
1416     else
1417     {
1418         IMAGELIST_InternalDraw(pimldp, cx, cy);
1419     }
1420     /*
1421         Apply the blend if needed to the Image
1422     */
1423     if((pimldp->fStyle & ILD_BLEND50)
1424         || (pimldp->fStyle & ILD_BLEND25))
1425     {
1426         IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1427     }
1428     /*
1429         Apply the Overlay if needed
1430     */
1431     if (pimldp->fStyle & ILD_OVERLAYMASK)
1432     {
1433         IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1434     }
1435
1436     return TRUE;
1437 }
1438
1439
1440 /*************************************************************************
1441  * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1442  *
1443  * PARAMS
1444  *     himlSrc [I] source image list handle
1445  *
1446  * RETURNS
1447  *     Success: Handle of duplicated image list.
1448  *     Failure: NULL
1449  */
1450
1451 HIMAGELIST WINAPI
1452 ImageList_Duplicate (HIMAGELIST himlSrc)
1453 {
1454     HIMAGELIST himlDst;
1455     HDC hdcSrc, hdcDst;
1456
1457     if (himlSrc == NULL) {
1458         ERR("Invalid image list handle!\n");
1459         return NULL;
1460     }
1461
1462     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1463                                 himlSrc->cInitial, himlSrc->cGrow);
1464
1465     if (himlDst)
1466     {
1467         hdcSrc = CreateCompatibleDC (0);
1468         hdcDst = CreateCompatibleDC (0);
1469         SelectObject (hdcSrc, himlSrc->hbmImage);
1470         SelectObject (hdcDst, himlDst->hbmImage);
1471         BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1472                   hdcSrc, 0, 0, SRCCOPY);
1473
1474         if (himlDst->hbmMask)
1475         {
1476             SelectObject (hdcSrc, himlSrc->hbmMask);
1477             SelectObject (hdcDst, himlDst->hbmMask);
1478             BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1479                       himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1480         }
1481
1482         DeleteDC (hdcDst);
1483         DeleteDC (hdcSrc);
1484
1485         himlDst->cCurImage = himlSrc->cCurImage;
1486         himlDst->cMaxImage = himlSrc->cMaxImage;
1487     }
1488     return himlDst;
1489 }
1490
1491
1492 /*************************************************************************
1493  * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1494  *
1495  * Finishes a drag operation.
1496  *
1497  * PARAMS
1498  *     no Parameters
1499  *
1500  * RETURNS
1501  *     Success: TRUE
1502  *     Failure: FALSE
1503  */
1504
1505 BOOL WINAPI
1506 ImageList_EndDrag (void)
1507 {
1508     /* cleanup the InternalDrag struct */
1509     InternalDrag.hwnd = 0;
1510     ImageList_Destroy (InternalDrag.himl);
1511     InternalDrag.himl = 0;
1512     InternalDrag.x= 0;
1513     InternalDrag.y= 0;
1514     InternalDrag.dxHotspot = 0;
1515     InternalDrag.dyHotspot = 0;
1516     InternalDrag.bShow = FALSE;
1517     DeleteObject(InternalDrag.hbmBg);
1518     InternalDrag.hbmBg = 0;
1519     InternalDrag.bHSPending = FALSE;
1520
1521     return TRUE;
1522 }
1523
1524
1525 /*************************************************************************
1526  * ImageList_GetBkColor [COMCTL32.56]
1527  *
1528  * Returns the background color of an image list.
1529  *
1530  * PARAMS
1531  *     himl [I] Image list handle.
1532  *
1533  * RETURNS
1534  *     Success: background color
1535  *     Failure: CLR_NONE
1536  */
1537
1538 COLORREF WINAPI
1539 ImageList_GetBkColor (HIMAGELIST himl)
1540 {
1541     if (himl == NULL)
1542         return CLR_NONE;
1543
1544     return himl->clrBk;
1545 }
1546
1547
1548 /*************************************************************************
1549  * ImageList_GetDragImage [COMCTL32.57]
1550  *
1551  * Returns the handle to the internal drag image list.
1552  *
1553  * PARAMS
1554  *     ppt        [O] Pointer to the drag position. Can be NULL.
1555  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1556  *
1557  * RETURNS
1558  *     Success: Handle of the drag image list.
1559  *     Failure: NULL.
1560  */
1561
1562 HIMAGELIST WINAPI
1563 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1564 {
1565     if (InternalDrag.himl) {
1566         if (ppt) {
1567             ppt->x = InternalDrag.x;
1568             ppt->y = InternalDrag.y;
1569         }
1570         if (pptHotspot) {
1571             pptHotspot->x = InternalDrag.dxHotspot;
1572             pptHotspot->y = InternalDrag.dyHotspot;
1573         }
1574         return (InternalDrag.himl);
1575     }
1576
1577     return NULL;
1578 }
1579
1580
1581 /*************************************************************************
1582  * ImageList_GetFlags [COMCTL32.58]
1583  *
1584  * BUGS
1585  *    Stub.
1586  */
1587
1588 DWORD WINAPI
1589 ImageList_GetFlags(HIMAGELIST himl)
1590 {
1591     FIXME("(%p):empty stub\n", himl);
1592     return 0;
1593 }
1594
1595
1596 /*************************************************************************
1597  * ImageList_GetIcon [COMCTL32.59]
1598  *
1599  * Creates an icon from a masked image of an image list.
1600  *
1601  * PARAMS
1602  *     himl  [I] handle to image list
1603  *     i     [I] image index
1604  *     flags [I] drawing style flags
1605  *
1606  * RETURNS
1607  *     Success: icon handle
1608  *     Failure: NULL
1609  */
1610
1611 HICON WINAPI
1612 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1613 {
1614     ICONINFO ii;
1615     HICON  hIcon;
1616     HBITMAP hOldSrcBitmap,hOldDstBitmap;
1617     HDC    hdcSrc, hdcDst;
1618
1619     if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1620         FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1621         return 0;
1622    }
1623
1624     hdcSrc = CreateCompatibleDC(0);
1625     hdcDst = CreateCompatibleDC(0);
1626
1627     ii.fIcon = TRUE;
1628     ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1629
1630     /* draw mask*/
1631     hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1632     if (himl->hbmMask) {
1633         SelectObject (hdcSrc, himl->hbmMask);
1634         BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1635                   hdcSrc, i * himl->cx, 0, SRCCOPY);
1636     }
1637     else
1638         PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1639
1640     /* draw image*/
1641     hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1642     ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1643     SelectObject (hdcDst, ii.hbmColor);
1644     BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1645               hdcSrc, i * himl->cx, 0, SRCCOPY);
1646
1647     /*
1648      * CreateIconIndirect requires us to deselect the bitmaps from
1649      * the DCs before calling
1650      */
1651     SelectObject(hdcSrc, hOldSrcBitmap);
1652     SelectObject(hdcDst, hOldDstBitmap);
1653
1654     hIcon = CreateIconIndirect (&ii);
1655
1656     DeleteDC (hdcSrc);
1657     DeleteDC (hdcDst);
1658     DeleteObject (ii.hbmMask);
1659     DeleteObject (ii.hbmColor);
1660
1661     return hIcon;
1662 }
1663
1664
1665 /*************************************************************************
1666  * ImageList_GetIconSize [COMCTL32.60]
1667  *
1668  * Retrieves the size of an image in an image list.
1669  *
1670  * PARAMS
1671  *     himl [I] handle to image list
1672  *     cx   [O] pointer to the image width.
1673  *     cy   [O] pointer to the image height.
1674  *
1675  * RETURNS
1676  *     Success: TRUE
1677  *     Failure: FALSE
1678  *
1679  * NOTES
1680  *     All images in an image list have the same size.
1681  */
1682
1683 BOOL WINAPI
1684 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1685 {
1686     if (himl == NULL)
1687         return FALSE;
1688     if ((himl->cx <= 0) || (himl->cy <= 0))
1689         return FALSE;
1690
1691     if (cx)
1692         *cx = himl->cx;
1693     if (cy)
1694         *cy = himl->cy;
1695
1696     return TRUE;
1697 }
1698
1699
1700 /*************************************************************************
1701  * ImageList_GetImageCount [COMCTL32.61]
1702  *
1703  * Returns the number of images in an image list.
1704  *
1705  * PARAMS
1706  *     himl [I] handle to image list
1707  *
1708  * RETURNS
1709  *     Success: Number of images.
1710  *     Failure: 0
1711  */
1712
1713 INT WINAPI
1714 ImageList_GetImageCount (HIMAGELIST himl)
1715 {
1716     if (himl == NULL)
1717         return 0;
1718
1719     return himl->cCurImage;
1720 }
1721
1722
1723 /*************************************************************************
1724  * ImageList_GetImageInfo [COMCTL32.62]
1725  *
1726  * Returns information about an image in an image list.
1727  *
1728  * PARAMS
1729  *     himl       [I] handle to image list
1730  *     i          [I] image index
1731  *     pImageInfo [O] pointer to the image information
1732  *
1733  * RETURNS
1734  *     Success: TRUE
1735  *     Failure: FALSE
1736  */
1737
1738 BOOL WINAPI
1739 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1740 {
1741     if ((himl == NULL) || (pImageInfo == NULL))
1742         return FALSE;
1743     if ((i < 0) || (i >= himl->cCurImage))
1744         return FALSE;
1745
1746     pImageInfo->hbmImage = himl->hbmImage;
1747     pImageInfo->hbmMask  = himl->hbmMask;
1748
1749     pImageInfo->rcImage.top    = 0;
1750     pImageInfo->rcImage.bottom = himl->cy;
1751     pImageInfo->rcImage.left   = i * himl->cx;
1752     pImageInfo->rcImage.right  = (i+1) * himl->cx;
1753
1754     return TRUE;
1755 }
1756
1757
1758 /*************************************************************************
1759  * ImageList_GetImageRect [COMCTL32.63]
1760  *
1761  * Retrieves the rectangle of the specified image in an image list.
1762  *
1763  * PARAMS
1764  *     himl   [I] handle to image list
1765  *     i      [I] image index
1766  *     lpRect [O] pointer to the image rectangle
1767  *
1768  * RETURNS
1769  *    Success: TRUE
1770  *    Failure: FALSE
1771  *
1772  * NOTES
1773  *    This is an UNDOCUMENTED function!!!
1774  */
1775
1776 BOOL WINAPI
1777 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1778 {
1779     if ((himl == NULL) || (lpRect == NULL))
1780         return FALSE;
1781     if ((i < 0) || (i >= himl->cCurImage))
1782         return FALSE;
1783
1784     lpRect->left   = i * himl->cx;
1785     lpRect->top    = 0;
1786     lpRect->right  = lpRect->left + himl->cx;
1787     lpRect->bottom = himl->cy;
1788
1789     return TRUE;
1790 }
1791
1792
1793 /*************************************************************************
1794  * ImageList_LoadImage  [COMCTL32.64]
1795  * ImageList_LoadImageA [COMCTL32.65]
1796  *
1797  * Creates an image list from a bitmap, icon or cursor.
1798  *
1799  * PARAMS
1800  *     hi      [I] instance handle
1801  *     lpbmp   [I] name or id of the image
1802  *     cx      [I] width of each image
1803  *     cGrow   [I] number of images to expand
1804  *     clrMask [I] mask color
1805  *     uType   [I] type of image to load
1806  *     uFlags  [I] loading flags
1807  *
1808  * RETURNS
1809  *     Success: handle to the loaded image list
1810  *     Failure: NULL
1811  *
1812  * SEE
1813  *     LoadImage ()
1814  */
1815
1816 HIMAGELIST WINAPI
1817 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1818                         COLORREF clrMask, UINT uType, UINT uFlags)
1819 {
1820     HIMAGELIST himl = NULL;
1821     HANDLE   handle;
1822     INT      nImageCount;
1823
1824     handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1825     if (!handle) {
1826         ERR("Error loading image!\n");
1827         return NULL;
1828     }
1829
1830     if (uType == IMAGE_BITMAP) {
1831         BITMAP bmp;
1832         GetObjectA (handle, sizeof(BITMAP), &bmp);
1833
1834         /* To match windows behavior, if cx is set to zero and
1835          the flag DI_DEFAULTSIZE is specified, cx becomes the
1836          system metric value for icons. If the flag is not specified
1837          the function sets the size to the height of the bitmap */
1838         if (cx == 0)
1839         {
1840             if (uFlags & DI_DEFAULTSIZE)
1841                 cx = GetSystemMetrics (SM_CXICON);
1842             else
1843                 cx = bmp.bmHeight;
1844         }
1845
1846         nImageCount = bmp.bmWidth / cx;
1847
1848         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1849                                  nImageCount, cGrow);
1850         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1851     }
1852     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1853         ICONINFO ii;
1854         BITMAP bmp;
1855
1856         GetIconInfo (handle, &ii);
1857         GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1858         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1859                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1860         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1861         DeleteObject (ii.hbmColor);
1862         DeleteObject (ii.hbmMask);
1863     }
1864
1865     DeleteObject (handle);
1866
1867     return himl;
1868 }
1869
1870
1871 /*************************************************************************
1872  * ImageList_LoadImageW [COMCTL32.66]
1873  *
1874  * Creates an image list from a bitmap, icon or cursor.
1875  *
1876  * PARAMS
1877  *     hi      [I] instance handle
1878  *     lpbmp   [I] name or id of the image
1879  *     cx      [I] width of each image
1880  *     cGrow   [I] number of images to expand
1881  *     clrMask [I] mask color
1882  *     uType   [I] type of image to load
1883  *     uFlags  [I] loading flags
1884  *
1885  * RETURNS
1886  *     Success: handle to the loaded image list
1887  *     Failure: NULL
1888  *
1889  * SEE
1890  *     LoadImage ()
1891  */
1892
1893 HIMAGELIST WINAPI
1894 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1895                         COLORREF clrMask, UINT uType,   UINT uFlags)
1896 {
1897     HIMAGELIST himl = NULL;
1898     HANDLE   handle;
1899     INT      nImageCount;
1900
1901     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1902     if (!handle) {
1903         ERR("Error loading image!\n");
1904         return NULL;
1905     }
1906
1907     if (uType == IMAGE_BITMAP) {
1908         BITMAP bmp;
1909         GetObjectA (handle, sizeof(BITMAP), &bmp);
1910
1911         /* To match windows behavior, if cx is set to zero and
1912          the flag DI_DEFAULTSIZE is specified, cx becomes the
1913          system metric value for icons. If the flag is not specified
1914          the function sets the size to the height of the bitmap */
1915         if (cx == 0)
1916         {
1917             if (uFlags & DI_DEFAULTSIZE)
1918                 cx = GetSystemMetrics (SM_CXICON);
1919             else
1920                 cx = bmp.bmHeight;
1921         }
1922
1923         nImageCount = bmp.bmWidth / cx;
1924
1925         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1926                                  nImageCount, cGrow);
1927         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1928     }
1929     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1930         ICONINFO ii;
1931         BITMAP bmp;
1932
1933         GetIconInfo (handle, &ii);
1934         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1935         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1936                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1937         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1938         DeleteObject (ii.hbmColor);
1939         DeleteObject (ii.hbmMask);
1940     }
1941
1942     DeleteObject (handle);
1943
1944     return himl;
1945 }
1946
1947
1948 /*************************************************************************
1949  * ImageList_Merge [COMCTL32.67]
1950  *
1951  * Creates a new image list that contains a merged image from the specified
1952  * images of both source image lists.
1953  *
1954  * PARAMS
1955  *     himl1 [I] handle to first image list
1956  *     i1    [I] first image index
1957  *     himl2 [I] handle to second image list
1958  *     i2    [I] second image index
1959  *     dx    [I] X offset of the second image relative to the first.
1960  *     dy    [I] Y offset of the second image relative to the first.
1961  *
1962  * RETURNS
1963  *     Success: handle of the merged image list.
1964  *     Failure: NULL
1965  */
1966
1967 HIMAGELIST WINAPI
1968 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1969                  INT dx, INT dy)
1970 {
1971     HIMAGELIST himlDst = NULL;
1972     HDC      hdcSrcImage, hdcDstImage;
1973     INT      cxDst, cyDst;
1974     INT      xOff1, yOff1, xOff2, yOff2;
1975     INT      nX1, nX2;
1976
1977     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1978            i2, dx, dy);
1979
1980     if ((himl1 == NULL) || (himl2 == NULL))
1981         return NULL;
1982
1983     /* check indices */
1984     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1985         ERR("Index 1 out of range! %d\n", i1);
1986         return NULL;
1987     }
1988
1989     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1990         ERR("Index 2 out of range! %d\n", i2);
1991         return NULL;
1992     }
1993
1994     if (dx > 0) {
1995         cxDst = max (himl1->cx, dx + himl2->cx);
1996         xOff1 = 0;
1997         xOff2 = dx;
1998     }
1999     else if (dx < 0) {
2000         cxDst = max (himl2->cx, himl1->cx - dx);
2001         xOff1 = -dx;
2002         xOff2 = 0;
2003     }
2004     else {
2005         cxDst = max (himl1->cx, himl2->cx);
2006         xOff1 = 0;
2007         xOff2 = 0;
2008     }
2009
2010     if (dy > 0) {
2011         cyDst = max (himl1->cy, dy + himl2->cy);
2012         yOff1 = 0;
2013         yOff2 = dy;
2014     }
2015     else if (dy < 0) {
2016         cyDst = max (himl2->cy, himl1->cy - dy);
2017         yOff1 = -dy;
2018         yOff2 = 0;
2019     }
2020     else {
2021         cyDst = max (himl1->cy, himl2->cy);
2022         yOff1 = 0;
2023         yOff2 = 0;
2024     }
2025
2026     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2027
2028     if (himlDst) {
2029         hdcSrcImage = CreateCompatibleDC (0);
2030         hdcDstImage = CreateCompatibleDC (0);
2031         nX1 = i1 * himl1->cx;
2032         nX2 = i2 * himl2->cx;
2033
2034         /* copy image */
2035         SelectObject (hdcSrcImage, himl1->hbmImage);
2036         SelectObject (hdcDstImage, himlDst->hbmImage);
2037         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2038                   hdcSrcImage, 0, 0, BLACKNESS);
2039         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2040                   hdcSrcImage, nX1, 0, SRCCOPY);
2041
2042         SelectObject (hdcSrcImage, himl2->hbmMask);
2043         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2044                   hdcSrcImage, nX2, 0, SRCAND);
2045
2046         SelectObject (hdcSrcImage, himl2->hbmImage);
2047         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2048                   hdcSrcImage, nX2, 0, SRCPAINT);
2049
2050         /* copy mask */
2051         SelectObject (hdcSrcImage, himl1->hbmMask);
2052         SelectObject (hdcDstImage, himlDst->hbmMask);
2053         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2054                   hdcSrcImage, 0, 0, WHITENESS);
2055         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2056                   hdcSrcImage, nX1, 0, SRCCOPY);
2057
2058         SelectObject (hdcSrcImage, himl2->hbmMask);
2059         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2060                   hdcSrcImage, nX2, 0, SRCAND);
2061
2062         DeleteDC (hdcSrcImage);
2063         DeleteDC (hdcDstImage);
2064         himlDst->cCurImage = 1;
2065     }
2066
2067     return himlDst;
2068 }
2069
2070
2071 /* helper for _read_bitmap currently unused */
2072 #if 0
2073 static int may_use_dibsection(HDC hdc) {
2074     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2075     if (bitspixel>8)
2076         return TRUE;
2077     if (bitspixel<=4)
2078         return FALSE;
2079     return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2080 }
2081 #endif
2082
2083 /* helper for ImageList_Read, see comments below */
2084 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2085     HDC                 xdc = 0;
2086     BITMAPFILEHEADER    bmfh;
2087     BITMAPINFOHEADER    bmih;
2088     int                 bitsperpixel,palspace,longsperline,width,height;
2089     LPBITMAPINFOHEADER  bmihc = NULL;
2090     int                 result = 0;
2091     HBITMAP             hbitmap = 0;
2092     LPBYTE              bits = NULL,nbits = NULL;
2093     int                 nbytesperline,bytesperline;
2094
2095     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
2096         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
2097         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
2098         (bmih.biSize != sizeof(bmih))
2099     )
2100         return 0;
2101
2102     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2103     if (bitsperpixel<=8)
2104         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2105     else
2106         palspace = 0;
2107     width = bmih.biWidth;
2108     height = bmih.biHeight;
2109     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2110     memcpy(bmihc,&bmih,sizeof(bmih));
2111     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
2112     bmihc->biSizeImage  = (longsperline*height)<<2;
2113
2114     /* read the palette right after the end of the bitmapinfoheader */
2115     if (palspace)
2116         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2117             goto ret1;
2118
2119     xdc = GetDC(0);
2120 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2121     if ((bitsperpixel>1) &&
2122         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2123      ) {
2124         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2125         if (!hbitmap)
2126             goto ret1;
2127         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2128             goto ret1;
2129         result = 1;
2130     } else
2131 #endif
2132     {
2133         int i,nwidth,nheight;
2134
2135         nwidth  = width*(height/cy);
2136         nheight = cy;
2137
2138         if (bitsperpixel==1)
2139             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2140         else
2141             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2142
2143         /* Might be a bit excessive memory use here */
2144         bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2145         nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2146         if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2147                 goto ret1;
2148
2149         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2150         /* Do not forget that windows bitmaps are bottom->top */
2151         bytesperline    = longsperline*4;
2152         nbytesperline   = (height/cy)*bytesperline;
2153         for (i=0;i<height;i++) {
2154             memcpy(
2155                 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2156                 bits+bytesperline*(height-1-i),
2157                 bytesperline
2158             );
2159         }
2160         bmihc->biWidth  = nwidth;
2161         bmihc->biHeight = nheight;
2162         if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2163                 goto ret1;
2164         LocalFree((HLOCAL)nbits);
2165         LocalFree((HLOCAL)bits);
2166         result = 1;
2167     }
2168 ret1:
2169     if (xdc)    ReleaseDC(0,xdc);
2170     if (bmihc)  LocalFree((HLOCAL)bmihc);
2171     if (!result) {
2172         if (hbitmap) {
2173             DeleteObject(hbitmap);
2174             hbitmap = 0;
2175         }
2176     }
2177     return hbitmap;
2178 }
2179
2180 /*************************************************************************
2181  * ImageList_Read [COMCTL32.68]
2182  *
2183  * Reads an image list from a stream.
2184  *
2185  * PARAMS
2186  *     pstm [I] pointer to a stream
2187  *
2188  * RETURNS
2189  *     Success: handle to image list
2190  *     Failure: NULL
2191  *
2192  * The format is like this:
2193  *      ILHEAD                  ilheadstruct;
2194  *
2195  * for the color image part:
2196  *      BITMAPFILEHEADER        bmfh;
2197  *      BITMAPINFOHEADER        bmih;
2198  * only if it has a palette:
2199  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2200  *
2201  *      BYTE                    colorbits[imagesize];
2202  *
2203  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2204  *      BITMAPFILEHEADER        bmfh_mask;
2205  *      BITMAPINFOHEADER        bmih_mask;
2206  * only if it has a palette (it usually does not):
2207  *      RGBQUAD         rgbs[nr_of_paletted_colors];
2208  *
2209  *      BYTE                    maskbits[imagesize];
2210  *
2211  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2212  *         _read_bitmap needs to convert them.
2213  */
2214 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2215 {
2216     ILHEAD      ilHead;
2217     HIMAGELIST  himl;
2218     HBITMAP     hbmColor=0,hbmMask=0;
2219     int         i;
2220
2221     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2222         return NULL;
2223     if (ilHead.usMagic != (('L' << 8) | 'I'))
2224         return NULL;
2225     if (ilHead.usVersion != 0x101) /* probably version? */
2226         return NULL;
2227
2228 #if 0
2229     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
2230     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2231     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
2232     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2233     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2234     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2235     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2236     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2237     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2238     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2239 #endif
2240
2241     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2242     if (!hbmColor)
2243         return NULL;
2244     if (ilHead.flags & ILC_MASK) {
2245         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2246         if (!hbmMask) {
2247             DeleteObject(hbmColor);
2248             return NULL;
2249         }
2250     }
2251
2252     himl = ImageList_Create (
2253                     ilHead.cx,
2254                     ilHead.cy,
2255                     ilHead.flags,
2256                     1,          /* initial */
2257                     ilHead.cGrow
2258     );
2259     if (!himl) {
2260         DeleteObject(hbmColor);
2261         DeleteObject(hbmMask);
2262         return NULL;
2263     }
2264     himl->hbmImage = hbmColor;
2265     himl->hbmMask = hbmMask;
2266     himl->cCurImage = ilHead.cCurImage;
2267     himl->cMaxImage = ilHead.cMaxImage;
2268
2269     ImageList_SetBkColor(himl,ilHead.bkcolor);
2270     for (i=0;i<4;i++)
2271         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2272     return himl;
2273 }
2274
2275
2276 /*************************************************************************
2277  * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2278  *
2279  * PARAMS
2280  *     himl [I] image list handle
2281  *     i    [I] image index
2282  *
2283  * RETURNS
2284  *     Success: TRUE
2285  *     Failure: FALSE
2286  */
2287
2288 BOOL WINAPI
2289 ImageList_Remove (HIMAGELIST himl, INT i)
2290 {
2291     HBITMAP hbmNewImage, hbmNewMask;
2292     HDC     hdcSrc, hdcDst;
2293     INT     cxNew, nCount;
2294
2295     if (himl == NULL) {
2296         ERR("Invalid image list handle!\n");
2297         return FALSE;
2298     }
2299
2300     if ((i < -1) || (i >= himl->cCurImage)) {
2301         ERR("index out of range! %d\n", i);
2302         return FALSE;
2303     }
2304
2305     if (himl->cCurImage == 0) {
2306         ERR("image list is already empty!\n");
2307         return FALSE;
2308     }
2309
2310     if (i == -1) {
2311         /* remove all */
2312         TRACE("remove all!\n");
2313
2314         himl->cMaxImage = himl->cInitial + himl->cGrow;
2315         himl->cCurImage = 0;
2316         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2317              himl->nOvlIdx[nCount] = -1;
2318
2319         DeleteObject (himl->hbmImage);
2320         himl->hbmImage =
2321             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2322                             1, himl->uBitsPixel, NULL);
2323
2324         if (himl->hbmMask) {
2325             DeleteObject (himl->hbmMask);
2326             himl->hbmMask =
2327                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2328                                 1, 1, NULL);
2329         }
2330     }
2331     else {
2332         /* delete one image */
2333         TRACE("Remove single image! %d\n", i);
2334
2335         /* create new bitmap(s) */
2336         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2337
2338         TRACE(" - Number of images: %d / %d (Old/New)\n",
2339                  himl->cCurImage, himl->cCurImage - 1);
2340         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2341                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2342
2343         hbmNewImage =
2344             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2345
2346         if (himl->hbmMask)
2347             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2348         else
2349             hbmNewMask = 0;  /* Just to keep compiler happy! */
2350
2351         hdcSrc = CreateCompatibleDC (0);
2352         hdcDst = CreateCompatibleDC (0);
2353
2354         /* copy all images and masks prior to the "removed" image */
2355         if (i > 0) {
2356             TRACE("Pre image copy: Copy %d images\n", i);
2357
2358             SelectObject (hdcSrc, himl->hbmImage);
2359             SelectObject (hdcDst, hbmNewImage);
2360             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2361                       hdcSrc, 0, 0, SRCCOPY);
2362
2363             if (himl->hbmMask) {
2364                 SelectObject (hdcSrc, himl->hbmMask);
2365                 SelectObject (hdcDst, hbmNewMask);
2366                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2367                           hdcSrc, 0, 0, SRCCOPY);
2368             }
2369         }
2370
2371         /* copy all images and masks behind the removed image */
2372         if (i < himl->cCurImage - 1) {
2373             TRACE("Post image copy!\n");
2374             SelectObject (hdcSrc, himl->hbmImage);
2375             SelectObject (hdcDst, hbmNewImage);
2376             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2377                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2378
2379             if (himl->hbmMask) {
2380                 SelectObject (hdcSrc, himl->hbmMask);
2381                 SelectObject (hdcDst, hbmNewMask);
2382                 BitBlt (hdcDst, i * himl->cx, 0,
2383                           (himl->cCurImage - i - 1) * himl->cx,
2384                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2385             }
2386         }
2387
2388         DeleteDC (hdcSrc);
2389         DeleteDC (hdcDst);
2390
2391         /* delete old images and insert new ones */
2392         DeleteObject (himl->hbmImage);
2393         himl->hbmImage = hbmNewImage;
2394         if (himl->hbmMask) {
2395             DeleteObject (himl->hbmMask);
2396             himl->hbmMask = hbmNewMask;
2397         }
2398
2399         himl->cCurImage--;
2400         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2401     }
2402
2403     return TRUE;
2404 }
2405
2406
2407 /*************************************************************************
2408  * ImageList_Replace [COMCTL32.70]
2409  *
2410  * Replaces an image in an image list with a new image.
2411  *
2412  * PARAMS
2413  *     himl     [I] handle to image list
2414  *     i        [I] image index
2415  *     hbmImage [I] handle to image bitmap
2416  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2417  *
2418  * RETURNS
2419  *     Success: TRUE
2420  *     Failure: FALSE
2421  */
2422
2423 BOOL WINAPI
2424 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2425                    HBITMAP hbmMask)
2426 {
2427     HDC hdcImageList, hdcImage;
2428     BITMAP bmp;
2429
2430     if (himl == NULL) {
2431         ERR("Invalid image list handle!\n");
2432         return FALSE;
2433     }
2434
2435     if ((i >= himl->cMaxImage) || (i < 0)) {
2436         ERR("Invalid image index!\n");
2437         return FALSE;
2438     }
2439
2440     hdcImageList = CreateCompatibleDC (0);
2441     hdcImage = CreateCompatibleDC (0);
2442     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2443
2444     /* Replace Image */
2445     SelectObject (hdcImageList, himl->hbmImage);
2446     SelectObject (hdcImage, hbmImage);
2447
2448     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2449                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2450
2451     if (himl->hbmMask)
2452     {
2453         /* Replace Mask */
2454         SelectObject (hdcImageList, himl->hbmMask);
2455         SelectObject (hdcImage, hbmMask);
2456
2457         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2458                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2459
2460
2461         /* Remove the background from the image
2462         */
2463         SelectObject (hdcImageList, himl->hbmImage);
2464         StretchBlt (hdcImageList,
2465             i*himl->cx, 0, himl->cx, himl->cy,
2466             hdcImage,
2467             0, 0, bmp.bmWidth, bmp.bmHeight,
2468             0x220326); /* NOTSRCAND */
2469     }
2470
2471     DeleteDC (hdcImage);
2472     DeleteDC (hdcImageList);
2473
2474     return TRUE;
2475 }
2476
2477
2478 /*************************************************************************
2479  * ImageList_ReplaceIcon [COMCTL32.75]
2480  *
2481  * Replaces an image in an image list using an icon.
2482  *
2483  * PARAMS
2484  *     himl  [I] handle to image list
2485  *     i     [I] image index
2486  *     hIcon [I] handle to icon
2487  *
2488  * RETURNS
2489  *     Success: index of the replaced image
2490  *     Failure: -1
2491  */
2492
2493 INT WINAPI
2494 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2495 {
2496     HDC     hdcImageList, hdcImage;
2497     INT     nIndex;
2498     HICON   hBestFitIcon;
2499     HBITMAP hbmOldSrc, hbmOldDst;
2500     ICONINFO  ii;
2501     BITMAP  bmp;
2502
2503     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2504
2505     if (himl == NULL)
2506         return -1;
2507     if ((i >= himl->cMaxImage) || (i < -1))
2508         return -1;
2509
2510     hBestFitIcon = CopyImage(
2511         hIcon, IMAGE_ICON,
2512         himl->cx, himl->cy,
2513         LR_COPYFROMRESOURCE);
2514
2515     GetIconInfo (hBestFitIcon, &ii);
2516     if (ii.hbmMask == 0)
2517         ERR("no mask!\n");
2518     if (ii.hbmColor == 0)
2519         ERR("no color!\n");
2520     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2521
2522     if (i == -1) {
2523         if (himl->cCurImage + 1 > himl->cMaxImage)
2524             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2525
2526         nIndex = himl->cCurImage;
2527         himl->cCurImage++;
2528     }
2529     else
2530         nIndex = i;
2531
2532     hdcImageList = CreateCompatibleDC (0);
2533     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2534     if (hdcImageList == 0)
2535         ERR("invalid hdcImageList!\n");
2536
2537     hdcImage = CreateCompatibleDC (0);
2538     TRACE("hdcImage=0x%x!\n", hdcImage);
2539     if (hdcImage == 0)
2540         ERR("invalid hdcImage!\n");
2541
2542     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2543     SetTextColor( hdcImageList, RGB(0,0,0));
2544     SetBkColor( hdcImageList, RGB(255,255,255));
2545     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2546     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2547                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2548
2549     if (himl->hbmMask) {
2550         SelectObject (hdcImageList, himl->hbmMask);
2551         SelectObject (hdcImage, ii.hbmMask);
2552         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2553                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2554     }
2555
2556     SelectObject (hdcImage, hbmOldSrc);
2557     SelectObject (hdcImageList, hbmOldDst);
2558
2559     if(hBestFitIcon)
2560         DestroyIcon(hBestFitIcon);
2561     if (hdcImageList)
2562         DeleteDC (hdcImageList);
2563     if (hdcImage)
2564         DeleteDC (hdcImage);
2565     if (ii.hbmColor)
2566         DeleteObject (ii.hbmColor);
2567     if (ii.hbmMask)
2568         DeleteObject (ii.hbmMask);
2569
2570     return nIndex;
2571 }
2572
2573
2574 /*************************************************************************
2575  * ImageList_SetBkColor [COMCTL32.76]
2576  *
2577  * Sets the background color of an image list.
2578  *
2579  * PARAMS
2580  *     himl  [I] handle to image list
2581  *     clrBk [I] background color
2582  *
2583  * RETURNS
2584  *     Success: previous background color
2585  *     Failure: CLR_NONE
2586  */
2587
2588 COLORREF WINAPI
2589 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2590 {
2591     COLORREF clrOldBk;
2592
2593     if (himl == NULL)
2594         return CLR_NONE;
2595
2596     clrOldBk = himl->clrBk;
2597     himl->clrBk = clrBk;
2598     return clrOldBk;
2599 }
2600
2601
2602 /*************************************************************************
2603  * ImageList_SetDragCursorImage [COMCTL32.77]
2604  *
2605  * Combines the specified image with the current drag image
2606  *
2607  * PARAMS
2608  *     himlDrag  [I] handle to drag image list
2609  *     iDrag     [I] drag image index
2610  *     dxHotspot [I] X position of the hot spot
2611  *     dyHotspot [I] Y position of the hot spot
2612  *
2613  * RETURNS
2614  *     Success: TRUE
2615  *     Failure: FALSE
2616  *
2617  * NOTES
2618  *     When this function is called and the drag image is visible, a
2619  *     short flickering occurs but this matches the Win9x behavior. It is
2620  *     possible to fix the flickering using code like in ImageList_DragMove.
2621  */
2622
2623 BOOL WINAPI
2624 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2625                               INT dxHotspot, INT dyHotspot)
2626 {
2627     HIMAGELIST himlTemp;
2628     INT dx, dy;
2629     BOOL visible;
2630
2631     if (InternalDrag.himl == NULL)
2632         return FALSE;
2633
2634     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2635            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2636
2637     visible = InternalDrag.bShow;
2638
2639     /* Calculate the offset between the origin of the old image and the
2640      * origin of the second image.
2641      * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2642      * hotspot) to the origin of the second image.
2643      * See M$DN for details */
2644     if(InternalDrag.bHSPending) {
2645         dx = 0;
2646         dy = 0;
2647         InternalDrag.bHSPending = FALSE;
2648     } else {
2649         dx = InternalDrag.dxHotspot - dxHotspot;
2650         dy = InternalDrag.dyHotspot - dyHotspot;
2651     }
2652     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2653
2654     if (visible) {
2655         /* hide the drag image */
2656         ImageList_DragShowNolock(FALSE);
2657     }
2658     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2659            (InternalDrag.himl->cy != himlTemp->cy)) {
2660         /* the size of the drag image changed, invalidate the buffer */
2661         DeleteObject(InternalDrag.hbmBg);
2662         InternalDrag.hbmBg = 0;
2663     }
2664
2665     ImageList_Destroy (InternalDrag.himl);
2666     InternalDrag.himl = himlTemp;
2667
2668     /* update the InternalDragOffset, if the origin of the
2669      * DragImage was changed by ImageList_Merge. */
2670     if (dx <= 0)
2671         InternalDrag.dxHotspot = dxHotspot;
2672     if (dy <= 0)
2673         InternalDrag.dyHotspot = dyHotspot;
2674
2675     if (visible) {
2676         /* show the drag image */
2677         ImageList_DragShowNolock(TRUE);
2678     }
2679
2680     return TRUE;
2681 }
2682
2683
2684 /*************************************************************************
2685  * ImageList_SetFilter [COMCTL32.78]
2686  *
2687  * Sets a filter (or does something completely different)!!???
2688  *
2689  * PARAMS
2690  *     himl     [I] handle to image list
2691  *     i        [I] ???
2692  *     dwFilter [I] ???
2693  *
2694  * RETURNS
2695  *     Success: TRUE ???
2696  *     Failure: FALSE ???
2697  *
2698  * BUGS
2699  *     This is an UNDOCUMENTED function!!!!
2700  *     empty stub.
2701  */
2702
2703 BOOL WINAPI
2704 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2705 {
2706     FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2707            himl, i, dwFilter);
2708
2709     return FALSE;
2710 }
2711
2712
2713 /*************************************************************************
2714  * ImageList_SetFlags [COMCTL32.79]
2715  *
2716  * BUGS
2717  *    Stub.
2718  */
2719
2720 DWORD WINAPI
2721 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2722 {
2723     FIXME("(%p %08lx):empty stub\n", himl, flags);
2724     return 0;
2725 }
2726
2727
2728 /*************************************************************************
2729  * ImageList_SetIconSize [COMCTL32.80]
2730  *
2731  * Sets the image size of the bitmap and deletes all images.
2732  *
2733  * PARAMS
2734  *     himl [I] handle to image list
2735  *     cx   [I] image width
2736  *     cy   [I] image height
2737  *
2738  * RETURNS
2739  *     Success: TRUE
2740  *     Failure: FALSE
2741  */
2742
2743 BOOL WINAPI
2744 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2745 {
2746     INT nCount;
2747
2748     if (!himl)
2749         return FALSE;
2750
2751     /* remove all images */
2752     himl->cMaxImage = himl->cInitial + himl->cGrow;
2753     himl->cCurImage = 0;
2754     himl->cx        = cx;
2755     himl->cy        = cy;
2756
2757     /* initialize overlay mask indices */
2758     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2759         himl->nOvlIdx[nCount] = -1;
2760
2761     DeleteObject (himl->hbmImage);
2762     himl->hbmImage =
2763         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2764                         1, himl->uBitsPixel, NULL);
2765
2766     if (himl->hbmMask) {
2767         DeleteObject (himl->hbmMask);
2768         himl->hbmMask =
2769             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2770                             1, 1, NULL);
2771     }
2772
2773     return TRUE;
2774 }
2775
2776
2777 /*************************************************************************
2778  * ImageList_SetImageCount [COMCTL32.81]
2779  *
2780  * Resizes an image list to the specified number of images.
2781  *
2782  * PARAMS
2783  *     himl        [I] handle to image list
2784  *     iImageCount [I] number of images in the image list
2785  *
2786  * RETURNS
2787  *     Success: TRUE
2788  *     Failure: FALSE
2789  */
2790
2791 BOOL WINAPI
2792 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2793 {
2794     HDC     hdcImageList, hdcBitmap;
2795     HBITMAP hbmNewBitmap;
2796     INT     nNewCount, nCopyCount;
2797
2798     if (!himl)
2799         return FALSE;
2800     if (himl->cCurImage >= iImageCount)
2801         return FALSE;
2802     if (himl->cMaxImage > iImageCount)
2803         return TRUE;
2804
2805     nNewCount = iImageCount + himl->cGrow;
2806     nCopyCount = min(himl->cCurImage, iImageCount);
2807
2808     hdcImageList = CreateCompatibleDC (0);
2809     hdcBitmap = CreateCompatibleDC (0);
2810
2811     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2812                                    1, himl->uBitsPixel, NULL);
2813     if (hbmNewBitmap != 0)
2814     {
2815         SelectObject (hdcImageList, himl->hbmImage);
2816         SelectObject (hdcBitmap, hbmNewBitmap);
2817
2818         /* copy images */
2819         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2820                   hdcImageList, 0, 0, SRCCOPY);
2821 #if 0
2822         /* delete 'empty' image space */
2823         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2824         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2825         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2826                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2827 #endif
2828         DeleteObject (himl->hbmImage);
2829         himl->hbmImage = hbmNewBitmap;
2830     }
2831     else
2832         ERR("Could not create new image bitmap !\n");
2833
2834     if (himl->hbmMask)
2835     {
2836         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2837                                        1, 1, NULL);
2838         if (hbmNewBitmap != 0)
2839         {
2840             SelectObject (hdcImageList, himl->hbmMask);
2841             SelectObject (hdcBitmap, hbmNewBitmap);
2842
2843             /* copy images */
2844             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2845                       hdcImageList, 0, 0, SRCCOPY);
2846 #if 0
2847             /* delete 'empty' image space */
2848             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2849             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2850             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0,
2851                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2852 #endif
2853             DeleteObject (himl->hbmMask);
2854             himl->hbmMask = hbmNewBitmap;
2855         }
2856         else
2857             ERR("Could not create new mask bitmap!\n");
2858     }
2859
2860     DeleteDC (hdcImageList);
2861     DeleteDC (hdcBitmap);
2862
2863     /* Update max image count and current image count */
2864     himl->cMaxImage = nNewCount;
2865     if (himl->cCurImage > nCopyCount)
2866         himl->cCurImage = nCopyCount;
2867
2868     return TRUE;
2869 }
2870
2871
2872 /*************************************************************************
2873  * ImageList_SetOverlayImage [COMCTL32.82]
2874  *
2875  * Assigns an overlay mask index to an existing image in an image list.
2876  *
2877  * PARAMS
2878  *     himl     [I] handle to image list
2879  *     iImage   [I] image index
2880  *     iOverlay [I] overlay mask index
2881  *
2882  * RETURNS
2883  *     Success: TRUE
2884  *     Failure: FALSE
2885  */
2886
2887 BOOL WINAPI
2888 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2889 {
2890     if (!himl)
2891         return FALSE;
2892     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2893         return FALSE;
2894     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2895         return FALSE;
2896     himl->nOvlIdx[iOverlay - 1] = iImage;
2897     return TRUE;
2898 }
2899
2900
2901
2902 /* helper for ImageList_Write - write bitmap to pstm
2903  * currently everything is written as 24 bit RGB, except masks
2904  */
2905 static BOOL
2906 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2907 {
2908     LPBITMAPFILEHEADER bmfh;
2909     LPBITMAPINFOHEADER bmih;
2910     LPBYTE data, lpBits, lpBitsOrg;
2911     BITMAP bm;
2912     INT bitCount, sizeImage, offBits, totalSize;
2913     INT nwidth, nheight, nsizeImage, icount;
2914     HDC xdc;
2915     BOOL result = FALSE;
2916
2917
2918     xdc = GetDC(0);
2919     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2920
2921     /* XXX is this always correct? */
2922     icount = bm.bmWidth / cx;
2923     nwidth = cx << 2;
2924     nheight = cy * ((icount+3)>>2);
2925
2926     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2927     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2928     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2929
2930     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2931     if(bitCount != 24)
2932         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2933     offBits = totalSize;
2934     totalSize += nsizeImage;
2935
2936     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2937     bmfh = (LPBITMAPFILEHEADER)data;
2938     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2939     lpBits = data + offBits;
2940
2941     /* setup BITMAPFILEHEADER */
2942     bmfh->bfType      = (('M' << 8) | 'B');
2943     bmfh->bfSize      = 0;
2944     bmfh->bfReserved1 = 0;
2945     bmfh->bfReserved2 = 0;
2946     bmfh->bfOffBits   = offBits;
2947
2948     /* setup BITMAPINFOHEADER */
2949     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2950     bmih->biWidth         = bm.bmWidth;
2951     bmih->biHeight        = bm.bmHeight;
2952     bmih->biPlanes        = 1;
2953     bmih->biBitCount      = bitCount;
2954     bmih->biCompression   = BI_RGB;
2955     bmih->biSizeImage     = nsizeImage;
2956     bmih->biXPelsPerMeter = 0;
2957     bmih->biYPelsPerMeter = 0;
2958     bmih->biClrUsed       = 0;
2959     bmih->biClrImportant  = 0;
2960
2961     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2962     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2963                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2964         goto failed;
2965     else {
2966         int i;
2967         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2968         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2969
2970         for(i = 0; i < nheight; i++) {
2971             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2972             int noff = (nbpl * (nheight-1-i));
2973             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2974         }
2975     }
2976
2977     bmih->biWidth  = nwidth;
2978     bmih->biHeight = nheight;
2979
2980     if(bitCount == 1) {
2981         /* Hack. */
2982         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2983         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2984         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2985     }
2986
2987     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2988         goto failed;
2989
2990     result = TRUE;
2991
2992     failed:
2993     ReleaseDC(0, xdc);
2994     LocalFree((HLOCAL)lpBitsOrg);
2995
2996     return result;
2997 }
2998
2999
3000 /*************************************************************************
3001  * ImageList_Write [COMCTL32.83]
3002  *
3003  * Writes an image list to a stream.
3004  *
3005  * PARAMS
3006  *     himl [I] handle to image list
3007  *     pstm [O] Pointer to a stream.
3008  *
3009  * RETURNS
3010  *     Success: TRUE
3011  *     Failure: FALSE
3012  *
3013  * BUGS
3014  *     probably.
3015  */
3016
3017 BOOL WINAPI
3018 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3019 {
3020     ILHEAD ilHead;
3021     int i;
3022
3023     if (!himl)
3024         return FALSE;
3025
3026     ilHead.usMagic   = (('L' << 8) | 'I');
3027     ilHead.usVersion = 0x101;
3028     ilHead.cCurImage = himl->cCurImage;
3029     ilHead.cMaxImage = himl->cMaxImage;
3030     ilHead.cGrow     = himl->cGrow;
3031     ilHead.cx        = himl->cx;
3032     ilHead.cy        = himl->cy;
3033     ilHead.bkcolor   = himl->clrBk;
3034     ilHead.flags     = himl->flags;
3035     for(i = 0; i < 4; i++) {
3036         ilHead.ovls[i] = himl->nOvlIdx[i];
3037     }
3038
3039     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3040         return FALSE;
3041
3042     /* write the bitmap */
3043     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3044         return FALSE;
3045
3046     /* write the mask if we have one */
3047     if(himl->flags & ILC_MASK) {
3048         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
3049             return FALSE;
3050     }
3051
3052     return TRUE;
3053 }
3054