No longer directly accessing debuggee memory.
[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_LoadImage32A [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_LoadImage32W [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     DeleteDC (hdcImage);
2278     DeleteDC (hdcImageList);
2279
2280     return TRUE;
2281 }
2282
2283
2284 /*************************************************************************
2285  * ImageList_ReplaceIcon [COMCTL32.69]
2286  *
2287  * Replaces an image in an image list using an icon.
2288  *
2289  * PARAMS
2290  *     himl  [I] handle to image list
2291  *     i     [I] image index
2292  *     hIcon [I] handle to icon
2293  *
2294  * RETURNS
2295  *     Success: index of the replaced image
2296  *     Failure: -1
2297  */
2298
2299 INT WINAPI
2300 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2301 {
2302     HDC     hdcImageList, hdcImage;
2303     INT     nIndex;
2304     HICON   hBestFitIcon;
2305     HBITMAP hbmOldSrc, hbmOldDst;
2306     ICONINFO  ii;
2307     BITMAP  bmp;
2308
2309     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2310
2311     if (himl == NULL)
2312         return -1;
2313     if ((i >= himl->cCurImage) || (i < -1))
2314         return -1;
2315
2316     hBestFitIcon = CopyImage(
2317         hIcon, IMAGE_ICON, 
2318         himl->cx, himl->cy, 
2319         LR_COPYFROMRESOURCE);
2320
2321     GetIconInfo (hBestFitIcon, &ii);
2322     if (ii.hbmMask == 0)
2323         ERR("no mask!\n");
2324     if (ii.hbmColor == 0)
2325         ERR("no color!\n");
2326     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2327
2328     if (i == -1) {
2329         if (himl->cCurImage + 1 >= himl->cMaxImage)
2330             IMAGELIST_InternalExpandBitmaps (himl, 1);
2331
2332         nIndex = himl->cCurImage;
2333         himl->cCurImage++;
2334     }
2335     else
2336         nIndex = i;
2337
2338     hdcImageList = CreateCompatibleDC (0);
2339     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2340     if (hdcImageList == 0)
2341         ERR("invalid hdcImageList!\n");
2342
2343     hdcImage = CreateCompatibleDC (0);
2344     TRACE("hdcImage=0x%x!\n", hdcImage);
2345     if (hdcImage == 0)
2346         ERR("invalid hdcImage!\n");
2347
2348     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2349     SetTextColor( hdcImageList, RGB(0,0,0));
2350     SetBkColor( hdcImageList, RGB(255,255,255));
2351     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2352     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2353                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2354
2355     if (himl->hbmMask) {
2356         SelectObject (hdcImageList, himl->hbmMask);
2357         SelectObject (hdcImage, ii.hbmMask);
2358         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2359                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2360     }
2361
2362     SelectObject (hdcImage, hbmOldSrc);
2363     SelectObject (hdcImageList, hbmOldDst);
2364
2365     if(hBestFitIcon)
2366         DestroyIcon(hBestFitIcon);
2367     if (hdcImageList)
2368         DeleteDC (hdcImageList);
2369     if (hdcImage)
2370         DeleteDC (hdcImage);
2371     if (ii.hbmColor)
2372         DeleteObject (ii.hbmColor);
2373     if (ii.hbmMask)
2374         DeleteObject (ii.hbmMask);
2375
2376     return nIndex;
2377 }
2378
2379
2380 /*************************************************************************
2381  * ImageList_SetBkColor [COMCTL32.70] 
2382  *
2383  * Sets the background color of an image list.
2384  *
2385  * PARAMS
2386  *     himl  [I] handle to image list
2387  *     clrBk [I] background color
2388  *
2389  * RETURNS
2390  *     Success: previous background color
2391  *     Failure: CLR_NONE
2392  */
2393
2394 COLORREF WINAPI
2395 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2396 {
2397     COLORREF clrOldBk;
2398
2399     if (himl == NULL)
2400         return CLR_NONE;
2401
2402     clrOldBk = himl->clrBk;
2403     himl->clrBk = clrBk;
2404     return clrOldBk;
2405 }
2406
2407
2408 /*************************************************************************
2409  * ImageList_SetDragCursorImage [COMCTL32.75]
2410  *
2411  * Combines the specified image with the current drag image
2412  *
2413  * PARAMS
2414  *     himlDrag  [I] handle to drag image list
2415  *     iDrag     [I] drag image index
2416  *     dxHotspot [I] X position of the hot spot
2417  *     dyHotspot [I] Y position of the hot spot
2418  *
2419  * RETURNS
2420  *     Success: TRUE
2421  *     Failure: FALSE
2422  *
2423  * BUGS
2424  *     semi-stub.
2425  */
2426
2427 BOOL WINAPI
2428 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2429                               INT dxHotspot, INT dyHotspot)
2430 {
2431     HIMAGELIST himlTemp;
2432
2433     FIXME("semi-stub!\n");
2434
2435     if (himlInternalDrag == NULL)
2436         return FALSE;
2437
2438     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2439            dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2440
2441     himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2442                                 dxHotspot, dyHotspot);
2443
2444     ImageList_Destroy (himlInternalDrag);
2445     himlInternalDrag = himlTemp;
2446
2447     nInternalDragHotspotX = dxHotspot;
2448     nInternalDragHotspotY = dyHotspot;
2449
2450     return FALSE;
2451 }
2452
2453
2454 /*************************************************************************
2455  * ImageList_SetFilter [COMCTL32.76] 
2456  *
2457  * Sets a filter (or does something completely different)!!???
2458  *
2459  * PARAMS
2460  *     himl     [I] handle to image list
2461  *     i        [I] ???
2462  *     dwFilter [I] ???
2463  *
2464  * RETURNS
2465  *     Success: TRUE ???
2466  *     Failure: FALSE ???
2467  *
2468  * BUGS
2469  *     This is an UNDOCUMENTED function!!!!
2470  *     empty stub.
2471  */
2472
2473 BOOL WINAPI
2474 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2475 {
2476     FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2477            himl, i, dwFilter);
2478
2479     return FALSE;
2480 }
2481
2482
2483 /*************************************************************************
2484  * ImageList_SetIconSize [COMCTL32.77]
2485  *
2486  * Sets the image size of the bitmap and deletes all images.
2487  *
2488  * PARAMS
2489  *     himl [I] handle to image list
2490  *     cx   [I] image width
2491  *     cy   [I] image height
2492  *
2493  * RETURNS
2494  *     Success: TRUE
2495  *     Failure: FALSE
2496  */
2497
2498 BOOL WINAPI
2499 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2500 {
2501     INT nCount;
2502
2503     if (!himl)
2504         return FALSE;
2505
2506     /* remove all images*/
2507     himl->cMaxImage = himl->cInitial + himl->cGrow;
2508     himl->cCurImage = 0;
2509     himl->cx        = cx;
2510     himl->cy        = cy;
2511
2512     /* initialize overlay mask indices */
2513     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2514         himl->nOvlIdx[nCount] = -1;
2515
2516     DeleteObject (himl->hbmImage);
2517     himl->hbmImage =
2518         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2519                         1, himl->uBitsPixel, NULL);
2520
2521     if (himl->hbmMask) {
2522         DeleteObject (himl->hbmMask);
2523         himl->hbmMask =
2524             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2525                             1, 1, NULL);
2526     }
2527
2528     return TRUE;
2529 }
2530
2531
2532 /*************************************************************************
2533  * ImageList_SetImageCount [COMCTL32.78]
2534  *
2535  * Resizes an image list to the specified number of images.
2536  *
2537  * PARAMS
2538  *     himl        [I] handle to image list
2539  *     iImageCount [I] number of images in the image list
2540  *
2541  * RETURNS
2542  *     Success: TRUE
2543  *     Failure: FALSE
2544  */
2545
2546 BOOL WINAPI
2547 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2548 {
2549     HDC     hdcImageList, hdcBitmap;
2550     HBITMAP hbmNewBitmap;
2551     INT     nNewCount, nCopyCount;
2552
2553     if (!himl)
2554         return FALSE;
2555     if (himl->cCurImage >= iImageCount)
2556         return FALSE;
2557     if (himl->cMaxImage > iImageCount)
2558         return TRUE;
2559
2560     nNewCount = iImageCount + himl->cGrow;
2561     nCopyCount = _MIN(himl->cCurImage, iImageCount);
2562
2563     hdcImageList = CreateCompatibleDC (0);
2564     hdcBitmap = CreateCompatibleDC (0);
2565
2566     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2567                                    1, himl->uBitsPixel, NULL);
2568     if (hbmNewBitmap != 0)
2569     {
2570         SelectObject (hdcImageList, himl->hbmImage);
2571         SelectObject (hdcBitmap, hbmNewBitmap);
2572
2573         /* copy images */
2574         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2575                   hdcImageList, 0, 0, SRCCOPY);
2576 #if 0
2577         /* delete 'empty' image space */
2578         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2579         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2580         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2581                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2582 #endif
2583         DeleteObject (himl->hbmImage);
2584         himl->hbmImage = hbmNewBitmap;
2585     }
2586     else
2587         ERR("Could not create new image bitmap !\n");
2588
2589     if (himl->hbmMask)
2590     {
2591         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2592                                        1, 1, NULL);
2593         if (hbmNewBitmap != 0)
2594         {
2595             SelectObject (hdcImageList, himl->hbmMask);
2596             SelectObject (hdcBitmap, hbmNewBitmap);
2597
2598             /* copy images */
2599             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2600                       hdcImageList, 0, 0, SRCCOPY);
2601 #if 0
2602             /* delete 'empty' image space */
2603             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2604             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2605             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2606                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2607 #endif
2608             DeleteObject (himl->hbmMask);
2609             himl->hbmMask = hbmNewBitmap;
2610         }
2611         else
2612             ERR("Could not create new mask bitmap!\n");
2613     }
2614
2615     DeleteDC (hdcImageList);
2616     DeleteDC (hdcBitmap);
2617
2618     /* Update max image count and current image count */
2619     himl->cMaxImage = nNewCount;
2620     if (himl->cCurImage > nCopyCount)
2621         himl->cCurImage = nCopyCount;
2622
2623     return TRUE;
2624 }
2625
2626
2627 /*************************************************************************
2628  * ImageList_SetOverlayImage [COMCTL32.79]
2629  *
2630  * Assigns an overlay mask index to an existing image in an image list.
2631  *
2632  * PARAMS
2633  *     himl     [I] handle to image list
2634  *     iImage   [I] image index
2635  *     iOverlay [I] overlay mask index
2636  *
2637  * RETURNS
2638  *     Success: TRUE
2639  *     Failure: FALSE
2640  */
2641
2642 BOOL WINAPI
2643 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2644 {
2645     if (!himl)
2646         return FALSE;
2647     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2648         return FALSE;
2649     if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2650         return FALSE;
2651     himl->nOvlIdx[iOverlay - 1] = iImage;
2652     return TRUE;
2653 }
2654
2655
2656 /*************************************************************************
2657  * ImageList_Write [COMCTL32.80]
2658  *
2659  * Writes an image list to a stream.
2660  *
2661  * PARAMS
2662  *     himl [I] handle to image list
2663  *     pstm [O] Pointer to a stream.
2664  *
2665  * RETURNS
2666  *     Success: TRUE
2667  *     Failure: FALSE
2668  *
2669  * NOTES
2670  *     This function can not be implemented yet, because
2671  *     IStream32::Write is not implemented.
2672  *
2673  * BUGS
2674  *     empty stub.
2675  */
2676
2677 BOOL WINAPI
2678 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2679 {
2680     if (!himl)
2681         return FALSE;
2682
2683     FIXME("empty stub!\n");
2684
2685     return FALSE;
2686 }
2687