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