The COM virtual tables must use the
[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_Read and 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     hImageDC = CreateCompatibleDC(0);
153     hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
154     BitBlt(pimldp->hdcDst, 
155         pimldp->x, pimldp->y, cx, cy,
156         hImageDC, 
157         pimldp->himl->cx * pimldp->i, 0, 
158         SRCCOPY);
159
160     SelectObject(hImageDC, hOldBitmap);
161     DeleteDC(hImageDC);
162 }
163
164
165 /*************************************************************************
166  * IMAGELIST_InternalDrawMask [Internal] 
167  *
168  * Draws the image in the ImageList witht the mask
169  *
170  * PARAMS
171  *     pimldp        [I] pointer to IMAGELISTDRAWPARAMS structure.
172  *     cx            [I] the width of the image to display
173  *     cy............[I] the height of the image to display
174  *
175  * RETURNS
176  *     nothing
177  *
178  * NOTES
179  *     This functions is used by ImageList_DrawIndirect, when it is 
180  *     required to draw the Image with the mask to the screen.
181  *
182  *     Blending and Overlays styles are accomplised by another function.
183  */
184 static VOID
185 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
186 {
187     HDC     hMaskDC, hImageDC;
188     BOOL bUseCustomBackground, bBlendFlag;
189     HBRUSH hBrush, hOldBrush;
190     HBITMAP hOldBitmapImage, hOldBitmapMask;
191     HIMAGELIST himlLocal = pimldp->himl;
192     COLORREF oldBkColor, oldFgColor;
193
194     bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
195     bBlendFlag = (pimldp->fStyle & ILD_BLEND50 ) 
196         || (pimldp->fStyle & ILD_BLEND25);
197
198     hImageDC = CreateCompatibleDC(0);
199     hMaskDC = CreateCompatibleDC(0);
200
201     hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
202     hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
203     /* Draw the Background for the appropriate Styles
204     */
205     if( bUseCustomBackground && (pimldp->fStyle == ILD_NORMAL 
206           || pimldp->fStyle & ILD_IMAGE 
207           || 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(pimldp->fStyle == ILD_NORMAL
221         || pimldp->fStyle & ILD_TRANSPARENT
222         || ((pimldp->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(pimldp->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(pimldp->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 & 0x0700) >> 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         return FALSE;
1257     /*
1258         Get the Height and Width to display
1259     */
1260     cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1261     cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1262     /*
1263         Draw the image
1264     */
1265     if(pimldp->himl->hbmMask != 0)
1266     {
1267         IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1268     }
1269     else
1270     {
1271         IMAGELIST_InternalDraw(pimldp, cx, cy);
1272     }
1273     /* 
1274         Apply the blend if needed to the Image
1275     */
1276     if((pimldp->fStyle & ILD_BLEND50)
1277         || (pimldp->fStyle & ILD_BLEND25))
1278     {
1279         IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1280     }
1281     /*
1282         Apply the Overlay if needed
1283     */
1284     if (pimldp->fStyle & 0x0700)
1285     {
1286         IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1287     }
1288
1289     return TRUE;
1290 }
1291
1292
1293 /*************************************************************************
1294  * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1295  *
1296  * PARAMS
1297  *     himlSrc [I] source image list handle
1298  *
1299  * RETURNS
1300  *     Success: Handle of duplicated image list.
1301  *     Failure: NULL
1302  */
1303
1304 HIMAGELIST WINAPI
1305 ImageList_Duplicate (HIMAGELIST himlSrc)
1306 {
1307     HIMAGELIST himlDst;
1308     HDC hdcSrc, hdcDst;
1309
1310     if (himlSrc == NULL) {
1311         ERR("Invalid image list handle!\n");
1312         return NULL;
1313     }
1314
1315     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1316                                 himlSrc->cInitial, himlSrc->cGrow);
1317
1318     if (himlDst)
1319     {
1320         hdcSrc = CreateCompatibleDC (0);
1321         hdcDst = CreateCompatibleDC (0);
1322         SelectObject (hdcSrc, himlSrc->hbmImage);
1323         SelectObject (hdcDst, himlDst->hbmImage);
1324         BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1325                   hdcSrc, 0, 0, SRCCOPY);
1326
1327         if (himlDst->hbmMask)
1328         {
1329             SelectObject (hdcSrc, himlSrc->hbmMask);
1330             SelectObject (hdcDst, himlDst->hbmMask);
1331             BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1332                       himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1333         }
1334
1335         DeleteDC (hdcDst);
1336         DeleteDC (hdcSrc);
1337     }
1338
1339     return himlDst;
1340 }
1341
1342
1343 /*************************************************************************
1344  * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1345  *
1346  * Finishes a drag operation.
1347  *
1348  * PARAMS
1349  *     no Parameters
1350  *
1351  * RETURNS
1352  *     Success: TRUE
1353  *     Failure: FALSE
1354  *
1355  * BUGS
1356  *     semi-stub.
1357  */
1358
1359 BOOL WINAPI
1360 ImageList_EndDrag (void)
1361 {
1362     FIXME("semi-stub!\n");
1363
1364     if (himlInternalDrag)
1365     {
1366
1367         ImageList_Destroy (himlInternalDrag);
1368         himlInternalDrag = NULL;
1369
1370         nInternalDragHotspotX = 0;
1371         nInternalDragHotspotY = 0;
1372
1373     }
1374
1375     return TRUE;
1376 }
1377
1378
1379 /*************************************************************************
1380  * ImageList_GetBkColor [COMCTL32.55]
1381  *
1382  * Returns the background color of an image list.
1383  *
1384  * PARAMS
1385  *     himl [I] Image list handle.
1386  *
1387  * RETURNS
1388  *     Success: background color
1389  *     Failure: CLR_NONE
1390  */
1391
1392 COLORREF WINAPI
1393 ImageList_GetBkColor (HIMAGELIST himl)
1394 {
1395     if (himl == NULL)
1396         return CLR_NONE;
1397
1398     return himl->clrBk;
1399 }
1400
1401
1402 /*************************************************************************
1403  * ImageList_GetDragImage [COMCTL32.56]
1404  *
1405  * Returns the handle to the internal drag image list.
1406  *
1407  * PARAMS
1408  *     ppt        [O] Pointer to the drag position. Can be NULL.
1409  *     pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1410  *
1411  * RETURNS
1412  *     Success: Handle of the drag image list.
1413  *     Failure: NULL.
1414  *
1415  * BUGS
1416  *     semi-stub.
1417  */
1418
1419 HIMAGELIST WINAPI
1420 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1421 {
1422     FIXME("semi-stub!\n");
1423
1424     if (himlInternalDrag)
1425         return (himlInternalDrag);
1426
1427     return NULL;
1428 }
1429
1430
1431 /*************************************************************************
1432  * ImageList_GetIcon [COMCTL32.57] 
1433  *
1434  * Creates an icon from a masked image of an image list.
1435  *
1436  * PARAMS
1437  *     himl  [I] handle to image list
1438  *     i     [I] image index
1439  *     flags [I] drawing style flags
1440  *
1441  * RETURNS
1442  *     Success: icon handle
1443  *     Failure: NULL
1444  */
1445
1446 HICON WINAPI
1447 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1448 {
1449     ICONINFO ii;
1450     HICON  hIcon;
1451     HBITMAP hOldSrcBitmap,hOldDstBitmap;
1452     HDC    hdcSrc, hdcDst;
1453
1454     if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage))
1455         return 0;
1456
1457     hdcSrc = CreateCompatibleDC(0);
1458     hdcDst = CreateCompatibleDC(0);
1459
1460     ii.fIcon = TRUE;
1461     ii.hbmMask  = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1462
1463     /* draw mask*/
1464     hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1465     if (himl->hbmMask) {
1466         SelectObject (hdcSrc, himl->hbmMask);
1467         BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1468                   hdcSrc, i * himl->cx, 0, SRCCOPY);
1469     }
1470     else
1471         PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1472
1473     /* draw image*/
1474     hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1475     ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1476     SelectObject (hdcDst, ii.hbmColor);
1477     BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1478               hdcSrc, i * himl->cx, 0, SRCCOPY);
1479
1480     /*
1481      * CreateIconIndirect requires us to deselect the bitmaps from
1482      * the DCs before calling 
1483      */
1484     SelectObject(hdcSrc, hOldSrcBitmap);
1485     SelectObject(hdcDst, hOldDstBitmap);
1486
1487     hIcon = CreateIconIndirect (&ii);    
1488
1489     DeleteDC (hdcSrc);
1490     DeleteDC (hdcDst);
1491     DeleteObject (ii.hbmMask);
1492     DeleteObject (ii.hbmColor);
1493
1494     return hIcon;
1495 }
1496
1497
1498 /*************************************************************************
1499  * ImageList_GetIconSize [COMCTL32.58]
1500  *
1501  * Retrieves the size of an image in an image list.
1502  *
1503  * PARAMS
1504  *     himl [I] handle to image list
1505  *     cx   [O] pointer to the image width.
1506  *     cy   [O] pointer to the image height.
1507  *
1508  * RETURNS
1509  *     Success: TRUE
1510  *     Failure: FALSE
1511  *
1512  * NOTES
1513  *     All images in an image list have the same size.
1514  */
1515
1516 BOOL WINAPI
1517 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1518 {
1519     if (himl == NULL)
1520         return FALSE;
1521     if ((himl->cx <= 0) || (himl->cy <= 0))
1522         return FALSE;
1523
1524     if (cx)
1525         *cx = himl->cx;
1526     if (cy)
1527         *cy = himl->cy;
1528
1529     return TRUE;
1530 }
1531
1532
1533 /*************************************************************************
1534  * ImageList_GetImageCount [COMCTL32.59]
1535  *
1536  * Returns the number of images in an image list.
1537  *
1538  * PARAMS
1539  *     himl [I] handle to image list
1540  *
1541  * RETURNS
1542  *     Success: Number of images.
1543  *     Failure: 0
1544  */
1545
1546 INT WINAPI
1547 ImageList_GetImageCount (HIMAGELIST himl)
1548 {
1549     if (himl == NULL)
1550         return 0;
1551
1552     return himl->cCurImage;
1553 }
1554
1555
1556 /*************************************************************************
1557  * ImageList_GetImageInfo [COMCTL32.60]
1558  *
1559  * Returns information about an image in an image list.
1560  *
1561  * PARAMS
1562  *     himl       [I] handle to image list
1563  *     i          [I] image index
1564  *     pImageInfo [O] pointer to the image information
1565  *
1566  * RETURNS
1567  *     Success: TRUE
1568  *     Failure: FALSE
1569  */
1570
1571 BOOL WINAPI
1572 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1573 {
1574     if ((himl == NULL) || (pImageInfo == NULL))
1575         return FALSE;
1576     if ((i < 0) || (i >= himl->cCurImage))
1577         return FALSE;
1578
1579     pImageInfo->hbmImage = himl->hbmImage;
1580     pImageInfo->hbmMask  = himl->hbmMask;
1581     
1582     pImageInfo->rcImage.top    = 0;
1583     pImageInfo->rcImage.bottom = himl->cy;
1584     pImageInfo->rcImage.left   = i * himl->cx;
1585     pImageInfo->rcImage.right  = (i+1) * himl->cx;
1586     
1587     return TRUE;
1588 }
1589
1590
1591 /*************************************************************************
1592  * ImageList_GetImageRect [COMCTL32.61] 
1593  *
1594  * Retrieves the rectangle of the specified image in an image list.
1595  *
1596  * PARAMS
1597  *     himl   [I] handle to image list
1598  *     i      [I] image index
1599  *     lpRect [O] pointer to the image rectangle
1600  *
1601  * RETURNS
1602  *    Success: TRUE
1603  *    Failure: FALSE
1604  *
1605  * NOTES
1606  *    This is an UNDOCUMENTED function!!!
1607  */
1608
1609 BOOL WINAPI
1610 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1611 {
1612     if ((himl == NULL) || (lpRect == NULL))
1613         return FALSE;
1614     if ((i < 0) || (i >= himl->cCurImage))
1615         return FALSE;
1616
1617     lpRect->left   = i * himl->cx;
1618     lpRect->top    = 0;
1619     lpRect->right  = lpRect->left + himl->cx;
1620     lpRect->bottom = himl->cy;
1621
1622     return TRUE;
1623 }
1624
1625
1626 /*************************************************************************
1627  * ImageList_LoadImage32A [COMCTL32.63][COMCTL32.62]
1628  *
1629  * Creates an image list from a bitmap, icon or cursor.
1630  *
1631  * PARAMS
1632  *     hi      [I] instance handle
1633  *     lpbmp   [I] name or id of the image
1634  *     cx      [I] width of each image
1635  *     cGrow   [I] number of images to expand
1636  *     clrMask [I] mask color
1637  *     uType   [I] type of image to load
1638  *     uFlags  [I] loading flags
1639  *
1640  * RETURNS
1641  *     Success: handle to the loaded image list
1642  *     Failure: NULL
1643  *
1644  * SEE
1645  *     LoadImage ()
1646  */
1647
1648 HIMAGELIST WINAPI
1649 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx,       INT cGrow,
1650                         COLORREF clrMask, UINT uType,   UINT uFlags)
1651 {
1652     HIMAGELIST himl = NULL;
1653     HANDLE   handle;
1654     INT      nImageCount;
1655
1656     handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1657     if (!handle) {
1658         ERR("Error loading image!\n");
1659         return NULL;
1660     }
1661
1662     if (uType == IMAGE_BITMAP) {
1663         BITMAP bmp;
1664         GetObjectA (handle, sizeof(BITMAP), &bmp);
1665
1666         /* To match windows behavior, if cx is set to zero and
1667          the flag DI_DEFAULTSIZE is specified, cx becomes the
1668          system metric value for icons. If the flag is not specified
1669          the function sets the size to the height of the bitmap */
1670         if (cx == 0)
1671         {
1672             if (uFlags & DI_DEFAULTSIZE)
1673                 cx = GetSystemMetrics (SM_CXICON);
1674             else
1675                 cx = bmp.bmHeight;
1676         }
1677
1678         nImageCount = bmp.bmWidth / cx;
1679
1680         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1681                                  nImageCount, cGrow);
1682         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1683     }
1684     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1685         ICONINFO ii;
1686         BITMAP bmp;
1687
1688         GetIconInfo (handle, &ii);
1689         GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1690         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
1691                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1692         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1693         DeleteObject (ii.hbmColor);
1694         DeleteObject (ii.hbmMask);
1695     }
1696
1697     DeleteObject (handle);
1698     
1699     return himl;
1700 }
1701
1702
1703 /*************************************************************************
1704  * ImageList_LoadImage32W [COMCTL32.64]
1705  *
1706  * Creates an image list from a bitmap, icon or cursor.
1707  *
1708  * PARAMS
1709  *     hi      [I] instance handle
1710  *     lpbmp   [I] name or id of the image
1711  *     cx      [I] width of each image
1712  *     cGrow   [I] number of images to expand
1713  *     clrMask [I] mask color
1714  *     uType   [I] type of image to load
1715  *     uFlags  [I] loading flags
1716  *
1717  * RETURNS
1718  *     Success: handle to the loaded image list
1719  *     Failure: NULL
1720  *
1721  * SEE
1722  *     LoadImage ()
1723  */
1724
1725 HIMAGELIST WINAPI
1726 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1727                         COLORREF clrMask, UINT uType,   UINT uFlags)
1728 {
1729     HIMAGELIST himl = NULL;
1730     HANDLE   handle;
1731     INT      nImageCount;
1732
1733     handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1734     if (!handle) {
1735         ERR("Error loading image!\n");
1736         return NULL;
1737     }
1738
1739     if (uType == IMAGE_BITMAP) {
1740         BITMAP bmp;
1741         GetObjectA (handle, sizeof(BITMAP), &bmp);
1742         nImageCount = bmp.bmWidth / cx;
1743
1744         himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1745                                  nImageCount, cGrow);
1746         ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1747     }
1748     else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1749         ICONINFO ii;
1750         BITMAP bmp;
1751
1752         GetIconInfo (handle, &ii);
1753         GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1754         himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, 
1755                                  ILC_MASK | ILC_COLOR, 1, cGrow);
1756         ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1757         DeleteObject (ii.hbmColor);
1758         DeleteObject (ii.hbmMask);
1759     }
1760
1761     DeleteObject (handle);
1762     
1763     return himl;
1764 }
1765
1766
1767 /*************************************************************************
1768  * ImageList_Merge [COMCTL32.65] 
1769  *
1770  * Creates a new image list that contains a merged image from the specified
1771  * images of both source image lists.
1772  *
1773  * PARAMS
1774  *     himl1 [I] handle to first image list
1775  *     i1    [I] first image index
1776  *     himl2 [I] handle to second image list
1777  *     i2    [I] second image index
1778  *     dx    [I] X offset of the second image relative to the first.
1779  *     dy    [I] Y offset of the second image relative to the first.
1780  *
1781  * RETURNS
1782  *     Success: handle of the merged image list.
1783  *     Failure: NULL
1784  */
1785
1786 HIMAGELIST WINAPI
1787 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1788                  INT dx, INT dy)
1789 {
1790     HIMAGELIST himlDst = NULL;
1791     HDC      hdcSrcImage, hdcDstImage;
1792     INT      cxDst, cyDst;
1793     INT      xOff1, yOff1, xOff2, yOff2;
1794     INT      nX1, nX2;
1795
1796     if ((himl1 == NULL) || (himl2 == NULL))
1797         return NULL;
1798
1799     /* check indices */
1800     if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1801         ERR("Index 1 out of range! %d\n", i1);
1802         return NULL;
1803     }
1804
1805     if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1806         ERR("Index 2 out of range! %d\n", i2);
1807         return NULL;
1808     }
1809
1810     if (dx > 0) {
1811         cxDst = _MAX (himl1->cx, dx + himl2->cx);
1812         xOff1 = 0;
1813         xOff2 = dx;
1814     }
1815     else if (dx < 0) {
1816         cxDst = _MAX (himl2->cx, himl1->cx - dx);
1817         xOff1 = -dx;
1818         xOff2 = 0;
1819     }
1820     else {
1821         cxDst = _MAX (himl1->cx, himl2->cx);
1822         xOff1 = 0;
1823         xOff2 = 0;
1824     }
1825
1826     if (dy > 0) {
1827         cyDst = _MAX (himl1->cy, dy + himl2->cy);
1828         yOff1 = 0;
1829         yOff2 = dy;
1830     }
1831     else if (dy < 0) {
1832         cyDst = _MAX (himl2->cy, himl1->cy - dy);
1833         yOff1 = -dy;
1834         yOff2 = 0;
1835     }
1836     else {
1837         cyDst = _MAX (himl1->cy, himl2->cy);
1838         yOff1 = 0;
1839         yOff2 = 0;
1840     }
1841
1842     himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1843
1844     if (himlDst) {
1845         hdcSrcImage = CreateCompatibleDC (0);
1846         hdcDstImage = CreateCompatibleDC (0);
1847         nX1 = i1 * himl1->cx;
1848         nX2 = i2 * himl2->cx;
1849         
1850         /* copy image */
1851         SelectObject (hdcSrcImage, himl1->hbmImage);
1852         SelectObject (hdcDstImage, himlDst->hbmImage);
1853         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
1854                   hdcSrcImage, 0, 0, BLACKNESS);
1855         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
1856                   hdcSrcImage, nX1, 0, SRCCOPY);
1857
1858         SelectObject (hdcSrcImage, himl2->hbmMask);
1859         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1860                   hdcSrcImage, nX2, 0, SRCAND);
1861
1862         SelectObject (hdcSrcImage, himl2->hbmImage);
1863         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1864                   hdcSrcImage, nX2, 0, SRCPAINT);
1865
1866         /* copy mask */
1867         SelectObject (hdcSrcImage, himl1->hbmMask);
1868         SelectObject (hdcDstImage, himlDst->hbmMask);
1869         BitBlt (hdcDstImage, 0, 0, cxDst, cyDst, 
1870                   hdcSrcImage, 0, 0, WHITENESS);
1871         BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy, 
1872                   hdcSrcImage, nX1, 0, SRCCOPY);
1873
1874         SelectObject (hdcSrcImage, himl2->hbmMask);
1875         BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy, 
1876                   hdcSrcImage, nX2, 0, SRCAND);
1877
1878         DeleteDC (hdcSrcImage);
1879         DeleteDC (hdcDstImage);
1880     }
1881    
1882     return himlDst;
1883 }
1884
1885
1886 static int may_use_dibsection(HDC hdc) {
1887     int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1888     if (bitspixel>8)
1889         return TRUE;
1890     if (bitspixel<=4)
1891         return FALSE;
1892     return GetDeviceCaps(hdc,94) & 0x10;
1893 }
1894
1895 static HBITMAP _read_bitmap(LPSTREAM pstm,int x) {
1896     HDC                 xdc = 0;
1897     BITMAPFILEHEADER    bmfh;
1898     BITMAPINFOHEADER    bmih;
1899     int                 bitsperpixel,palspace,longsperline,width,height;
1900     LPBITMAPINFOHEADER  bmihc = NULL;
1901     int                 result = 0;
1902     HBITMAP             hbitmap = 0;
1903     LPBYTE              bits = NULL;
1904
1905     if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL))     ||
1906         (bmfh.bfType != (('M'<<8)|'B'))                                 ||
1907         !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL))     ||
1908         (bmih.biSize != sizeof(bmih))
1909     )
1910         return 0;
1911
1912     bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1913     if (bitsperpixel<=8)
1914         palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1915     else
1916         palspace = 0;
1917     width = bmih.biWidth;
1918     height = bmih.biHeight;
1919     bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1920     memcpy(bmihc,&bmih,sizeof(bmih));
1921     longsperline        = ((width*bitsperpixel+31)&~0x1f)>>5;
1922     bmihc->biSizeImage  = (longsperline*height)<<2;
1923
1924     /* read the palette right after the end of the bitmapinfoheader */
1925     if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1926         goto ret1;
1927
1928     xdc = GetDC(0);
1929     if ((bitsperpixel>1) &&
1930         ((x!=0xfe) && (!x || may_use_dibsection(xdc)))
1931      ) {
1932         hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1933         if (!hbitmap)
1934             goto ret1;
1935         if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1936             goto ret1;
1937         bits = NULL;
1938         result = 1;
1939     } else {
1940         if (bitsperpixel==1)
1941             hbitmap = CreateBitmap(width,height,1,1,NULL);
1942         else
1943             hbitmap = CreateCompatibleBitmap(xdc,width,height);
1944
1945         /* Might be a bit excessive memory use here */
1946         bits = (LPBYTE)LocalAlloc(0,longsperline*4*height);
1947         if (!SUCCEEDED(IStream_Read ( pstm, bits, longsperline*4*height, NULL)))
1948                 goto ret1;
1949         if (!SetDIBits(xdc,hbitmap,0,height,bits,(BITMAPINFO*)bmihc,0))
1950                 goto ret1;
1951         result = 1;
1952     }
1953 ret1:
1954     if (xdc)    ReleaseDC(0,xdc);
1955     if (bmihc)  LocalFree((HLOCAL)bmihc);
1956     if (bits)   LocalFree((HLOCAL)bits);
1957     if (!result) {
1958         if (hbitmap) {
1959             DeleteObject(hbitmap);
1960             hbitmap = 0;
1961         }
1962     }
1963     return hbitmap;
1964 }
1965
1966 /*************************************************************************
1967  * ImageList_Read [COMCTL32.66]
1968  *
1969  * Reads an image list from a stream.
1970  *
1971  * PARAMS
1972  *     pstm [I] pointer to a stream
1973  *
1974  * RETURNS
1975  *     Success: handle to image list
1976  *     Failure: NULL
1977  *
1978  * BUGS
1979  *     still not complete functional
1980  */
1981 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1982 {
1983     ILHEAD      ilHead;
1984     HIMAGELIST  himl;
1985     HBITMAP     hbmColor=0,hbmMask=0;
1986     int         i;
1987
1988     if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1989         return NULL;
1990     if (ilHead.usMagic != (('L' << 8) | 'I'))
1991         return NULL;
1992     if (ilHead.usVersion != 0x101) /* probably version? */
1993         return NULL;
1994
1995 #if 0
1996     FIXME("     ilHead.cCurImage = %d\n",ilHead.cCurImage);
1997     FIXME("     ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1998     FIXME("     ilHead.grow = %d\n",ilHead.grow);
1999     FIXME("     ilHead.cx = %d\n",ilHead.cx);
2000     FIXME("     ilHead.cy = %d\n",ilHead.cy);
2001     FIXME("     ilHead.flags = %x\n",ilHead.flags);
2002     FIXME("     ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2003     FIXME("     ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2004     FIXME("     ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2005     FIXME("     ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2006 #endif
2007
2008     hbmColor = _read_bitmap(pstm,ilHead.flags & 0xfe);
2009     if (!hbmColor)
2010         return NULL;
2011     if (ilHead.flags & 1) {
2012         hbmMask = _read_bitmap(pstm,0);
2013         if (!hbmMask) {
2014             DeleteObject(hbmColor);
2015             return NULL;
2016         }
2017     }
2018
2019     himl = ImageList_Create (
2020                     ilHead.cx,
2021                     ilHead.cy,
2022                     ilHead.flags,
2023                     1,          /* initial */
2024                     ilHead.grow
2025     );
2026     if (!himl) {
2027         DeleteObject(hbmColor);
2028         DeleteObject(hbmMask);
2029         return NULL;
2030    }
2031
2032     himl->hbmImage = hbmColor;
2033     himl->hbmMask = hbmMask;
2034
2035     ImageList_SetBkColor(himl,ilHead.bkcolor);
2036
2037     for (i=0;i<4;i++)
2038         ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2039
2040     return himl;
2041 }
2042
2043
2044 /*************************************************************************
2045  * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2046  *
2047  * PARAMS
2048  *     himl [I] image list handle
2049  *     i    [I] image index
2050  *
2051  * RETURNS
2052  *     Success: TRUE
2053  *     Failure: FALSE
2054  */
2055
2056 BOOL WINAPI
2057 ImageList_Remove (HIMAGELIST himl, INT i)
2058 {
2059     HBITMAP hbmNewImage, hbmNewMask;
2060     HDC     hdcSrc, hdcDst;
2061     INT     cxNew, nCount;
2062
2063     if ((i < -1) || (i >= himl->cCurImage)) {
2064         ERR("index out of range! %d\n", i);
2065         return FALSE;
2066     }
2067
2068     if (himl->cCurImage == 0) {
2069         ERR("image list is already empty!\n");
2070         return FALSE;
2071     }
2072
2073     if (i == -1) {
2074         /* remove all */
2075         TRACE("remove all!\n");
2076
2077         himl->cMaxImage = himl->cInitial + himl->cGrow;
2078         himl->cCurImage = 0;
2079         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2080              himl->nOvlIdx[nCount] = -1;
2081
2082         DeleteObject (himl->hbmImage);
2083         himl->hbmImage =
2084             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2085                             1, himl->uBitsPixel, NULL);
2086
2087         if (himl->hbmMask) {
2088             DeleteObject (himl->hbmMask);
2089             himl->hbmMask =
2090                 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2091                                 1, 1, NULL);
2092         }
2093     }
2094     else {
2095         /* delete one image */
2096         TRACE("Remove single image! %d\n", i);
2097
2098         /* create new bitmap(s) */
2099         cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2100
2101         TRACE(" - Number of images: %d / %d (Old/New)\n",
2102                  himl->cCurImage, himl->cCurImage - 1);
2103         TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2104                  himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2105         
2106         hbmNewImage =
2107             CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2108
2109         if (himl->hbmMask)
2110             hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2111         else
2112             hbmNewMask = 0;  /* Just to keep compiler happy! */
2113
2114         hdcSrc = CreateCompatibleDC (0);
2115         hdcDst = CreateCompatibleDC (0);
2116
2117         /* copy all images and masks prior to the "removed" image */
2118         if (i > 0) {
2119             TRACE("Pre image copy: Copy %d images\n", i);
2120        
2121             SelectObject (hdcSrc, himl->hbmImage);
2122             SelectObject (hdcDst, hbmNewImage);
2123             BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2124                       hdcSrc, 0, 0, SRCCOPY);
2125
2126             if (himl->hbmMask) {
2127                 SelectObject (hdcSrc, himl->hbmMask);
2128                 SelectObject (hdcDst, hbmNewMask);
2129                 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2130                           hdcSrc, 0, 0, SRCCOPY);
2131             }
2132         }
2133
2134         /* copy all images and masks behind the removed image */
2135         if (i < himl->cCurImage - 1) {
2136             TRACE("Post image copy!\n");
2137             SelectObject (hdcSrc, himl->hbmImage);
2138             SelectObject (hdcDst, hbmNewImage);
2139             BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2140                       himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2141
2142             if (himl->hbmMask) {
2143                 SelectObject (hdcSrc, himl->hbmMask);
2144                 SelectObject (hdcDst, hbmNewMask);
2145                 BitBlt (hdcDst, i * himl->cx, 0,
2146                           (himl->cCurImage - i - 1) * himl->cx,
2147                           himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2148             }
2149         }
2150
2151         DeleteDC (hdcSrc);
2152         DeleteDC (hdcDst);
2153
2154         /* delete old images and insert new ones */
2155         DeleteObject (himl->hbmImage);
2156         himl->hbmImage = hbmNewImage;
2157         if (himl->hbmMask) {
2158             DeleteObject (himl->hbmMask);
2159             himl->hbmMask = hbmNewMask;
2160         }
2161
2162         himl->cCurImage--;
2163         himl->cMaxImage = himl->cCurImage + himl->cGrow;
2164     }
2165
2166     return TRUE;
2167 }
2168
2169
2170 /*************************************************************************
2171  * ImageList_Replace [COMCTL32.68] 
2172  *
2173  * Replaces an image in an image list with a new image.
2174  *
2175  * PARAMS
2176  *     himl     [I] handle to image list
2177  *     i        [I] image index
2178  *     hbmImage [I] handle to image bitmap
2179  *     hbmMask  [I] handle to mask bitmap. Can be NULL.
2180  *
2181  * RETURNS
2182  *     Success: TRUE
2183  *     Failure: FALSE
2184  */
2185
2186 BOOL WINAPI
2187 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2188                    HBITMAP hbmMask)
2189 {
2190     HDC hdcImageList, hdcImage;
2191     BITMAP bmp;
2192
2193     if (himl == NULL) {
2194         ERR("Invalid image list handle!\n");
2195         return FALSE;
2196     }
2197     
2198     if ((i >= himl->cCurImage) || (i < 0)) {
2199         ERR("Invalid image index!\n");
2200         return FALSE;
2201     }
2202
2203     hdcImageList = CreateCompatibleDC (0);
2204     hdcImage = CreateCompatibleDC (0);
2205     GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2206
2207     /* Replace Image */
2208     SelectObject (hdcImageList, himl->hbmImage);
2209     SelectObject (hdcImage, hbmImage);
2210
2211     StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2212                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2213
2214     if (himl->hbmMask)
2215     {
2216         /* Replace Mask */
2217         SelectObject (hdcImageList, himl->hbmMask);
2218         SelectObject (hdcImage, hbmMask);
2219
2220         StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2221                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2222     }
2223
2224     DeleteDC (hdcImage);
2225     DeleteDC (hdcImageList);
2226
2227     return TRUE;
2228 }
2229
2230
2231 /*************************************************************************
2232  * ImageList_ReplaceIcon [COMCTL32.69]
2233  *
2234  * Replaces an image in an image list using an icon.
2235  *
2236  * PARAMS
2237  *     himl  [I] handle to image list
2238  *     i     [I] image index
2239  *     hIcon [I] handle to icon
2240  *
2241  * RETURNS
2242  *     Success: index of the replaced image
2243  *     Failure: -1
2244  */
2245
2246 INT WINAPI
2247 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2248 {
2249     HDC     hdcImageList, hdcImage;
2250     INT     nIndex;
2251     HICON   hBestFitIcon;
2252     HBITMAP hbmOldSrc, hbmOldDst;
2253     ICONINFO  ii;
2254     BITMAP  bmp;
2255
2256     TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2257
2258     if (himl == NULL)
2259         return -1;
2260     if ((i >= himl->cCurImage) || (i < -1))
2261         return -1;
2262
2263     hBestFitIcon = CopyImage(
2264         hIcon, IMAGE_ICON, 
2265         himl->cx, himl->cy, 
2266         LR_COPYFROMRESOURCE);
2267
2268     GetIconInfo (hBestFitIcon, &ii);
2269     if (ii.hbmMask == 0)
2270         ERR("no mask!\n");
2271     if (ii.hbmColor == 0)
2272         ERR("no color!\n");
2273     GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2274
2275     if (i == -1) {
2276         if (himl->cCurImage + 1 >= himl->cMaxImage)
2277             IMAGELIST_InternalExpandBitmaps (himl, 1);
2278
2279         nIndex = himl->cCurImage;
2280         himl->cCurImage++;
2281     }
2282     else
2283         nIndex = i;
2284
2285     hdcImageList = CreateCompatibleDC (0);
2286     TRACE("hdcImageList=0x%x!\n", hdcImageList);
2287     if (hdcImageList == 0)
2288         ERR("invalid hdcImageList!\n");
2289
2290     hdcImage = CreateCompatibleDC (0);
2291     TRACE("hdcImage=0x%x!\n", hdcImage);
2292     if (hdcImage == 0)
2293         ERR("invalid hdcImage!\n");
2294
2295     hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2296     SetTextColor( hdcImageList, RGB(0,0,0));
2297     SetBkColor( hdcImageList, RGB(255,255,255));
2298     hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2299     StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2300                   hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2301
2302     if (himl->hbmMask) {
2303         SelectObject (hdcImageList, himl->hbmMask);
2304         SelectObject (hdcImage, ii.hbmMask);
2305         StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2306                       hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2307     }
2308
2309     SelectObject (hdcImage, hbmOldSrc);
2310     SelectObject (hdcImageList, hbmOldDst);
2311
2312     if(hBestFitIcon)
2313         DestroyIcon(hBestFitIcon);
2314     if (hdcImageList)
2315         DeleteDC (hdcImageList);
2316     if (hdcImage)
2317         DeleteDC (hdcImage);
2318     if (ii.hbmColor)
2319         DeleteObject (ii.hbmColor);
2320     if (ii.hbmMask)
2321         DeleteObject (ii.hbmMask);
2322
2323     return nIndex;
2324 }
2325
2326
2327 /*************************************************************************
2328  * ImageList_SetBkColor [COMCTL32.70] 
2329  *
2330  * Sets the background color of an image list.
2331  *
2332  * PARAMS
2333  *     himl  [I] handle to image list
2334  *     clrBk [I] background color
2335  *
2336  * RETURNS
2337  *     Success: previous background color
2338  *     Failure: CLR_NONE
2339  */
2340
2341 COLORREF WINAPI
2342 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2343 {
2344     COLORREF clrOldBk;
2345
2346     if (himl == NULL)
2347         return CLR_NONE;
2348
2349     clrOldBk = himl->clrBk;
2350     himl->clrBk = clrBk;
2351     return clrOldBk;
2352 }
2353
2354
2355 /*************************************************************************
2356  * ImageList_SetDragCursorImage [COMCTL32.75]
2357  *
2358  * Combines the specified image with the current drag image
2359  *
2360  * PARAMS
2361  *     himlDrag  [I] handle to drag image list
2362  *     iDrag     [I] drag image index
2363  *     dxHotspot [I] X position of the hot spot
2364  *     dyHotspot [I] Y position of the hot spot
2365  *
2366  * RETURNS
2367  *     Success: TRUE
2368  *     Failure: FALSE
2369  *
2370  * BUGS
2371  *     semi-stub.
2372  */
2373
2374 BOOL WINAPI
2375 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2376                               INT dxHotspot, INT dyHotspot)
2377 {
2378     HIMAGELIST himlTemp;
2379
2380     FIXME("semi-stub!\n");
2381
2382     if (himlInternalDrag == NULL)
2383         return FALSE;
2384
2385     TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2386            dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2387
2388     himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2389                                 dxHotspot, dyHotspot);
2390
2391     ImageList_Destroy (himlInternalDrag);
2392     himlInternalDrag = himlTemp;
2393
2394     nInternalDragHotspotX = dxHotspot;
2395     nInternalDragHotspotY = dyHotspot;
2396
2397     return FALSE;
2398 }
2399
2400
2401 /*************************************************************************
2402  * ImageList_SetFilter [COMCTL32.76] 
2403  *
2404  * Sets a filter (or does something completely different)!!???
2405  *
2406  * PARAMS
2407  *     himl     [I] handle to image list
2408  *     i        [I] ???
2409  *     dwFilter [I] ???
2410  *
2411  * RETURNS
2412  *     Success: TRUE ???
2413  *     Failure: FALSE ???
2414  *
2415  * BUGS
2416  *     This is an UNDOCUMENTED function!!!!
2417  *     empty stub.
2418  */
2419
2420 BOOL WINAPI
2421 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2422 {
2423     FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2424            himl, i, dwFilter);
2425
2426     return FALSE;
2427 }
2428
2429
2430 /*************************************************************************
2431  * ImageList_SetIconSize [COMCTL32.77]
2432  *
2433  * Sets the image size of the bitmap and deletes all images.
2434  *
2435  * PARAMS
2436  *     himl [I] handle to image list
2437  *     cx   [I] image width
2438  *     cy   [I] image height
2439  *
2440  * RETURNS
2441  *     Success: TRUE
2442  *     Failure: FALSE
2443  */
2444
2445 BOOL WINAPI
2446 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2447 {
2448     INT nCount;
2449
2450     if (!himl)
2451         return FALSE;
2452
2453     /* remove all images*/
2454     himl->cMaxImage = himl->cInitial + himl->cGrow;
2455     himl->cCurImage = 0;
2456     himl->cx        = cx;
2457     himl->cy        = cy;
2458
2459     /* initialize overlay mask indices */
2460     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2461         himl->nOvlIdx[nCount] = -1;
2462
2463     DeleteObject (himl->hbmImage);
2464     himl->hbmImage =
2465         CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2466                         1, himl->uBitsPixel, NULL);
2467
2468     if (himl->hbmMask) {
2469         DeleteObject (himl->hbmMask);
2470         himl->hbmMask =
2471             CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2472                             1, 1, NULL);
2473     }
2474
2475     return TRUE;
2476 }
2477
2478
2479 /*************************************************************************
2480  * ImageList_SetImageCount [COMCTL32.78]
2481  *
2482  * Resizes an image list to the specified number of images.
2483  *
2484  * PARAMS
2485  *     himl        [I] handle to image list
2486  *     iImageCount [I] number of images in the image list
2487  *
2488  * RETURNS
2489  *     Success: TRUE
2490  *     Failure: FALSE
2491  */
2492
2493 BOOL WINAPI
2494 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2495 {
2496     HDC     hdcImageList, hdcBitmap;
2497     HBITMAP hbmNewBitmap;
2498     INT     nNewCount, nCopyCount;
2499
2500     if (!himl)
2501         return FALSE;
2502     if (himl->cCurImage >= iImageCount)
2503         return FALSE;
2504     if (himl->cMaxImage > iImageCount)
2505         return TRUE;
2506
2507     nNewCount = iImageCount + himl->cGrow;
2508     nCopyCount = _MIN(himl->cCurImage, iImageCount);
2509
2510     hdcImageList = CreateCompatibleDC (0);
2511     hdcBitmap = CreateCompatibleDC (0);
2512
2513     hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2514                                    1, himl->uBitsPixel, NULL);
2515     if (hbmNewBitmap != 0)
2516     {
2517         SelectObject (hdcImageList, himl->hbmImage);
2518         SelectObject (hdcBitmap, hbmNewBitmap);
2519
2520         /* copy images */
2521         BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2522                   hdcImageList, 0, 0, SRCCOPY);
2523 #if 0
2524         /* delete 'empty' image space */
2525         SetBkColor (hdcBitmap, RGB(255, 255, 255));
2526         SetTextColor (hdcBitmap, RGB(0, 0, 0));
2527         PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2528                   (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2529 #endif
2530         DeleteObject (himl->hbmImage);
2531         himl->hbmImage = hbmNewBitmap;
2532     }
2533     else
2534         ERR("Could not create new image bitmap !\n");
2535
2536     if (himl->hbmMask)
2537     {
2538         hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2539                                        1, 1, NULL);
2540         if (hbmNewBitmap != 0)
2541         {
2542             SelectObject (hdcImageList, himl->hbmMask);
2543             SelectObject (hdcBitmap, hbmNewBitmap);
2544
2545             /* copy images */
2546             BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2547                       hdcImageList, 0, 0, SRCCOPY);
2548 #if 0
2549             /* delete 'empty' image space */
2550             SetBkColor (hdcBitmap, RGB(255, 255, 255));
2551             SetTextColor (hdcBitmap, RGB(0, 0, 0));
2552             PatBlt (hdcBitmap,  nCopyCount * himl->cx, 0, 
2553                       (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2554 #endif
2555             DeleteObject (himl->hbmMask);
2556             himl->hbmMask = hbmNewBitmap;
2557         }
2558         else
2559             ERR("Could not create new mask bitmap!\n");
2560     }
2561
2562     DeleteDC (hdcImageList);
2563     DeleteDC (hdcBitmap);
2564
2565     /* Update max image count and current image count */
2566     himl->cMaxImage = nNewCount;
2567     if (himl->cCurImage > nCopyCount)
2568         himl->cCurImage = nCopyCount;
2569
2570     return TRUE;
2571 }
2572
2573
2574 /*************************************************************************
2575  * ImageList_SetOverlayImage [COMCTL32.79]
2576  *
2577  * Assigns an overlay mask index to an existing image in an image list.
2578  *
2579  * PARAMS
2580  *     himl     [I] handle to image list
2581  *     iImage   [I] image index
2582  *     iOverlay [I] overlay mask index
2583  *
2584  * RETURNS
2585  *     Success: TRUE
2586  *     Failure: FALSE
2587  */
2588
2589 BOOL WINAPI
2590 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2591 {
2592     if (!himl)
2593         return FALSE;
2594     if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2595         return FALSE;
2596     if ((iImage < 0) || (iImage > himl->cCurImage))
2597         return FALSE;
2598     
2599     himl->nOvlIdx[iOverlay - 1] = iImage;
2600     return TRUE;
2601 }
2602
2603
2604 /*************************************************************************
2605  * ImageList_Write [COMCTL32.80]
2606  *
2607  * Writes an image list to a stream.
2608  *
2609  * PARAMS
2610  *     himl [I] handle to image list
2611  *     pstm [O] Pointer to a stream.
2612  *
2613  * RETURNS
2614  *     Success: TRUE
2615  *     Failure: FALSE
2616  *
2617  * NOTES
2618  *     This function can not be implemented yet, because
2619  *     IStream32::Write is not implemented.
2620  *
2621  * BUGS
2622  *     empty stub.
2623  */
2624
2625 BOOL WINAPI
2626 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2627 {
2628     if (!himl)
2629         return FALSE;
2630
2631     FIXME("empty stub!\n");
2632
2633     return FALSE;
2634 }
2635