[COMCTL32] Improve failure cases.
[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 if (!BitBlt( hdc, 0, 0, cx, cy, srce_dc, src_x, src_y, SRCCOPY ))
1320 {
1321 TRACE("BitBlt failed\n");
1322 goto done;
1323 }
1324 #else
1325 BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
1326 #endif
1327
1328 if (blend_col != CLR_NONE)
1329 {
1330 BYTE r = GetRValue( blend_col );
1331 BYTE g = GetGValue( blend_col );
1332 BYTE b = GetBValue( blend_col );
1333
1334 if (style & ILD_BLEND25)
1335 {
1336 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1337 *ptr = ((*ptr & 0xff000000) |
1338 ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
1339 ((((*ptr & 0x0000ff00) * 3 + (g << 8)) / 4) & 0x0000ff00) |
1340 ((((*ptr & 0x000000ff) * 3 + (b << 0)) / 4) & 0x000000ff));
1341 }
1342 else if (style & ILD_BLEND50)
1343 {
1344 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1345 *ptr = ((*ptr & 0xff000000) |
1346 ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
1347 ((((*ptr & 0x0000ff00) + (g << 8)) / 2) & 0x0000ff00) |
1348 ((((*ptr & 0x000000ff) + (b << 0)) / 2) & 0x000000ff));
1349 }
1350 }
1351
1352 if (himl->has_alpha) /* we already have an alpha channel in this case */
1353 {
1354 /* pre-multiply by the alpha channel */
1355 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1356 {
1357 DWORD alpha = *ptr >> 24;
1358 *ptr = ((*ptr & 0xff000000) |
1359 (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
1360 (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
1361 (((*ptr & 0x000000ff) * alpha / 255)));
1362 }
1363 }
1364 else if (himl->hbmMask)
1365 {
1366 unsigned int width_bytes = (cx + 31) / 32 * 4;
1367 /* generate alpha channel from the mask */
1368 info->bmiHeader.biBitCount = 1;
1369 info->bmiHeader.biSizeImage = width_bytes * cy;
1370 info->bmiColors[0].rgbRed = 0;
1371 info->bmiColors[0].rgbGreen = 0;
1372 info->bmiColors[0].rgbBlue = 0;
1373 info->bmiColors[0].rgbReserved = 0;
1374 info->bmiColors[1].rgbRed = 0xff;
1375 info->bmiColors[1].rgbGreen = 0xff;
1376 info->bmiColors[1].rgbBlue = 0xff;
1377 info->bmiColors[1].rgbReserved = 0;
1378 if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
1379 {
1380 TRACE("CreateDIBSection failed %i\n", GetLastError());
1381 goto done;
1382 }
1383 if (SelectObject(hdc, mask) == NULL)
1384 {
1385 TRACE("SelectObject failed %i\n", GetLastError());
1386 SelectObject(hdc, bmp);
1387 goto done;
1388 }
1389 if (!BitBlt(hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY))
1390 {
1391 TRACE("BitBlt failed %i\n", GetLastError());
1392 SelectObject(hdc, bmp);
1393 goto done;
1394 }
1395 if (SelectObject(hdc, bmp) == NULL)
1396 {
1397 TRACE("SelectObject failed %i\n", GetLastError());
1398 goto done;
1399 }
1400 for (i = 0, ptr = bits; i < cy; i++)
1401 for (j = 0; j < cx; j++, ptr++)
1402 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1403 else *ptr |= 0xff000000;
1404 }
1405
1406 ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
1407
1408 done:
1409 DeleteDC( hdc );
1410 if (bmp) DeleteObject( bmp );
1411 if (mask) DeleteObject( mask );
1412 heap_free( info );
1413 return ret;
1414 }
1415
1416 #ifdef __REACTOS__
1417 HDC saturate_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1418 int src_x, int src_y, int cx, int cy, COLORREF rgbFg)
1419 {
1420 HDC hdc = NULL;
1421 HBITMAP bmp = 0;
1422 BITMAPINFO *info;
1423
1424 unsigned int *ptr;
1425 void *bits;
1426 int i;
1427
1428 /* create a dc and its device independent bitmap for doing the work,
1429 shamelessly copied from the alpha-blending function above */
1430 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1431 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1432 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1433 info->bmiHeader.biWidth = cx;
1434 info->bmiHeader.biHeight = cy;
1435 info->bmiHeader.biPlanes = 1;
1436 info->bmiHeader.biBitCount = 32;
1437 info->bmiHeader.biCompression = BI_RGB;
1438 info->bmiHeader.biSizeImage = cx * cy * 4;
1439 info->bmiHeader.biXPelsPerMeter = 0;
1440 info->bmiHeader.biYPelsPerMeter = 0;
1441 info->bmiHeader.biClrUsed = 0;
1442 info->bmiHeader.biClrImportant = 0;
1443 if (!(bmp = CreateDIBSection(himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1444
1445 /* bind both surfaces */
1446 if (SelectObject(hdc, bmp) == NULL)
1447 {
1448 TRACE("SelectObject failed\n");
1449 goto done;
1450 }
1451
1452 /* copy into our dc the section that covers just the icon we we're asked for */
1453 if (!BitBlt(hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY))
1454 {
1455 TRACE("BitBlt failed!\n");
1456 goto done;
1457 }
1458
1459 /* loop every pixel of the bitmap */
1460 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1461 {
1462 COLORREF orig_color = *ptr;
1463
1464 /* calculate the effective luminance using the constants from here, adapted to the human eye:
1465 <http://bobpowell.net/grayscale.aspx> */
1466 float mixed_color = (GetRValue(orig_color) * .30 +
1467 GetGValue(orig_color) * .59 +
1468 GetBValue(orig_color) * .11);
1469
1470 *ptr = RGBA(mixed_color, mixed_color, mixed_color, GetAValue(orig_color));
1471 }
1472
1473 done:
1474
1475 if (bmp)
1476 DeleteObject(bmp);
1477
1478 if (info)
1479 HeapFree(GetProcessHeap(), 0, info);
1480
1481 /* return the handle to our desaturated dc, that will substitute its original counterpart in the next calls */
1482 return hdc;
1483 }
1484 #endif /* __REACTOS__ */
1485
1486 /*************************************************************************
1487 * ImageList_DrawIndirect [COMCTL32.@]
1488 *
1489 * Draws an image using various parameters specified in pimldp.
1490 *
1491 * PARAMS
1492 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1493 *
1494 * RETURNS
1495 * Success: TRUE
1496 * Failure: FALSE
1497 */
1498
1499 BOOL WINAPI
1500 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1501 {
1502 INT cx, cy, nOvlIdx;
1503 DWORD fState, dwRop;
1504 UINT fStyle;
1505 COLORREF oldImageBk, oldImageFg;
1506 HDC hImageDC, hImageListDC, hMaskListDC;
1507 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1508 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1509 HIMAGELIST himl;
1510 HBRUSH hOldBrush;
1511 POINT pt;
1512 BOOL has_alpha;
1513 #ifdef __REACTOS__
1514 HDC hdcSaturated = NULL;
1515 #endif
1516
1517 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1518 if (!is_valid(himl)) return FALSE;
1519 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1520
1521 imagelist_point_from_index( himl, pimldp->i, &pt );
1522 pt.x += pimldp->xBitmap;
1523 pt.y += pimldp->yBitmap;
1524
1525 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1526 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1527 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1528 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1529
1530 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1531 if( pimldp->rgbBk == CLR_NONE )
1532 bIsTransparent = TRUE;
1533 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1534 bIsTransparent = TRUE;
1535 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1536 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1537
1538 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1539 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1540
1541 /* we will use these DCs to access the images and masks in the ImageList */
1542 hImageListDC = himl->hdcImage;
1543 hMaskListDC = himl->hdcMask;
1544
1545 /* these will accumulate the image and mask for the image we're drawing */
1546 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1547 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1548 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1549
1550 /* Create a compatible DC. */
1551 if (!hImageListDC || !hImageDC || !hImageBmp ||
1552 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1553 goto cleanup;
1554
1555 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1556
1557 /*
1558 * To obtain a transparent look, background color should be set
1559 * to white and foreground color to black when blitting the
1560 * monochrome mask.
1561 */
1562 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1563 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1564
1565 #ifdef __REACTOS__
1566 /*
1567 * If the ILS_SATURATE bit is enabled we should multiply the
1568 * RGB colors of the original image by the contents of rgbFg.
1569 */
1570 if (fState & ILS_SATURATE)
1571 {
1572 hdcSaturated = saturate_image(himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1573 pt.x, pt.y, cx, cy, pimldp->rgbFg);
1574
1575 if (hdcSaturated != NULL)
1576 {
1577 hImageListDC = hdcSaturated;
1578 /* shitty way of getting subroutines to blit at the right place (top left corner),
1579 as our modified imagelist only contains a single image for performance reasons */
1580 pt.x = 0;
1581 pt.y = 0;
1582 }
1583 }
1584 #endif
1585
1586 has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
1587 if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1588 {
1589 COLORREF colour, blend_col = CLR_NONE;
1590 BLENDFUNCTION func;
1591
1592 if (bBlend)
1593 {
1594 blend_col = pimldp->rgbFg;
1595 if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
1596 else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
1597 }
1598
1599 func.BlendOp = AC_SRC_OVER;
1600 func.BlendFlags = 0;
1601 func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
1602 func.AlphaFormat = AC_SRC_ALPHA;
1603
1604 if (bIsTransparent)
1605 {
1606 #ifdef __REACTOS__
1607 bResult = alpha_blend_image( himl, hImageListDC, pimldp->hdcDst, pimldp->x, pimldp->y,
1608 #else
1609 bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1610 #endif
1611 pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1612 goto end;
1613 }
1614 colour = pimldp->rgbBk;
1615 if (colour == CLR_DEFAULT) colour = himl->clrBk;
1616 if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
1617
1618 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1619 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1620 #ifdef __REACTOS__
1621 alpha_blend_image( himl, hImageListDC, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1622 #else
1623 alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1624 #endif
1625 DeleteObject (SelectObject (hImageDC, hOldBrush));
1626 bResult = BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
1627 goto end;
1628 }
1629
1630 /*
1631 * Draw the initial image
1632 */
1633 if( bMask ) {
1634 if (himl->hbmMask) {
1635 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1636 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1637 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1638 DeleteObject (SelectObject (hImageDC, hOldBrush));
1639 if( bIsTransparent )
1640 {
1641 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1642 bResult = TRUE;
1643 goto end;
1644 }
1645 } else {
1646 hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1647 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1648 SelectObject(hImageDC, hOldBrush);
1649 }
1650 } else {
1651 /* blend the image with the needed solid background */
1652 COLORREF colour = RGB(0,0,0);
1653
1654 if( !bIsTransparent )
1655 {
1656 colour = pimldp->rgbBk;
1657 if( colour == CLR_DEFAULT )
1658 colour = himl->clrBk;
1659 if( colour == CLR_NONE )
1660 colour = GetBkColor(pimldp->hdcDst);
1661 }
1662
1663 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1664 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1665 if (himl->hbmMask)
1666 {
1667 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1668 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1669 }
1670 else
1671 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1672 DeleteObject (SelectObject (hImageDC, hOldBrush));
1673 }
1674
1675 /* Time for blending, if required */
1676 if (bBlend) {
1677 HBRUSH hBlendBrush;
1678 COLORREF clrBlend = pimldp->rgbFg;
1679 HDC hBlendMaskDC = hImageListDC;
1680 HBITMAP hOldBitmap;
1681
1682 /* Create the blend Mask */
1683 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1684 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1685 hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1686 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1687 SelectObject(hBlendMaskDC, hOldBrush);
1688
1689 /* Modify the blend mask if an Image Mask exist */
1690 if(himl->hbmMask) {
1691 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1692 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1693 }
1694
1695 /* now apply blend to the current image given the BlendMask */
1696 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1697 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1698 hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1699 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1700 DeleteObject(SelectObject(hImageDC, hOldBrush));
1701 SelectObject(hBlendMaskDC, hOldBitmap);
1702 }
1703
1704 /* Now do the overlay image, if any */
1705 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1706 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1707 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1708 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1709 POINT ptOvl;
1710 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1711 ptOvl.x += pimldp->xBitmap;
1712 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1713 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1714 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1715 }
1716 }
1717
1718 #ifndef __REACTOS__
1719 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1720 #endif
1721 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1722 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1723
1724 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1725 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1726 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1727
1728 /* now copy the image to the screen */
1729 dwRop = SRCCOPY;
1730 if (himl->hbmMask && bIsTransparent ) {
1731 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1732 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1733 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1734 SetBkColor(pimldp->hdcDst, oldDstBk);
1735 SetTextColor(pimldp->hdcDst, oldDstFg);
1736 dwRop = SRCPAINT;
1737 }
1738 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1739 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1740
1741 bResult = TRUE;
1742 end:
1743 /* cleanup the mess */
1744 SetBkColor(hImageDC, oldImageBk);
1745 SetTextColor(hImageDC, oldImageFg);
1746 SelectObject(hImageDC, hOldImageBmp);
1747 cleanup:
1748 #ifdef __REACTOS__
1749 if (hdcSaturated)
1750 DeleteDC(hdcSaturated);
1751 #endif
1752 DeleteObject(hBlendMaskBmp);
1753 DeleteObject(hImageBmp);
1754 DeleteDC(hImageDC);
1755
1756 return bResult;
1757 }
1758
1759
1760 /*************************************************************************
1761 * ImageList_Duplicate [COMCTL32.@]
1762 *
1763 * Duplicates an image list.
1764 *
1765 * PARAMS
1766 * himlSrc [I] source image list handle
1767 *
1768 * RETURNS
1769 * Success: Handle of duplicated image list.
1770 * Failure: NULL
1771 */
1772
1773 HIMAGELIST WINAPI
1774 ImageList_Duplicate (HIMAGELIST himlSrc)
1775 {
1776 HIMAGELIST himlDst;
1777
1778 if (!is_valid(himlSrc)) {
1779 ERR("Invalid image list handle!\n");
1780 return NULL;
1781 }
1782
1783 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1784 himlSrc->cCurImage, himlSrc->cGrow);
1785
1786 if (himlDst)
1787 {
1788 SIZE sz;
1789
1790 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1791 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1792 himlSrc->hdcImage, 0, 0, SRCCOPY);
1793
1794 if (himlDst->hbmMask)
1795 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1796 himlSrc->hdcMask, 0, 0, SRCCOPY);
1797
1798 himlDst->cCurImage = himlSrc->cCurImage;
1799 if (himlSrc->has_alpha && himlDst->has_alpha)
1800 memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1801 }
1802 return himlDst;
1803 }
1804
1805
1806 /*************************************************************************
1807 * ImageList_EndDrag [COMCTL32.@]
1808 *
1809 * Finishes a drag operation.
1810 *
1811 * PARAMS
1812 * no Parameters
1813 *
1814 * RETURNS
1815 * Success: TRUE
1816 * Failure: FALSE
1817 */
1818
1819 VOID WINAPI
1820 ImageList_EndDrag (void)
1821 {
1822 /* cleanup the InternalDrag struct */
1823 InternalDrag.hwnd = 0;
1824 if (InternalDrag.himl != InternalDrag.himlNoCursor)
1825 ImageList_Destroy (InternalDrag.himlNoCursor);
1826 ImageList_Destroy (InternalDrag.himl);
1827 InternalDrag.himlNoCursor = InternalDrag.himl = 0;
1828 InternalDrag.x= 0;
1829 InternalDrag.y= 0;
1830 InternalDrag.dxHotspot = 0;
1831 InternalDrag.dyHotspot = 0;
1832 InternalDrag.bShow = FALSE;
1833 DeleteObject(InternalDrag.hbmBg);
1834 InternalDrag.hbmBg = 0;
1835 }
1836
1837
1838 /*************************************************************************
1839 * ImageList_GetBkColor [COMCTL32.@]
1840 *
1841 * Returns the background color of an image list.
1842 *
1843 * PARAMS
1844 * himl [I] Image list handle.
1845 *
1846 * RETURNS
1847 * Success: background color
1848 * Failure: CLR_NONE
1849 */
1850
1851 COLORREF WINAPI
1852 ImageList_GetBkColor (HIMAGELIST himl)
1853 {
1854 return himl ? himl->clrBk : CLR_NONE;
1855 }
1856
1857
1858 /*************************************************************************
1859 * ImageList_GetDragImage [COMCTL32.@]
1860 *
1861 * Returns the handle to the internal drag image list.
1862 *
1863 * PARAMS
1864 * ppt [O] Pointer to the drag position. Can be NULL.
1865 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1866 *
1867 * RETURNS
1868 * Success: Handle of the drag image list.
1869 * Failure: NULL.
1870 */
1871
1872 HIMAGELIST WINAPI
1873 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1874 {
1875 if (is_valid(InternalDrag.himl)) {
1876 if (ppt) {
1877 ppt->x = InternalDrag.x;
1878 ppt->y = InternalDrag.y;
1879 }
1880 if (pptHotspot) {
1881 pptHotspot->x = InternalDrag.dxHotspot;
1882 pptHotspot->y = InternalDrag.dyHotspot;
1883 }
1884 return (InternalDrag.himl);
1885 }
1886
1887 return NULL;
1888 }
1889
1890
1891 /*************************************************************************
1892 * ImageList_GetFlags [COMCTL32.@]
1893 *
1894 * Gets the flags of the specified image list.
1895 *
1896 * PARAMS
1897 * himl [I] Handle to image list
1898 *
1899 * RETURNS
1900 * Image list flags.
1901 *
1902 * BUGS
1903 * Stub.
1904 */
1905
1906 DWORD WINAPI
1907 ImageList_GetFlags(HIMAGELIST himl)
1908 {
1909 TRACE("%p\n", himl);
1910 #ifdef __REACTOS__
1911 if(!is_valid2(himl))
1912 return 0;
1913 return himl->flags;
1914 #else
1915 return is_valid(himl) ? himl->flags : 0;
1916 #endif
1917 }
1918
1919
1920 /*************************************************************************
1921 * ImageList_GetIcon [COMCTL32.@]
1922 *
1923 * Creates an icon from a masked image of an image list.
1924 *
1925 * PARAMS
1926 * himl [I] handle to image list
1927 * i [I] image index
1928 * flags [I] drawing style flags
1929 *
1930 * RETURNS
1931 * Success: icon handle
1932 * Failure: NULL
1933 */
1934
1935 HICON WINAPI
1936 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1937 {
1938 ICONINFO ii;
1939 HICON hIcon;
1940 HBITMAP hOldDstBitmap;
1941 HDC hdcDst;
1942 POINT pt;
1943
1944 TRACE("%p %d %d\n", himl, i, fStyle);
1945 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1946
1947 ii.fIcon = TRUE;
1948 ii.xHotspot = 0;
1949 ii.yHotspot = 0;
1950
1951 /* create colour bitmap */
1952 hdcDst = GetDC(0);
1953 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1954 ReleaseDC(0, hdcDst);
1955
1956 hdcDst = CreateCompatibleDC(0);
1957
1958 imagelist_point_from_index( himl, i, &pt );
1959
1960 /* draw mask*/
1961 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1962 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1963 if (himl->hbmMask) {
1964 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1965 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1966 }
1967 else
1968 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1969
1970 /* draw image*/
1971 SelectObject (hdcDst, ii.hbmColor);
1972 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1973 himl->hdcImage, pt.x, pt.y, SRCCOPY);
1974
1975 /*
1976 * CreateIconIndirect requires us to deselect the bitmaps from
1977 * the DCs before calling
1978 */
1979 SelectObject(hdcDst, hOldDstBitmap);
1980
1981 hIcon = CreateIconIndirect (&ii);
1982
1983 DeleteObject (ii.hbmMask);
1984 DeleteObject (ii.hbmColor);
1985 DeleteDC (hdcDst);
1986
1987 return hIcon;
1988 }
1989
1990
1991 /*************************************************************************
1992 * ImageList_GetIconSize [COMCTL32.@]
1993 *
1994 * Retrieves the size of an image in an image list.
1995 *
1996 * PARAMS
1997 * himl [I] handle to image list
1998 * cx [O] pointer to the image width.
1999 * cy [O] pointer to the image height.
2000 *
2001 * RETURNS
2002 * Success: TRUE
2003 * Failure: FALSE
2004 *
2005 * NOTES
2006 * All images in an image list have the same size.
2007 */
2008
2009 BOOL WINAPI
2010 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
2011 {
2012 if (!is_valid(himl) || !cx || !cy)
2013 return FALSE;
2014
2015 *cx = himl->cx;
2016 *cy = himl->cy;
2017
2018 return TRUE;
2019 }
2020
2021
2022 /*************************************************************************
2023 * ImageList_GetImageCount [COMCTL32.@]
2024 *
2025 * Returns the number of images in an image list.
2026 *
2027 * PARAMS
2028 * himl [I] handle to image list
2029 *
2030 * RETURNS
2031 * Success: Number of images.
2032 * Failure: 0
2033 */
2034
2035 INT WINAPI
2036 ImageList_GetImageCount (HIMAGELIST himl)
2037 {
2038 if (!is_valid(himl))
2039 return 0;
2040
2041 return himl->cCurImage;
2042 }
2043
2044
2045 /*************************************************************************
2046 * ImageList_GetImageInfo [COMCTL32.@]
2047 *
2048 * Returns information about an image in an image list.
2049 *
2050 * PARAMS
2051 * himl [I] handle to image list
2052 * i [I] image index
2053 * pImageInfo [O] pointer to the image information
2054 *
2055 * RETURNS
2056 * Success: TRUE
2057 * Failure: FALSE
2058 */
2059
2060 BOOL WINAPI
2061 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
2062 {
2063 POINT pt;
2064
2065 if (!is_valid(himl) || (pImageInfo == NULL))
2066 return FALSE;
2067 if ((i < 0) || (i >= himl->cCurImage))
2068 return FALSE;
2069
2070 pImageInfo->hbmImage = himl->hbmImage;
2071 pImageInfo->hbmMask = himl->hbmMask;
2072
2073 imagelist_point_from_index( himl, i, &pt );
2074 pImageInfo->rcImage.top = pt.y;
2075 pImageInfo->rcImage.bottom = pt.y + himl->cy;
2076 pImageInfo->rcImage.left = pt.x;
2077 pImageInfo->rcImage.right = pt.x + himl->cx;
2078
2079 return TRUE;
2080 }
2081
2082
2083 /*************************************************************************
2084 * ImageList_GetImageRect [COMCTL32.@]
2085 *
2086 * Retrieves the rectangle of the specified image in an image list.
2087 *
2088 * PARAMS
2089 * himl [I] handle to image list
2090 * i [I] image index
2091 * lpRect [O] pointer to the image rectangle
2092 *
2093 * RETURNS
2094 * Success: TRUE
2095 * Failure: FALSE
2096 *
2097 * NOTES
2098 * This is an UNDOCUMENTED function!!!
2099 */
2100
2101 BOOL WINAPI
2102 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
2103 {
2104 #ifdef __REACTOS__
2105 IMAGEINFO ImageInfo;
2106 if (!ImageList_GetImageInfo(himl, i, &ImageInfo))
2107 return FALSE;
2108 *lpRect = ImageInfo.rcImage;
2109 #else
2110 POINT pt;
2111
2112 if (!is_valid(himl) || (lpRect == NULL))
2113 return FALSE;
2114 if ((i < 0) || (i >= himl->cCurImage))
2115 return FALSE;
2116
2117 imagelist_point_from_index( himl, i, &pt );
2118 lpRect->left = pt.x;
2119 lpRect->top = pt.y;
2120 lpRect->right = pt.x + himl->cx;
2121 lpRect->bottom = pt.y + himl->cy;
2122 #endif
2123 return TRUE;
2124 }
2125
2126
2127 /*************************************************************************
2128 * ImageList_LoadImage [COMCTL32.@]
2129 * ImageList_LoadImageA [COMCTL32.@]
2130 *
2131 * Creates an image list from a bitmap, icon or cursor.
2132 *
2133 * See ImageList_LoadImageW.
2134 */
2135
2136 HIMAGELIST WINAPI
2137 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
2138 COLORREF clrMask, UINT uType, UINT uFlags)
2139 {
2140 HIMAGELIST himl;
2141 LPWSTR lpbmpW;
2142 DWORD len;
2143
2144 if (IS_INTRESOURCE(lpbmp))
2145 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
2146 uType, uFlags);
2147
2148 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
2149 lpbmpW = heap_alloc(len * sizeof(WCHAR));
2150 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
2151
2152 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
2153 heap_free (lpbmpW);
2154 return himl;
2155 }
2156
2157
2158 /*************************************************************************
2159 * ImageList_LoadImageW [COMCTL32.@]
2160 *
2161 * Creates an image list from a bitmap, icon or cursor.
2162 *
2163 * PARAMS
2164 * hi [I] instance handle
2165 * lpbmp [I] name or id of the image
2166 * cx [I] width of each image
2167 * cGrow [I] number of images to expand
2168 * clrMask [I] mask color
2169 * uType [I] type of image to load
2170 * uFlags [I] loading flags
2171 *
2172 * RETURNS
2173 * Success: handle to the loaded image list
2174 * Failure: NULL
2175 *
2176 * SEE
2177 * LoadImage ()
2178 */
2179
2180 HIMAGELIST WINAPI
2181 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
2182 COLORREF clrMask, UINT uType, UINT uFlags)
2183 {
2184 HIMAGELIST himl = NULL;
2185 HANDLE handle;
2186 INT nImageCount;
2187
2188 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
2189 if (!handle) {
2190 WARN("Couldn't load image\n");
2191 return NULL;
2192 }
2193
2194 if (uType == IMAGE_BITMAP) {
2195 DIBSECTION dib;
2196 UINT color;
2197
2198 if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
2199 else color = dib.dsBm.bmBitsPixel;
2200
2201 /* To match windows behavior, if cx is set to zero and
2202 the flag DI_DEFAULTSIZE is specified, cx becomes the
2203 system metric value for icons. If the flag is not specified
2204 the function sets the size to the height of the bitmap */
2205 if (cx == 0)
2206 {
2207 if (uFlags & DI_DEFAULTSIZE)
2208 cx = GetSystemMetrics (SM_CXICON);
2209 else
2210 cx = dib.dsBm.bmHeight;
2211 }
2212
2213 nImageCount = dib.dsBm.bmWidth / cx;
2214
2215 if (clrMask != CLR_NONE) color |= ILC_MASK;
2216 himl = ImageList_Create (cx, dib.dsBm.bmHeight, color, nImageCount, cGrow);
2217 if (!himl) {
2218 DeleteObject (handle);
2219 return NULL;
2220 }
2221 ImageList_AddMasked (himl, handle, clrMask);
2222 }
2223 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2224 ICONINFO ii;
2225 BITMAP bmp;
2226
2227 GetIconInfo (handle, &ii);
2228 GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2229 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
2230 ILC_MASK | ILC_COLOR, 1, cGrow);
2231 if (!himl) {
2232 DeleteObject (ii.hbmColor);
2233 DeleteObject (ii.hbmMask);
2234 DeleteObject (handle);
2235 return NULL;
2236 }
2237 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
2238 DeleteObject (ii.hbmColor);
2239 DeleteObject (ii.hbmMask);
2240 }
2241
2242 DeleteObject (handle);
2243
2244 return himl;
2245 }
2246
2247
2248 /*************************************************************************
2249 * ImageList_Merge [COMCTL32.@]
2250 *
2251 * Create an image list containing a merged image from two image lists.
2252 *
2253 * PARAMS
2254 * himl1 [I] handle to first image list
2255 * i1 [I] first image index
2256 * himl2 [I] handle to second image list
2257 * i2 [I] second image index
2258 * dx [I] X offset of the second image relative to the first.
2259 * dy [I] Y offset of the second image relative to the first.
2260 *
2261 * RETURNS
2262 * Success: The newly created image list. It contains a single image
2263 * consisting of the second image merged with the first.
2264 * Failure: NULL, if either himl1 or himl2 is invalid.
2265 *
2266 * NOTES
2267 * - The returned image list should be deleted by the caller using
2268 * ImageList_Destroy() when it is no longer required.
2269 * - If either i1 or i2 is not a valid image index, they will be treated
2270 * as blank images.
2271 */
2272 HIMAGELIST WINAPI
2273 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
2274 INT dx, INT dy)
2275 {
2276 HIMAGELIST himlDst = NULL;
2277 INT cxDst, cyDst;
2278 INT xOff1, yOff1, xOff2, yOff2;
2279 POINT pt1, pt2;
2280 INT newFlags;
2281
2282 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
2283 i2, dx, dy);
2284
2285 if (!is_valid(himl1) || !is_valid(himl2))
2286 return NULL;
2287
2288 if (dx > 0) {
2289 cxDst = max (himl1->cx, dx + himl2->cx);
2290 xOff1 = 0;
2291 xOff2 = dx;
2292 }
2293 else if (dx < 0) {
2294 cxDst = max (himl2->cx, himl1->cx - dx);
2295 xOff1 = -dx;
2296 xOff2 = 0;
2297 }
2298 else {
2299 cxDst = max (himl1->cx, himl2->cx);
2300 xOff1 = 0;
2301 xOff2 = 0;
2302 }
2303
2304 if (dy > 0) {
2305 cyDst = max (himl1->cy, dy + himl2->cy);
2306 yOff1 = 0;
2307 yOff2 = dy;
2308 }
2309 else if (dy < 0) {
2310 cyDst = max (himl2->cy, himl1->cy - dy);
2311 yOff1 = -dy;
2312 yOff2 = 0;
2313 }
2314 else {
2315 cyDst = max (himl1->cy, himl2->cy);
2316 yOff1 = 0;
2317 yOff2 = 0;
2318 }
2319
2320 newFlags = (himl1->flags > himl2->flags ? himl1->flags : himl2->flags) & ILC_COLORDDB;
2321 if (newFlags == ILC_COLORDDB && (himl1->flags & ILC_COLORDDB) == ILC_COLOR16)
2322 newFlags = ILC_COLOR16; /* this is what native (at least v5) does, don't know why */
2323 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | newFlags, 1, 1);
2324
2325 if (himlDst)
2326 {
2327 imagelist_point_from_index( himl1, i1, &pt1 );
2328 imagelist_point_from_index( himl2, i2, &pt2 );
2329
2330 /* copy image */
2331 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
2332 if (i1 >= 0 && i1 < himl1->cCurImage)
2333 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2334 if (i2 >= 0 && i2 < himl2->cCurImage)
2335 {
2336 if (himl2->flags & ILC_MASK)
2337 {
2338 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
2339 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2340 }
2341 else
2342 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCCOPY);
2343 }
2344
2345 /* copy mask */
2346 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
2347 if (i1 >= 0 && i1 < himl1->cCurImage)
2348 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
2349 if (i2 >= 0 && i2 < himl2->cCurImage)
2350 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
2351
2352 himlDst->cCurImage = 1;
2353 }
2354
2355 return himlDst;
2356 }
2357
2358
2359 /* helper for ImageList_Read, see comments below */
2360 static void *read_bitmap(IStream *pstm, BITMAPINFO *bmi)
2361 {
2362 BITMAPFILEHEADER bmfh;
2363 int bitsperpixel, palspace;
2364 void *bits;
2365
2366 if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2367 return NULL;
2368
2369 if (bmfh.bfType != (('M'<<8)|'B'))
2370 return NULL;
2371
2372 if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2373 return NULL;
2374
2375 if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2376 return NULL;
2377
2378 TRACE("width %u, height %u, planes %u, bpp %u\n",
2379 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
2380 bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
2381
2382 bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2383 if (bitsperpixel<=8)
2384 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2385 else
2386 palspace = 0;
2387
2388 bmi->bmiHeader.biSizeImage = get_dib_image_size( bmi );
2389
2390 /* read the palette right after the end of the bitmapinfoheader */
2391 if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2392 return NULL;
2393
2394 bits = heap_alloc_zero(bmi->bmiHeader.biSizeImage);
2395 if (!bits) return NULL;
2396
2397 if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
2398 {
2399 heap_free(bits);
2400 return NULL;
2401 }
2402 return bits;
2403 }
2404
2405 /*************************************************************************
2406 * ImageList_Read [COMCTL32.@]
2407 *
2408 * Reads an image list from a stream.
2409 *
2410 * PARAMS
2411 * pstm [I] pointer to a stream
2412 *
2413 * RETURNS
2414 * Success: handle to image list
2415 * Failure: NULL
2416 *
2417 * The format is like this:
2418 * ILHEAD ilheadstruct;
2419 *
2420 * for the color image part:
2421 * BITMAPFILEHEADER bmfh;
2422 * BITMAPINFOHEADER bmih;
2423 * only if it has a palette:
2424 * RGBQUAD rgbs[nr_of_paletted_colors];
2425 *
2426 * BYTE colorbits[imagesize];
2427 *
2428 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2429 * BITMAPFILEHEADER bmfh_mask;
2430 * BITMAPINFOHEADER bmih_mask;
2431 * only if it has a palette (it usually does not):
2432 * RGBQUAD rgbs[nr_of_paletted_colors];
2433 *
2434 * BYTE maskbits[imagesize];
2435 */
2436 HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
2437 {
2438 char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2439 char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2440 BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
2441 BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
2442 void *image_bits, *mask_bits = NULL;
2443 ILHEAD ilHead;
2444 HIMAGELIST himl;
2445 unsigned int i;
2446
2447 TRACE("%p\n", pstm);
2448
2449 if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2450 return NULL;
2451 if (ilHead.usMagic != (('L' << 8) | 'I'))
2452 return NULL;
2453 if (ilHead.usVersion != 0x101) /* probably version? */
2454 return NULL;
2455
2456 TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
2457 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2458
2459 himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2460 if (!himl)
2461 return NULL;
2462
2463 if (!(image_bits = read_bitmap(pstm, image_info)))
2464 {
2465 WARN("failed to read bitmap from stream\n");
2466 return NULL;
2467 }
2468 if (ilHead.flags & ILC_MASK)
2469 {
2470 if (!(mask_bits = read_bitmap(pstm, mask_info)))
2471 {
2472 WARN("failed to read mask bitmap from stream\n");
2473 return NULL;
2474 }
2475 }
2476 else mask_info = NULL;
2477
2478 if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
2479 {
2480 DWORD *ptr = image_bits;
2481 BYTE *mask_ptr = mask_bits;
2482 int stride = himl->cy * image_info->bmiHeader.biWidth;
2483
2484 if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
2485 {
2486 ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
2487 mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2488 stride = -stride;
2489 image_info->bmiHeader.biHeight = himl->cy;
2490 }
2491 else image_info->bmiHeader.biHeight = -himl->cy;
2492
2493 for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
2494 {
2495 add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
2496 himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
2497 ptr += stride;
2498 mask_ptr += stride / 8;
2499 }
2500 }
2501 else
2502 {
2503 StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2504 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2505 image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
2506 if (mask_info)
2507 StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2508 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2509 mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
2510 }
2511 heap_free( image_bits );
2512 heap_free( mask_bits );
2513
2514 himl->cCurImage = ilHead.cCurImage;
2515 himl->cMaxImage = ilHead.cMaxImage;
2516
2517 ImageList_SetBkColor(himl,ilHead.bkcolor);
2518 for (i=0;i<4;i++)
2519 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2520 return himl;
2521 }
2522
2523
2524 /*************************************************************************
2525 * ImageList_Remove [COMCTL32.@]
2526 *
2527 * Removes an image from an image list
2528 *
2529 * PARAMS
2530 * himl [I] image list handle
2531 * i [I] image index
2532 *
2533 * RETURNS
2534 * Success: TRUE
2535 * Failure: FALSE
2536 *
2537 * FIXME: as the image list storage test shows, native comctl32 simply shifts
2538 * images without creating a new bitmap.
2539 */
2540 BOOL WINAPI
2541 ImageList_Remove (HIMAGELIST himl, INT i)
2542 {
2543 HBITMAP hbmNewImage, hbmNewMask;
2544 HDC hdcBmp;
2545 SIZE sz;
2546
2547 TRACE("(himl=%p i=%d)\n", himl, i);
2548
2549 if (!is_valid(himl)) {
2550 ERR("Invalid image list handle!\n");
2551 return FALSE;
2552 }
2553
2554 if ((i < -1) || (i >= himl->cCurImage)) {
2555 TRACE("index out of range! %d\n", i);
2556 return FALSE;
2557 }
2558
2559 if (i == -1) {
2560 INT nCount;
2561
2562 /* remove all */
2563 if (himl->cCurImage == 0) {
2564 /* remove all on empty ImageList is allowed */
2565 TRACE("remove all on empty ImageList!\n");
2566 return TRUE;
2567 }
2568
2569 himl->cMaxImage = himl->cGrow;
2570 himl->cCurImage = 0;
2571 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2572 himl->nOvlIdx[nCount] = -1;
2573
2574 if (himl->has_alpha)
2575 {
2576 heap_free( himl->has_alpha );
2577 himl->has_alpha = heap_alloc_zero( himl->cMaxImage );
2578 }
2579
2580 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2581 SelectObject (himl->hdcImage, hbmNewImage);
2582 DeleteObject (himl->hbmImage);
2583 himl->hbmImage = hbmNewImage;
2584
2585 if (himl->hbmMask) {
2586
2587 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2588 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2589 SelectObject (himl->hdcMask, hbmNewMask);
2590 DeleteObject (himl->hbmMask);
2591 himl->hbmMask = hbmNewMask;
2592 }
2593 }
2594 else {
2595 /* delete one image */
2596 TRACE("Remove single image! %d\n", i);
2597
2598 /* create new bitmap(s) */
2599 TRACE(" - Number of images: %d / %d (Old/New)\n",
2600 himl->cCurImage, himl->cCurImage - 1);
2601
2602 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2603
2604 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
2605 if (himl->hbmMask)
2606 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2607 else
2608 hbmNewMask = 0; /* Just to keep compiler happy! */
2609
2610 hdcBmp = CreateCompatibleDC (0);
2611
2612 /* copy all images and masks prior to the "removed" image */
2613 if (i > 0) {
2614 TRACE("Pre image copy: Copy %d images\n", i);
2615
2616 SelectObject (hdcBmp, hbmNewImage);
2617 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2618
2619 if (himl->hbmMask) {
2620 SelectObject (hdcBmp, hbmNewMask);
2621 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2622 }
2623 }
2624
2625 /* copy all images and masks behind the removed image */
2626 if (i < himl->cCurImage - 1) {
2627 TRACE("Post image copy!\n");
2628
2629 SelectObject (hdcBmp, hbmNewImage);
2630 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
2631 (himl->cCurImage - i), i );
2632
2633 if (himl->hbmMask) {
2634 SelectObject (hdcBmp, hbmNewMask);
2635 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
2636 (himl->cCurImage - i), i );
2637 }
2638 }
2639
2640 DeleteDC (hdcBmp);
2641
2642 /* delete old images and insert new ones */
2643 SelectObject (himl->hdcImage, hbmNewImage);
2644 DeleteObject (himl->hbmImage);
2645 himl->hbmImage = hbmNewImage;
2646 if (himl->hbmMask) {
2647 SelectObject (himl->hdcMask, hbmNewMask);
2648 DeleteObject (himl->hbmMask);
2649 himl->hbmMask = hbmNewMask;
2650 }
2651
2652 himl->cCurImage--;
2653 }
2654
2655 return TRUE;
2656 }
2657
2658
2659 /*************************************************************************
2660 * ImageList_Replace [COMCTL32.@]
2661 *
2662 * Replaces an image in an image list with a new image.
2663 *
2664 * PARAMS
2665 * himl [I] handle to image list
2666 * i [I] image index
2667 * hbmImage [I] handle to image bitmap
2668 * hbmMask [I] handle to mask bitmap. Can be NULL.
2669 *
2670 * RETURNS
2671 * Success: TRUE
2672 * Failure: FALSE
2673 */
2674
2675 BOOL WINAPI
2676 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2677 HBITMAP hbmMask)
2678 {
2679 HDC hdcImage;
2680 BITMAP bmp;
2681 POINT pt;
2682
2683 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2684
2685 if (!is_valid(himl)) {
2686 ERR("Invalid image list handle!\n");
2687 return FALSE;
2688 }
2689
2690 if ((i >= himl->cMaxImage) || (i < 0)) {
2691 ERR("Invalid image index!\n");
2692 return FALSE;
2693 }
2694
2695 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2696 return FALSE;
2697
2698 hdcImage = CreateCompatibleDC (0);
2699
2700 /* Replace Image */
2701 SelectObject (hdcImage, hbmImage);
2702
2703 if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
2704 goto done;
2705
2706 imagelist_point_from_index(himl, i, &pt);
2707 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2708 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2709
2710 if (himl->hbmMask)
2711 {
2712 HDC hdcTemp;
2713 HBITMAP hOldBitmapTemp;
2714
2715 hdcTemp = CreateCompatibleDC(0);
2716 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2717
2718 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2719 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2720 SelectObject(hdcTemp, hOldBitmapTemp);
2721 DeleteDC(hdcTemp);
2722
2723 /* Remove the background from the image
2724 */
2725 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2726 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2727 }
2728
2729 done:
2730 DeleteDC (hdcImage);
2731
2732 return TRUE;
2733 }
2734
2735
2736 /*************************************************************************
2737 * ImageList_ReplaceIcon [COMCTL32.@]
2738 *
2739 * Replaces an image in an image list using an icon.
2740 *
2741 * PARAMS
2742 * himl [I] handle to image list
2743 * i [I] image index
2744 * hIcon [I] handle to icon
2745 *
2746 * RETURNS
2747 * Success: index of the replaced image
2748 * Failure: -1
2749 */
2750
2751 INT WINAPI
2752 ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
2753 {
2754 HICON hBestFitIcon;
2755 ICONINFO ii;
2756 BITMAP bmp;
2757 BOOL ret;
2758 POINT pt;
2759
2760 TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
2761
2762 if (!is_valid(himl)) {
2763 ERR("invalid image list\n");
2764 return -1;
2765 }
2766 if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
2767 ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2768 return -1;
2769 }
2770
2771 hBestFitIcon = CopyImage(
2772 hIcon, IMAGE_ICON,
2773 himl->cx, himl->cy,
2774 LR_COPYFROMRESOURCE);
2775 /* the above will fail if the icon wasn't loaded from a resource, so try
2776 * again without LR_COPYFROMRESOURCE flag */
2777 if (!hBestFitIcon)
2778 hBestFitIcon = CopyImage(
2779 hIcon, IMAGE_ICON,
2780 himl->cx, himl->cy,
2781 0);
2782 if (!hBestFitIcon)
2783 return -1;
2784
2785 if (nIndex == -1) {
2786 if (himl->cCurImage + 1 >= himl->cMaxImage)
2787 IMAGELIST_InternalExpandBitmaps(himl, 1);
2788
2789 nIndex = himl->cCurImage;
2790 himl->cCurImage++;
2791 }
2792
2793 if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2794 {
2795 HDC hdcImage = CreateCompatibleDC( 0 );
2796 GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);
2797
2798 if (!ii.hbmColor)
2799 {
2800 UINT height = bmp.bmHeight / 2;
2801 HDC hdcMask = CreateCompatibleDC( 0 );
2802 HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
2803 SelectObject( hdcImage, color );
2804 SelectObject( hdcMask, ii.hbmMask );
2805 BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2806 ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2807 DeleteDC( hdcMask );
2808 DeleteObject( color );
2809 }
2810 else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
2811 ii.hbmColor, ii.hbmMask );
2812
2813 DeleteDC( hdcImage );
2814 DeleteObject (ii.hbmMask);
2815 if (ii.hbmColor) DeleteObject (ii.hbmColor);
2816 if (ret) goto done;
2817 }
2818
2819 imagelist_point_from_index(himl, nIndex, &pt);
2820
2821 if (himl->hbmMask)
2822 {
2823 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
2824 PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
2825 DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2826 }
2827 else
2828 {
2829 COLORREF color = himl->clrBk != CLR_NONE ? himl->clrBk : comctl32_color.clrWindow;
2830 HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));
2831
2832 SelectObject( himl->hdcImage, brush );
2833 PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
2834 SelectObject( himl->hdcImage, GetStockObject(BLACK_BRUSH) );
2835 DeleteObject( brush );
2836 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
2837 }
2838
2839 done:
2840 DestroyIcon(hBestFitIcon);
2841
2842 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2843 return nIndex;
2844 }
2845
2846
2847 /*************************************************************************
2848 * ImageList_SetBkColor [COMCTL32.@]
2849 *
2850 * Sets the background color of an image list.
2851 *
2852 * PARAMS
2853 * himl [I] handle to image list
2854 * clrBk [I] background color
2855 *
2856 * RETURNS
2857 * Success: previous background color
2858 * Failure: CLR_NONE
2859 */
2860
2861 COLORREF WINAPI
2862 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2863 {
2864 COLORREF clrOldBk;
2865
2866 if (!is_valid(himl))
2867 return CLR_NONE;
2868
2869 clrOldBk = himl->clrBk;
2870 himl->clrBk = clrBk;
2871 return clrOldBk;
2872 }
2873
2874
2875 /*************************************************************************
2876 * ImageList_SetDragCursorImage [COMCTL32.@]
2877 *
2878 * Combines the specified image with the current drag image
2879 *
2880 * PARAMS
2881 * himlDrag [I] handle to drag image list
2882 * iDrag [I] drag image index
2883 * dxHotspot [I] X position of the hot spot
2884 * dyHotspot [I] Y position of the hot spot
2885 *
2886 * RETURNS
2887 * Success: TRUE
2888 * Failure: FALSE
2889 *
2890 * NOTES
2891 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2892 * to do with a hotspot but are only the offset of the origin of the new
2893 * image relative to the origin of the old image.
2894 *
2895 * - When this function is called and the drag image is visible, a
2896 * short flickering occurs but this matches the Win9x behavior. It is
2897 * possible to fix the flickering using code like in ImageList_DragMove.
2898 */
2899
2900 BOOL WINAPI
2901 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2902 INT dxHotspot, INT dyHotspot)
2903 {
2904 HIMAGELIST himlTemp;
2905 BOOL visible;
2906
2907 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2908 return FALSE;
2909
2910 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2911 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2912
2913 visible = InternalDrag.bShow;
2914
2915 himlTemp = ImageList_Merge (InternalDrag.himlNoCursor, 0, himlDrag, iDrag,
2916 dxHotspot, dyHotspot);
2917
2918 if (visible) {
2919 /* hide the drag image */
2920 ImageList_DragShowNolock(FALSE);
2921 }
2922 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2923 (InternalDrag.himl->cy != himlTemp->cy)) {
2924 /* the size of the drag image changed, invalidate the buffer */
2925 DeleteObject(InternalDrag.hbmBg);
2926 InternalDrag.hbmBg = 0;
2927 }
2928
2929 if (InternalDrag.himl != InternalDrag.himlNoCursor)
2930 ImageList_Destroy (InternalDrag.himl);
2931 InternalDrag.himl = himlTemp;
2932
2933 if (visible) {
2934 /* show the drag image */
2935 ImageList_DragShowNolock(TRUE);
2936 }
2937
2938 return TRUE;
2939 }
2940
2941
2942 /*************************************************************************
2943 * ImageList_SetFilter [COMCTL32.@]
2944 *
2945 * Sets a filter (or does something completely different)!!???
2946 * It removes 12 Bytes from the stack (3 Parameters).
2947 *
2948 * PARAMS
2949 * himl [I] SHOULD be a handle to image list
2950 * i [I] COULD be an index?
2951 * dwFilter [I] ???
2952 *
2953 * RETURNS
2954 * Success: TRUE ???
2955 * Failure: FALSE ???
2956 *
2957 * BUGS
2958 * This is an UNDOCUMENTED function!!!!
2959 * empty stub.
2960 */
2961
2962 BOOL WINAPI
2963 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2964 {
2965 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2966
2967 return FALSE;
2968 }
2969
2970
2971 /*************************************************************************
2972 * ImageList_SetFlags [COMCTL32.@]
2973 *
2974 * Sets the image list flags.
2975 *
2976 * PARAMS
2977 * himl [I] Handle to image list
2978 * flags [I] Flags to set
2979 *
2980 * RETURNS
2981 * Old flags?
2982 *
2983 * BUGS
2984 * Stub.
2985 */
2986
2987 DWORD WINAPI
2988 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2989 {
2990 FIXME("(%p %08x):empty stub\n", himl, flags);
2991 return 0;
2992 }
2993
2994
2995 /*************************************************************************
2996 * ImageList_SetIconSize [COMCTL32.@]
2997 *
2998 * Sets the image size of the bitmap and deletes all images.
2999 *
3000 * PARAMS
3001 * himl [I] handle to image list
3002 * cx [I] image width
3003 * cy [I] image height
3004 *
3005 * RETURNS
3006 * Success: TRUE
3007 * Failure: FALSE
3008 */
3009
3010 BOOL WINAPI
3011 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
3012 {
3013 INT nCount;
3014 HBITMAP hbmNew;
3015
3016 if (!is_valid(himl))
3017 return FALSE;
3018
3019 /* remove all images */
3020 himl->cMaxImage = himl->cInitial + 1;
3021 himl->cCurImage = 0;
3022 himl->cx = cx;
3023 himl->cy = cy;
3024
3025 /* initialize overlay mask indices */
3026 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
3027 himl->nOvlIdx[nCount] = -1;
3028
3029 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
3030 SelectObject (himl->hdcImage, hbmNew);
3031 DeleteObject (himl->hbmImage);
3032 himl->hbmImage = hbmNew;
3033
3034 if (himl->hbmMask) {
3035 SIZE sz;
3036 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
3037 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
3038 SelectObject (himl->hdcMask, hbmNew);
3039 DeleteObject (himl->hbmMask);
3040 himl->hbmMask = hbmNew;
3041 }
3042
3043 return TRUE;
3044 }
3045
3046
3047 /*************************************************************************
3048 * ImageList_SetImageCount [COMCTL32.@]
3049 *
3050 * Resizes an image list to the specified number of images.
3051 *
3052 * PARAMS
3053 * himl [I] handle to image list
3054 * iImageCount [I] number of images in the image list
3055 *
3056 * RETURNS
3057 * Success: TRUE
3058 * Failure: FALSE
3059 */
3060
3061 BOOL WINAPI
3062 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
3063 {
3064 HDC hdcBitmap;
3065 HBITMAP hbmNewBitmap, hbmOld;
3066 INT nNewCount, nCopyCount;
3067
3068 TRACE("%p %d\n",himl,iImageCount);
3069
3070 if (!is_valid(himl))
3071 return FALSE;
3072
3073 nNewCount = iImageCount + 1;
3074 nCopyCount = min(himl->cCurImage, iImageCount);
3075
3076 hdcBitmap = CreateCompatibleDC (0);
3077
3078 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
3079
3080 if (hbmNewBitmap != 0)
3081 {
3082 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
3083 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
3084 SelectObject (hdcBitmap, hbmOld);
3085
3086 /* FIXME: delete 'empty' image space? */
3087
3088 SelectObject (himl->hdcImage, hbmNewBitmap);
3089 DeleteObject (himl->hbmImage);
3090 himl->hbmImage = hbmNewBitmap;
3091 }
3092 else
3093 ERR("Could not create new image bitmap!\n");
3094
3095 if (himl->hbmMask)
3096 {
3097 SIZE sz;
3098 imagelist_get_bitmap_size( himl, nNewCount, &sz );
3099 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
3100 if (hbmNewBitmap != 0)
3101 {
3102 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
3103 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
3104 SelectObject (hdcBitmap, hbmOld);
3105
3106 /* FIXME: delete 'empty' image space? */
3107
3108 SelectObject (himl->hdcMask, hbmNewBitmap);
3109 DeleteObject (himl->hbmMask);
3110 himl->hbmMask = hbmNewBitmap;
3111 }
3112 else
3113 ERR("Could not create new mask bitmap!\n");
3114 }
3115
3116 DeleteDC (hdcBitmap);
3117
3118 if (himl->has_alpha)
3119 {
3120 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
3121 if (new_alpha) himl->has_alpha = new_alpha;
3122 else
3123 {
3124 heap_free( himl->has_alpha );
3125 himl->has_alpha = NULL;
3126 }
3127 }
3128
3129 /* Update max image count and current image count */
3130 himl->cMaxImage = nNewCount;
3131 himl->cCurImage = iImageCount;
3132
3133 return TRUE;
3134 }
3135
3136
3137 /*************************************************************************
3138 * ImageList_SetOverlayImage [COMCTL32.@]
3139 *
3140 * Assigns an overlay mask index to an existing image in an image list.
3141 *
3142 * PARAMS
3143 * himl [I] handle to image list
3144 * iImage [I] image index
3145 * iOverlay [I] overlay mask index
3146 *
3147 * RETURNS
3148 * Success: TRUE
3149 * Failure: FALSE
3150 */
3151
3152 BOOL WINAPI
3153 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
3154 {
3155 if (!is_valid(himl))
3156 return FALSE;
3157 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
3158 return FALSE;
3159 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
3160 return FALSE;
3161 himl->nOvlIdx[iOverlay - 1] = iImage;
3162 return TRUE;
3163 }
3164
3165
3166
3167 /* helper for ImageList_Write - write bitmap to pstm
3168 * currently everything is written as 24 bit RGB, except masks
3169 */
3170 static BOOL _write_bitmap(HBITMAP hBitmap, IStream *pstm)
3171 {
3172 LPBITMAPFILEHEADER bmfh;
3173 LPBITMAPINFOHEADER bmih;
3174 LPBYTE data = NULL, lpBits;
3175 BITMAP bm;
3176 INT bitCount, sizeImage, offBits, totalSize;
3177 HDC xdc;
3178 BOOL result = FALSE;
3179
3180 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
3181 return FALSE;
3182
3183 bitCount = bm.bmBitsPixel;
3184 sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
3185
3186 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
3187 if(bitCount <= 8)
3188 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
3189 offBits = totalSize;