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