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