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