[COMCTL32] Sync with Wine Staging 1.9.4. CORE-10912
[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 if (!((flags&ILC_COLORDDB) == ILC_COLORDDB) && (cx == 0 || cy == 0)) return NULL;
768
769 /* Create the IImageList interface for the image list */
770 if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
771 return NULL;
772
773 cGrow = (WORD)((max( cGrow, 1 ) + 3) & ~3);
774
775 if (cGrow > 256)
776 {
777 /* Windows doesn't limit the size here, but X11 doesn't let us allocate such huge bitmaps */
778 WARN( "grow %d too large, limiting to 256\n", cGrow );
779 cGrow = 256;
780 }
781
782 himl->cx = cx;
783 himl->cy = cy;
784 himl->flags = flags;
785 himl->cMaxImage = cInitial + 1;
786 himl->cInitial = cInitial;
787 himl->cGrow = cGrow;
788 himl->clrFg = CLR_DEFAULT;
789 himl->clrBk = CLR_NONE;
790
791 /* initialize overlay mask indices */
792 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
793 himl->nOvlIdx[nCount] = -1;
794
795 /* Create Image & Mask DCs */
796 himl->hdcImage = CreateCompatibleDC (0);
797 if (!himl->hdcImage)
798 goto cleanup;
799 if (himl->flags & ILC_MASK){
800 himl->hdcMask = CreateCompatibleDC(0);
801 if (!himl->hdcMask)
802 goto cleanup;
803 }
804
805 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
806 if (ilc == ILC_COLOR)
807 {
808 ilc = ILC_COLOR4;
809 himl->flags |= ILC_COLOR4;
810 }
811
812 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
813 himl->uBitsPixel = ilc;
814 else
815 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
816
817 if (himl->cMaxImage > 0) {
818 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
819 SelectObject(himl->hdcImage, himl->hbmImage);
820 } else
821 himl->hbmImage = 0;
822
823 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
824 SIZE sz;
825
826 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
827 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
828 if (himl->hbmMask == 0) {
829 ERR("Error creating mask bitmap!\n");
830 goto cleanup;
831 }
832 SelectObject(himl->hdcMask, himl->hbmMask);
833 }
834 else
835 himl->hbmMask = 0;
836
837 if (ilc == ILC_COLOR32)
838 himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
839 else
840 himl->has_alpha = NULL;
841
842 /* create blending brushes */
843 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
844 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
845 DeleteObject (hbmTemp);
846
847 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
848 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
849 DeleteObject (hbmTemp);
850
851 TRACE("created imagelist %p\n", himl);
852 return himl;
853
854 cleanup:
855 ImageList_Destroy(himl);
856 return NULL;
857 }
858
859
860 /*************************************************************************
861 * ImageList_Destroy [COMCTL32.@]
862 *
863 * Destroys an image list.
864 *
865 * PARAMS
866 * himl [I] handle to image list
867 *
868 * RETURNS
869 * Success: TRUE
870 * Failure: FALSE
871 */
872
873 BOOL WINAPI
874 ImageList_Destroy (HIMAGELIST himl)
875 {
876 if (!is_valid(himl))
877 return FALSE;
878
879 IImageList_Release((IImageList *) himl);
880 return TRUE;
881 }
882
883
884 /*************************************************************************
885 * ImageList_DragEnter [COMCTL32.@]
886 *
887 * Locks window update and displays the drag image at the given position.
888 *
889 * PARAMS
890 * hwndLock [I] handle of the window that owns the drag image.
891 * x [I] X position of the drag image.
892 * y [I] Y position of the drag image.
893 *
894 * RETURNS
895 * Success: TRUE
896 * Failure: FALSE
897 *
898 * NOTES
899 * The position of the drag image is relative to the window, not
900 * the client area.
901 */
902
903 BOOL WINAPI
904 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
905 {
906 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
907
908 if (!is_valid(InternalDrag.himl))
909 return FALSE;
910
911 if (hwndLock)
912 InternalDrag.hwnd = hwndLock;
913 else
914 InternalDrag.hwnd = GetDesktopWindow ();
915
916 InternalDrag.x = x;
917 InternalDrag.y = y;
918
919 /* draw the drag image and save the background */
920 if (!ImageList_DragShowNolock(TRUE)) {
921 return FALSE;
922 }
923
924 return TRUE;
925 }
926
927
928 /*************************************************************************
929 * ImageList_DragLeave [COMCTL32.@]
930 *
931 * Unlocks window update and hides the drag image.
932 *
933 * PARAMS
934 * hwndLock [I] handle of the window that owns the drag image.
935 *
936 * RETURNS
937 * Success: TRUE
938 * Failure: FALSE
939 */
940
941 BOOL WINAPI
942 ImageList_DragLeave (HWND hwndLock)
943 {
944 /* As we don't save drag info in the window this can lead to problems if
945 an app does not supply the same window as DragEnter */
946 /* if (hwndLock)
947 InternalDrag.hwnd = hwndLock;
948 else
949 InternalDrag.hwnd = GetDesktopWindow (); */
950 if(!hwndLock)
951 hwndLock = GetDesktopWindow();
952 if(InternalDrag.hwnd != hwndLock)
953 FIXME("DragLeave hWnd != DragEnter hWnd\n");
954
955 ImageList_DragShowNolock (FALSE);
956
957 return TRUE;
958 }
959
960
961 /*************************************************************************
962 * ImageList_InternalDragDraw [Internal]
963 *
964 * Draws the drag image.
965 *
966 * PARAMS
967 * hdc [I] device context to draw into.
968 * x [I] X position of the drag image.
969 * y [I] Y position of the drag image.
970 *
971 * RETURNS
972 * Success: TRUE
973 * Failure: FALSE
974 *
975 * NOTES
976 * The position of the drag image is relative to the window, not
977 * the client area.
978 *
979 */
980
981 static inline void
982 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
983 {
984 IMAGELISTDRAWPARAMS imldp;
985
986 ZeroMemory (&imldp, sizeof(imldp));
987 imldp.cbSize = sizeof(imldp);
988 imldp.himl = InternalDrag.himl;
989 imldp.i = 0;
990 imldp.hdcDst = hdc,
991 imldp.x = x;
992 imldp.y = y;
993 imldp.rgbBk = CLR_DEFAULT;
994 imldp.rgbFg = CLR_DEFAULT;
995 imldp.fStyle = ILD_NORMAL;
996 imldp.fState = ILS_ALPHA;
997 imldp.Frame = 192;
998 ImageList_DrawIndirect (&imldp);
999 }
1000
1001 /*************************************************************************
1002 * ImageList_DragMove [COMCTL32.@]
1003 *
1004 * Moves the drag image.
1005 *
1006 * PARAMS
1007 * x [I] X position of the drag image.
1008 * y [I] Y position of the drag image.
1009 *
1010 * RETURNS
1011 * Success: TRUE
1012 * Failure: FALSE
1013 *
1014 * NOTES
1015 * The position of the drag image is relative to the window, not
1016 * the client area.
1017 */
1018
1019 BOOL WINAPI
1020 ImageList_DragMove (INT x, INT y)
1021 {
1022 TRACE("(x=%d y=%d)\n", x, y);
1023
1024 if (!is_valid(InternalDrag.himl))
1025 return FALSE;
1026
1027 /* draw/update the drag image */
1028 if (InternalDrag.bShow) {
1029 HDC hdcDrag;
1030 HDC hdcOffScreen;
1031 HDC hdcBg;
1032 HBITMAP hbmOffScreen;
1033 INT origNewX, origNewY;
1034 INT origOldX, origOldY;
1035 INT origRegX, origRegY;
1036 INT sizeRegX, sizeRegY;
1037
1038
1039 /* calculate the update region */
1040 origNewX = x - InternalDrag.dxHotspot;
1041 origNewY = y - InternalDrag.dyHotspot;
1042 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1043 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1044 origRegX = min(origNewX, origOldX);
1045 origRegY = min(origNewY, origOldY);
1046 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1047 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1048
1049 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1050 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1051 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1052 hdcBg = CreateCompatibleDC(hdcDrag);
1053
1054 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1055 SelectObject(hdcOffScreen, hbmOffScreen);
1056 SelectObject(hdcBg, InternalDrag.hbmBg);
1057
1058 /* get the actual background of the update region */
1059 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1060 origRegX, origRegY, SRCCOPY);
1061 /* erase the old image */
1062 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1063 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1064 SRCCOPY);
1065 /* save the background */
1066 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1067 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1068 /* draw the image */
1069 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
1070 origNewY - origRegY);
1071 /* draw the update region to the screen */
1072 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1073 hdcOffScreen, 0, 0, SRCCOPY);
1074
1075 DeleteDC(hdcBg);
1076 DeleteDC(hdcOffScreen);
1077 DeleteObject(hbmOffScreen);
1078 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1079 }
1080
1081 /* update the image position */
1082 InternalDrag.x = x;
1083 InternalDrag.y = y;
1084
1085 return TRUE;
1086 }
1087
1088
1089 /*************************************************************************
1090 * ImageList_DragShowNolock [COMCTL32.@]
1091 *
1092 * Shows or hides the drag image.
1093 *
1094 * PARAMS
1095 * bShow [I] TRUE shows the drag image, FALSE hides it.
1096 *
1097 * RETURNS
1098 * Success: TRUE
1099 * Failure: FALSE
1100 */
1101
1102 BOOL WINAPI
1103 ImageList_DragShowNolock (BOOL bShow)
1104 {
1105 HDC hdcDrag;
1106 HDC hdcBg;
1107 INT x, y;
1108
1109 if (!is_valid(InternalDrag.himl))
1110 return FALSE;
1111
1112 TRACE("bShow=0x%X!\n", bShow);
1113
1114 /* DragImage is already visible/hidden */
1115 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1116 return FALSE;
1117 }
1118
1119 /* position of the origin of the DragImage */
1120 x = InternalDrag.x - InternalDrag.dxHotspot;
1121 y = InternalDrag.y - InternalDrag.dyHotspot;
1122
1123 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1124 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1125 if (!hdcDrag) {
1126 return FALSE;
1127 }
1128
1129 hdcBg = CreateCompatibleDC(hdcDrag);
1130 if (!InternalDrag.hbmBg) {
1131 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1132 InternalDrag.himl->cx, InternalDrag.himl->cy);
1133 }
1134 SelectObject(hdcBg, InternalDrag.hbmBg);
1135
1136 if (bShow) {
1137 /* save the background */
1138 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1139 hdcDrag, x, y, SRCCOPY);
1140 /* show the image */
1141 ImageList_InternalDragDraw(hdcDrag, x, y);
1142 } else {
1143 /* hide the image */
1144 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1145 hdcBg, 0, 0, SRCCOPY);
1146 }
1147
1148 InternalDrag.bShow = !InternalDrag.bShow;
1149
1150 DeleteDC(hdcBg);
1151 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1152 return TRUE;
1153 }
1154
1155
1156 /*************************************************************************
1157 * ImageList_Draw [COMCTL32.@]
1158 *
1159 * Draws an image.
1160 *
1161 * PARAMS
1162 * himl [I] handle to image list
1163 * i [I] image index
1164 * hdc [I] handle to device context
1165 * x [I] x position
1166 * y [I] y position
1167 * fStyle [I] drawing flags
1168 *
1169 * RETURNS
1170 * Success: TRUE
1171 * Failure: FALSE
1172 *
1173 * SEE
1174 * ImageList_DrawEx.
1175 */
1176
1177 BOOL WINAPI
1178 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1179 {
1180 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1181 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1182 }
1183
1184
1185 /*************************************************************************
1186 * ImageList_DrawEx [COMCTL32.@]
1187 *
1188 * Draws an image and allows using extended drawing features.
1189 *
1190 * PARAMS
1191 * himl [I] handle to image list
1192 * i [I] image index
1193 * hdc [I] handle to device context
1194 * x [I] X position
1195 * y [I] Y position
1196 * dx [I] X offset
1197 * dy [I] Y offset
1198 * rgbBk [I] background color
1199 * rgbFg [I] foreground color
1200 * fStyle [I] drawing flags
1201 *
1202 * RETURNS
1203 * Success: TRUE
1204 * Failure: FALSE
1205 *
1206 * NOTES
1207 * Calls ImageList_DrawIndirect.
1208 *
1209 * SEE
1210 * ImageList_DrawIndirect.
1211 */
1212
1213 BOOL WINAPI
1214 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1215 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1216 UINT fStyle)
1217 {
1218 IMAGELISTDRAWPARAMS imldp;
1219
1220 ZeroMemory (&imldp, sizeof(imldp));
1221 imldp.cbSize = sizeof(imldp);
1222 imldp.himl = himl;
1223 imldp.i = i;
1224 imldp.hdcDst = hdc,
1225 imldp.x = x;
1226 imldp.y = y;
1227 imldp.cx = dx;
1228 imldp.cy = dy;
1229 imldp.rgbBk = rgbBk;
1230 imldp.rgbFg = rgbFg;
1231 imldp.fStyle = fStyle;
1232
1233 return ImageList_DrawIndirect (&imldp);
1234 }
1235
1236 #ifdef __REACTOS__
1237 static BOOL alpha_blend_image( HIMAGELIST himl, HDC srce_dc, HDC dest_dc, int dest_x, int dest_y,
1238 #else
1239 static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1240 #endif
1241 int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
1242 UINT style, COLORREF blend_col )
1243 {
1244 BOOL ret = FALSE;
1245 HDC hdc;
1246 HBITMAP bmp = 0, mask = 0;
1247 BITMAPINFO *info;
1248 void *bits, *mask_bits;
1249 unsigned int *ptr;
1250 int i, j;
1251
1252 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1253 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1254 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1255 info->bmiHeader.biWidth = cx;
1256 info->bmiHeader.biHeight = cy;
1257 info->bmiHeader.biPlanes = 1;
1258 info->bmiHeader.biBitCount = 32;
1259 info->bmiHeader.biCompression = BI_RGB;
1260 info->bmiHeader.biSizeImage = cx * cy * 4;
1261 info->bmiHeader.biXPelsPerMeter = 0;
1262 info->bmiHeader.biYPelsPerMeter = 0;
1263 info->bmiHeader.biClrUsed = 0;
1264 info->bmiHeader.biClrImportant = 0;
1265 #ifdef __REACTOS__
1266 if (!(bmp = CreateDIBSection( srce_dc, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1267 #else
1268 if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1269 #endif
1270 SelectObject( hdc, bmp );
1271 #ifdef __REACTOS__
1272 BitBlt( hdc, 0, 0, cx, cy, srce_dc, src_x, src_y, SRCCOPY );
1273 #else
1274 BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
1275 #endif
1276
1277 if (blend_col != CLR_NONE)
1278 {
1279 BYTE r = GetRValue( blend_col );
1280 BYTE g = GetGValue( blend_col );
1281 BYTE b = GetBValue( blend_col );
1282
1283 if (style & ILD_BLEND25)
1284 {
1285 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1286 *ptr = ((*ptr & 0xff000000) |
1287 ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
1288 ((((*ptr & 0x0000ff00) * 3 + (g << 8)) / 4) & 0x0000ff00) |
1289 ((((*ptr & 0x000000ff) * 3 + (b << 0)) / 4) & 0x000000ff));
1290 }
1291 else if (style & ILD_BLEND50)
1292 {
1293 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1294 *ptr = ((*ptr & 0xff000000) |
1295 ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
1296 ((((*ptr & 0x0000ff00) + (g << 8)) / 2) & 0x0000ff00) |
1297 ((((*ptr & 0x000000ff) + (b << 0)) / 2) & 0x000000ff));
1298 }
1299 }
1300
1301 if (himl->has_alpha) /* we already have an alpha channel in this case */
1302 {
1303 /* pre-multiply by the alpha channel */
1304 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1305 {
1306 DWORD alpha = *ptr >> 24;
1307 *ptr = ((*ptr & 0xff000000) |
1308 (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
1309 (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
1310 (((*ptr & 0x000000ff) * alpha / 255)));
1311 }
1312 }
1313 else if (himl->hbmMask)
1314 {
1315 unsigned int width_bytes = (cx + 31) / 32 * 4;
1316 /* generate alpha channel from the mask */
1317 info->bmiHeader.biBitCount = 1;
1318 info->bmiHeader.biSizeImage = width_bytes * cy;
1319 info->bmiColors[0].rgbRed = 0;
1320 info->bmiColors[0].rgbGreen = 0;
1321 info->bmiColors[0].rgbBlue = 0;
1322 info->bmiColors[0].rgbReserved = 0;
1323 info->bmiColors[1].rgbRed = 0xff;
1324 info->bmiColors[1].rgbGreen = 0xff;
1325 info->bmiColors[1].rgbBlue = 0xff;
1326 info->bmiColors[1].rgbReserved = 0;
1327 if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
1328 goto done;
1329 SelectObject( hdc, mask );
1330 BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
1331 SelectObject( hdc, bmp );
1332 for (i = 0, ptr = bits; i < cy; i++)
1333 for (j = 0; j < cx; j++, ptr++)
1334 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1335 else *ptr |= 0xff000000;
1336 }
1337
1338 ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
1339
1340 done:
1341 DeleteDC( hdc );
1342 if (bmp) DeleteObject( bmp );
1343 if (mask) DeleteObject( mask );
1344 HeapFree( GetProcessHeap(), 0, info );
1345 return ret;
1346 }
1347
1348 #ifdef __REACTOS__
1349 HDC saturate_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1350 int src_x, int src_y, int cx, int cy, COLORREF rgbFg)
1351 {
1352 HDC hdc = NULL;
1353 HBITMAP bmp = 0;
1354 BITMAPINFO *info;
1355
1356 unsigned int *ptr;
1357 void *bits;
1358 int i;
1359
1360 /* create a dc and its device independent bitmap for doing the work,
1361 shamelessly copied from the alpha-blending function above */
1362 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1363 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1364 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1365 info->bmiHeader.biWidth = cx;
1366 info->bmiHeader.biHeight = cy;
1367 info->bmiHeader.biPlanes = 1;
1368 info->bmiHeader.biBitCount = 32;
1369 info->bmiHeader.biCompression = BI_RGB;
1370 info->bmiHeader.biSizeImage = cx * cy * 4;
1371 info->bmiHeader.biXPelsPerMeter = 0;
1372 info->bmiHeader.biYPelsPerMeter = 0;
1373 info->bmiHeader.biClrUsed = 0;
1374 info->bmiHeader.biClrImportant = 0;
1375 if (!(bmp = CreateDIBSection(himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1376
1377 /* bind both surfaces */
1378 SelectObject(hdc, bmp);
1379
1380 /* copy into our dc the section that covers just the icon we we're asked for */
1381 BitBlt(hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY);
1382
1383 /* loop every pixel of the bitmap */
1384 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1385 {
1386 COLORREF orig_color = *ptr;
1387
1388 /* calculate the effective luminance using the constants from here, adapted to the human eye:
1389 <http://bobpowell.net/grayscale.aspx> */
1390 float mixed_color = (GetRValue(orig_color) * .30 +
1391 GetGValue(orig_color) * .59 +
1392 GetBValue(orig_color) * .11);
1393
1394 *ptr = RGBA(mixed_color, mixed_color, mixed_color, GetAValue(orig_color));
1395 }
1396
1397 done:
1398
1399 if (bmp)
1400 DeleteObject(bmp);
1401
1402 if (info)
1403 HeapFree(GetProcessHeap(), 0, info);
1404
1405 /* return the handle to our desaturated dc, that will substitute its original counterpart in the next calls */
1406 return hdc;
1407 }
1408 #endif /* __REACTOS__ */
1409
1410 /*************************************************************************
1411 * ImageList_DrawIndirect [COMCTL32.@]
1412 *
1413 * Draws an image using various parameters specified in pimldp.
1414 *
1415 * PARAMS
1416 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1417 *
1418 * RETURNS
1419 * Success: TRUE
1420 * Failure: FALSE
1421 */
1422
1423 BOOL WINAPI
1424 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1425 {
1426 INT cx, cy, nOvlIdx;
1427 DWORD fState, dwRop;
1428 UINT fStyle;
1429 COLORREF oldImageBk, oldImageFg;
1430 HDC hImageDC, hImageListDC, hMaskListDC;
1431 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1432 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1433 HIMAGELIST himl;
1434 HBRUSH hOldBrush;
1435 POINT pt;
1436 BOOL has_alpha;
1437
1438 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1439 if (!is_valid(himl)) return FALSE;
1440 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1441
1442 imagelist_point_from_index( himl, pimldp->i, &pt );
1443 pt.x += pimldp->xBitmap;
1444 pt.y += pimldp->yBitmap;
1445
1446 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1447 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1448 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1449 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1450
1451 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1452 if( pimldp->rgbBk == CLR_NONE )
1453 bIsTransparent = TRUE;
1454 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1455 bIsTransparent = TRUE;
1456 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1457 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1458
1459 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1460 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1461
1462 /* we will use these DCs to access the images and masks in the ImageList */
1463 hImageListDC = himl->hdcImage;
1464 hMaskListDC = himl->hdcMask;
1465
1466 /* these will accumulate the image and mask for the image we're drawing */
1467 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1468 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1469 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1470
1471 /* Create a compatible DC. */
1472 if (!hImageListDC || !hImageDC || !hImageBmp ||
1473 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1474 goto cleanup;
1475
1476 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1477
1478 /*
1479 * To obtain a transparent look, background color should be set
1480 * to white and foreground color to black when blitting the
1481 * monochrome mask.
1482 */
1483 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1484 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1485
1486 #ifdef __REACTOS__
1487 /*
1488 * If the ILS_SATURATE bit is enabled we should multiply the
1489 * RGB colors of the original image by the contents of rgbFg.
1490 */
1491 if (fState & ILS_SATURATE)
1492 {
1493 hImageListDC = saturate_image(himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1494 pt.x, pt.y, cx, cy, pimldp->rgbFg);
1495
1496 /* shitty way of getting subroutines to blit at the right place (top left corner),
1497 as our modified imagelist only contains a single image for performance reasons */
1498 pt.x = 0;
1499 pt.y = 0;
1500 }
1501 #endif
1502
1503 has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
1504 if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1505 {
1506 COLORREF colour, blend_col = CLR_NONE;
1507 BLENDFUNCTION func;
1508
1509 if (bBlend)
1510 {
1511 blend_col = pimldp->rgbFg;
1512 if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
1513 else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
1514 }
1515
1516 func.BlendOp = AC_SRC_OVER;
1517 func.BlendFlags = 0;
1518 func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
1519 func.AlphaFormat = AC_SRC_ALPHA;
1520
1521 if (bIsTransparent)
1522 {
1523 #ifdef __REACTOS__
1524 bResult = alpha_blend_image( himl, hImageListDC, pimldp->hdcDst, pimldp->x, pimldp->y,
1525 #else
1526 bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1527 #endif
1528 pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1529 goto end;
1530 }
1531 colour = pimldp->rgbBk;
1532 if (colour == CLR_DEFAULT) colour = himl->clrBk;
1533 if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
1534
1535 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1536 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1537 #ifdef __REACTOS__
1538 alpha_blend_image( himl, hImageListDC, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1539 #else
1540 alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1541 #endif
1542 DeleteObject (SelectObject (hImageDC, hOldBrush));
1543 bResult = BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
1544 goto end;
1545 }
1546
1547 /*
1548 * Draw the initial image
1549 */
1550 if( bMask ) {
1551 if (himl->hbmMask) {
1552 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1553 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1554 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1555 DeleteObject (SelectObject (hImageDC, hOldBrush));
1556 if( bIsTransparent )
1557 {
1558 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1559 bResult = TRUE;
1560 goto end;
1561 }
1562 } else {
1563 hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1564 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1565 SelectObject(hImageDC, hOldBrush);
1566 }
1567 } else {
1568 /* blend the image with the needed solid background */
1569 COLORREF colour = RGB(0,0,0);
1570
1571 if( !bIsTransparent )
1572 {
1573 colour = pimldp->rgbBk;
1574 if( colour == CLR_DEFAULT )
1575 colour = himl->clrBk;
1576 if( colour == CLR_NONE )
1577 colour = GetBkColor(pimldp->hdcDst);
1578 }
1579
1580 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1581 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1582 if (himl->hbmMask)
1583 {
1584 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1585 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1586 }
1587 else
1588 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1589 DeleteObject (SelectObject (hImageDC, hOldBrush));
1590 }
1591
1592 /* Time for blending, if required */
1593 if (bBlend) {
1594 HBRUSH hBlendBrush;
1595 COLORREF clrBlend = pimldp->rgbFg;
1596 HDC hBlendMaskDC = hImageListDC;
1597 HBITMAP hOldBitmap;
1598
1599 /* Create the blend Mask */
1600 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1601 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1602 hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1603 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1604 SelectObject(hBlendMaskDC, hOldBrush);
1605
1606 /* Modify the blend mask if an Image Mask exist */
1607 if(himl->hbmMask) {
1608 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1609 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1610 }
1611
1612 /* now apply blend to the current image given the BlendMask */
1613 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1614 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1615 hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1616 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1617 DeleteObject(SelectObject(hImageDC, hOldBrush));
1618 SelectObject(hBlendMaskDC, hOldBitmap);
1619 }
1620
1621 /* Now do the overlay image, if any */
1622 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1623 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1624 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1625 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1626 POINT ptOvl;
1627 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1628 ptOvl.x += pimldp->xBitmap;
1629 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1630 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1631 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1632 }
1633 }
1634
1635 #ifndef __REACTOS__
1636 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1637 #endif
1638 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1639 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1640
1641 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1642 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1643 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1644
1645 /* now copy the image to the screen */
1646 dwRop = SRCCOPY;
1647 if (himl->hbmMask && bIsTransparent ) {
1648 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1649 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1650 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1651 SetBkColor(pimldp->hdcDst, oldDstBk);
1652 SetTextColor(pimldp->hdcDst, oldDstFg);
1653 dwRop = SRCPAINT;
1654 }
1655 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1656 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1657
1658 bResult = TRUE;
1659 end:
1660 /* cleanup the mess */
1661 SetBkColor(hImageDC, oldImageBk);
1662 SetTextColor(hImageDC, oldImageFg);
1663 SelectObject(hImageDC, hOldImageBmp);
1664 cleanup:
1665 DeleteObject(hBlendMaskBmp);
1666 DeleteObject(hImageBmp);
1667 DeleteDC(hImageDC);
1668
1669 return bResult;
1670 }
1671
1672
1673 /*************************************************************************
1674 * ImageList_Duplicate [COMCTL32.@]
1675 *
1676 * Duplicates an image list.
1677 *
1678 * PARAMS
1679 * himlSrc [I] source image list handle
1680 *
1681 * RETURNS
1682 * Success: Handle of duplicated image list.
1683 * Failure: NULL
1684 */
1685
1686 HIMAGELIST WINAPI
1687 ImageList_Duplicate (HIMAGELIST himlSrc)
1688 {
1689 HIMAGELIST himlDst;
1690
1691 if (!is_valid(himlSrc)) {
1692 ERR("Invalid image list handle!\n");
1693 return NULL;
1694 }
1695
1696 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1697 himlSrc->cCurImage, himlSrc->cGrow);
1698
1699 if (himlDst)
1700 {
1701 SIZE sz;
1702
1703 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1704 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1705 himlSrc->hdcImage, 0, 0, SRCCOPY);
1706
1707 if (himlDst->hbmMask)
1708 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1709 himlSrc->hdcMask, 0, 0, SRCCOPY);
1710
1711 himlDst->cCurImage = himlSrc->cCurImage;
1712 if (himlSrc->has_alpha && himlDst->has_alpha)
1713 memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1714 }
1715 return himlDst;
1716 }
1717
1718
1719 /*************************************************************************
1720 * ImageList_EndDrag [COMCTL32.@]
1721 *
1722 * Finishes a drag operation.
1723 *
1724 * PARAMS
1725 * no Parameters
1726 *
1727 * RETURNS
1728 * Success: TRUE
1729 * Failure: FALSE
1730 */
1731
1732 VOID WINAPI
1733 ImageList_EndDrag (void)
1734 {
1735 /* cleanup the InternalDrag struct */
1736 InternalDrag.hwnd = 0;
1737 if (InternalDrag.himl != InternalDrag.himlNoCursor)
1738 ImageList_Destroy (InternalDrag.himlNoCursor);
1739 ImageList_Destroy (InternalDrag.himl);
1740 InternalDrag.himlNoCursor = InternalDrag.himl = 0;
1741 InternalDrag.x= 0;
1742 InternalDrag.y= 0;
1743 InternalDrag.dxHotspot = 0;
1744 InternalDrag.dyHotspot = 0;
1745 InternalDrag.bShow = FALSE;
1746 DeleteObject(InternalDrag.hbmBg);
1747 InternalDrag.hbmBg = 0;
1748 }
1749
1750
1751 /*************************************************************************
1752 * ImageList_GetBkColor [COMCTL32.@]
1753 *
1754 * Returns the background color of an image list.
1755 *
1756 * PARAMS
1757 * himl [I] Image list handle.
1758 *
1759 * RETURNS
1760 * Success: background color
1761 * Failure: CLR_NONE
1762 */
1763
1764 COLORREF WINAPI
1765 ImageList_GetBkColor (HIMAGELIST himl)
1766 {
1767 return himl ? himl->clrBk : CLR_NONE;
1768 }
1769
1770
1771 /*************************************************************************
1772 * ImageList_GetDragImage [COMCTL32.@]
1773 *
1774 * Returns the handle to the internal drag image list.
1775 *
1776 * PARAMS
1777 * ppt [O] Pointer to the drag position. Can be NULL.
1778 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1779 *
1780 * RETURNS
1781 * Success: Handle of the drag image list.
1782 * Failure: NULL.
1783 */
1784
1785 HIMAGELIST WINAPI
1786 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1787 {
1788 if (is_valid(InternalDrag.himl)) {
1789 if (ppt) {
1790 ppt->x = InternalDrag.x;
1791 ppt->y = InternalDrag.y;
1792 }
1793 if (pptHotspot) {
1794 pptHotspot->x = InternalDrag.dxHotspot;
1795 pptHotspot->y = InternalDrag.dyHotspot;
1796 }
1797 return (InternalDrag.himl);
1798 }
1799
1800 return NULL;
1801 }
1802
1803
1804 /*************************************************************************
1805 * ImageList_GetFlags [COMCTL32.@]
1806 *
1807 * Gets the flags of the specified image list.
1808 *
1809 * PARAMS
1810 * himl [I] Handle to image list
1811 *
1812 * RETURNS
1813 * Image list flags.
1814 *
1815 * BUGS
1816 * Stub.
1817 */
1818
1819 DWORD WINAPI
1820 ImageList_GetFlags(HIMAGELIST himl)
1821 {
1822 TRACE("%p\n", himl);
1823
1824 return is_valid(himl) ? himl->flags : 0;
1825 }
1826
1827
1828 /*************************************************************************
1829 * ImageList_GetIcon [COMCTL32.@]
1830 *
1831 * Creates an icon from a masked image of an image list.
1832 *
1833 * PARAMS
1834 * himl [I] handle to image list
1835 * i [I] image index
1836 * flags [I] drawing style flags
1837 *
1838 * RETURNS
1839 * Success: icon handle
1840 * Failure: NULL
1841 */
1842
1843 HICON WINAPI
1844 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1845 {
1846 ICONINFO ii;
1847 HICON hIcon;
1848 HBITMAP hOldDstBitmap;
1849 HDC hdcDst;
1850 POINT pt;
1851
1852 TRACE("%p %d %d\n", himl, i, fStyle);
1853 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1854
1855 ii.fIcon = TRUE;
1856 ii.xHotspot = 0;
1857 ii.yHotspot = 0;
1858
1859 /* create colour bitmap */
1860 hdcDst = GetDC(0);
1861 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1862 ReleaseDC(0, hdcDst);
1863
1864 hdcDst = CreateCompatibleDC(0);
1865
1866 imagelist_point_from_index( himl, i, &pt );
1867
1868 /* draw mask*/
1869 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1870 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1871 if (himl->hbmMask) {
1872 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1873 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1874 }
1875 else
1876 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1877
1878 /* draw image*/
1879 SelectObject (hdcDst, ii.hbmColor);
1880 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1881 himl->hdcImage, pt.x, pt.y, SRCCOPY);
1882
1883 /*
1884 * CreateIconIndirect requires us to deselect the bitmaps from
1885 * the DCs before calling
1886 */
1887 SelectObject(hdcDst, hOldDstBitmap);
1888
1889 hIcon = CreateIconIndirect (&ii);
1890
1891 DeleteObject (ii.hbmMask);
1892 DeleteObject (ii.hbmColor);
1893 DeleteDC (hdcDst);
1894
1895 return hIcon;
1896 }
1897
1898
1899 /*************************************************************************
1900 * ImageList_GetIconSize [COMCTL32.@]
1901 *
1902 * Retrieves the size of an image in an image list.
1903 *
1904 * PARAMS
1905 * himl [I] handle to image list
1906 * cx [O] pointer to the image width.
1907 * cy [O] pointer to the image height.
1908 *
1909 * RETURNS
1910 * Success: TRUE
1911 * Failure: FALSE
1912 *
1913 * NOTES
1914 * All images in an image list have the same size.
1915 */
1916
1917 BOOL WINAPI
1918 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1919 {
1920 if (!is_valid(himl) || !cx || !cy)
1921 return FALSE;
1922
1923 *cx = himl->cx;
1924 *cy = himl->cy;
1925
1926 return TRUE;
1927 }
1928
1929
1930 /*************************************************************************
1931 * ImageList_GetImageCount [COMCTL32.@]
1932 *
1933 * Returns the number of images in an image list.
1934 *
1935 * PARAMS
1936 * himl [I] handle to image list
1937 *
1938 * RETURNS
1939 * Success: Number of images.
1940 * Failure: 0
1941 */
1942
1943 INT WINAPI
1944 ImageList_GetImageCount (HIMAGELIST himl)
1945 {
1946 if (!is_valid(himl))
1947 return 0;
1948
1949 return himl->cCurImage;
1950 }
1951
1952
1953 /*************************************************************************
1954 * ImageList_GetImageInfo [COMCTL32.@]
1955 *
1956 * Returns information about an image in an image list.
1957 *
1958 * PARAMS
1959 * himl [I] handle to image list
1960 * i [I] image index
1961 * pImageInfo [O] pointer to the image information
1962 *
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE
1966 */
1967
1968 BOOL WINAPI
1969 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1970 {
1971 POINT pt;
1972
1973 if (!is_valid(himl) || (pImageInfo == NULL))
1974 return FALSE;
1975 if ((i < 0) || (i >= himl->cCurImage))
1976 return FALSE;
1977
1978 pImageInfo->hbmImage = himl->hbmImage;
1979 pImageInfo->hbmMask = himl->hbmMask;
1980
1981 imagelist_point_from_index( himl, i, &pt );
1982 pImageInfo->rcImage.top = pt.y;
1983 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1984 pImageInfo->rcImage.left = pt.x;
1985 pImageInfo->rcImage.right = pt.x + himl->cx;
1986
1987 return TRUE;
1988 }
1989
1990
1991 /*************************************************************************
1992 * ImageList_GetImageRect [COMCTL32.@]
1993 *
1994 * Retrieves the rectangle of the specified image in an image list.
1995 *
1996 * PARAMS
1997 * himl [I] handle to image list
1998 * i [I] image index
1999 * lpRect [O] pointer to the image rectangle
2000 *
2001 * RETURNS
2002 * Success: TRUE
2003 * Failure: FALSE
2004 *
2005 * NOTES
2006 * This is an UNDOCUMENTED function!!!
2007 */
2008
2009 BOOL WINAPI
2010 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
2011 {
2012 POINT pt;
2013
2014 if (!is_valid(himl) || (lpRect == NULL))
2015 return FALSE;
2016 if ((i < 0) || (i >= himl->cCurImage))
2017 return FALSE;
2018
2019 imagelist_point_from_index( himl, i, &pt );
2020 lpRect->left = pt.x;
2021 lpRect->top = pt.y;
2022 lpRect->right = pt.x + himl->cx;
2023 lpRect->bottom = pt.y + himl->cy;
2024
2025 return TRUE;
2026 }
2027
2028
2029 /*************************************************************************
2030 * ImageList_LoadImage [COMCTL32.@]
2031 * ImageList_LoadImageA [COMCTL32.@]
2032 *
2033 * Creates an image list from a bitmap, icon or cursor.
2034 *
2035 * See ImageList_LoadImageW.
2036 */
2037
2038 HIMAGELIST WINAPI
2039 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
2040 COLORREF clrMask, UINT uType, UINT uFlags)
2041 {
2042 HIMAGELIST himl;
2043 LPWSTR lpbmpW;
2044 DWORD len;
2045
2046 if (IS_INTRESOURCE(lpbmp))
2047 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
2048 uType, uFlags);
2049
2050 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
2051 lpbmpW = Alloc(len * sizeof(WCHAR));
2052 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
2053
2054 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
2055 Free (lpbmpW);
2056 return himl;
2057 }
2058
2059
2060 /*************************************************************************
2061 * ImageList_LoadImageW [COMCTL32.@]
2062 *
2063 * Creates an image list from a bitmap, icon or cursor.
2064 *
2065 * PARAMS
2066 * hi [I] instance handle
2067 * lpbmp [I] name or id of the image
2068 * cx [I] width of each image
2069 * cGrow [I] number of images to expand
2070 * clrMask [I] mask color
2071 * uType [I] type of image to load
2072 * uFlags [I] loading flags
2073 *
2074 * RETURNS
2075 * Success: handle to the loaded image list
2076 * Failure: NULL
2077 *
2078 * SEE
2079 * LoadImage ()
2080 */
2081
2082 HIMAGELIST WINAPI
2083 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
2084 COLORREF clrMask, UINT uType, UINT uFlags)
2085 {
2086 HIMAGELIST himl = NULL;
2087 HANDLE handle;
2088 INT nImageCount;
2089
2090 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
2091 if (!handle) {
2092 WARN("Couldn't load image\n");
2093 return NULL;
2094 }
2095
2096 if (uType == IMAGE_BITMAP) {
2097 DIBSECTION dib;
2098 UINT color;
2099
2100 if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
2101 else color = dib.dsBm.bmBitsPixel;
2102
2103 /* To match windows behavior, if cx is set to zero and
2104 the flag DI_DEFAULTSIZE is specified, cx becomes the
2105 system metric value for icons. If the flag is not specified
2106 the function sets the size to the height of the bitmap */
2107 if (cx == 0)
2108 {
2109 if (uFlags & DI_DEFAULTSIZE)
2110 cx = GetSystemMetrics (SM_CXICON);
2111 else
2112 cx = dib.dsBm.bmHeight;
2113 }
2114
2115 nImageCount = dib.dsBm.bmWidth / cx;
2116
2117 himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);
2118 if (!himl) {
2119 DeleteObject (handle);
2120 return NULL;
2121 }
2122 ImageList_AddMasked (himl, handle, clrMask);
2123 }
2124 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2125 ICONINFO ii;
2126 BITMAP bmp;
2127
2128 GetIconInfo (handle, &ii);
2129 GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2130 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
2131 ILC_MASK | ILC_COLOR, 1, cGrow);
2132 if (!himl) {
2133 DeleteObject (ii.hbmColor);
2134 DeleteObject (ii.hbmMask);
2135 DeleteObject (handle);
2136 return NULL;
2137 }
2138 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
2139 DeleteObject (ii.hbmColor);
2140 DeleteObject (ii.hbmMask);
2141 }
2142
2143 DeleteObject (handle);
2144
2145 return himl;
2146 }
2147
2148
2149 /*************************************************************************
2150 * ImageList_Merge [COMCTL32.@]
2151 *
2152 * Create an image list containing a merged image from two image lists.
2153 *
2154 * PARAMS
2155 * himl1 [I] handle to first image list
2156 * i1 [I] first image index
2157 * himl2 [I] handle to second image list
2158 * i2 [I] second image index
2159 * dx [I] X offset of the second image relative to the first.
2160 * dy [I] Y offset of the second image relative to the first.
2161 *
2162 * RETURNS
2163 * Success: The newly created image list. It contains a single image
2164 * consisting of the second image merged with the first.
2165 * Failure: NULL, if either himl1 or himl2 is invalid.
2166 *
2167 * NOTES
2168 * - The returned image list should be deleted by the caller using
2169 * ImageList_Destroy() when it is no longer required.
2170 * - If either i1 or i2 is not a valid image index, they will be treated
2171 * as blank images.
2172 */
2173 HIMAGELIST WINAPI
2174 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
2175 INT dx, INT dy)
2176 {
2177 HIMAGELIST himlDst = NULL;
2178 INT cxDst, cyDst;
2179 INT xOff1, yOff1, xOff2, yOff2;
2180 POINT pt1, pt2;
2181 INT newFlags;
2182
2183 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
2184 i2, dx, dy);
2185
2186 if (!is_valid(himl1) || !is_valid(himl2))
2187 return NULL;
2188
2189 if (dx > 0) {
2190 cxDst = max (himl1->cx, dx + himl2->cx);
2191 xOff1 = 0;
2192 xOff2 = dx;
2193 }
2194 else if (dx < 0) {
2195 cxDst = max (himl2->cx, himl1->cx - dx);
2196 xOff1 = -dx;
2197 xOff2 = 0;
2198 }
2199 else {
2200 cxDst = max (himl1->cx, himl2->cx);
2201 xOff1 = 0;
2202 xOff2 = 0;
2203 }
2204
2205 if (dy > 0) {
2206 cyDst = max (himl1->cy, dy + himl2->cy);
2207 yOff1 = 0;
2208 yOff2 = dy;
2209 }
2210 else if (dy < 0) {
2211 cyDst = max (himl2->cy, himl1->cy - dy);
2212 yOff1 = -dy;
2213 yOff2 = 0;
2214 }
2215 else {
2216 cyDst = max (himl1->cy, himl2->cy);
2217 yOff1 = 0;
2218 yOff2 = 0;
2219 }
2220
2221 newFlags = (himl1->flags > himl2->flags ? himl1->flags : himl2->flags) & ILC_COLORDDB;
2222 if (newFlags == ILC_COLORDDB && (himl1->flags & ILC_COLORDDB) == ILC_COLOR16)
2223 newFlags = ILC_COLOR16; /* this is what native (at least v5) does, don't know why */
2224 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | newFlags, 1, 1);
2225
2226 if (himlDst)
2227 {
2228 imagelist_point_from_index( himl1, i1, &pt1 );
2229 imagelist_point_from_index( himl2, i2, &pt2 );
2230
2231 /* copy image */
2232 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
2233 if (i1 >= 0 && i1 < himl1->cCurImage)
2234 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2235 if (i2 >= 0 && i2 < himl2->cCurImage)
2236 {
2237 if (himl2->flags & ILC_MASK)
2238 {
2239 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
2240 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2241 }
2242 else
2243 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCCOPY);
2244 }
2245
2246 /* copy mask */
2247 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
2248 if (i1 >= 0 && i1 < himl1->cCurImage)
2249 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
2250 if (i2 >= 0 && i2 < himl2->cCurImage)
2251 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
2252
2253 himlDst->cCurImage = 1;
2254 }
2255
2256 return himlDst;
2257 }
2258
2259
2260 /* helper for ImageList_Read, see comments below */
2261 static void *read_bitmap(LPSTREAM pstm, BITMAPINFO *bmi)
2262 {
2263 BITMAPFILEHEADER bmfh;
2264 int bitsperpixel, palspace;
2265 void *bits;
2266
2267 if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2268 return NULL;
2269
2270 if (bmfh.bfType != (('M'<<8)|'B'))
2271 return NULL;
2272
2273 if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2274 return NULL;
2275
2276 if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2277 return NULL;
2278
2279 TRACE("width %u, height %u, planes %u, bpp %u\n",
2280 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
2281 bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount);
2282
2283 bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2284 if (bitsperpixel<=8)
2285 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2286 else
2287 palspace = 0;
2288
2289 bmi->bmiHeader.biSizeImage = get_dib_image_size( bmi );
2290
2291 /* read the palette right after the end of the bitmapinfoheader */
2292 if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2293 return NULL;
2294
2295 bits = Alloc(bmi->bmiHeader.biSizeImage);
2296 if (!bits) return NULL;
2297
2298 if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
2299 {
2300 Free(bits);
2301 return NULL;
2302 }
2303 return bits;
2304 }
2305
2306 /*************************************************************************
2307 * ImageList_Read [COMCTL32.@]
2308 *
2309 * Reads an image list from a stream.
2310 *
2311 * PARAMS
2312 * pstm [I] pointer to a stream
2313 *
2314 * RETURNS
2315 * Success: handle to image list
2316 * Failure: NULL
2317 *
2318 * The format is like this:
2319 * ILHEAD ilheadstruct;
2320 *
2321 * for the color image part:
2322 * BITMAPFILEHEADER bmfh;
2323 * BITMAPINFOHEADER bmih;
2324 * only if it has a palette:
2325 * RGBQUAD rgbs[nr_of_paletted_colors];
2326 *
2327 * BYTE colorbits[imagesize];
2328 *
2329 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2330 * BITMAPFILEHEADER bmfh_mask;
2331 * BITMAPINFOHEADER bmih_mask;
2332 * only if it has a palette (it usually does not):
2333 * RGBQUAD rgbs[nr_of_paletted_colors];
2334 *
2335 * BYTE maskbits[imagesize];
2336 */
2337 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2338 {
2339 char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2340 char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2341 BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
2342 BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
2343 void *image_bits, *mask_bits = NULL;
2344 ILHEAD ilHead;
2345 HIMAGELIST himl;
2346 unsigned int i;
2347
2348 TRACE("%p\n", pstm);
2349
2350 if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2351 return NULL;
2352 if (ilHead.usMagic != (('L' << 8) | 'I'))
2353 return NULL;
2354 if (ilHead.usVersion != 0x101) /* probably version? */
2355 return NULL;
2356
2357 TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
2358 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2359
2360 himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2361 if (!himl)
2362 return NULL;
2363
2364 if (!(image_bits = read_bitmap(pstm, image_info)))
2365 {
2366 WARN("failed to read bitmap from stream\n");
2367 return NULL;
2368 }
2369 if (ilHead.flags & ILC_MASK)
2370 {
2371 if (!(mask_bits = read_bitmap(pstm, mask_info)))
2372 {
2373 WARN("failed to read mask bitmap from stream\n");
2374 return NULL;
2375 }
2376 }
2377 else mask_info = NULL;
2378
2379 if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
2380 {
2381 DWORD *ptr = image_bits;
2382 BYTE *mask_ptr = mask_bits;
2383 int stride = himl->cy * image_info->bmiHeader.biWidth;
2384
2385 if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
2386 {
2387 ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
2388 mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2389 stride = -stride;
2390 image_info->bmiHeader.biHeight = himl->cy;
2391 }
2392 else image_info->bmiHeader.biHeight = -himl->cy;
2393
2394 for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
2395 {
2396 add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
2397 himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
2398 ptr += stride;
2399 mask_ptr += stride / 8;
2400 }
2401 }
2402 else
2403 {
2404 StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2405 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2406 image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
2407 if (mask_info)
2408 StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2409 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2410 mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
2411 }
2412 Free( image_bits );
2413 Free( mask_bits );
2414
2415 himl->cCurImage = ilHead.cCurImage;
2416 himl->cMaxImage = ilHead.cMaxImage;
2417
2418 ImageList_SetBkColor(himl,ilHead.bkcolor);
2419 for (i=0;i<4;i++)
2420 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2421 return himl;
2422 }
2423
2424
2425 /*************************************************************************
2426 * ImageList_Remove [COMCTL32.@]
2427 *
2428 * Removes an image from an image list
2429 *
2430 * PARAMS
2431 * himl [I] image list handle
2432 * i [I] image index
2433 *
2434 * RETURNS
2435 * Success: TRUE
2436 * Failure: FALSE
2437 *
2438 * FIXME: as the image list storage test shows, native comctl32 simply shifts
2439 * images without creating a new bitmap.
2440 */
2441 BOOL WINAPI
2442 ImageList_Remove (HIMAGELIST himl, INT i)
2443 {
2444 HBITMAP hbmNewImage, hbmNewMask;
2445 HDC hdcBmp;
2446 SIZE sz;
2447
2448 TRACE("(himl=%p i=%d)\n", himl, i);
2449
2450 if (!is_valid(himl)) {
2451 ERR("Invalid image list handle!\n");
2452 return FALSE;
2453 }
2454
2455 if ((i < -1) || (i >= himl->cCurImage)) {
2456 TRACE("index out of range! %d\n", i);
2457 return FALSE;
2458 }
2459
2460 if (i == -1) {
2461 INT nCount;
2462
2463 /* remove all */
2464 if (himl->cCurImage == 0) {
2465 /* remove all on empty ImageList is allowed */
2466 TRACE("remove all on empty ImageList!\n");
2467 return TRUE;
2468 }
2469
2470 himl->cMaxImage = himl->cGrow;
2471 himl->cCurImage = 0;
2472 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2473 himl->nOvlIdx[nCount] = -1;
2474
2475 if (himl->has_alpha)
2476 {
2477 HeapFree( GetProcessHeap(), 0, himl->has_alpha );
2478 himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
2479 }
2480
2481 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2482 SelectObject (himl->hdcImage, hbmNewImage);
2483 DeleteObject (himl->hbmImage);
2484 himl->hbmImage = hbmNewImage;
2485
2486 if (himl->hbmMask) {
2487
2488 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2489 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2490 SelectObject (himl->hdcMask, hbmNewMask);
2491 DeleteObject (himl->hbmMask);
2492 himl->hbmMask = hbmNewMask;
2493 }
2494 }
2495 else {
2496 /* delete one image */
2497 TRACE("Remove single image! %d\n", i);
2498
2499 /* create new bitmap(s) */
2500 TRACE(" - Number of images: %d / %d (Old/New)\n",
2501 himl->cCurImage, himl->cCurImage - 1);
2502
2503 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2504
2505 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
2506 if (himl->hbmMask)
2507 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2508 else
2509 hbmNewMask = 0; /* Just to keep compiler happy! */
2510
2511 hdcBmp = CreateCompatibleDC (0);
2512
2513 /* copy all images and masks prior to the "removed" image */
2514 if (i > 0) {
2515 TRACE("Pre image copy: Copy %d images\n", i);
2516
2517 SelectObject (hdcBmp, hbmNewImage);
2518 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2519
2520 if (himl->hbmMask) {
2521 SelectObject (hdcBmp, hbmNewMask);
2522 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2523 }
2524 }
2525
2526 /* copy all images and masks behind the removed image */
2527 if (i < himl->cCurImage - 1) {
2528 TRACE("Post image copy!\n");
2529
2530 SelectObject (hdcBmp, hbmNewImage);
2531 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
2532 (himl->cCurImage - i), i );
2533
2534 if (himl->hbmMask) {
2535 SelectObject (hdcBmp, hbmNewMask);
2536 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
2537 (himl->cCurImage - i), i );
2538 }
2539 }
2540
2541 DeleteDC (hdcBmp);
2542
2543 /* delete old images and insert new ones */
2544 SelectObject (himl->hdcImage, hbmNewImage);
2545 DeleteObject (himl->hbmImage);
2546 himl->hbmImage = hbmNewImage;
2547 if (himl->hbmMask) {
2548 SelectObject (himl->hdcMask, hbmNewMask);
2549 DeleteObject (himl->hbmMask);
2550 himl->hbmMask = hbmNewMask;
2551 }
2552
2553 himl->cCurImage--;
2554 }
2555
2556 return TRUE;
2557 }
2558
2559
2560 /*************************************************************************
2561 * ImageList_Replace [COMCTL32.@]
2562 *
2563 * Replaces an image in an image list with a new image.
2564 *
2565 * PARAMS
2566 * himl [I] handle to image list
2567 * i [I] image index
2568 * hbmImage [I] handle to image bitmap
2569 * hbmMask [I] handle to mask bitmap. Can be NULL.
2570 *
2571 * RETURNS
2572 * Success: TRUE
2573 * Failure: FALSE
2574 */
2575
2576 BOOL WINAPI
2577 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2578 HBITMAP hbmMask)
2579 {
2580 HDC hdcImage;
2581 BITMAP bmp;
2582 POINT pt;
2583
2584 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2585
2586 if (!is_valid(himl)) {
2587 ERR("Invalid image list handle!\n");
2588 return FALSE;
2589 }
2590
2591 if ((i >= himl->cMaxImage) || (i < 0)) {
2592 ERR("Invalid image index!\n");
2593 return FALSE;
2594 }
2595
2596 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2597 return FALSE;
2598
2599 hdcImage = CreateCompatibleDC (0);
2600
2601 /* Replace Image */
2602 SelectObject (hdcImage, hbmImage);
2603
2604 if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
2605 goto done;
2606
2607 imagelist_point_from_index(himl, i, &pt);
2608 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2609 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2610
2611 if (himl->hbmMask)
2612 {
2613 HDC hdcTemp;
2614 HBITMAP hOldBitmapTemp;
2615
2616 hdcTemp = CreateCompatibleDC(0);
2617 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2618
2619 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2620 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2621 SelectObject(hdcTemp, hOldBitmapTemp);
2622 DeleteDC(hdcTemp);
2623
2624 /* Remove the background from the image
2625 */
2626 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2627 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2628 }
2629
2630 done:
2631 DeleteDC (hdcImage);
2632
2633 return TRUE;
2634 }
2635
2636
2637 /*************************************************************************
2638 * ImageList_ReplaceIcon [COMCTL32.@]
2639 *
2640 * Replaces an image in an image list using an icon.
2641 *
2642 * PARAMS
2643 * himl [I] handle to image list
2644 * i [I] image index
2645 * hIcon [I] handle to icon
2646 *
2647 * RETURNS
2648 * Success: index of the replaced image
2649 * Failure: -1
2650 */
2651
2652 INT WINAPI
2653 ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
2654 {
2655 HICON hBestFitIcon;
2656 ICONINFO ii;
2657 BITMAP bmp;
2658 BOOL ret;
2659 POINT pt;
2660
2661 TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
2662
2663 if (!is_valid(himl)) {
2664 ERR("invalid image list\n");
2665 return -1;
2666 }
2667 if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
2668 ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2669 return -1;
2670 }
2671
2672 hBestFitIcon = CopyImage(
2673 hIcon, IMAGE_ICON,
2674 himl->cx, himl->cy,
2675 LR_COPYFROMRESOURCE);
2676 /* the above will fail if the icon wasn't loaded from a resource, so try
2677 * again without LR_COPYFROMRESOURCE flag */
2678 if (!hBestFitIcon)
2679 hBestFitIcon = CopyImage(
2680 hIcon, IMAGE_ICON,
2681 himl->cx, himl->cy,
2682 0);
2683 if (!hBestFitIcon)
2684 return -1;
2685
2686 if (nIndex == -1) {
2687 if (himl->cCurImage + 1 >= himl->cMaxImage)
2688 IMAGELIST_InternalExpandBitmaps(himl, 1);
2689
2690 nIndex = himl->cCurImage;
2691 himl->cCurImage++;
2692 }
2693
2694 if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2695 {
2696 HDC hdcImage = CreateCompatibleDC( 0 );
2697 GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);
2698
2699 if (!ii.hbmColor)
2700 {
2701 UINT height = bmp.bmHeight / 2;
2702 HDC hdcMask = CreateCompatibleDC( 0 );
2703 HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
2704 SelectObject( hdcImage, color );
2705 SelectObject( hdcMask, ii.hbmMask );
2706 BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2707 ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2708 DeleteDC( hdcMask );
2709 DeleteObject( color );
2710 }
2711 else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
2712 ii.hbmColor, ii.hbmMask );
2713
2714 DeleteDC( hdcImage );
2715 DeleteObject (ii.hbmMask);
2716 if (ii.hbmColor) DeleteObject (ii.hbmColor);
2717 if (ret) goto done;
2718 }
2719
2720 imagelist_point_from_index(himl, nIndex, &pt);
2721
2722 if (himl->hbmMask)
2723 {
2724 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
2725 PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
2726 DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2727 }
2728 else
2729 {
2730 COLORREF color = himl->clrBk != CLR_NONE ? himl->clrBk : comctl32_color.clrWindow;
2731 HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));
2732
2733 SelectObject( himl->hdcImage, brush );
2734 PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
2735 SelectObject( himl->hdcImage, GetStockObject(BLACK_BRUSH) );
2736 DeleteObject( brush );
2737 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
2738 }
2739
2740 done:
2741 DestroyIcon(hBestFitIcon);
2742
2743 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2744 return nIndex;
2745 }
2746
2747
2748 /*************************************************************************
2749 * ImageList_SetBkColor [COMCTL32.@]
2750 *
2751 * Sets the background color of an image list.
2752 *
2753 * PARAMS
2754 * himl [I] handle to image list
2755 * clrBk [I] background color
2756 *
2757 * RETURNS
2758 * Success: previous background color
2759 * Failure: CLR_NONE
2760 */
2761
2762 COLORREF WINAPI
2763 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2764 {
2765 COLORREF clrOldBk;
2766
2767 if (!is_valid(himl))
2768 return CLR_NONE;
2769
2770 clrOldBk = himl->clrBk;
2771 himl->clrBk = clrBk;
2772 return clrOldBk;
2773 }
2774
2775
2776 /*************************************************************************
2777 * ImageList_SetDragCursorImage [COMCTL32.@]
2778 *
2779 * Combines the specified image with the current drag image
2780 *
2781 * PARAMS
2782 * himlDrag [I] handle to drag image list
2783 * iDrag [I] drag image index
2784 * dxHotspot [I] X position of the hot spot
2785 * dyHotspot [I] Y position of the hot spot
2786 *
2787 * RETURNS
2788 * Success: TRUE
2789 * Failure: FALSE
2790 *
2791 * NOTES
2792 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2793 * to do with a hotspot but are only the offset of the origin of the new
2794 * image relative to the origin of the old image.
2795 *
2796 * - When this function is called and the drag image is visible, a
2797 * short flickering occurs but this matches the Win9x behavior. It is
2798 * possible to fix the flickering using code like in ImageList_DragMove.
2799 */
2800
2801 BOOL WINAPI
2802 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2803 INT dxHotspot, INT dyHotspot)
2804 {
2805 HIMAGELIST himlTemp;
2806 BOOL visible;
2807
2808 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2809 return FALSE;
2810
2811 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2812 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2813
2814 visible = InternalDrag.bShow;
2815
2816 himlTemp = ImageList_Merge (InternalDrag.himlNoCursor, 0, himlDrag, iDrag,
2817 dxHotspot, dyHotspot);
2818
2819 if (visible) {
2820 /* hide the drag image */
2821 ImageList_DragShowNolock(FALSE);
2822 }
2823 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2824 (InternalDrag.himl->cy != himlTemp->cy)) {
2825 /* the size of the drag image changed, invalidate the buffer */
2826 DeleteObject(InternalDrag.hbmBg);
2827 InternalDrag.hbmBg = 0;
2828 }
2829
2830 if (InternalDrag.himl != InternalDrag.himlNoCursor)
2831 ImageList_Destroy (InternalDrag.himl);
2832 InternalDrag.himl = himlTemp;
2833
2834 if (visible) {
2835 /* show the drag image */
2836 ImageList_DragShowNolock(TRUE);
2837 }
2838
2839 return TRUE;
2840 }
2841
2842
2843 /*************************************************************************
2844 * ImageList_SetFilter [COMCTL32.@]
2845 *
2846 * Sets a filter (or does something completely different)!!???
2847 * It removes 12 Bytes from the stack (3 Parameters).
2848 *
2849 * PARAMS
2850 * himl [I] SHOULD be a handle to image list
2851 * i [I] COULD be an index?
2852 * dwFilter [I] ???
2853 *
2854 * RETURNS
2855 * Success: TRUE ???
2856 * Failure: FALSE ???
2857 *
2858 * BUGS
2859 * This is an UNDOCUMENTED function!!!!
2860 * empty stub.
2861 */
2862
2863 BOOL WINAPI
2864 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2865 {
2866 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2867
2868 return FALSE;
2869 }
2870
2871
2872 /*************************************************************************
2873 * ImageList_SetFlags [COMCTL32.@]
2874 *
2875 * Sets the image list flags.
2876 *
2877 * PARAMS
2878 * himl [I] Handle to image list
2879 * flags [I] Flags to set
2880 *
2881 * RETURNS
2882 * Old flags?
2883 *
2884 * BUGS
2885 * Stub.
2886 */
2887
2888 DWORD WINAPI
2889 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2890 {
2891 FIXME("(%p %08x):empty stub\n", himl, flags);
2892 return 0;
2893 }
2894
2895
2896 /*************************************************************************
2897 * ImageList_SetIconSize [COMCTL32.@]
2898 *
2899 * Sets the image size of the bitmap and deletes all images.
2900 *
2901 * PARAMS
2902 * himl [I] handle to image list
2903 * cx [I] image width
2904 * cy [I] image height
2905 *
2906 * RETURNS
2907 * Success: TRUE
2908 * Failure: FALSE
2909 */
2910
2911 BOOL WINAPI
2912 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2913 {
2914 INT nCount;
2915 HBITMAP hbmNew;
2916
2917 if (!is_valid(himl))
2918 return FALSE;
2919
2920 /* remove all images */
2921 himl->cMaxImage = himl->cInitial + 1;
2922 himl->cCurImage = 0;
2923 himl->cx = cx;
2924 himl->cy = cy;
2925
2926 /* initialize overlay mask indices */
2927 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2928 himl->nOvlIdx[nCount] = -1;
2929
2930 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
2931 SelectObject (himl->hdcImage, hbmNew);
2932 DeleteObject (himl->hbmImage);
2933 himl->hbmImage = hbmNew;
2934
2935 if (himl->hbmMask) {
2936 SIZE sz;
2937 imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
2938 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2939 SelectObject (himl->hdcMask, hbmNew);
2940 DeleteObject (himl->hbmMask);
2941 himl->hbmMask = hbmNew;
2942 }
2943
2944 return TRUE;
2945 }
2946
2947
2948 /*************************************************************************
2949 * ImageList_SetImageCount [COMCTL32.@]
2950 *
2951 * Resizes an image list to the specified number of images.
2952 *
2953 * PARAMS
2954 * himl [I] handle to image list
2955 * iImageCount [I] number of images in the image list
2956 *
2957 * RETURNS
2958 * Success: TRUE
2959 * Failure: FALSE
2960 */
2961
2962 BOOL WINAPI
2963 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2964 {
2965 HDC hdcBitmap;
2966 HBITMAP hbmNewBitmap, hbmOld;
2967 INT nNewCount, nCopyCount;
2968
2969 TRACE("%p %d\n",himl,iImageCount);
2970
2971 if (!is_valid(himl))
2972 return FALSE;
2973
2974 nNewCount = iImageCount + 1;
2975 nCopyCount = min(himl->cCurImage, iImageCount);
2976
2977 hdcBitmap = CreateCompatibleDC (0);
2978
2979 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
2980
2981 if (hbmNewBitmap != 0)
2982 {
2983 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
2984 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2985 SelectObject (hdcBitmap, hbmOld);
2986
2987 /* FIXME: delete 'empty' image space? */
2988
2989 SelectObject (himl->hdcImage, hbmNewBitmap);
2990 DeleteObject (himl->hbmImage);
2991 himl->hbmImage = hbmNewBitmap;
2992 }
2993 else
2994 ERR("Could not create new image bitmap!\n");
2995
2996 if (himl->hbmMask)
2997 {
2998 SIZE sz;
2999 imagelist_get_bitmap_size( himl, nNewCount, &sz );
3000 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
3001 if (hbmNewBitmap != 0)
3002 {
3003 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
3004 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
3005 SelectObject (hdcBitmap, hbmOld);
3006
3007 /* FIXME: delete 'empty' image space? */
3008
3009 SelectObject (himl->hdcMask, hbmNewBitmap);
3010 DeleteObject (himl->hbmMask);
3011 himl->hbmMask = hbmNewBitmap;
3012 }
3013 else
3014 ERR("Could not create new mask bitmap!\n");
3015 }
3016
3017 DeleteDC (hdcBitmap);
3018
3019 if (himl->has_alpha)
3020 {
3021 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
3022 if (new_alpha) himl->has_alpha = new_alpha;
3023 else
3024 {
3025 HeapFree( GetProcessHeap(), 0, himl->has_alpha );
3026 himl->has_alpha = NULL;
3027 }
3028 }
3029
3030 /* Update max image count and current image count */
3031 himl->cMaxImage = nNewCount;
3032 himl->cCurImage = iImageCount;
3033
3034 return TRUE;
3035 }
3036
3037
3038 /*************************************************************************
3039 * ImageList_SetOverlayImage [COMCTL32.@]
3040 *
3041 * Assigns an overlay mask index to an existing image in an image list.
3042 *
3043 * PARAMS
3044 * himl [I] handle to image list
3045 * iImage [I] image index
3046 * iOverlay [I] overlay mask index
3047 *
3048 * RETURNS
3049 * Success: TRUE
3050 * Failure: FALSE
3051 */
3052
3053 BOOL WINAPI
3054 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
3055 {
3056 if (!is_valid(himl))
3057 return FALSE;
3058 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
3059 return FALSE;
3060 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
3061 return FALSE;
3062 himl->nOvlIdx[iOverlay - 1] = iImage;
3063 return TRUE;
3064 }
3065
3066
3067
3068 /* helper for ImageList_Write - write bitmap to pstm
3069 * currently everything is written as 24 bit RGB, except masks
3070 */
3071 static BOOL
3072 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm)
3073 {
3074 LPBITMAPFILEHEADER bmfh;
3075 LPBITMAPINFOHEADER bmih;
3076 LPBYTE data = NULL, lpBits;
3077 BITMAP bm;
3078 INT bitCount, sizeImage, offBits, totalSize;
3079 HDC xdc;
3080 BOOL result = FALSE;
3081
3082 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
3083 return FALSE;
3084
3085 bitCount = bm.bmBitsPixel;
3086 sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
3087
3088 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
3089 if(bitCount <= 8)
3090 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
3091 offBits = totalSize;
3092 totalSize += sizeImage;
3093
3094 data = Alloc(totalSize);
3095 bmfh = (LPBITMAPFILEHEADER)data;
3096 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
3097 lpBits = data + offBits;
3098
3099 /* setup BITMAPFILEHEADER */
3100 bmfh->bfType = (('M' << 8) | 'B');
3101 bmfh->bfSize = offBits;
3102 bmfh->bfReserved1 = 0;
3103 bmfh->bfReserved2 = 0;
3104 bmfh->bfOffBits = offBits;
3105
3106 /* setup BITMAPINFOHEADER */
3107 bmih->biSize = sizeof(BITMAPINFOHEADER);