Removed most inclusions of options.h.
[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         nImageCount = bmp.bmWidth / cx;
1911
1912         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1913                                  nImageCount, cGrow);
1914         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1915     }
1916     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1917         ICONINFO ii;
1918         BITMAP bmp;
1919
1920         GetIconInfo (handle, &ii);
1921         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1922         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
1923                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1924         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1925         DeleteObject (ii.hbmColor);
1926         DeleteObject (ii.hbmMask);
1927     }
1928
1929     DeleteObject (handle);
1930     
1931     return himl;
1932 }
1933
1934
1935 /*************************************************************************
1936  * ImageList_Merge [COMCTL32.67] 
1937  *
1938  * Creates a new image list that contains a merged image from the specified
1939  * images of both source image lists.
1940  *
1941  * PARAMS
1942  *     himl1 [I] handle to first image list
1943  *     i1    [I] first image index
1944  *     himl2 [I] handle to second image list
1945  *     i2    [I] second image index
1946  *     dx    [I] X offset of the second image relative to the first.
1947  *     dy    [I] Y offset of the second image relative to the first.
1948  *
1949  * RETURNS
1950  *     Success: handle of the merged image list.
1951  *     Failure: NULL
1952  */
1953
1954 HIMAGELIST WINAPI
1955 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1956                  INT dx, INT dy)
1957 {
1958     HIMAGELIST himlDst = NULL;
1959     HDC      hdcSrcImage, hdcDstImage;
1960     INT      cxDst, cyDst;
1961     INT      xOff1, yOff1, xOff2, yOff2;
1962     INT      nX1, nX2;
1963
1964     TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1965            i2, dx, dy);
1966
1967     if ((himl1 == NULL) || (himl2 == NULL))
1968         return NULL;
1969
1970     /* check indices */
1971     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1972         ERR("Index 1 out of range! %d\n", i1);
1973         return NULL;
1974     }
1975
1976     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1977         ERR("Index 2 out of range! %d\n", i2);
1978         return NULL;
1979     }
1980
1981     if (dx > 0) {
1982         cxDst = max (himl1->cx, dx + himl2->cx);
1983         xOff1 = 0;
1984         xOff2 = dx;
1985     }
1986     else if (dx < 0) {
1987         cxDst = max (himl2->cx, himl1->cx - dx);
1988         xOff1 = -dx;
1989         xOff2 = 0;
1990     }
1991     else {
1992         cxDst = max (himl1->cx, himl2->cx);
1993         xOff1 = 0;
1994         xOff2 = 0;
1995     }
1996
1997     if (dy > 0) {
1998         cyDst = max (himl1->cy, dy + himl2->cy);
1999         yOff1 = 0;
2000         yOff2 = dy;
2001     }
2002     else if (dy < 0) {
2003         cyDst = max (himl2->cy, himl1->cy - dy);
2004         yOff1 = -dy;
2005         yOff2 = 0;
2006     }
2007     else {
2008         cyDst = max (himl1->cy, himl2->cy);
2009         yOff1 = 0;
2010         yOff2 = 0;
2011     }
2012
2013     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
2014
2015     if (himlDst) {
2016         hdcSrcImage = CreateCompatibleDC (0);
2017         hdcDstImage = CreateCompatibleDC (0);
2018         nX1 = i1 * himl1->cx;
2019         nX2 = i2 * himl2->cx;
2020         
2021         /* copy image */
2022         SelectObject (hdcSrcImage, himl1->hbmImage);
2023         SelectObject (hdcDstImage, himlDst->hbmImage);
2024         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
2025                   hdcSrcImage, 0, 0, BLACKNESS);
2026         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
2027                   hdcSrcImage, nX1, 0, SRCCOPY);
2028
2029         SelectObject (hdcSrcImage, himl2->hbmMask);
2030         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
2031                   hdcSrcImage, nX2, 0, SRCAND);
2032
2033         SelectObject (hdcSrcImage, himl2->hbmImage);
2034         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
2035                   hdcSrcImage, nX2, 0, SRCPAINT);
2036
2037         /* copy mask */
2038         SelectObject (hdcSrcImage, himl1->hbmMask);
2039         SelectObject (hdcDstImage, himlDst->hbmMask);
2040         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
2041                   hdcSrcImage, 0, 0, WHITENESS);
2042         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
2043                   hdcSrcImage, nX1, 0, SRCCOPY);
2044
2045         SelectObject (hdcSrcImage, himl2->hbmMask);
2046         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
2047                   hdcSrcImage, nX2, 0, SRCAND);
2048
2049         DeleteDC (hdcSrcImage);
2050         DeleteDC (hdcDstImage);
2051         himlDst->cCurImage = 1;
2052     }
2053    
2054     return himlDst;
2055 }
2056
2057
2058 /* helper for _read_bitmap currently unused */
2059 #if 0
2060 static int may_use_dibsection(HDC hdc) {
2061     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2062     if (bitspixel>8)
2063         return TRUE;
2064     if (bitspixel<=4)
2065         return FALSE;
2066     return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2067 }
2068 #endif
2069
2070 /* helper for ImageList_Read, see comments below */
2071 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2072     HDC                 xdc = 0;
2073     BITMAPFILEHEADER    bmfh;
2074     BITMAPINFOHEADER    bmih;
2075     int                 bitsperpixel,palspace,longsperline,width,height;
2076     LPBITMAPINFOHEADER  bmihc = NULL;
2077     int                 result = 0;
2078     HBITMAP             hbitmap = 0;
2079     LPBYTE              bits = NULL,nbits = NULL;
2080     int                 nbytesperline,bytesperline;
2081
2082     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
2083         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
2084         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
2085         (bmih.biSize != sizeof(bmih))
2086     )
2087         return 0;
2088
2089     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2090     if (bitsperpixel<=8)
2091         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2092     else
2093         palspace = 0;
2094     width = bmih.biWidth;
2095     height = bmih.biHeight;
2096     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2097     memcpy(bmihc,&bmih,sizeof(bmih));
2098     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
2099     bmihc->biSizeImage  = (longsperline*height)<<2;
2100
2101     /* read the palette right after the end of the bitmapinfoheader */
2102     if (palspace)
2103         if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2104             goto ret1;
2105
2106     xdc = GetDC(0);
2107 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2108     if ((bitsperpixel>1) &&
2109         ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2110      ) {
2111         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2112         if (!hbitmap)
2113             goto ret1;
2114         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2115             goto ret1;
2116         result = 1;
2117     } else
2118 #endif
2119     {
2120         int i,nwidth,nheight;
2121
2122         nwidth  = width*(height/cy);
2123         nheight = cy;
2124
2125         if (bitsperpixel==1)
2126             hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2127         else
2128             hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2129
2130         /* Might be a bit excessive memory use here */
2131         bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2132         nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2133         if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2134                 goto ret1;
2135
2136         /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2137         /* Do not forget that windows bitmaps are bottom->top */
2138         bytesperline    = longsperline*4;
2139         nbytesperline   = (height/cy)*bytesperline;
2140         for (i=0;i<height;i++) {
2141             memcpy(
2142                 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2143                 bits+bytesperline*(height-1-i),
2144                 bytesperline
2145             );
2146         }
2147         bmihc->biWidth  = nwidth;
2148         bmihc->biHeight = nheight;
2149         if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2150                 goto ret1;
2151         LocalFree((HLOCAL)nbits);
2152         LocalFree((HLOCAL)bits);
2153         result = 1;
2154     }
2155 ret1:
2156     if (xdc)    ReleaseDC(0,xdc);
2157     if (bmihc)  LocalFree((HLOCAL)bmihc);
2158     if (!result) {
2159         if (hbitmap) {
2160             DeleteObject(hbitmap);
2161             hbitmap = 0;
2162         }
2163     }
2164     return hbitmap;
2165 }
2166
2167 /*************************************************************************
2168  * ImageList_Read [COMCTL32.68]
2169  *
2170  * Reads an image list from a stream.
2171  *
2172  * PARAMS
2173  *     pstm [I] pointer to a stream
2174  *
2175  * RETURNS
2176  *     Success: handle to image list
2177  *     Failure: NULL
2178  *
2179  * The format is like this:
2180  *      ILHEAD                  ilheadstruct;
2181  *
2182  * for the color image part:
2183  *      BITMAPFILEHEADER        bmfh; 
2184  *      BITMAPINFOHEADER        bmih;
2185  * only if it has a palette:
2186  *      RGBQUAD         rgbs[nr_of_paletted_colors]; 
2187  *
2188  *      BYTE                    colorbits[imagesize];
2189  *
2190  * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2191  *      BITMAPFILEHEADER        bmfh_mask;
2192  *      BITMAPINFOHEADER        bmih_mask;
2193  * only if it has a palette (it usually does not):
2194  *      RGBQUAD         rgbs[nr_of_paletted_colors]; 
2195  *
2196  *      BYTE                    maskbits[imagesize];
2197  *
2198  * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2199  *         _read_bitmap needs to convert them.
2200  */
2201 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2202 {
2203     ILHEAD      ilHead;
2204     HIMAGELIST  himl;
2205     HBITMAP     hbmColor=0,hbmMask=0;
2206     int         i;
2207
2208     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2209         return NULL;
2210     if (ilHead.usMagic != (('L' << 8) | 'I'))
2211         return NULL;
2212     if (ilHead.usVersion != 0x101) /* probably version? */
2213         return NULL;
2214
2215 #if 0
2216     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
2217     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2218     FIXME("     ilHead.cGrow = %d\n",ilHead.cGrow);
2219     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2220     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2221     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2222     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2223     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2224     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2225     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2226 #endif
2227
2228     hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2229     if (!hbmColor)
2230         return NULL;
2231     if (ilHead.flags & ILC_MASK) {
2232         hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2233         if (!hbmMask) {
2234             DeleteObject(hbmColor);
2235             return NULL;
2236         }
2237     }
2238
2239     himl = ImageList_Create (
2240                     ilHead.cx,
2241                     ilHead.cy,
2242                     ilHead.flags,
2243                     1,          /* initial */
2244                     ilHead.cGrow
2245     );
2246     if (!himl) {
2247         DeleteObject(hbmColor);
2248         DeleteObject(hbmMask);
2249         return NULL;
2250     }
2251     himl->hbmImage = hbmColor;
2252     himl->hbmMask = hbmMask;
2253     himl->cCurImage = ilHead.cCurImage;
2254     himl->cMaxImage = ilHead.cMaxImage;
2255
2256     ImageList_SetBkColor(himl,ilHead.bkcolor);
2257     for (i=0;i<4;i++)
2258         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2259     return himl;
2260 }
2261
2262
2263 /*************************************************************************
2264  * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2265  *
2266  * PARAMS
2267  *     himl [I] image list handle
2268  *     i    [I] image index
2269  *
2270  * RETURNS
2271  *     Success: TRUE
2272  *     Failure: FALSE
2273  */
2274
2275 BOOL WINAPI
2276 ImageList_Remove (HIMAGELIST himl, INT i)
2277 {
2278     HBITMAP hbmNewImage, hbmNewMask;
2279     HDC     hdcSrc, hdcDst;
2280     INT     cxNew, nCount;
2281
2282     if (himl == NULL) {
2283         ERR("Invalid image list handle!\n");
2284         return FALSE;
2285     }
2286     
2287     if ((i < -1) || (i >= himl->cCurImage)) {
2288         ERR("index out of range! %d\n", i);
2289         return FALSE;
2290     }
2291
2292     if (himl->cCurImage == 0) {
2293         ERR("image list is already empty!\n");
2294         return FALSE;
2295     }
2296
2297     if (i == -1) {
2298         /* remove all */
2299         TRACE("remove all!\n");
2300
2301         himl->cMaxImage = himl->cInitial + himl->cGrow;
2302         himl->cCurImage = 0;
2303         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2304              himl->nOvlIdx[nCount] = -1;
2305
2306         DeleteObject (himl->hbmImage);
2307         himl->hbmImage =
2308             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2309                             1, himl->uBitsPixel, NULL);
2310
2311         if (himl->hbmMask) {
2312             DeleteObject (himl->hbmMask);
2313             himl->hbmMask =
2314                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2315                                 1, 1, NULL);
2316         }
2317     }
2318     else {
2319         /* delete one image */
2320         TRACE("Remove single image! %d\n", i);
2321
2322         /* create new bitmap(s) */
2323         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2324
2325         TRACE(" - Number of images: %d / %d (Old/New)\n",
2326                  himl->cCurImage, himl->cCurImage - 1);
2327         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2328                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2329         
2330         hbmNewImage =
2331             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2332
2333         if (himl->hbmMask)
2334             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2335         else
2336             hbmNewMask = 0;  /* Just to keep compiler happy! */
2337
2338         hdcSrc = CreateCompatibleDC (0);
2339         hdcDst = CreateCompatibleDC (0);
2340
2341         /* copy all images and masks prior to the "removed" image */
2342         if (i > 0) {
2343             TRACE("Pre image copy: Copy %d images\n", i);
2344        
2345             SelectObject (hdcSrc, himl->hbmImage);
2346             SelectObject (hdcDst, hbmNewImage);
2347             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2348                       hdcSrc, 0, 0, SRCCOPY);
2349
2350             if (himl->hbmMask) {
2351                 SelectObject (hdcSrc, himl->hbmMask);
2352                 SelectObject (hdcDst, hbmNewMask);
2353                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2354                           hdcSrc, 0, 0, SRCCOPY);
2355             }
2356         }
2357
2358         /* copy all images and masks behind the removed image */
2359         if (i < himl->cCurImage - 1) {
2360             TRACE("Post image copy!\n");
2361             SelectObject (hdcSrc, himl->hbmImage);
2362             SelectObject (hdcDst, hbmNewImage);
2363             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2364                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2365
2366             if (himl->hbmMask) {
2367                 SelectObject (hdcSrc, himl->hbmMask);
2368                 SelectObject (hdcDst, hbmNewMask);
2369                 BitBlt (hdcDst, i * himl->cx, 0,
2370                           (himl->cCurImage - i - 1) * himl->cx,
2371                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2372             }
2373         }
2374
2375         DeleteDC (hdcSrc);
2376         DeleteDC (hdcDst);
2377
2378         /* delete old images and insert new ones */
2379         DeleteObject (himl->hbmImage);
2380         himl->hbmImage = hbmNewImage;
2381         if (himl->hbmMask) {
2382             DeleteObject (himl->hbmMask);
2383             himl->hbmMask = hbmNewMask;
2384         }
2385
2386         himl->cCurImage--;
2387         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2388     }
2389
2390     return TRUE;
2391 }
2392
2393
2394 /*************************************************************************
2395  * ImageList_Replace [COMCTL32.70] 
2396  *
2397  * Replaces an image in an image list with a new image.
2398  *
2399  * PARAMS
2400  *     himl     [I] handle to image list
2401  *     i        [I] image index
2402  *     hbmImage [I] handle to image bitmap
2403  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2404  *
2405  * RETURNS
2406  *     Success: TRUE
2407  *     Failure: FALSE
2408  */
2409
2410 BOOL WINAPI
2411 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2412                    HBITMAP hbmMask)
2413 {
2414     HDC hdcImageList, hdcImage;
2415     BITMAP bmp;
2416
2417     if (himl == NULL) {
2418         ERR("Invalid image list handle!\n");
2419         return FALSE;
2420     }
2421     
2422     if ((i >= himl->cMaxImage) || (i < 0)) {
2423         ERR("Invalid image index!\n");
2424         return FALSE;
2425     }
2426
2427     hdcImageList = CreateCompatibleDC (0);
2428     hdcImage = CreateCompatibleDC (0);
2429     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2430
2431     /* Replace Image */
2432     SelectObject (hdcImageList, himl->hbmImage);
2433     SelectObject (hdcImage, hbmImage);
2434
2435     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2436                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2437
2438     if (himl->hbmMask)
2439     {
2440         /* Replace Mask */
2441         SelectObject (hdcImageList, himl->hbmMask);
2442         SelectObject (hdcImage, hbmMask);
2443
2444         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2445                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2446
2447
2448         /* Remove the background from the image
2449         */
2450         SelectObject (hdcImageList, himl->hbmImage);
2451         StretchBlt (hdcImageList, 
2452             i*himl->cx, 0, himl->cx, himl->cy,
2453             hdcImage, 
2454             0, 0, bmp.bmWidth, bmp.bmHeight, 
2455             0x220326); /* NOTSRCAND */
2456     }
2457
2458     DeleteDC (hdcImage);
2459     DeleteDC (hdcImageList);
2460
2461     return TRUE;
2462 }
2463
2464
2465 /*************************************************************************
2466  * ImageList_ReplaceIcon [COMCTL32.75]
2467  *
2468  * Replaces an image in an image list using an icon.
2469  *
2470  * PARAMS
2471  *     himl  [I] handle to image list
2472  *     i     [I] image index
2473  *     hIcon [I] handle to icon
2474  *
2475  * RETURNS
2476  *     Success: index of the replaced image
2477  *     Failure: -1
2478  */
2479
2480 INT WINAPI
2481 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2482 {
2483     HDC     hdcImageList, hdcImage;
2484     INT     nIndex;
2485     HICON   hBestFitIcon;
2486     HBITMAP hbmOldSrc, hbmOldDst;
2487     ICONINFO  ii;
2488     BITMAP  bmp;
2489
2490     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2491
2492     if (himl == NULL)
2493         return -1;
2494     if ((i >= himl->cMaxImage) || (i < -1))
2495         return -1;
2496
2497     hBestFitIcon = CopyImage(
2498         hIcon, IMAGE_ICON, 
2499         himl->cx, himl->cy, 
2500         LR_COPYFROMRESOURCE);
2501
2502     GetIconInfo (hBestFitIcon, &ii);
2503     if (ii.hbmMask == 0)
2504         ERR("no mask!\n");
2505     if (ii.hbmColor == 0)
2506         ERR("no color!\n");
2507     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2508
2509     if (i == -1) {
2510         if (himl->cCurImage + 1 > himl->cMaxImage)
2511             IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2512
2513         nIndex = himl->cCurImage;
2514         himl->cCurImage++;
2515     }
2516     else
2517         nIndex = i;
2518
2519     hdcImageList = CreateCompatibleDC (0);
2520     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2521     if (hdcImageList == 0)
2522         ERR("invalid hdcImageList!\n");
2523
2524     hdcImage = CreateCompatibleDC (0);
2525     TRACE("hdcImage=0x%x!\n", hdcImage);
2526     if (hdcImage == 0)
2527         ERR("invalid hdcImage!\n");
2528
2529     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2530     SetTextColor( hdcImageList, RGB(0,0,0));
2531     SetBkColor( hdcImageList, RGB(255,255,255));
2532     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2533     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2534                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2535
2536     if (himl->hbmMask) {
2537         SelectObject (hdcImageList, himl->hbmMask);
2538         SelectObject (hdcImage, ii.hbmMask);
2539         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2540                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2541     }
2542
2543     SelectObject (hdcImage, hbmOldSrc);
2544     SelectObject (hdcImageList, hbmOldDst);
2545
2546     if(hBestFitIcon)
2547         DestroyIcon(hBestFitIcon);
2548     if (hdcImageList)
2549         DeleteDC (hdcImageList);
2550     if (hdcImage)
2551         DeleteDC (hdcImage);
2552     if (ii.hbmColor)
2553         DeleteObject (ii.hbmColor);
2554     if (ii.hbmMask)
2555         DeleteObject (ii.hbmMask);
2556
2557     return nIndex;
2558 }
2559
2560
2561 /*************************************************************************
2562  * ImageList_SetBkColor [COMCTL32.76] 
2563  *
2564  * Sets the background color of an image list.
2565  *
2566  * PARAMS
2567  *     himl  [I] handle to image list
2568  *     clrBk [I] background color
2569  *
2570  * RETURNS
2571  *     Success: previous background color
2572  *     Failure: CLR_NONE
2573  */
2574
2575 COLORREF WINAPI
2576 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2577 {
2578     COLORREF clrOldBk;
2579
2580     if (himl == NULL)
2581         return CLR_NONE;
2582
2583     clrOldBk = himl->clrBk;
2584     himl->clrBk = clrBk;
2585     return clrOldBk;
2586 }
2587
2588
2589 /*************************************************************************
2590  * ImageList_SetDragCursorImage [COMCTL32.77]
2591  *
2592  * Combines the specified image with the current drag image
2593  *
2594  * PARAMS
2595  *     himlDrag  [I] handle to drag image list
2596  *     iDrag     [I] drag image index
2597  *     dxHotspot [I] X position of the hot spot
2598  *     dyHotspot [I] Y position of the hot spot
2599  *
2600  * RETURNS
2601  *     Success: TRUE
2602  *     Failure: FALSE
2603  *
2604  * NOTES
2605  *     When this function is called and the drag image is visible, a
2606  *     short flickering occurs but this matches the Win9x behavior. It is
2607  *     possible to fix the flickering using code like in ImageList_DragMove.
2608  */
2609
2610 BOOL WINAPI
2611 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2612                               INT dxHotspot, INT dyHotspot)
2613 {
2614     HIMAGELIST himlTemp;
2615     INT dx, dy;
2616     BOOL visible;
2617
2618     if (InternalDrag.himl == NULL)
2619         return FALSE;
2620
2621     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2622            dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2623
2624     visible = InternalDrag.bShow;
2625
2626     /* Calculate the offset between the origin of the old image and the
2627      * origin of the second image.
2628      * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2629      * hotspot) to the origin of the second image.
2630      * See M$DN for details */
2631     if(InternalDrag.bHSPending) {
2632         dx = 0;
2633         dy = 0;
2634         InternalDrag.bHSPending = FALSE;
2635     } else {
2636         dx = InternalDrag.dxHotspot - dxHotspot;
2637         dy = InternalDrag.dyHotspot - dyHotspot;
2638     }
2639     himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2640
2641     if (visible) {
2642         /* hide the drag image */
2643         ImageList_DragShowNolock(FALSE);
2644     }
2645     if ((InternalDrag.himl->cx != himlTemp->cx) ||
2646            (InternalDrag.himl->cy != himlTemp->cy)) {
2647         /* the size of the drag image changed, invalidate the buffer */
2648         DeleteObject(InternalDrag.hbmBg);
2649         InternalDrag.hbmBg = 0;
2650     }
2651
2652     ImageList_Destroy (InternalDrag.himl);
2653     InternalDrag.himl = himlTemp;
2654
2655     /* update the InternalDragOffset, if the origin of the
2656      * DragImage was changed by ImageList_Merge. */
2657     if (dx <= 0)
2658         InternalDrag.dxHotspot = dxHotspot;
2659     if (dy <= 0)
2660         InternalDrag.dyHotspot = dyHotspot;
2661
2662     if (visible) {
2663         /* show the drag image */
2664         ImageList_DragShowNolock(TRUE);
2665     }
2666
2667     return TRUE;
2668 }
2669
2670
2671 /*************************************************************************
2672  * ImageList_SetFilter [COMCTL32.78] 
2673  *
2674  * Sets a filter (or does something completely different)!!???
2675  *
2676  * PARAMS
2677  *     himl     [I] handle to image list
2678  *     i        [I] ???
2679  *     dwFilter [I] ???
2680  *
2681  * RETURNS
2682  *     Success: TRUE ???
2683  *     Failure: FALSE ???
2684  *
2685  * BUGS
2686  *     This is an UNDOCUMENTED function!!!!
2687  *     empty stub.
2688  */
2689
2690 BOOL WINAPI
2691 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2692 {
2693     FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2694            himl, i, dwFilter);
2695
2696     return FALSE;
2697 }
2698
2699
2700 /*************************************************************************
2701  * ImageList_SetFlags [COMCTL32.79]
2702  *
2703  * BUGS
2704  *    Stub.
2705  */
2706
2707 DWORD WINAPI
2708 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2709 {
2710     FIXME("(%p %08lx):empty stub\n", himl, flags);
2711     return 0;
2712 }
2713
2714
2715 /*************************************************************************
2716  * ImageList_SetIconSize [COMCTL32.80]
2717  *
2718  * Sets the image size of the bitmap and deletes all images.
2719  *
2720  * PARAMS
2721  *     himl [I] handle to image list
2722  *     cx   [I] image width
2723  *     cy   [I] image height
2724  *
2725  * RETURNS
2726  *     Success: TRUE
2727  *     Failure: FALSE
2728  */
2729
2730 BOOL WINAPI
2731 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2732 {
2733     INT nCount;
2734
2735     if (!himl)
2736         return FALSE;
2737
2738     /* remove all images */
2739     himl->cMaxImage = himl->cInitial + himl->cGrow;
2740     himl->cCurImage = 0;
2741     himl->cx        = cx;
2742     himl->cy        = cy;
2743
2744     /* initialize overlay mask indices */
2745     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2746         himl->nOvlIdx[nCount] = -1;
2747
2748     DeleteObject (himl->hbmImage);
2749     himl->hbmImage =
2750         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2751                         1, himl->uBitsPixel, NULL);
2752
2753     if (himl->hbmMask) {
2754         DeleteObject (himl->hbmMask);
2755         himl->hbmMask =
2756             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2757                             1, 1, NULL);
2758     }
2759
2760     return TRUE;
2761 }
2762
2763
2764 /*************************************************************************
2765  * ImageList_SetImageCount [COMCTL32.81]
2766  *
2767  * Resizes an image list to the specified number of images.
2768  *
2769  * PARAMS
2770  *     himl        [I] handle to image list
2771  *     iImageCount [I] number of images in the image list
2772  *
2773  * RETURNS
2774  *     Success: TRUE
2775  *     Failure: FALSE
2776  */
2777
2778 BOOL WINAPI
2779 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2780 {
2781     HDC     hdcImageList, hdcBitmap;
2782     HBITMAP hbmNewBitmap;
2783     INT     nNewCount, nCopyCount;
2784
2785     if (!himl)
2786         return FALSE;
2787     if (himl->cCurImage >= iImageCount)
2788         return FALSE;
2789     if (himl->cMaxImage > iImageCount)
2790         return TRUE;
2791
2792     nNewCount = iImageCount + himl->cGrow;
2793     nCopyCount = min(himl->cCurImage, iImageCount);
2794
2795     hdcImageList = CreateCompatibleDC (0);
2796     hdcBitmap = CreateCompatibleDC (0);
2797
2798     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2799                                    1, himl->uBitsPixel, NULL);
2800     if (hbmNewBitmap != 0)
2801     {
2802         SelectObject (hdcImageList, himl->hbmImage);
2803         SelectObject (hdcBitmap, hbmNewBitmap);
2804
2805         /* copy images */
2806         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2807                   hdcImageList, 0, 0, SRCCOPY);
2808 #if 0
2809         /* delete 'empty' image space */
2810         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2811         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2812         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2813                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2814 #endif
2815         DeleteObject (himl->hbmImage);
2816         himl->hbmImage = hbmNewBitmap;
2817     }
2818     else
2819         ERR("Could not create new image bitmap !\n");
2820
2821     if (himl->hbmMask)
2822     {
2823         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2824                                        1, 1, NULL);
2825         if (hbmNewBitmap != 0)
2826         {
2827             SelectObject (hdcImageList, himl->hbmMask);
2828             SelectObject (hdcBitmap, hbmNewBitmap);
2829
2830             /* copy images */
2831             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2832                       hdcImageList, 0, 0, SRCCOPY);
2833 #if 0
2834             /* delete 'empty' image space */
2835             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2836             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2837             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2838                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2839 #endif
2840             DeleteObject (himl->hbmMask);
2841             himl->hbmMask = hbmNewBitmap;
2842         }
2843         else
2844             ERR("Could not create new mask bitmap!\n");
2845     }
2846
2847     DeleteDC (hdcImageList);
2848     DeleteDC (hdcBitmap);
2849
2850     /* Update max image count and current image count */
2851     himl->cMaxImage = nNewCount;
2852     if (himl->cCurImage > nCopyCount)
2853         himl->cCurImage = nCopyCount;
2854
2855     return TRUE;
2856 }
2857
2858
2859 /*************************************************************************
2860  * ImageList_SetOverlayImage [COMCTL32.82]
2861  *
2862  * Assigns an overlay mask index to an existing image in an image list.
2863  *
2864  * PARAMS
2865  *     himl     [I] handle to image list
2866  *     iImage   [I] image index
2867  *     iOverlay [I] overlay mask index
2868  *
2869  * RETURNS
2870  *     Success: TRUE
2871  *     Failure: FALSE
2872  */
2873
2874 BOOL WINAPI
2875 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2876 {
2877     if (!himl)
2878         return FALSE;
2879     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2880         return FALSE;
2881     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2882         return FALSE;
2883     himl->nOvlIdx[iOverlay - 1] = iImage;
2884     return TRUE;
2885 }
2886
2887
2888
2889 /* helper for ImageList_Write - write bitmap to pstm 
2890  * currently everything is written as 24 bit RGB, except masks
2891  */
2892 static BOOL 
2893 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2894 {
2895     LPBITMAPFILEHEADER bmfh;
2896     LPBITMAPINFOHEADER bmih;
2897     LPBYTE data, lpBits, lpBitsOrg;
2898     BITMAP bm;
2899     INT bitCount, sizeImage, offBits, totalSize;
2900     INT nwidth, nheight, nsizeImage, icount;
2901     HDC xdc;
2902     BOOL result = FALSE;
2903
2904
2905     xdc = GetDC(0);
2906     GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2907     
2908     /* XXX is this always correct? */
2909     icount = bm.bmWidth / cx;
2910     nwidth = cx << 2;
2911     nheight = cy * ((icount+3)>>2);
2912
2913     bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2914     sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2915     nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2916
2917     totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2918     if(bitCount != 24)
2919         totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2920     offBits = totalSize;
2921     totalSize += nsizeImage;
2922
2923     data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2924     bmfh = (LPBITMAPFILEHEADER)data;
2925     bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2926     lpBits = data + offBits;
2927
2928     /* setup BITMAPFILEHEADER */
2929     bmfh->bfType      = (('M' << 8) | 'B');
2930     bmfh->bfSize      = 0;
2931     bmfh->bfReserved1 = 0;
2932     bmfh->bfReserved2 = 0;
2933     bmfh->bfOffBits   = offBits;
2934
2935     /* setup BITMAPINFOHEADER */
2936     bmih->biSize          = sizeof(BITMAPINFOHEADER);
2937     bmih->biWidth         = bm.bmWidth;
2938     bmih->biHeight        = bm.bmHeight;
2939     bmih->biPlanes        = 1;
2940     bmih->biBitCount      = bitCount;
2941     bmih->biCompression   = BI_RGB;
2942     bmih->biSizeImage     = nsizeImage;
2943     bmih->biXPelsPerMeter = 0;
2944     bmih->biYPelsPerMeter = 0;
2945     bmih->biClrUsed       = 0;
2946     bmih->biClrImportant  = 0;
2947
2948     lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2949     if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg, 
2950                   (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2951         goto failed;
2952     else {
2953         int i;
2954         int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2955         int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2956                 
2957         for(i = 0; i < nheight; i++) {
2958             int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2959             int noff = (nbpl * (nheight-1-i));
2960             memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2961         }
2962     }
2963     
2964     bmih->biWidth  = nwidth;
2965     bmih->biHeight = nheight;
2966
2967     if(bitCount == 1) {
2968         /* Hack. */
2969         LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2970         inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2971         inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2972     }
2973
2974     if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2975         goto failed;
2976
2977     result = TRUE;
2978
2979     failed:
2980     ReleaseDC(0, xdc);
2981     LocalFree((HLOCAL)lpBitsOrg);
2982
2983     return result;
2984 }
2985
2986
2987 /*************************************************************************
2988  * ImageList_Write [COMCTL32.83]
2989  *
2990  * Writes an image list to a stream.
2991  *
2992  * PARAMS
2993  *     himl [I] handle to image list
2994  *     pstm [O] Pointer to a stream.
2995  *
2996  * RETURNS
2997  *     Success: TRUE
2998  *     Failure: FALSE
2999  *
3000  * BUGS
3001  *     probably.
3002  */
3003
3004 BOOL WINAPI
3005 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
3006 {
3007     ILHEAD ilHead;
3008     int i;
3009
3010     if (!himl)
3011         return FALSE;
3012
3013     ilHead.usMagic   = (('L' << 8) | 'I');
3014     ilHead.usVersion = 0x101;
3015     ilHead.cCurImage = himl->cCurImage;
3016     ilHead.cMaxImage = himl->cMaxImage;
3017     ilHead.cGrow     = himl->cGrow;
3018     ilHead.cx        = himl->cx;
3019     ilHead.cy        = himl->cy;
3020     ilHead.bkcolor   = himl->clrBk;
3021     ilHead.flags     = himl->flags;
3022     for(i = 0; i < 4; i++) {
3023         ilHead.ovls[i] = himl->nOvlIdx[i];
3024     }
3025
3026     if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3027         return FALSE;
3028
3029     /* write the bitmap */
3030     if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
3031         return FALSE;
3032
3033     /* write the mask if we have one */
3034     if(himl->flags & ILC_MASK) {
3035         if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
3036             return FALSE;
3037     }
3038
3039     return TRUE;
3040 }
3041