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