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