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