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