ReactOS 0.4.16-dev-753-g705a985
imagelist.c
Go to the documentation of this file.
1/*
2 * ImageList implementation
3 *
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001, 2004 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
9 * Copyright 2009 Owen Rudge for CodeWeavers
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 *
25 * TODO:
26 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
27 * - Add support for ILS_GLOW, ILS_SHADOW
28 * - Thread-safe locking
29 */
30
31#include <stdarg.h>
32#include <stdlib.h>
33#include <string.h>
34
35#define COBJMACROS
36
37#include "winerror.h"
38#include "windef.h"
39#include "winbase.h"
40#include "objbase.h"
41#include "wingdi.h"
42#include "winuser.h"
43#include "commctrl.h"
44#include "comctl32.h"
45#include "commoncontrols.h"
46#include "wine/debug.h"
47#include "wine/exception.h"
48#include "wine/heap.h"
49
51
52#define MAX_OVERLAYIMAGE 15
53
54#ifdef __REACTOS__
55//The big bad reactos image list hack!
56BOOL is_valid2(HIMAGELIST himl);
57INT WINAPI Internal_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon);
58BOOL WINAPI Internal_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp);
59COLORREF WINAPI Internal_SetBkColor (HIMAGELIST himl, COLORREF clrBk);
60BOOL WINAPI Internal_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay);
61
62#define ImageList_Add Internal_Add
63#define ImageList_ReplaceIcon Internal_ReplaceIcon
64#define ImageList_SetOverlayImage Internal_SetOverlayImage
65#define ImageList_Replace Internal_Replace
66#define ImageList_AddMasked Internal_AddMasked
67#define ImageList_Remove Internal_Remove
68#define ImageList_GetIcon Internal_GetIcon
69#define ImageList_GetImageInfo Internal_GetImageInfo
70#define ImageList_Copy Internal_Copy
71#define ImageList_Merge Internal_Merge
72#define ImageList_Duplicate Internal_Duplicate
73#define ImageList_GetIconSize Internal_GetIconSize
74#define ImageList_SetIconSize Internal_SetIconSize
75#define ImageList_GetImageCount Internal_GetImageCount
76#define ImageList_SetImageCount Internal_SetImageCount
77#define ImageList_SetBkColor Internal_SetBkColor
78#define ImageList_GetBkColor Internal_GetBkColor
79#define ImageList_BeginDrag Internal_BeginDrag
80#define ImageList_DrawIndirect Internal_DrawIndirect
81#endif
82
84{
85 IImageList2 IImageList2_iface; /* 00: IImageList vtable */
86 INT cCurImage; /* 04: ImageCount */
87 INT cMaxImage; /* 08: maximages */
88 INT cGrow; /* 0C: cGrow */
89 INT cx; /* 10: cx */
90 INT cy; /* 14: cy */
92 UINT flags; /* 1C: flags */
93 COLORREF clrFg; /* 20: foreground color */
94 COLORREF clrBk; /* 24: background color */
95
96
97 HBITMAP hbmImage; /* 28: images Bitmap */
98 HBITMAP hbmMask; /* 2C: masks Bitmap */
99 HDC hdcImage; /* 30: images MemDC */
100 HDC hdcMask; /* 34: masks MemDC */
101 INT nOvlIdx[MAX_OVERLAYIMAGE]; /* 38: overlay images index */
102
103 /* not yet found out */
104 #ifdef __REACTOS__
105 ULONG usMagic;
106 #endif
113
114 LONG ref; /* reference count */
115#ifdef __REACTOS__
116 USHORT usVersion; /* hack for IL from stream. Keep version here */
117#endif
118};
119
120#define IMAGELIST_MAGIC 0x53414D58
121#ifdef __REACTOS__
122#define IMAGELIST_MAGIC_DESTROYED 0x44454144
123#define IMAGELIST_VERSION 0x101
124
125#define WinVerMajor() LOBYTE(GetVersion())
126
127#include <comctl32_undoc.h>
128#define ILC_PUBLICFLAGS ( 0xFFFFFFFF ) /* Allow all flags for now */
129#define ILC_COLORMASK 0xFE
130#endif /* __REACTOS__ */
131
132/* Header used by ImageList_Read() and ImageList_Write() */
133#include "pshpack2.h"
134typedef struct _ILHEAD
135{
147#include "poppack.h"
148
149/* internal image list data used for Drag & Drop operations */
150typedef struct
151{
155 /* position of the drag image relative to the window */
158 /* offset of the hotspot relative to the origin of the image */
161 /* is the drag image visible */
163 /* saved background */
166
167static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, 0, FALSE, 0 };
168
170{
171 return CONTAINING_RECORD(iface, struct _IMAGELIST, IImageList2_iface);
172}
173
175static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv);
177
178/*
179 * An imagelist with N images is tiled like this:
180 *
181 * N/4 ->
182 *
183 * 4 048C..
184 * 159D..
185 * | 26AE.N
186 * V 37BF.
187 */
188
189#define TILE_COUNT 4
190
192{
193 return ((count + TILE_COUNT - 1)/TILE_COUNT);
194}
195
197{
198 pt->x = (index%TILE_COUNT) * himl->cx;
199 pt->y = (index/TILE_COUNT) * himl->cy;
200}
201
203{
204 sz->cx = himl->cx * TILE_COUNT;
205 sz->cy = imagelist_height( count ) * himl->cy;
206}
207
208static inline int get_dib_stride( int width, int bpp )
209{
210 return ((width * bpp + 31) >> 3) & ~3;
211}
212
213static inline int get_dib_image_size( const BITMAPINFO *info )
214{
215 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
216 * abs( info->bmiHeader.biHeight );
217}
218
219/*
220 * imagelist_copy_images()
221 *
222 * Copies a block of count images from offset src in the list to offset dest.
223 * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
224 */
225static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
227{
228 POINT ptSrc, ptDest;
229 SIZE sz;
230 UINT i;
231
232 for ( i=0; i<TILE_COUNT; i++ )
233 {
236 sz.cx = himl->cx;
237 sz.cy = himl->cy * imagelist_height( count - i );
238
239 BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
240 hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
241 }
242}
243
244static void add_dib_bits( HIMAGELIST himl, int pos, int count, int width, int height,
245 BITMAPINFO *info, BITMAPINFO *mask_info, DWORD *bits, BYTE *mask_bits )
246{
247 int i, j, n;
248 POINT pt;
249 int stride = info->bmiHeader.biWidth;
250 int mask_stride = (info->bmiHeader.biWidth + 31) / 32 * 4;
251
252 for (n = 0; n < count; n++)
253 {
254 BOOL has_alpha = FALSE;
255
257
258 /* check if bitmap has an alpha channel */
259 for (i = 0; i < height && !has_alpha; i++)
260 for (j = n * width; j < (n + 1) * width; j++)
261 if ((has_alpha = ((bits[i * stride + j] & 0xff000000) != 0))) break;
262
263 if (!has_alpha) /* generate alpha channel from the mask */
264 {
265 for (i = 0; i < height; i++)
266 for (j = n * width; j < (n + 1) * width; j++)
267 if (!mask_info || !((mask_bits[i * mask_stride + j / 8] << (j % 8)) & 0x80))
268 bits[i * stride + j] |= 0xff000000;
269 else
270 bits[i * stride + j] = 0;
271 }
272 else
273 {
274 himl->has_alpha[pos + n] = 1;
275
276 if (mask_info && himl->hbmMask) /* generate the mask from the alpha channel */
277 {
278 for (i = 0; i < height; i++)
279 for (j = n * width; j < (n + 1) * width; j++)
280 if ((bits[i * stride + j] >> 24) > 25) /* more than 10% alpha */
281 mask_bits[i * mask_stride + j / 8] &= ~(0x80 >> (j % 8));
282 else
283 mask_bits[i * mask_stride + j / 8] |= 0x80 >> (j % 8);
284 }
285 }
288 if (mask_info)
290 n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
291 }
292}
293
294/* add images with an alpha channel when the image list is 32 bpp */
296 int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
297{
298 BOOL ret = FALSE;
299 BITMAP bm;
300 BITMAPINFO *info, *mask_info = NULL;
301 DWORD *bits = NULL;
302 BYTE *mask_bits = NULL;
303 DWORD mask_width;
304
305 if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
306
307 /* if either the imagelist or the source bitmap don't have an alpha channel, bail out now */
308 if (!himl->has_alpha) return FALSE;
309 if (bm.bmBitsPixel != 32) return FALSE;
310
311 SelectObject( hdc, hbmImage );
312 mask_width = (bm.bmWidth + 31) / 32 * 4;
313
314 if (!(info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
315 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
316 info->bmiHeader.biWidth = bm.bmWidth;
317 info->bmiHeader.biHeight = -height;
318 info->bmiHeader.biPlanes = 1;
319 info->bmiHeader.biBitCount = 32;
320 info->bmiHeader.biCompression = BI_RGB;
321 info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
322 info->bmiHeader.biXPelsPerMeter = 0;
323 info->bmiHeader.biYPelsPerMeter = 0;
324 info->bmiHeader.biClrUsed = 0;
325 info->bmiHeader.biClrImportant = 0;
326 if (!(bits = heap_alloc( info->bmiHeader.biSizeImage ))) goto done;
327 if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
328
329 if (hbmMask)
330 {
331 if (!(mask_info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
332 goto done;
333 mask_info->bmiHeader = info->bmiHeader;
334 mask_info->bmiHeader.biBitCount = 1;
335 mask_info->bmiHeader.biSizeImage = mask_width * height;
336 if (!(mask_bits = heap_alloc_zero( mask_info->bmiHeader.biSizeImage )))
337 goto done;
338 if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
339 }
340
341 add_dib_bits( himl, pos, count, width, height, info, mask_info, bits, mask_bits );
342 ret = TRUE;
343
344done:
345 heap_free( info );
346 heap_free( mask_info );
347 heap_free( bits );
348 heap_free( mask_bits );
349 return ret;
350}
351
354
355/*************************************************************************
356 * IMAGELIST_InternalExpandBitmaps [Internal]
357 *
358 * Expands the bitmaps of an image list by the given number of images.
359 *
360 * PARAMS
361 * himl [I] handle to image list
362 * nImageCount [I] number of images to add
363 *
364 * RETURNS
365 * nothing
366 *
367 * NOTES
368 * This function CANNOT be used to reduce the number of images.
369 */
370static void
372{
374 HBITMAP hbmNewBitmap, hbmNull;
375 INT nNewCount;
376 SIZE sz;
377
378 TRACE("%p has allocated %d, max %d, grow %d images\n", himl, himl->cCurImage, himl->cMaxImage, himl->cGrow);
379
380 if (himl->cCurImage + nImageCount < himl->cMaxImage)
381 return;
382
383 nNewCount = himl->cMaxImage + max(nImageCount, himl->cGrow) + 1;
384
385 imagelist_get_bitmap_size(himl, nNewCount, &sz);
386
387 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, sz.cy, nNewCount);
389
390 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
391
392 if (hbmNewBitmap == 0)
393 ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, sz.cy);
394
395 if (himl->cCurImage)
396 {
397 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
398 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
399 himl->hdcImage, 0, 0, SRCCOPY);
400 SelectObject (hdcBitmap, hbmNull);
401 }
402 SelectObject (himl->hdcImage, hbmNewBitmap);
404 himl->hbmImage = hbmNewBitmap;
405
406 if (himl->flags & ILC_MASK)
407 {
408 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
409
410 if (hbmNewBitmap == 0)
411 ERR("creating new mask bitmap!\n");
412
413 if(himl->cCurImage)
414 {
415 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
416 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
417 himl->hdcMask, 0, 0, SRCCOPY);
418 SelectObject (hdcBitmap, hbmNull);
419 }
420 SelectObject (himl->hdcMask, hbmNewBitmap);
422 himl->hbmMask = hbmNewBitmap;
423 }
424
425 if (himl->has_alpha)
426 {
427 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
428 if (new_alpha) himl->has_alpha = new_alpha;
429 else
430 {
433 }
434 }
435
436 himl->cMaxImage = nNewCount;
437
439}
440
441
442/*************************************************************************
443 * ImageList_Add [COMCTL32.@]
444 *
445 * Add an image or images to an image list.
446 *
447 * PARAMS
448 * himl [I] handle to image list
449 * hbmImage [I] handle to image bitmap
450 * hbmMask [I] handle to mask bitmap
451 *
452 * RETURNS
453 * Success: Index of the first new image.
454 * Failure: -1
455 */
456
459{
460 HDC hdcBitmap, hdcTemp = 0;
461 INT nFirstIndex, nImageCount, i;
462 BITMAP bmp;
463 POINT pt;
464
465 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
466 if (!is_valid(himl))
467 return -1;
468
469 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
470 return -1;
471
472 TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
474
475 nImageCount = bmp.bmWidth / himl->cx;
476
477 TRACE("%p has %d images (%d x %d) bpp %d\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight,
478 bmp.bmBitsPixel);
479
481
483
484 SelectObject(hdcBitmap, hbmImage);
485
486 if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
487 himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
488 goto done;
489
490 if (himl->hbmMask)
491 {
492 hdcTemp = CreateCompatibleDC(0);
493 SelectObject(hdcTemp, hbmMask);
494 }
495
496 if (himl->uBitsPixel <= 8 && bmp.bmBitsPixel <= 8 &&
498 {
499 RGBQUAD colors[256];
500 UINT num = GetDIBColorTable( hdcBitmap, 0, 1 << bmp.bmBitsPixel, colors );
501 if (num) ImageList_SetColorTable( himl, 0, num, colors );
502 }
503
504 for (i=0; i<nImageCount; i++)
505 {
507
508 /* Copy result to the imagelist
509 */
510 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
511 hdcBitmap, i*himl->cx, 0, SRCCOPY );
512
513 if (!himl->hbmMask)
514 continue;
515
516 BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
517 hdcTemp, i*himl->cx, 0, SRCCOPY );
518
519 /* Remove the background from the image
520 */
521 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
522 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
523 }
524 if (hdcTemp) DeleteDC(hdcTemp);
525
526done:
528
529 nFirstIndex = himl->cCurImage;
530 himl->cCurImage += nImageCount;
531
532 return nFirstIndex;
533}
534
535
536/*************************************************************************
537 * ImageList_AddIcon [COMCTL32.@]
538 *
539 * Adds an icon to an image list.
540 *
541 * PARAMS
542 * himl [I] handle to image list
543 * hIcon [I] handle to icon
544 *
545 * RETURNS
546 * Success: index of the new image
547 * Failure: -1
548 */
549#undef ImageList_AddIcon
551{
552 return ImageList_ReplaceIcon (himl, -1, hIcon);
553}
554
555
556/*************************************************************************
557 * ImageList_AddMasked [COMCTL32.@]
558 *
559 * Adds an image or images to an image list and creates a mask from the
560 * specified bitmap using the mask color.
561 *
562 * PARAMS
563 * himl [I] handle to image list.
564 * hBitmap [I] handle to bitmap
565 * clrMask [I] mask color.
566 *
567 * RETURNS
568 * Success: Index of the first new image.
569 * Failure: -1
570 */
571
574{
575 HDC hdcMask, hdcBitmap;
576 INT ret;
577 BITMAP bmp;
578 HBITMAP hMaskBitmap;
579 COLORREF bkColor;
580
581 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
582 if (!is_valid(himl))
583 return -1;
584
585 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
586 return -1;
587
590
591 /* Create a temp Mask so we can remove the background of the Image */
592 hdcMask = CreateCompatibleDC(0);
593 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
594 SelectObject(hdcMask, hMaskBitmap);
595
596 /* create monochrome image to the mask bitmap */
597 bkColor = (clrMask != CLR_DEFAULT) ? clrMask : GetPixel (hdcBitmap, 0, 0);
598 SetBkColor (hdcBitmap, bkColor);
599 BitBlt (hdcMask, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
600
601 /*
602 * Remove the background from the image
603 *
604 * WINDOWS BUG ALERT!!!!!!
605 * The statement below should not be done in common practice
606 * but this is how ImageList_AddMasked works in Windows.
607 * It overwrites the original bitmap passed, this was discovered
608 * by using the same bitmap to iterate the different styles
609 * on windows where it failed (BUT ImageList_Add is OK)
610 * This is here in case some apps rely on this bug
611 *
612 * Blt mode 0x220326 is NOTSRCAND
613 */
614 if (bmp.bmBitsPixel > 8) /* NOTSRCAND can't work with palettes */
615 {
616 SetBkColor(hdcBitmap, RGB(255,255,255));
617 BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
618 }
619
621 DeleteDC(hdcMask);
622
623 ret = ImageList_Add( himl, hBitmap, hMaskBitmap );
624
625 DeleteObject(hMaskBitmap);
626 return ret;
627}
628
629
630/*************************************************************************
631 * ImageList_BeginDrag [COMCTL32.@]
632 *
633 * Creates a temporary image list that contains one image. It will be used
634 * as a drag image.
635 *
636 * PARAMS
637 * himlTrack [I] handle to the source image list
638 * iTrack [I] index of the drag image in the source image list
639 * dxHotspot [I] X position of the hot spot of the drag image
640 * dyHotspot [I] Y position of the hot spot of the drag image
641 *
642 * RETURNS
643 * Success: TRUE
644 * Failure: FALSE
645 */
646
649 INT dxHotspot, INT dyHotspot)
650{
651 INT cx, cy;
652 POINT src, dst;
653
654 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
655 dxHotspot, dyHotspot);
656
657 if (!is_valid(himlTrack))
658 return FALSE;
659
660 if (iTrack >= himlTrack->cCurImage)
661 return FALSE;
662
663 if (InternalDrag.himl)
664 return FALSE;
665
666 cx = himlTrack->cx;
667 cy = himlTrack->cy;
668
670 if (InternalDrag.himl == NULL) {
671 WARN("Error creating drag image list!\n");
672 return FALSE;
673 }
674
675 InternalDrag.dxHotspot = dxHotspot;
676 InternalDrag.dyHotspot = dyHotspot;
677
678 /* copy image */
680 imagelist_point_from_index(himlTrack, iTrack, &src);
681 BitBlt(InternalDrag.himl->hdcImage, dst.x, dst.y, cx, cy, himlTrack->hdcImage, src.x, src.y,
682 SRCCOPY);
683 BitBlt(InternalDrag.himl->hdcMask, dst.x, dst.y, cx, cy, himlTrack->hdcMask, src.x, src.y,
684 SRCCOPY);
685
687
688 return TRUE;
689}
690
691
692/*************************************************************************
693 * ImageList_Copy [COMCTL32.@]
694 *
695 * Copies an image of the source image list to an image of the
696 * destination image list. Images can be copied or swapped.
697 *
698 * PARAMS
699 * himlDst [I] handle to the destination image list
700 * iDst [I] destination image index.
701 * himlSrc [I] handle to the source image list
702 * iSrc [I] source image index
703 * uFlags [I] flags for the copy operation
704 *
705 * RETURNS
706 * Success: TRUE
707 * Failure: FALSE
708 *
709 * NOTES
710 * Copying from one image list to another is possible. The original
711 * implementation just copies or swaps within one image list.
712 * Could this feature become a bug??? ;-)
713 */
714
716ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
717 INT iSrc, UINT uFlags)
718{
719 POINT ptSrc, ptDst;
720
721 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
722
723 if (!is_valid(himlSrc) || !is_valid(himlDst))
724 return FALSE;
725 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
726 return FALSE;
727 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
728 return FALSE;
729
730 imagelist_point_from_index( himlDst, iDst, &ptDst );
731 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
732
733 if (uFlags & ILCF_SWAP) {
734 /* swap */
735 HDC hdcBmp;
736 HBITMAP hbmTempImage, hbmTempMask;
737
738 hdcBmp = CreateCompatibleDC (0);
739
740 /* create temporary bitmaps */
741 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
742 himlSrc->uBitsPixel, NULL);
743 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
744 1, NULL);
745
746 /* copy (and stretch) destination to temporary bitmaps.(save) */
747 /* image */
748 SelectObject (hdcBmp, hbmTempImage);
749 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
750 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
751 SRCCOPY);
752 /* mask */
753 SelectObject (hdcBmp, hbmTempMask);
754 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
755 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
756 SRCCOPY);
757
758 /* copy (and stretch) source to destination */
759 /* image */
760 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
761 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
762 SRCCOPY);
763 /* mask */
764 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
765 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
766 SRCCOPY);
767
768 /* copy (without stretching) temporary bitmaps to source (restore) */
769 /* mask */
770 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
771 hdcBmp, 0, 0, SRCCOPY);
772
773 /* image */
774 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
775 hdcBmp, 0, 0, SRCCOPY);
776 /* delete temporary bitmaps */
777 DeleteObject (hbmTempMask);
778 DeleteObject (hbmTempImage);
779 DeleteDC(hdcBmp);
780 }
781 else {
782 /* copy image */
783 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
784 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
785 SRCCOPY);
786
787 /* copy mask */
788 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
789 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
790 SRCCOPY);
791 }
792
793 return TRUE;
794}
795
796
797/*************************************************************************
798 * ImageList_Create [COMCTL32.@]
799 *
800 * Creates a new image list.
801 *
802 * PARAMS
803 * cx [I] image height
804 * cy [I] image width
805 * flags [I] creation flags
806 * cInitial [I] initial number of images in the image list
807 * cGrow [I] number of images by which image list grows
808 *
809 * RETURNS
810 * Success: Handle to the created image list
811 * Failure: NULL
812 */
815 INT cInitial, INT cGrow)
816{
818 INT nCount;
819 HBITMAP hbmTemp;
820 UINT ilc = (flags & 0xFE);
821 static const WORD aBitBlend25[] =
822 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
823
824 static const WORD aBitBlend50[] =
825 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
826
827 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
828
829 if (cx < 0 || cy < 0) return NULL;
830 if (!((flags&ILC_COLORDDB) == ILC_COLORDDB) && (cx == 0 || cy == 0)) return NULL;
831
832 /* Create the IImageList interface for the image list */
833 if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
834 return NULL;
835
836 cGrow = (WORD)((max( cGrow, 1 ) + 3) & ~3);
837
838 if (cGrow > 256)
839 {
840 /* Windows doesn't limit the size here, but X11 doesn't let us allocate such huge bitmaps */
841 WARN( "grow %d too large, limiting to 256\n", cGrow );
842 cGrow = 256;
843 }
844
845 himl->cx = cx;
846 himl->cy = cy;
847 himl->flags = flags;
848 himl->cMaxImage = cInitial + 1;
849 himl->cInitial = cInitial;
850 himl->cGrow = cGrow;
854#ifdef __REACTOS__
855 himl->usVersion = 0;
856#endif
857
858 /* initialize overlay mask indices */
859 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
860 himl->nOvlIdx[nCount] = -1;
861
862 /* Create Image & Mask DCs */
864 if (!himl->hdcImage)
865 goto cleanup;
866 if (himl->flags & ILC_MASK){
868 if (!himl->hdcMask)
869 goto cleanup;
870 }
871
872 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
873 if (ilc == ILC_COLOR)
874 {
875 ilc = ILC_COLOR4;
877 }
878
879 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
880 himl->uBitsPixel = ilc;
881 else
883
884 if (himl->cMaxImage > 0) {
887 } else
888 himl->hbmImage = 0;
889
890 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
891 SIZE sz;
892
894 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
895 if (himl->hbmMask == 0) {
896 ERR("Error creating mask bitmap!\n");
897 goto cleanup;
898 }
900 }
901 else
902 himl->hbmMask = 0;
903
904 if (ilc == ILC_COLOR32)
905 himl->has_alpha = heap_alloc_zero( himl->cMaxImage );
906 else
908
909 /* create blending brushes */
910 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
912 DeleteObject (hbmTemp);
913
914 hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend50);
916 DeleteObject (hbmTemp);
917
918 TRACE("created imagelist %p\n", himl);
919 return himl;
920
921cleanup:
923 return NULL;
924}
925
926
927/*************************************************************************
928 * ImageList_Destroy [COMCTL32.@]
929 *
930 * Destroys an image list.
931 *
932 * PARAMS
933 * himl [I] handle to image list
934 *
935 * RETURNS
936 * Success: TRUE
937 * Failure: FALSE
938 */
939
942{
943 if (!is_valid(himl))
944 return FALSE;
945
946#ifdef __REACTOS__
947 if ((himl->flags & ILC_SYSTEM) && WinVerMajor() >= 6)
948 return FALSE;
949#endif
950
951 IImageList_Release((IImageList *) himl);
952 return TRUE;
953}
954
955
956/*************************************************************************
957 * ImageList_DragEnter [COMCTL32.@]
958 *
959 * Locks window update and displays the drag image at the given position.
960 *
961 * PARAMS
962 * hwndLock [I] handle of the window that owns the drag image.
963 * x [I] X position of the drag image.
964 * y [I] Y position of the drag image.
965 *
966 * RETURNS
967 * Success: TRUE
968 * Failure: FALSE
969 *
970 * NOTES
971 * The position of the drag image is relative to the window, not
972 * the client area.
973 */
974
977{
978 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
979
981 return FALSE;
982
983 if (hwndLock)
984 InternalDrag.hwnd = hwndLock;
985 else
987
988 InternalDrag.x = x;
989 InternalDrag.y = y;
990
991 /* draw the drag image and save the background */
993}
994
995
996/*************************************************************************
997 * ImageList_DragLeave [COMCTL32.@]
998 *
999 * Unlocks window update and hides the drag image.
1000 *
1001 * PARAMS
1002 * hwndLock [I] handle of the window that owns the drag image.
1003 *
1004 * RETURNS
1005 * Success: TRUE
1006 * Failure: FALSE
1007 */
1008
1011{
1012 /* As we don't save drag info in the window this can lead to problems if
1013 an app does not supply the same window as DragEnter */
1014 /* if (hwndLock)
1015 InternalDrag.hwnd = hwndLock;
1016 else
1017 InternalDrag.hwnd = GetDesktopWindow (); */
1018 if(!hwndLock)
1019 hwndLock = GetDesktopWindow();
1020 if(InternalDrag.hwnd != hwndLock)
1021 FIXME("DragLeave hWnd != DragEnter hWnd\n");
1022
1024
1025 return TRUE;
1026}
1027
1028
1029/*************************************************************************
1030 * ImageList_InternalDragDraw [Internal]
1031 *
1032 * Draws the drag image.
1033 *
1034 * PARAMS
1035 * hdc [I] device context to draw into.
1036 * x [I] X position of the drag image.
1037 * y [I] Y position of the drag image.
1038 *
1039 * RETURNS
1040 * Success: TRUE
1041 * Failure: FALSE
1042 *
1043 * NOTES
1044 * The position of the drag image is relative to the window, not
1045 * the client area.
1046 *
1047 */
1048
1049static inline void
1051{
1052 IMAGELISTDRAWPARAMS imldp;
1053
1054 ZeroMemory (&imldp, sizeof(imldp));
1055 imldp.cbSize = sizeof(imldp);
1056 imldp.himl = InternalDrag.himl;
1057 imldp.i = 0;
1058 imldp.hdcDst = hdc;
1059 imldp.x = x;
1060 imldp.y = y;
1061 imldp.rgbBk = CLR_DEFAULT;
1062 imldp.rgbFg = CLR_DEFAULT;
1063 imldp.fStyle = ILD_NORMAL;
1064 imldp.fState = ILS_ALPHA;
1065 imldp.Frame = 192;
1066 ImageList_DrawIndirect (&imldp);
1067}
1068
1069/*************************************************************************
1070 * ImageList_DragMove [COMCTL32.@]
1071 *
1072 * Moves the drag image.
1073 *
1074 * PARAMS
1075 * x [I] X position of the drag image.
1076 * y [I] Y position of the drag image.
1077 *
1078 * RETURNS
1079 * Success: TRUE
1080 * Failure: FALSE
1081 *
1082 * NOTES
1083 * The position of the drag image is relative to the window, not
1084 * the client area.
1085 */
1086
1089{
1090 TRACE("(x=%d y=%d)\n", x, y);
1091
1093 return FALSE;
1094
1095 /* draw/update the drag image */
1096 if (InternalDrag.bShow) {
1097 HDC hdcDrag;
1098 HDC hdcOffScreen;
1099 HDC hdcBg;
1100 HBITMAP hbmOffScreen;
1101 INT origNewX, origNewY;
1102 INT origOldX, origOldY;
1103 INT origRegX, origRegY;
1104 INT sizeRegX, sizeRegY;
1105
1106
1107 /* calculate the update region */
1108 origNewX = x - InternalDrag.dxHotspot;
1109 origNewY = y - InternalDrag.dyHotspot;
1110 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1111 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1112 origRegX = min(origNewX, origOldX);
1113 origRegY = min(origNewY, origOldY);
1114 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1115 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1116
1117 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1119 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1120 hdcBg = CreateCompatibleDC(hdcDrag);
1121
1122 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1123 SelectObject(hdcOffScreen, hbmOffScreen);
1125
1126 /* get the actual background of the update region */
1127 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1128 origRegX, origRegY, SRCCOPY);
1129 /* erase the old image */
1130 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1131 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1132 SRCCOPY);
1133 /* save the background */
1134 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1135 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1136 /* draw the image */
1137 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
1138 origNewY - origRegY);
1139 /* draw the update region to the screen */
1140 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1141 hdcOffScreen, 0, 0, SRCCOPY);
1142
1143 DeleteDC(hdcBg);
1144 DeleteDC(hdcOffScreen);
1145 DeleteObject(hbmOffScreen);
1146 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1147 }
1148
1149 /* update the image position */
1150 InternalDrag.x = x;
1151 InternalDrag.y = y;
1152
1153 return TRUE;
1154}
1155
1156
1157/*************************************************************************
1158 * ImageList_DragShowNolock [COMCTL32.@]
1159 *
1160 * Shows or hides the drag image.
1161 *
1162 * PARAMS
1163 * bShow [I] TRUE shows the drag image, FALSE hides it.
1164 *
1165 * RETURNS
1166 * Success: TRUE
1167 * Failure: FALSE
1168 */
1169
1172{
1173 HDC hdcDrag;
1174 HDC hdcBg;
1175 INT x, y;
1176
1178 return FALSE;
1179
1180 TRACE("bShow=0x%X!\n", bShow);
1181
1182 /* DragImage is already visible/hidden */
1183 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1184 return FALSE;
1185 }
1186
1187 /* position of the origin of the DragImage */
1190
1191 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1193 if (!hdcDrag) {
1194 return FALSE;
1195 }
1196
1197 hdcBg = CreateCompatibleDC(hdcDrag);
1198 if (!InternalDrag.hbmBg) {
1201 }
1203
1204 if (bShow) {
1205 /* save the background */
1206 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1207 hdcDrag, x, y, SRCCOPY);
1208 /* show the image */
1209 ImageList_InternalDragDraw(hdcDrag, x, y);
1210 } else {
1211 /* hide the image */
1213 hdcBg, 0, 0, SRCCOPY);
1214 }
1215
1217
1218 DeleteDC(hdcBg);
1219 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1220 return TRUE;
1221}
1222
1223
1224/*************************************************************************
1225 * ImageList_Draw [COMCTL32.@]
1226 *
1227 * Draws an image.
1228 *
1229 * PARAMS
1230 * himl [I] handle to image list
1231 * i [I] image index
1232 * hdc [I] handle to device context
1233 * x [I] x position
1234 * y [I] y position
1235 * fStyle [I] drawing flags
1236 *
1237 * RETURNS
1238 * Success: TRUE
1239 * Failure: FALSE
1240 *
1241 * SEE
1242 * ImageList_DrawEx.
1243 */
1244
1247{
1248 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1249 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1250}
1251
1252
1253/*************************************************************************
1254 * ImageList_DrawEx [COMCTL32.@]
1255 *
1256 * Draws an image and allows using extended drawing features.
1257 *
1258 * PARAMS
1259 * himl [I] handle to image list
1260 * i [I] image index
1261 * hdc [I] handle to device context
1262 * x [I] X position
1263 * y [I] Y position
1264 * dx [I] X offset
1265 * dy [I] Y offset
1266 * rgbBk [I] background color
1267 * rgbFg [I] foreground color
1268 * fStyle [I] drawing flags
1269 *
1270 * RETURNS
1271 * Success: TRUE
1272 * Failure: FALSE
1273 *
1274 * NOTES
1275 * Calls ImageList_DrawIndirect.
1276 *
1277 * SEE
1278 * ImageList_DrawIndirect.
1279 */
1280
1283 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1284 UINT fStyle)
1285{
1286 IMAGELISTDRAWPARAMS imldp;
1287
1288 ZeroMemory (&imldp, sizeof(imldp));
1289 imldp.cbSize = sizeof(imldp);
1290 imldp.himl = himl;
1291 imldp.i = i;
1292 imldp.hdcDst = hdc;
1293 imldp.x = x;
1294 imldp.y = y;
1295 imldp.cx = dx;
1296 imldp.cy = dy;
1297 imldp.rgbBk = rgbBk;
1298 imldp.rgbFg = rgbFg;
1299 imldp.fStyle = fStyle;
1300
1301 return ImageList_DrawIndirect (&imldp);
1302}
1303
1304#ifdef __REACTOS__
1305static BOOL alpha_blend_image( HIMAGELIST himl, HDC srce_dc, HDC srce_dcMask, HDC dest_dc, int dest_x, int dest_y,
1306#else
1307static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1308#endif
1309 int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
1310 UINT style, COLORREF blend_col )
1311{
1312 BOOL ret = FALSE;
1313 HDC hdc;
1314 HBITMAP bmp = 0, mask = 0;
1316 void *bits, *mask_bits;
1317 unsigned int *ptr;
1318 int i, j;
1319
1320 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1321 if (!(info = heap_alloc( FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1322 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1323 info->bmiHeader.biWidth = cx;
1324 info->bmiHeader.biHeight = cy;
1325 info->bmiHeader.biPlanes = 1;
1326 info->bmiHeader.biBitCount = 32;
1327 info->bmiHeader.biCompression = BI_RGB;
1328 info->bmiHeader.biSizeImage = cx * cy * 4;
1329 info->bmiHeader.biXPelsPerMeter = 0;
1330 info->bmiHeader.biYPelsPerMeter = 0;
1331 info->bmiHeader.biClrUsed = 0;
1332 info->bmiHeader.biClrImportant = 0;
1333#ifdef __REACTOS__
1334 if (!(bmp = CreateDIBSection( srce_dc, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1335#else
1336 if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1337#endif
1338 SelectObject( hdc, bmp );
1339#ifdef __REACTOS__
1340 if (!BitBlt(hdc, 0, 0, cx, cy, srce_dc, src_x, src_y, SRCCOPY))
1341 {
1342 TRACE("BitBlt failed\n");
1343 goto done;
1344 }
1345#else
1346 BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
1347#endif
1348
1349 if (blend_col != CLR_NONE)
1350 {
1351 BYTE r = GetRValue( blend_col );
1352 BYTE g = GetGValue( blend_col );
1353 BYTE b = GetBValue( blend_col );
1354
1355 if (style & ILD_BLEND25)
1356 {
1357 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1358 *ptr = ((*ptr & 0xff000000) |
1359 ((((*ptr & 0x00ff0000) * 3 + (r << 16)) / 4) & 0x00ff0000) |
1360 ((((*ptr & 0x0000ff00) * 3 + (g << 8)) / 4) & 0x0000ff00) |
1361 ((((*ptr & 0x000000ff) * 3 + (b << 0)) / 4) & 0x000000ff));
1362 }
1363 else if (style & ILD_BLEND50)
1364 {
1365 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1366 *ptr = ((*ptr & 0xff000000) |
1367 ((((*ptr & 0x00ff0000) + (r << 16)) / 2) & 0x00ff0000) |
1368 ((((*ptr & 0x0000ff00) + (g << 8)) / 2) & 0x0000ff00) |
1369 ((((*ptr & 0x000000ff) + (b << 0)) / 2) & 0x000000ff));
1370 }
1371 }
1372
1373 if (himl->has_alpha) /* we already have an alpha channel in this case */
1374 {
1375 /* pre-multiply by the alpha channel */
1376 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1377 {
1378 DWORD alpha = *ptr >> 24;
1379 *ptr = ((*ptr & 0xff000000) |
1380 (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
1381 (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
1382 (((*ptr & 0x000000ff) * alpha / 255)));
1383 }
1384 }
1385 else if (himl->hbmMask)
1386 {
1387 unsigned int width_bytes = (cx + 31) / 32 * 4;
1388 /* generate alpha channel from the mask */
1389 info->bmiHeader.biBitCount = 1;
1390 info->bmiHeader.biSizeImage = width_bytes * cy;
1391 info->bmiColors[0].rgbRed = 0;
1392 info->bmiColors[0].rgbGreen = 0;
1393 info->bmiColors[0].rgbBlue = 0;
1394 info->bmiColors[0].rgbReserved = 0;
1395 info->bmiColors[1].rgbRed = 0xff;
1396 info->bmiColors[1].rgbGreen = 0xff;
1397 info->bmiColors[1].rgbBlue = 0xff;
1398 info->bmiColors[1].rgbReserved = 0;
1399 if (!(mask = CreateDIBSection( srce_dcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0)))
1400 {
1401 TRACE("CreateDIBSection failed %i\n", GetLastError());
1402 goto done;
1403 }
1404 if (SelectObject(hdc, mask) == NULL)
1405 {
1406 TRACE("SelectObject failed %i\n", GetLastError());
1408 goto done;
1409 }
1410 if (!BitBlt( hdc, 0, 0, cx, cy, srce_dcMask, src_x, src_y, SRCCOPY))
1411 {
1412 TRACE("BitBlt failed %i\n", GetLastError());
1414 goto done;
1415 }
1416 if (SelectObject( hdc, bmp) == NULL)
1417 {
1418 TRACE("SelectObject failed %i\n", GetLastError());
1419 goto done;
1420 }
1421 for (i = 0, ptr = bits; i < cy; i++)
1422 for (j = 0; j < cx; j++, ptr++)
1423 if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
1424 else *ptr |= 0xff000000;
1425 }
1426
1427 ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
1428
1429done:
1430 DeleteDC( hdc );
1431 if (bmp) DeleteObject( bmp );
1432 if (mask) DeleteObject( mask );
1433 heap_free( info );
1434 return ret;
1435}
1436
1437#ifdef __REACTOS__
1438BOOL saturate_image(HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
1439 int src_x, int src_y, int cx, int cy, COLORREF rgbFg,
1440 HDC *hdcImageListDC, HDC *hdcMaskListDC)
1441{
1442 HDC hdc = NULL, hdcMask = NULL;
1443 HBITMAP bmp = 0, bmpMask = 0;
1445
1446 unsigned int *ptr;
1447 void *bits;
1448 int i;
1449
1450 /* create a dc and its device independent bitmap for doing the work,
1451 shamelessly copied from the alpha-blending function above */
1452 if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
1453 if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
1454 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1455 info->bmiHeader.biWidth = cx;
1456 info->bmiHeader.biHeight = cy;
1457 info->bmiHeader.biPlanes = 1;
1458 info->bmiHeader.biBitCount = 32;
1459 info->bmiHeader.biCompression = BI_RGB;
1460 info->bmiHeader.biSizeImage = cx * cy * 4;
1461 info->bmiHeader.biXPelsPerMeter = 0;
1462 info->bmiHeader.biYPelsPerMeter = 0;
1463 info->bmiHeader.biClrUsed = 0;
1464 info->bmiHeader.biClrImportant = 0;
1465 if (!(bmp = CreateDIBSection(himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
1466
1467 /* bind both surfaces */
1468 if (SelectObject(hdc, bmp) == NULL)
1469 {
1470 TRACE("SelectObject failed\n");
1471 goto done;
1472 }
1473
1474 /* copy into our dc the section that covers just the icon we we're asked for */
1475 if (!BitBlt(hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY))
1476 {
1477 TRACE("BitBlt failed!\n");
1478 goto done;
1479 }
1480
1481 /* loop every pixel of the bitmap */
1482 for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
1483 {
1484 COLORREF orig_color = *ptr;
1485
1486 /* calculate the effective luminance using the constants from here, adapted to the human eye:
1487 <http://bobpowell.net/grayscale.aspx> */
1488 float mixed_color = (GetRValue(orig_color) * .30 +
1489 GetGValue(orig_color) * .59 +
1490 GetBValue(orig_color) * .11);
1491
1492 *ptr = RGBA(mixed_color, mixed_color, mixed_color, GetAValue(orig_color));
1493 }
1494
1495 if (himl->hdcMask)
1496 {
1497 hdcMask = CreateCompatibleDC(NULL);
1498 bmpMask = CreateCompatibleBitmap(hdcMask, cx, cy);
1499
1500 SelectObject(hdcMask, bmpMask);
1501
1502 if (!BitBlt(hdcMask, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY))
1503 {
1504 ERR("BitBlt failed %i\n", GetLastError());
1505 DeleteDC(hdcMask);
1506 hdcMask = NULL;
1507 goto done;
1508 }
1509 TRACE("mask ok\n");
1510 }
1511
1512done:
1513
1514 if (bmp)
1516 if (bmpMask)
1517 DeleteObject(bmpMask);
1518
1519 if (info)
1521
1522 /* return the handle to our desaturated dc, that will substitute its original counterpart in the next calls */
1523 *hdcMaskListDC = hdcMask;
1524 *hdcImageListDC = hdc;
1525 return (hdc != NULL);
1526}
1527#endif /* __REACTOS__ */
1528
1529/*************************************************************************
1530 * ImageList_DrawIndirect [COMCTL32.@]
1531 *
1532 * Draws an image using various parameters specified in pimldp.
1533 *
1534 * PARAMS
1535 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1536 *
1537 * RETURNS
1538 * Success: TRUE
1539 * Failure: FALSE
1540 */
1541
1544{
1545 INT cx, cy, nOvlIdx;
1546 DWORD fState, dwRop;
1547 UINT fStyle;
1548 COLORREF oldImageBk, oldImageFg;
1549 HDC hImageDC, hImageListDC, hMaskListDC;
1550 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1551 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1553 HBRUSH hOldBrush;
1554 POINT pt;
1555 BOOL has_alpha;
1556#ifdef __REACTOS__
1557 HDC hdcSaturated = NULL, hdcSaturatedMask = NULL;
1558#endif
1559
1560 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1561 if (!is_valid(himl)) return FALSE;
1562 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1563
1564 imagelist_point_from_index( himl, pimldp->i, &pt );
1565 pt.x += pimldp->xBitmap;
1566 pt.y += pimldp->yBitmap;
1567
1568 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1569 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1570 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1571 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1572
1573 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1574 if( pimldp->rgbBk == CLR_NONE )
1575 bIsTransparent = TRUE;
1576 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1577 bIsTransparent = TRUE;
1578 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1579 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1580
1581 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1582 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1583
1584 /* we will use these DCs to access the images and masks in the ImageList */
1585 hImageListDC = himl->hdcImage;
1586 hMaskListDC = himl->hdcMask;
1587
1588 /* these will accumulate the image and mask for the image we're drawing */
1589 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1590 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1591 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1592
1593 /* Create a compatible DC. */
1594 if (!hImageListDC || !hImageDC || !hImageBmp ||
1595 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1596 goto cleanup;
1597
1598 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1599
1600 /*
1601 * To obtain a transparent look, background color should be set
1602 * to white and foreground color to black when blitting the
1603 * monochrome mask.
1604 */
1605 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1606 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1607
1608#ifdef __REACTOS__
1609 /*
1610 * If the ILS_SATURATE bit is enabled we should multiply the
1611 * RGB colors of the original image by the contents of rgbFg.
1612 */
1613 if (fState & ILS_SATURATE)
1614 {
1615 if (saturate_image(himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1616 pt.x, pt.y, cx, cy, pimldp->rgbFg,
1617 &hdcSaturated, &hdcSaturatedMask))
1618 {
1619 hImageListDC = hdcSaturated;
1620 hMaskListDC = hdcSaturatedMask;
1621 /* shitty way of getting subroutines to blit at the right place (top left corner),
1622 as our modified imagelist only contains a single image for performance reasons */
1623 pt.x = 0;
1624 pt.y = 0;
1625 }
1626 }
1627#endif
1628
1629 has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
1630 if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
1631 {
1632 COLORREF colour, blend_col = CLR_NONE;
1634
1635 if (bBlend)
1636 {
1637 blend_col = pimldp->rgbFg;
1638 if (blend_col == CLR_DEFAULT) blend_col = GetSysColor( COLOR_HIGHLIGHT );
1639 else if (blend_col == CLR_NONE) blend_col = GetTextColor( pimldp->hdcDst );
1640 }
1641
1642 func.BlendOp = AC_SRC_OVER;
1643 func.BlendFlags = 0;
1644 func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
1645 func.AlphaFormat = AC_SRC_ALPHA;
1646
1647 if (bIsTransparent)
1648 {
1649#ifdef __REACTOS__
1650 bResult = alpha_blend_image( himl, hImageListDC, hMaskListDC, pimldp->hdcDst, pimldp->x, pimldp->y,
1651#else
1652 bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
1653#endif
1654 pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1655 goto end;
1656 }
1657 colour = pimldp->rgbBk;
1658 if (colour == CLR_DEFAULT) colour = himl->clrBk;
1659 if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
1660
1661 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1662 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1663#ifdef __REACTOS__
1664 alpha_blend_image( himl, hImageListDC, hMaskListDC, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1665#else
1666 alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
1667#endif
1668 DeleteObject (SelectObject (hImageDC, hOldBrush));
1669 bResult = BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
1670 goto end;
1671 }
1672
1673 /*
1674 * Draw the initial image
1675 */
1676 if( bMask ) {
1677 if (himl->hbmMask) {
1678 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1679 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1680 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1681 DeleteObject (SelectObject (hImageDC, hOldBrush));
1682 if( bIsTransparent )
1683 {
1684 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1685 bResult = TRUE;
1686 goto end;
1687 }
1688 } else {
1689 hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1690 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1691 SelectObject(hImageDC, hOldBrush);
1692 }
1693 } else {
1694 /* blend the image with the needed solid background */
1695 COLORREF colour = RGB(0,0,0);
1696
1697 if( !bIsTransparent )
1698 {
1699 colour = pimldp->rgbBk;
1700 if( colour == CLR_DEFAULT )
1701 colour = himl->clrBk;
1702 if( colour == CLR_NONE )
1703 colour = GetBkColor(pimldp->hdcDst);
1704 }
1705
1706 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1707 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1708 if (himl->hbmMask)
1709 {
1710 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1711 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1712 }
1713 else
1714 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCCOPY);
1715 DeleteObject (SelectObject (hImageDC, hOldBrush));
1716 }
1717
1718 /* Time for blending, if required */
1719 if (bBlend) {
1720 HBRUSH hBlendBrush;
1721 COLORREF clrBlend = pimldp->rgbFg;
1722 HDC hBlendMaskDC = hImageListDC;
1723 HBITMAP hOldBitmap;
1724
1725 /* Create the blend Mask */
1726 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1727 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1728 hOldBrush = SelectObject(hBlendMaskDC, hBlendBrush);
1729 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1730 SelectObject(hBlendMaskDC, hOldBrush);
1731
1732 /* Modify the blend mask if an Image Mask exist */
1733 if(himl->hbmMask) {
1734 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1735 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1736 }
1737
1738 /* now apply blend to the current image given the BlendMask */
1739 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1740 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1741 hOldBrush = SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1742 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1743 DeleteObject(SelectObject(hImageDC, hOldBrush));
1744 SelectObject(hBlendMaskDC, hOldBitmap);
1745 }
1746
1747 /* Now do the overlay image, if any */
1748 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1749 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1750 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1751 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1752 POINT ptOvl;
1753 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1754 ptOvl.x += pimldp->xBitmap;
1755 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1756 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1757 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1758 }
1759 }
1760
1761#ifndef __REACTOS__
1762 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1763#endif
1764 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1765 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1766
1767 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1768 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1769 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1770
1771 /* now copy the image to the screen */
1772 dwRop = SRCCOPY;
1773 if (himl->hbmMask && bIsTransparent ) {
1774 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1775 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1776 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1777 SetBkColor(pimldp->hdcDst, oldDstBk);
1778 SetTextColor(pimldp->hdcDst, oldDstFg);
1779 dwRop = SRCPAINT;
1780 }
1781 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1782 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1783
1784 bResult = TRUE;
1785end:
1786 /* cleanup the mess */
1787 SetBkColor(hImageDC, oldImageBk);
1788 SetTextColor(hImageDC, oldImageFg);
1789 SelectObject(hImageDC, hOldImageBmp);
1790cleanup:
1791#ifdef __REACTOS__
1792 if (hdcSaturated)
1793 DeleteDC(hdcSaturated);
1794 if (hdcSaturatedMask)
1795 DeleteDC(hdcSaturatedMask);
1796#endif
1797 DeleteObject(hBlendMaskBmp);
1798 DeleteObject(hImageBmp);
1799 DeleteDC(hImageDC);
1800
1801 return bResult;
1802}
1803
1804
1805/*************************************************************************
1806 * ImageList_Duplicate [COMCTL32.@]
1807 *
1808 * Duplicates an image list.
1809 *
1810 * PARAMS
1811 * himlSrc [I] source image list handle
1812 *
1813 * RETURNS
1814 * Success: Handle of duplicated image list.
1815 * Failure: NULL
1816 */
1817
1820{
1821 HIMAGELIST himlDst;
1822
1823 if (!is_valid(himlSrc)) {
1824 ERR("Invalid image list handle!\n");
1825 return NULL;
1826 }
1827
1828 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1829 himlSrc->cCurImage, himlSrc->cGrow);
1830
1831 if (himlDst)
1832 {
1833 SIZE sz;
1834
1835 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
1836 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1837 himlSrc->hdcImage, 0, 0, SRCCOPY);
1838
1839 if (himlDst->hbmMask)
1840 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1841 himlSrc->hdcMask, 0, 0, SRCCOPY);
1842
1843 himlDst->cCurImage = himlSrc->cCurImage;
1844 if (himlSrc->has_alpha && himlDst->has_alpha)
1845 memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
1846 }
1847 return himlDst;
1848}
1849
1850
1851/*************************************************************************
1852 * ImageList_EndDrag [COMCTL32.@]
1853 *
1854 * Finishes a drag operation.
1855 *
1856 * PARAMS
1857 * no Parameters
1858 *
1859 * RETURNS
1860 * Success: TRUE
1861 * Failure: FALSE
1862 */
1863
1866{
1867 /* cleanup the InternalDrag struct */
1868 InternalDrag.hwnd = 0;
1873 InternalDrag.x= 0;
1874 InternalDrag.y= 0;
1879 InternalDrag.hbmBg = 0;
1880}
1881
1882
1883/*************************************************************************
1884 * ImageList_GetBkColor [COMCTL32.@]
1885 *
1886 * Returns the background color of an image list.
1887 *
1888 * PARAMS
1889 * himl [I] Image list handle.
1890 *
1891 * RETURNS
1892 * Success: background color
1893 * Failure: CLR_NONE
1894 */
1895
1898{
1899 return himl ? himl->clrBk : CLR_NONE;
1900}
1901
1902
1903/*************************************************************************
1904 * ImageList_GetDragImage [COMCTL32.@]
1905 *
1906 * Returns the handle to the internal drag image list.
1907 *
1908 * PARAMS
1909 * ppt [O] Pointer to the drag position. Can be NULL.
1910 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1911 *
1912 * RETURNS
1913 * Success: Handle of the drag image list.
1914 * Failure: NULL.
1915 */
1916
1919{
1920 if (is_valid(InternalDrag.himl)) {
1921 if (ppt) {
1922 ppt->x = InternalDrag.x;
1923 ppt->y = InternalDrag.y;
1924 }
1925 if (pptHotspot) {
1928 }
1929 return (InternalDrag.himl);
1930 }
1931
1932 return NULL;
1933}
1934
1935
1936/*************************************************************************
1937 * ImageList_GetFlags [COMCTL32.@]
1938 *
1939 * Gets the flags of the specified image list.
1940 *
1941 * PARAMS
1942 * himl [I] Handle to image list
1943 *
1944 * RETURNS
1945 * Image list flags.
1946 *
1947 * BUGS
1948 * Stub.
1949 */
1950
1953{
1954 TRACE("%p\n", himl);
1955#ifdef __REACTOS__
1956 if(!is_valid2(himl))
1957 return 0;
1958 return himl->flags & ILC_PUBLICFLAGS;
1959#else
1960 return is_valid(himl) ? himl->flags : 0;
1961#endif
1962}
1963
1964
1965/*************************************************************************
1966 * ImageList_GetIcon [COMCTL32.@]
1967 *
1968 * Creates an icon from a masked image of an image list.
1969 *
1970 * PARAMS
1971 * himl [I] handle to image list
1972 * i [I] image index
1973 * flags [I] drawing style flags
1974 *
1975 * RETURNS
1976 * Success: icon handle
1977 * Failure: NULL
1978 */
1979
1982{
1983 ICONINFO ii;
1984 HICON hIcon;
1985 HBITMAP hOldDstBitmap;
1986 HDC hdcDst;
1987 POINT pt;
1988
1989 TRACE("%p %d %d\n", himl, i, fStyle);
1990 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1991
1992 ii.fIcon = TRUE;
1993 ii.xHotspot = 0;
1994 ii.yHotspot = 0;
1995
1996 /* create colour bitmap */
1997 hdcDst = GetDC(0);
1999 ReleaseDC(0, hdcDst);
2000
2002
2004
2005 /* draw mask*/
2006 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
2007 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
2008 if (himl->hbmMask) {
2009 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
2010 himl->hdcMask, pt.x, pt.y, SRCCOPY);
2011 }
2012 else
2013 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
2014
2015 /* draw image*/
2017 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
2018 himl->hdcImage, pt.x, pt.y, SRCCOPY);
2019
2020 /*
2021 * CreateIconIndirect requires us to deselect the bitmaps from
2022 * the DCs before calling
2023 */
2024 SelectObject(hdcDst, hOldDstBitmap);
2025
2026 hIcon = CreateIconIndirect (&ii);
2027
2028 DeleteObject (ii.hbmMask);
2030 DeleteDC (hdcDst);
2031
2032 return hIcon;
2033}
2034
2035
2036/*************************************************************************
2037 * ImageList_GetIconSize [COMCTL32.@]
2038 *
2039 * Retrieves the size of an image in an image list.
2040 *
2041 * PARAMS
2042 * himl [I] handle to image list
2043 * cx [O] pointer to the image width.
2044 * cy [O] pointer to the image height.
2045 *
2046 * RETURNS
2047 * Success: TRUE
2048 * Failure: FALSE
2049 *
2050 * NOTES
2051 * All images in an image list have the same size.
2052 */
2053
2056{
2057 if (!is_valid(himl) || !cx || !cy)
2058 return FALSE;
2059
2060 *cx = himl->cx;
2061 *cy = himl->cy;
2062
2063 return TRUE;
2064}
2065
2066
2067/*************************************************************************
2068 * ImageList_GetImageCount [COMCTL32.@]
2069 *
2070 * Returns the number of images in an image list.
2071 *
2072 * PARAMS
2073 * himl [I] handle to image list
2074 *
2075 * RETURNS
2076 * Success: Number of images.
2077 * Failure: 0
2078 */
2079
2080INT WINAPI
2082{
2083 if (!is_valid(himl))
2084 return 0;
2085
2086 return himl->cCurImage;
2087}
2088
2089
2090/*************************************************************************
2091 * ImageList_GetImageInfo [COMCTL32.@]
2092 *
2093 * Returns information about an image in an image list.
2094 *
2095 * PARAMS
2096 * himl [I] handle to image list
2097 * i [I] image index
2098 * pImageInfo [O] pointer to the image information
2099 *
2100 * RETURNS
2101 * Success: TRUE
2102 * Failure: FALSE
2103 */
2104
2107{
2108 POINT pt;
2109
2110 if (!is_valid(himl) || (pImageInfo == NULL))
2111 return FALSE;
2112 if ((i < 0) || (i >= himl->cCurImage))
2113 return FALSE;
2114
2117
2119 pImageInfo->rcImage.top = pt.y;
2122 pImageInfo->rcImage.right = pt.x + himl->cx;
2123
2124 return TRUE;
2125}
2126
2127
2128/*************************************************************************
2129 * ImageList_GetImageRect [COMCTL32.@]
2130 *
2131 * Retrieves the rectangle of the specified image in an image list.
2132 *
2133 * PARAMS
2134 * himl [I] handle to image list
2135 * i [I] image index
2136 * lpRect [O] pointer to the image rectangle
2137 *
2138 * RETURNS
2139 * Success: TRUE
2140 * Failure: FALSE
2141 *
2142 * NOTES
2143 * This is an UNDOCUMENTED function!!!
2144 */
2145
2148{
2149#ifdef __REACTOS__
2150 IMAGEINFO ImageInfo;
2151 if (!ImageList_GetImageInfo(himl, i, &ImageInfo))
2152 return FALSE;
2153 *lpRect = ImageInfo.rcImage;
2154#else
2155 POINT pt;
2156
2157 if (!is_valid(himl) || (lpRect == NULL))
2158 return FALSE;
2159 if ((i < 0) || (i >= himl->cCurImage))
2160 return FALSE;
2161
2163 lpRect->left = pt.x;
2164 lpRect->top = pt.y;
2165 lpRect->right = pt.x + himl->cx;
2166 lpRect->bottom = pt.y + himl->cy;
2167#endif
2168 return TRUE;
2169}
2170
2171
2172/*************************************************************************
2173 * ImageList_LoadImage [COMCTL32.@]
2174 * ImageList_LoadImageA [COMCTL32.@]
2175 *
2176 * Creates an image list from a bitmap, icon or cursor.
2177 *
2178 * See ImageList_LoadImageW.
2179 */
2180
2183 COLORREF clrMask, UINT uType, UINT uFlags)
2184{
2186 LPWSTR lpbmpW;
2187 DWORD len;
2188
2189 if (IS_INTRESOURCE(lpbmp))
2190 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
2191 uType, uFlags);
2192
2193 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
2194 lpbmpW = heap_alloc(len * sizeof(WCHAR));
2195 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
2196
2197 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
2198 heap_free (lpbmpW);
2199 return himl;
2200}
2201
2202
2203/*************************************************************************
2204 * ImageList_LoadImageW [COMCTL32.@]
2205 *
2206 * Creates an image list from a bitmap, icon or cursor.
2207 *
2208 * PARAMS
2209 * hi [I] instance handle
2210 * lpbmp [I] name or id of the image
2211 * cx [I] width of each image
2212 * cGrow [I] number of images to expand
2213 * clrMask [I] mask color
2214 * uType [I] type of image to load
2215 * uFlags [I] loading flags
2216 *
2217 * RETURNS
2218 * Success: handle to the loaded image list
2219 * Failure: NULL
2220 *
2221 * SEE
2222 * LoadImage ()
2223 */
2224
2227 COLORREF clrMask, UINT uType, UINT uFlags)
2228{
2230 HANDLE handle;
2231 INT nImageCount;
2232
2233 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
2234 if (!handle) {
2235 WARN("Couldn't load image\n");
2236 return NULL;
2237 }
2238
2239 if (uType == IMAGE_BITMAP) {
2241 UINT color;
2242
2243 if (GetObjectW (handle, sizeof(dib), &dib) == sizeof(BITMAP)) color = ILC_COLOR;
2244 else color = dib.dsBm.bmBitsPixel;
2245
2246 /* To match windows behavior, if cx is set to zero and
2247 the flag DI_DEFAULTSIZE is specified, cx becomes the
2248 system metric value for icons. If the flag is not specified
2249 the function sets the size to the height of the bitmap */
2250 if (cx == 0)
2251 {
2252 if (uFlags & DI_DEFAULTSIZE)
2254 else
2255 cx = dib.dsBm.bmHeight;
2256 }
2257
2258 nImageCount = dib.dsBm.bmWidth / cx;
2259
2260 if (clrMask != CLR_NONE) color |= ILC_MASK;
2261 himl = ImageList_Create (cx, dib.dsBm.bmHeight, color, nImageCount, cGrow);
2262 if (!himl) {
2264 return NULL;
2265 }
2266 ImageList_AddMasked (himl, handle, clrMask);
2267 }
2268 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
2269 ICONINFO ii;
2270 BITMAP bmp;
2271
2272 GetIconInfo (handle, &ii);
2273 GetObjectW (ii.hbmColor, sizeof(BITMAP), &bmp);
2274 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
2275 ILC_MASK | ILC_COLOR, 1, cGrow);
2276 if (!himl) {
2278 DeleteObject (ii.hbmMask);
2280 return NULL;
2281 }
2284 DeleteObject (ii.hbmMask);
2285 }
2286
2288
2289 return himl;
2290}
2291
2292
2293/*************************************************************************
2294 * ImageList_Merge [COMCTL32.@]
2295 *
2296 * Create an image list containing a merged image from two image lists.
2297 *
2298 * PARAMS
2299 * himl1 [I] handle to first image list
2300 * i1 [I] first image index
2301 * himl2 [I] handle to second image list
2302 * i2 [I] second image index
2303 * dx [I] X offset of the second image relative to the first.
2304 * dy [I] Y offset of the second image relative to the first.
2305 *
2306 * RETURNS
2307 * Success: The newly created image list. It contains a single image
2308 * consisting of the second image merged with the first.
2309 * Failure: NULL, if either himl1 or himl2 is invalid.
2310 *
2311 * NOTES
2312 * - The returned image list should be deleted by the caller using
2313 * ImageList_Destroy() when it is no longer required.
2314 * - If either i1 or i2 is not a valid image index, they will be treated
2315 * as blank images.
2316 */
2319 INT dx, INT dy)
2320{
2321 HIMAGELIST himlDst = NULL;
2322 INT cxDst, cyDst;
2323 INT xOff1, yOff1, xOff2, yOff2;
2324 POINT pt1, pt2;
2325 INT newFlags;
2326
2327 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
2328 i2, dx, dy);
2329
2330 if (!is_valid(himl1) || !is_valid(himl2))
2331 return NULL;
2332
2333 if (dx > 0) {
2334 cxDst = max (himl1->cx, dx + himl2->cx);
2335 xOff1 = 0;
2336 xOff2 = dx;
2337 }
2338 else if (dx < 0) {
2339 cxDst = max (himl2->cx, himl1->cx - dx);
2340 xOff1 = -dx;
2341 xOff2 = 0;
2342 }
2343 else {
2344 cxDst = max (himl1->cx, himl2->cx);
2345 xOff1 = 0;
2346 xOff2 = 0;
2347 }
2348
2349 if (dy > 0) {
2350 cyDst = max (himl1->cy, dy + himl2->cy);
2351 yOff1 = 0;
2352 yOff2 = dy;
2353 }
2354 else if (dy < 0) {
2355 cyDst = max (himl2->cy, himl1->cy - dy);
2356 yOff1 = -dy;
2357 yOff2 = 0;
2358 }
2359 else {
2360 cyDst = max (himl1->cy, himl2->cy);
2361 yOff1 = 0;
2362 yOff2 = 0;
2363 }
2364
2365 newFlags = (himl1->flags > himl2->flags ? himl1->flags : himl2->flags) & ILC_COLORDDB;
2366 if (newFlags == ILC_COLORDDB && (himl1->flags & ILC_COLORDDB) == ILC_COLOR16)
2367 newFlags = ILC_COLOR16; /* this is what native (at least v5) does, don't know why */
2368 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | newFlags, 1, 1);
2369
2370 if (himlDst)
2371 {
2372 imagelist_point_from_index( himl1, i1, &pt1 );
2373 imagelist_point_from_index( himl2, i2, &pt2 );
2374
2375 /* copy image */
2376 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
2377 if (i1 >= 0 && i1 < himl1->cCurImage)
2378 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
2379 if (i2 >= 0 && i2 < himl2->cCurImage)
2380 {
2381 if (himl2->flags & ILC_MASK)
2382 {
2383 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
2384 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
2385 }
2386 else
2387 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCCOPY);
2388 }
2389
2390 /* copy mask */
2391 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
2392 if (i1 >= 0 && i1 < himl1->cCurImage)
2393 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
2394 if (i2 >= 0 && i2 < himl2->cCurImage)
2395 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
2396
2397 himlDst->cCurImage = 1;
2398 }
2399
2400 return himlDst;
2401}
2402
2403
2404/* helper for ImageList_Read, see comments below */
2405static void *read_bitmap(IStream *pstm, BITMAPINFO *bmi)
2406{
2407 BITMAPFILEHEADER bmfh;
2408 int bitsperpixel, palspace;
2409 void *bits;
2410
2411 if (FAILED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)))
2412 return NULL;
2413
2414 if (bmfh.bfType != (('M'<<8)|'B'))
2415 return NULL;
2416
2417 if (FAILED(IStream_Read ( pstm, &bmi->bmiHeader, sizeof(bmi->bmiHeader), NULL)))
2418 return NULL;
2419
2420 if ((bmi->bmiHeader.biSize != sizeof(bmi->bmiHeader)))
2421 return NULL;
2422
2423 TRACE("width %u, height %u, planes %u, bpp %u\n",
2426
2427 bitsperpixel = bmi->bmiHeader.biPlanes * bmi->bmiHeader.biBitCount;
2428 if (bitsperpixel<=8)
2429 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2430 else
2431 palspace = 0;
2432
2434
2435 /* read the palette right after the end of the bitmapinfoheader */
2436 if (palspace && FAILED(IStream_Read(pstm, bmi->bmiColors, palspace, NULL)))
2437 return NULL;
2438
2439 bits = heap_alloc_zero(bmi->bmiHeader.biSizeImage);
2440 if (!bits) return NULL;
2441
2442 if (FAILED(IStream_Read(pstm, bits, bmi->bmiHeader.biSizeImage, NULL)))
2443 {
2444 heap_free(bits);
2445 return NULL;
2446 }
2447 return bits;
2448}
2449
2450/*************************************************************************
2451 * ImageList_Read [COMCTL32.@]
2452 *
2453 * Reads an image list from a stream.
2454 *
2455 * PARAMS
2456 * pstm [I] pointer to a stream
2457 *
2458 * RETURNS
2459 * Success: handle to image list
2460 * Failure: NULL
2461 *
2462 * The format is like this:
2463 * ILHEAD ilheadstruct;
2464 *
2465 * for the color image part:
2466 * BITMAPFILEHEADER bmfh;
2467 * BITMAPINFOHEADER bmih;
2468 * only if it has a palette:
2469 * RGBQUAD rgbs[nr_of_paletted_colors];
2470 *
2471 * BYTE colorbits[imagesize];
2472 *
2473 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2474 * BITMAPFILEHEADER bmfh_mask;
2475 * BITMAPINFOHEADER bmih_mask;
2476 * only if it has a palette (it usually does not):
2477 * RGBQUAD rgbs[nr_of_paletted_colors];
2478 *
2479 * BYTE maskbits[imagesize];
2480 */
2482{
2483 char image_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2484 char mask_buf[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256];
2485 BITMAPINFO *image_info = (BITMAPINFO *)image_buf;
2486 BITMAPINFO *mask_info = (BITMAPINFO *)mask_buf;
2487 void *image_bits, *mask_bits = NULL;
2488 ILHEAD ilHead;
2490 unsigned int i;
2491
2492 TRACE("%p\n", pstm);
2493
2494 if (FAILED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2495 return NULL;
2496 if (ilHead.usMagic != (('L' << 8) | 'I'))
2497 return NULL;
2498#ifdef __REACTOS__
2499 if (ilHead.usVersion != IMAGELIST_VERSION &&
2500 ilHead.usVersion != 0x600 && /* XP/2003 version */
2501 ilHead.usVersion != 0x620) /* Vista/7 version */
2502#else
2503 if (ilHead.usVersion != 0x101) /* probably version? */
2504#endif
2505 return NULL;
2506
2507 TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
2508 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
2509
2510 himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cMaxImage, ilHead.cGrow);
2511 if (!himl)
2512 return NULL;
2513
2514#ifdef __REACTOS__
2515 /* keep version from stream */
2516 himl->usVersion = ilHead.usVersion;
2517#endif
2518
2519 if (!(image_bits = read_bitmap(pstm, image_info)))
2520 {
2521 WARN("failed to read bitmap from stream\n");
2522 return NULL;
2523 }
2524 if (ilHead.flags & ILC_MASK)
2525 {
2526 if (!(mask_bits = read_bitmap(pstm, mask_info)))
2527 {
2528 WARN("failed to read mask bitmap from stream\n");
2529 return NULL;
2530 }
2531 }
2532 else mask_info = NULL;
2533
2534 if (himl->has_alpha && image_info->bmiHeader.biBitCount == 32)
2535 {
2536 DWORD *ptr = image_bits;
2537 BYTE *mask_ptr = mask_bits;
2538#ifdef __REACTOS__
2539 int stride = himl->cy * (ilHead.usVersion != IMAGELIST_VERSION ? himl->cx : image_info->bmiHeader.biWidth);
2540 int image_step = ilHead.usVersion != IMAGELIST_VERSION ? 1 : TILE_COUNT;
2541 int mask_step = ilHead.usVersion != IMAGELIST_VERSION ? 4 : 8;
2542#else
2543 int stride = himl->cy * image_info->bmiHeader.biWidth;
2544#endif
2545 if (image_info->bmiHeader.biHeight > 0) /* bottom-up */
2546 {
2547 ptr += image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride;
2548#ifdef __REACTOS__
2549 mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / mask_step;
2550#else
2551 mask_ptr += (image_info->bmiHeader.biHeight * image_info->bmiHeader.biWidth - stride) / 8;
2552#endif
2553 stride = -stride;
2554 image_info->bmiHeader.biHeight = himl->cy;
2555 }
2556 else image_info->bmiHeader.biHeight = -himl->cy;
2557#ifdef __REACTOS__
2558 for (i = 0; i < ilHead.cCurImage; i += image_step)
2559 {
2560 add_dib_bits(himl, i, min(ilHead.cCurImage - i, image_step),
2561 himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr);
2562 ptr += stride;
2563 mask_ptr += stride / mask_step;
2564 }
2565#else
2566 for (i = 0; i < ilHead.cCurImage; i += TILE_COUNT)
2567 {
2568 add_dib_bits( himl, i, min( ilHead.cCurImage - i, TILE_COUNT ),
2569 himl->cx, himl->cy, image_info, mask_info, ptr, mask_ptr );
2570 ptr += stride;
2571 mask_ptr += stride / 8;
2572 }
2573#endif
2574 }
2575 else
2576 {
2577 StretchDIBits( himl->hdcImage, 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2578 0, 0, image_info->bmiHeader.biWidth, image_info->bmiHeader.biHeight,
2579 image_bits, image_info, DIB_RGB_COLORS, SRCCOPY);
2580 if (mask_info)
2581 StretchDIBits( himl->hdcMask, 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2582 0, 0, mask_info->bmiHeader.biWidth, mask_info->bmiHeader.biHeight,
2583 mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY);
2584 }
2585 heap_free( image_bits );
2586 heap_free( mask_bits );
2587
2588 himl->cCurImage = ilHead.cCurImage;
2589 himl->cMaxImage = ilHead.cMaxImage;
2590
2592 for (i=0;i<4;i++)
2594 return himl;
2595}
2596
2597
2598/*************************************************************************
2599 * ImageList_Remove [COMCTL32.@]
2600 *
2601 * Removes an image from an image list
2602 *
2603 * PARAMS
2604 * himl [I] image list handle
2605 * i [I] image index
2606 *
2607 * RETURNS
2608 * Success: TRUE
2609 * Failure: FALSE
2610 *
2611 * FIXME: as the image list storage test shows, native comctl32 simply shifts
2612 * images without creating a new bitmap.
2613 */
2616{
2617 HBITMAP hbmNewImage, hbmNewMask;
2618 HDC hdcBmp;
2619 SIZE sz;
2620
2621 TRACE("(himl=%p i=%d)\n", himl, i);
2622
2623 if (!is_valid(himl)) {
2624 ERR("Invalid image list handle!\n");
2625 return FALSE;
2626 }
2627
2628 if ((i < -1) || (i >= himl->cCurImage)) {
2629 TRACE("index out of range! %d\n", i);
2630 return FALSE;
2631 }
2632
2633 if (i == -1) {
2634 INT nCount;
2635
2636 /* remove all */
2637 if (himl->cCurImage == 0) {
2638 /* remove all on empty ImageList is allowed */
2639 TRACE("remove all on empty ImageList!\n");
2640 return TRUE;
2641 }
2642
2644 himl->cCurImage = 0;
2645 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2646 himl->nOvlIdx[nCount] = -1;
2647
2648 if (himl->has_alpha)
2649 {
2651 himl->has_alpha = heap_alloc_zero( himl->cMaxImage );
2652 }
2653
2655 SelectObject (himl->hdcImage, hbmNewImage);
2657 himl->hbmImage = hbmNewImage;
2658
2659 if (himl->hbmMask) {
2660
2662 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2663 SelectObject (himl->hdcMask, hbmNewMask);
2665 himl->hbmMask = hbmNewMask;
2666 }
2667 }
2668 else {
2669 /* delete one image */
2670 TRACE("Remove single image! %d\n", i);
2671
2672 /* create new bitmap(s) */
2673 TRACE(" - Number of images: %d / %d (Old/New)\n",
2674 himl->cCurImage, himl->cCurImage - 1);
2675
2677
2679 if (himl->hbmMask)
2680 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2681 else
2682 hbmNewMask = 0; /* Just to keep compiler happy! */
2683
2684 hdcBmp = CreateCompatibleDC (0);
2685
2686 /* copy all images and masks prior to the "removed" image */
2687 if (i > 0) {
2688 TRACE("Pre image copy: Copy %d images\n", i);
2689
2690 SelectObject (hdcBmp, hbmNewImage);
2691 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2692
2693 if (himl->hbmMask) {
2694 SelectObject (hdcBmp, hbmNewMask);
2695 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2696 }
2697 }
2698
2699 /* copy all images and masks behind the removed image */
2700 if (i < himl->cCurImage - 1) {
2701 TRACE("Post image copy!\n");
2702
2703 SelectObject (hdcBmp, hbmNewImage);
2704 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i + 1,
2705 (himl->cCurImage - i), i );
2706
2707 if (himl->hbmMask) {
2708 SelectObject (hdcBmp, hbmNewMask);
2709 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i + 1,
2710 (himl->cCurImage - i), i );
2711 }
2712 }
2713
2714 DeleteDC (hdcBmp);
2715
2716 /* delete old images and insert new ones */
2717 SelectObject (himl->hdcImage, hbmNewImage);
2719 himl->hbmImage = hbmNewImage;
2720 if (himl->hbmMask) {
2721 SelectObject (himl->hdcMask, hbmNewMask);
2723 himl->hbmMask = hbmNewMask;
2724 }
2725
2726 himl->cCurImage--;
2727 }
2728
2729 return TRUE;
2730}
2731
2732
2733/*************************************************************************
2734 * ImageList_Replace [COMCTL32.@]
2735 *
2736 * Replaces an image in an image list with a new image.
2737 *
2738 * PARAMS
2739 * himl [I] handle to image list
2740 * i [I] image index
2741 * hbmImage [I] handle to image bitmap
2742 * hbmMask [I] handle to mask bitmap. Can be NULL.
2743 *
2744 * RETURNS
2745 * Success: TRUE
2746 * Failure: FALSE
2747 */
2748
2751 HBITMAP hbmMask)
2752{
2753 HDC hdcImage;
2754 BITMAP bmp;
2755 POINT pt;
2756
2757 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2758
2759 if (!is_valid(himl)) {
2760 ERR("Invalid image list handle!\n");
2761 return FALSE;
2762 }
2763
2764 if ((i >= himl->cMaxImage) || (i < 0)) {
2765 ERR("Invalid image index!\n");
2766 return FALSE;
2767 }
2768
2769 if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
2770 return FALSE;
2771
2772 hdcImage = CreateCompatibleDC (0);
2773
2774 /* Replace Image */
2775 SelectObject (hdcImage, hbmImage);
2776
2777 if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
2778 goto done;
2779
2781 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2782 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2783
2784 if (himl->hbmMask)
2785 {
2786 HDC hdcTemp;
2787 HBITMAP hOldBitmapTemp;
2788
2789 hdcTemp = CreateCompatibleDC(0);
2790 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2791
2792 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2793 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2794 SelectObject(hdcTemp, hOldBitmapTemp);
2795 DeleteDC(hdcTemp);
2796
2797 /* Remove the background from the image
2798 */
2799 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2800 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2801 }
2802
2803done:
2804 DeleteDC (hdcImage);
2805
2806 return TRUE;
2807}
2808
2809
2810/*************************************************************************
2811 * ImageList_ReplaceIcon [COMCTL32.@]
2812 *
2813 * Replaces an image in an image list using an icon.
2814 *
2815 * PARAMS
2816 * himl [I] handle to image list
2817 * i [I] image index
2818 * hIcon [I] handle to icon
2819 *
2820 * RETURNS
2821 * Success: index of the replaced image
2822 * Failure: -1
2823 */
2824
2825INT WINAPI
2827{
2828 HICON hBestFitIcon;
2829 ICONINFO ii;
2830 BITMAP bmp;
2831 BOOL ret;
2832 POINT pt;
2833
2834 TRACE("(%p %d %p)\n", himl, nIndex, hIcon);
2835
2836 if (!is_valid(himl)) {
2837 ERR("invalid image list\n");
2838 return -1;
2839 }
2840 if ((nIndex >= himl->cMaxImage) || (nIndex < -1)) {
2841 ERR("invalid image index %d / %d\n", nIndex, himl->cMaxImage);
2842 return -1;
2843 }
2844
2845 hBestFitIcon = CopyImage(
2847 himl->cx, himl->cy,
2849 /* the above will fail if the icon wasn't loaded from a resource, so try
2850 * again without LR_COPYFROMRESOURCE flag */
2851 if (!hBestFitIcon)
2852 hBestFitIcon = CopyImage(
2854 himl->cx, himl->cy,
2855 0);
2856 if (!hBestFitIcon)
2857 return -1;
2858
2859 if (nIndex == -1) {
2860 if (himl->cCurImage + 1 >= himl->cMaxImage)
2862
2863 nIndex = himl->cCurImage;
2864 himl->cCurImage++;
2865 }
2866
2867 if (himl->has_alpha && GetIconInfo (hBestFitIcon, &ii))
2868 {
2869 HDC hdcImage = CreateCompatibleDC( 0 );
2870 GetObjectW (ii.hbmMask, sizeof(BITMAP), &bmp);
2871
2872 if (!ii.hbmColor)
2873 {
2874 UINT height = bmp.bmHeight / 2;
2875 HDC hdcMask = CreateCompatibleDC( 0 );
2876 HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
2877 SelectObject( hdcImage, color );
2878 SelectObject( hdcMask, ii.hbmMask );
2879 BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
2880 ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
2881 DeleteDC( hdcMask );
2883 }
2884 else ret = add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight,
2885 ii.hbmColor, ii.hbmMask );
2886
2887 DeleteDC( hdcImage );
2888 DeleteObject (ii.hbmMask);
2889 if (ii.hbmColor) DeleteObject (ii.hbmColor);
2890 if (ret) goto done;
2891 }
2892
2894
2895 if (himl->hbmMask)
2896 {
2897 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_IMAGE );
2898 PatBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy, WHITENESS );
2899 DrawIconEx( himl->hdcMask, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_MASK );
2900 }
2901 else
2902 {
2904 HBRUSH brush = CreateSolidBrush( GetNearestColor( himl->hdcImage, color ));
2905
2906 SelectObject( himl->hdcImage, brush );
2907 PatBlt( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy, PATCOPY );
2909 DeleteObject( brush );
2910 DrawIconEx( himl->hdcImage, pt.x, pt.y, hBestFitIcon, himl->cx, himl->cy, 0, 0, DI_NORMAL );
2911 }
2912
2913done:
2914 DestroyIcon(hBestFitIcon);
2915
2916 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2917 return nIndex;
2918}
2919
2920
2921/*************************************************************************
2922 * ImageList_SetBkColor [COMCTL32.@]
2923 *
2924 * Sets the background color of an image list.
2925 *
2926 * PARAMS
2927 * himl [I] handle to image list
2928 * clrBk [I] background color
2929 *
2930 * RETURNS
2931 * Success: previous background color
2932 * Failure: CLR_NONE
2933 */
2934
2937{
2938 COLORREF clrOldBk;
2939
2940 if (!is_valid(himl))
2941 return CLR_NONE;
2942
2943 clrOldBk = himl->clrBk;
2944 himl->clrBk = clrBk;
2945 return clrOldBk;
2946}
2947
2948
2949/*************************************************************************
2950 * ImageList_SetDragCursorImage [COMCTL32.@]
2951 *
2952 * Combines the specified image with the current drag image
2953 *
2954 * PARAMS
2955 * himlDrag [I] handle to drag image list
2956 * iDrag [I] drag image index
2957 * dxHotspot [I] X position of the hot spot
2958 * dyHotspot [I] Y position of the hot spot
2959 *
2960 * RETURNS
2961 * Success: TRUE
2962 * Failure: FALSE
2963 *
2964 * NOTES
2965 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2966 * to do with a hotspot but are only the offset of the origin of the new
2967 * image relative to the origin of the old image.
2968 *
2969 * - When this function is called and the drag image is visible, a
2970 * short flickering occurs but this matches the Win9x behavior. It is
2971 * possible to fix the flickering using code like in ImageList_DragMove.
2972 */
2973
2976 INT dxHotspot, INT dyHotspot)
2977{
2978 HIMAGELIST himlTemp;
2979 BOOL visible;
2980
2981 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2982 return FALSE;
2983
2984 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2985 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2986
2987 visible = InternalDrag.bShow;
2988
2989 himlTemp = ImageList_Merge (InternalDrag.himlNoCursor, 0, himlDrag, iDrag,
2990 dxHotspot, dyHotspot);
2991
2992 if (visible) {
2993 /* hide the drag image */
2995 }
2996 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2997 (InternalDrag.himl->cy != himlTemp->cy)) {
2998 /* the size of the drag image changed, invalidate the buffer */
3000 InternalDrag.hbmBg = 0;
3001 }
3002
3005 InternalDrag.himl = himlTemp;
3006
3007 if (visible) {
3008 /* show the drag image */
3010 }
3011
3012 return TRUE;
3013}
3014
3015
3016/*************************************************************************
3017 * ImageList_SetFilter [COMCTL32.@]
3018 *
3019 * Sets a filter (or does something completely different)!!???
3020 * It removes 12 Bytes from the stack (3 Parameters).
3021 *
3022 * PARAMS
3023 * himl [I] SHOULD be a handle to image list
3024 * i [I] COULD be an index?
3025 * dwFilter [I] ???
3026 *
3027 * RETURNS
3028 * Success: TRUE ???
3029 * Failure: FALSE ???
3030 *
3031 * BUGS
3032 * This is an UNDOCUMENTED function!!!!
3033 * empty stub.
3034 */
3035
3038{
3039 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
3040
3041 return FALSE;
3042}
3043
3044
3045/*************************************************************************
3046 * ImageList_SetFlags [COMCTL32.@]
3047 *
3048 * Sets the image list flags.
3049 *
3050 * PARAMS
3051 * himl [I] Handle to image list
3052 * flags [I] Flags to set
3053 *
3054 * RETURNS
3055 * Old flags?
3056 *
3057 * BUGS
3058 * Stub.
3059 */
3060
3061#ifdef __REACTOS__
3062static BOOL
3063ChangeColorDepth(HIMAGELIST himl)
3064{
3065 UINT ilc = himl->flags & ILC_COLORMASK;
3066 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
3067 himl->uBitsPixel = ilc;
3068 else
3070
3071 /* Create new himl->hbmImage for BPP changes (for SHELL32) */
3072 return ((IImageList*)himl)->lpVtbl->SetImageCount((IImageList*)himl, 0) == S_OK;
3073}
3074
3077{
3078 if (!is_valid(himl))
3079 return FALSE;
3080
3081 if (flags & ~ILC_PUBLICFLAGS)
3082 return FALSE;
3083
3084 if (((himl->flags ^ flags) & ILC_SYSTEM) && WinVerMajor() < 6)
3085 return FALSE; /* Can't change this flag */
3086
3087 if (himl->flags == flags && WinVerMajor() >= 6)
3088 return TRUE;
3089
3090 himl->flags = flags;
3091 return ChangeColorDepth(himl);
3092}
3093#else
3096{
3097 FIXME("(%p %08x):empty stub\n", himl, flags);
3098 return 0;
3099}
3100#endif /* __REACTOS__ */
3101
3102
3103/*************************************************************************
3104 * ImageList_SetIconSize [COMCTL32.@]
3105 *
3106 * Sets the image size of the bitmap and deletes all images.
3107 *
3108 * PARAMS
3109 * himl [I] handle to image list
3110 * cx [I] image width
3111 * cy [I] image height
3112 *
3113 * RETURNS
3114 * Success: TRUE
3115 * Failure: FALSE
3116 */
3117
3120{
3121 INT nCount;
3122 HBITMAP hbmNew;
3123
3124 if (!is_valid(himl))
3125 return FALSE;
3126
3127 /* remove all images */
3128 himl->cMaxImage = himl->cInitial + 1;
3129 himl->cCurImage = 0;
3130 himl->cx = cx;
3131 himl->cy = cy;
3132
3133 /* initialize overlay mask indices */
3134 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
3135 himl->nOvlIdx[nCount] = -1;
3136
3138 SelectObject (himl->hdcImage, hbmNew);
3140 himl->hbmImage = hbmNew;
3141
3142 if (himl->hbmMask) {
3143 SIZE sz;
3145 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
3146 SelectObject (himl->hdcMask, hbmNew);
3148 himl->hbmMask = hbmNew;
3149 }
3150
3151 return TRUE;
3152}
3153
3154
3155/*************************************************************************
3156 * ImageList_SetImageCount [COMCTL32.@]
3157 *
3158 * Resizes an image list to the specified number of images.
3159 *
3160 * PARAMS
3161 * himl [I] handle to image list
3162 * iImageCount [I] number of images in the image list
3163 *
3164 * RETURNS
3165 * Success: TRUE
3166 * Failure: FALSE
3167 */
3168
3171{
3172 HDC hdcBitmap;
3173 HBITMAP hbmNewBitmap, hbmOld;
3174 INT nNewCount, nCopyCount;
3175
3176 TRACE("%p %d\n",himl,iImageCount);
3177
3178 if (!is_valid(himl))
3179 return FALSE;
3180
3181 nNewCount = iImageCount + 1;
3182 nCopyCount = min(himl->cCurImage, iImageCount);
3183
3185
3186 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
3187
3188 if (hbmNewBitmap != 0)
3189 {
3190 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
3191 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
3192 SelectObject (hdcBitmap, hbmOld);
3193
3194 /* FIXME: delete 'empty' image space? */
3195
3196 SelectObject (himl->hdcImage, hbmNewBitmap);
3198 himl->hbmImage = hbmNewBitmap;
3199 }
3200 else
3201 ERR("Could not create new image bitmap!\n");
3202
3203 if (himl->hbmMask)
3204 {
3205 SIZE sz;
3206 imagelist_get_bitmap_size( himl, nNewCount, &sz );
3207 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
3208 if (hbmNewBitmap != 0)
3209 {
3210 hbmOld = SelectObject (hdcBitmap, hbmNewBitmap);
3211 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
3212 SelectObject (hdcBitmap, hbmOld);
3213
3214 /* FIXME: delete 'empty' image space? */
3215
3216 SelectObject (himl->hdcMask, hbmNewBitmap);
3218 himl->hbmMask = hbmNewBitmap;
3219 }
3220 else
3221 ERR("Could not create new mask bitmap!\n");
3222 }
3223
3225
3226 if (himl->has_alpha)
3227 {
3228 char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
3229 if (new_alpha) himl->has_alpha = new_alpha;
3230 else
3231 {
3233 himl->has_alpha = NULL;
3234 }
3235 }
3236
3237 /* Update max image count and current image count */
3238 himl->cMaxImage = nNewCount;
3239 himl->cCurImage = iImageCount;
3240
3241 return TRUE;
3242}
3243
3244
3245/*************************************************************************
3246 * ImageList_SetOverlayImage [COMCTL32.@]
3247 *
3248 * Assigns an overlay mask index to an existing image in an image list.
3249 *
3250 * PARAMS
3251 * himl [I] handle to image list
3252 * iImage [I] image index
3253 * iOverlay [I] overlay mask index
3254 *
3255 * RETURNS
3256 * Success: TRUE
3257 * Failure: FALSE
3258 */
3259
3262{
3263 if (!is_valid(himl))
3264 return FALSE;
3265 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
3266 return FALSE;
3267 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
3268 return FALSE;
3269 himl->nOvlIdx[iOverlay - 1] = iImage;
3270 return TRUE;
3271}
3272
3273
3274
3275/* helper for ImageList_Write - write bitmap to pstm
3276 * currently everything is written as 24 bit RGB, except masks
3277 */
3279{
3280 LPBITMAPFILEHEADER bmfh;
3281 LPBITMAPINFOHEADER bmih;
3282 LPBYTE data = NULL, lpBits;
3283 BITMAP bm;
3284 INT bitCount, sizeImage, offBits, totalSize;
3285 HDC xdc;
3286 BOOL result = FALSE;
3287
3288 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bm))
3289 return FALSE;
3290
3291 bitCount = bm.bmBitsPixel;
3292 sizeImage = get_dib_stride(bm.bmWidth, bitCount) * bm.bmHeight;
3293
3294 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
3295 if(bitCount <= 8)
3296 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
3297 offBits = totalSize;
3298 totalSize += sizeImage;
3299
3300 data = heap_alloc_zero(totalSize);
3301 bmfh = (LPBITMAPFILEHEADER)data;
3302 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
3303 lpBits = data + offBits;
3304
3305 /* setup BITMAPFILEHEADER */
3306 bmfh->bfType = (('M' << 8) | 'B');
3307 bmfh->bfSize = offBits;
3308 bmfh->bfReserved1 = 0;
3309 bmfh->bfReserved2 = 0;
3310 bmfh->bfOffBits = offBits;
3311
3312 /* setup BITMAPINFOHEADER */
3313 bmih->biSize = sizeof(BITMAPINFOHEADER);
3314 bmih->biWidth = bm.bmWidth;
3315 bmih->biHeight = bm.bmHeight;
3316 bmih->biPlanes = 1;
3317 bmih->biBitCount = bitCount;
3318 bmih->biCompression = BI_RGB;
3319 bmih->biSizeImage = sizeImage;
3320 bmih->biXPelsPerMeter = 0;
3321 bmih->biYPelsPerMeter = 0;
3322 bmih->biClrUsed = 0;
3323 bmih->biClrImportant = 0;
3324
3325 xdc = GetDC(0);
3326 result = GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBits, (BITMAPINFO *)bmih, DIB_RGB_COLORS) == bm.bmHeight;
3327 ReleaseDC(0, xdc);
3328 if (!result)
3329 goto failed;
3330
3331 TRACE("width %u, height %u, planes %u, bpp %u\n",
3332 bmih->biWidth, bmih->biHeight,
3333 bmih->biPlanes, bmih->biBitCount);
3334
3335 if(FAILED(IStream_Write(pstm, data, totalSize, NULL)))
3336 goto failed;
3337
3338 result = TRUE;
3339
3340failed:
3341 heap_free(data);
3342
3343 return result;
3344}
3345
3346
3347/*************************************************************************
3348 * ImageList_Write [COMCTL32.@]
3349 *
3350 * Writes an image list to a stream.
3351 *
3352 * PARAMS
3353 * himl [I] handle to image list
3354 * pstm [O] Pointer to a stream.
3355 *
3356 * RETURNS
3357 * Success: TRUE
3358 * Failure: FALSE
3359 *
3360 * BUGS
3361 * probably.
3362 */
3363
3365{
3366 ILHEAD ilHead;
3367 int i;
3368
3369 TRACE("%p %p\n", himl, pstm);
3370
3371 if (!is_valid(himl))
3372 return FALSE;
3373
3374 ilHead.usMagic = (('L' << 8) | 'I');
3375 ilHead.usVersion = 0x101;
3376 ilHead.cCurImage = himl->cCurImage;
3377 ilHead.cMaxImage = himl->cMaxImage;
3378 ilHead.cGrow = himl->cGrow;
3379 ilHead.cx = himl->cx;
3380 ilHead.cy = himl->cy;
3381 ilHead.bkcolor = himl->clrBk;
3382 ilHead.flags = himl->flags;
3383 for(i = 0; i < 4; i++) {
3384 ilHead.ovls[i] = himl->nOvlIdx[i];
3385 }
3386
3387 TRACE("cx %u, cy %u, flags 0x04%x, cCurImage %u, cMaxImage %u\n",
3388 ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
3389
3390 if(FAILED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
3391 return FALSE;
3392
3393 /* write the bitmap */
3394 if(!_write_bitmap(himl->hbmImage, pstm))
3395 return FALSE;
3396
3397 /* write the mask if we have one */
3398 if(himl->flags & ILC_MASK) {
3399 if(!_write_bitmap(himl->hbmMask, pstm))
3400 return FALSE;
3401 }
3402
3403 return TRUE;
3404}
3405
3406
3408{
3409 HBITMAP hbmNewBitmap;
3410 UINT ilc = (himl->flags & 0xFE);
3411 SIZE sz;
3412
3414
3415 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
3416 {
3417 char buffer[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
3418 BITMAPINFO *bmi = (BITMAPINFO *)buffer;
3419
3420 TRACE("Creating DIBSection %d x %d, %d Bits per Pixel\n",
3421 sz.cx, sz.cy, himl->uBitsPixel);
3422
3423 memset( buffer, 0, sizeof(buffer) );
3424 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3425 bmi->bmiHeader.biWidth = sz.cx;
3426 bmi->bmiHeader.biHeight = sz.cy;
3427 bmi->bmiHeader.biPlanes = 1;
3430
3431 if (himl->uBitsPixel <= ILC_COLOR8)
3432 {
3433 if (!himl->color_table_set)
3434 {
3435 /* retrieve the default color map */
3436 HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
3437 GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
3438 DeleteObject( tmp );
3439 if (ilc == ILC_COLOR4)
3440 {
3441 RGBQUAD tmp;
3442 tmp = bmi->bmiColors[7];
3443 bmi->bmiColors[7] = bmi->bmiColors[8];
3444 bmi->bmiColors[8] = tmp;
3445 }
3446 }
3447 else
3448 {
3450 }
3451 }
3452 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
3453 }
3454 else /*if (ilc == ILC_COLORDDB)*/
3455 {
3456 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
3457
3458 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
3459 }
3460 TRACE("returning %p\n", hbmNewBitmap);
3461 return hbmNewBitmap;
3462}
3463
3464/*************************************************************************
3465 * ImageList_SetColorTable [COMCTL32.@]
3466 *
3467 * Sets the color table of an image list.
3468 *
3469 * PARAMS
3470 * himl [I] Handle to the image list.
3471 * uStartIndex [I] The first index to set.
3472 * cEntries [I] Number of entries to set.
3473 * prgb [I] New color information for color table for the image list.
3474 *
3475 * RETURNS
3476 * Success: Number of entries in the table that were set.
3477 * Failure: Zero.
3478 *
3479 * SEE
3480 * ImageList_Create(), SetDIBColorTable()
3481 */
3482
3485{
3486#ifdef __REACTOS__
3487 if(!is_valid2(himl))
3488 return 0;
3489#endif
3490 TRACE("(%p, %d, %d, %p)\n", himl, uStartIndex, cEntries, prgb);
3492 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
3493}
3494
3495/*************************************************************************
3496 * ImageList_CoCreateInstance [COMCTL32.@]
3497 *
3498 * Creates a new imagelist instance and returns an interface pointer to it.
3499 *
3500 * PARAMS
3501 * rclsid [I] A reference to the CLSID (CLSID_ImageList).
3502 * punkOuter [I] Pointer to IUnknown interface for aggregation, if desired
3503 * riid [I] Identifier of the requested interface.
3504 * ppv [O] Returns the address of the pointer requested, or NULL.
3505 *
3506 * RETURNS
3507 * Success: S_OK.
3508 * Failure: Error value.
3509 */
3511ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
3512{
3513 TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
3514
3515 if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
3516 return E_NOINTERFACE;
3517
3518 return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
3519}
3520
3521
3522/*************************************************************************
3523 * IImageList implementation
3524 */
3525
3527 REFIID iid, void **ppv)
3528{
3529 HIMAGELIST imgl = impl_from_IImageList2(iface);
3530
3531 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
3532
3533 if (!ppv) return E_INVALIDARG;
3534
3535 if (IsEqualIID(&IID_IUnknown, iid) ||
3536 IsEqualIID(&IID_IImageList, iid) ||
3537 IsEqualIID(&IID_IImageList2, iid))
3538 {
3539 *ppv = &imgl->IImageList2_iface;
3540 }
3541 else
3542 {
3543 *ppv = NULL;
3544 return E_NOINTERFACE;
3545 }
3546
3547 IImageList2_AddRef(iface);
3548 return S_OK;
3549}
3550
3552{
3553 HIMAGELIST imgl = impl_from_IImageList2(iface);
3555
3556 TRACE("(%p) refcount=%u\n", iface, ref);
3557 return ref;
3558}
3559
3561{
3564
3565 TRACE("(%p) refcount=%u\n", iface, ref);
3566
3567 if (ref == 0)
3568 {
3569 /* delete image bitmaps */
3570 if (This->hbmImage) DeleteObject (This->hbmImage);
3571 if (This->hbmMask) DeleteObject (This->hbmMask);
3572
3573 /* delete image & mask DCs */
3574 if (This->hdcImage) DeleteDC (This->hdcImage);
3575 if (This->hdcMask) DeleteDC (This->hdcMask);
3576
3577 /* delete blending brushes */
3578 if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
3579 if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
3580
3581#ifdef __REACTOS__
3582 This->usMagic = IMAGELIST_MAGIC_DESTROYED;
3583#endif
3584 This->IImageList2_iface.lpVtbl = NULL;
3585 heap_free(This->has_alpha);
3586 heap_free(This);
3587 }
3588
3589 return ref;
3590}
3591
3593 HBITMAP hbmMask, int *pi)
3594{
3595 HIMAGELIST imgl = impl_from_IImageList2(iface);
3596 int ret;
3597
3598 if (!pi)
3599 return E_FAIL;
3600
3601 ret = ImageList_Add(imgl, hbmImage, hbmMask);
3602
3603 if (ret == -1)
3604 return E_FAIL;
3605
3606 *pi = ret;
3607 return S_OK;
3608}
3609
3611 HICON hicon, int *pi)
3612{
3613 HIMAGELIST imgl = impl_from_IImageList2(iface);
3614 int ret;
3615
3616 if (!pi)
3617 return E_FAIL;
3618
3619 ret = ImageList_ReplaceIcon(imgl, i, hicon);
3620
3621 if (ret == -1)
3622 return E_FAIL;
3623
3624 *pi = ret;
3625 return S_OK;
3626}
3627
3629 int iImage, int iOverlay)
3630{
3631 HIMAGELIST imgl = impl_from_IImageList2(iface);
3632 return ImageList_SetOverlayImage(imgl, iImage, iOverlay) ? S_OK : E_FAIL;
3633}
3634
3636 HBITMAP hbmImage, HBITMAP hbmMask)
3637{
3638 HIMAGELIST imgl = impl_from_IImageList2(iface);
3639 return ImageList_Replace(imgl, i, hbmImage, hbmMask) ? S_OK : E_FAIL;
3640}
3641
3643 COLORREF crMask, int *pi)
3644{
3645 HIMAGELIST imgl = impl_from_IImageList2(iface);
3646 int ret;
3647
3648 if (!pi)
3649 return E_FAIL;
3650
3651 ret = ImageList_AddMasked(imgl, hbmImage, crMask);
3652
3653 if (ret == -1)
3654 return E_FAIL;
3655
3656 *pi = ret;
3657 return S_OK;
3658}
3659
3661 IMAGELISTDRAWPARAMS *pimldp)
3662{
3663 HIMAGELIST imgl = impl_from_IImageList2(iface);
3664 HIMAGELIST old_himl;
3665 int ret;
3666
3667 /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
3668 so we shall simulate the same */
3669 old_himl = pimldp->himl;
3670 pimldp->himl = imgl;
3671
3672 ret = ImageList_DrawIndirect(pimldp);
3673
3674 pimldp->himl = old_himl;
3675 return ret ? S_OK : E_INVALIDARG;
3676}
3677
3679{
3680 HIMAGELIST imgl = impl_from_IImageList2(iface);
3681 return (ImageList_Remove(imgl, i) == 0) ? E_INVALIDARG : S_OK;
3682}
3683
3685 HICON *picon)
3686{
3687 HIMAGELIST imgl = impl_from_IImageList2(iface);
3688 HICON hIcon;
3689
3690 if (!picon)
3691 return E_FAIL;
3692
3693 hIcon = ImageList_GetIcon(imgl, i, flags);
3694
3695 if (hIcon == NULL)
3696 return E_FAIL;
3697
3698 *picon = hIcon;
3699 return S_OK;
3700}
3701
3704{
3705 HIMAGELIST imgl = impl_from_IImageList2(iface);
3706 return ImageList_GetImageInfo(imgl, i, pImageInfo) ? S_OK : E_FAIL;
3707}
3708
3709static HRESULT WINAPI ImageListImpl_Copy(IImageList2 *iface, int dst_index,
3710 IUnknown *unk_src, int src_index, UINT flags)
3711{
3712 HIMAGELIST imgl = impl_from_IImageList2(iface);
3713 IImageList *src = NULL;
3714 HRESULT ret;
3715
3716 if (!unk_src)
3717 return E_FAIL;
3718
3719#ifdef __REACTOS__
3720 /* Make sure that the second image list uses the same implementation with the first */
3721 if (!is_valid2((HIMAGELIST)unk_src))
3722 return E_FAIL;
3723#endif
3724
3725 /* TODO: Add test for IID_ImageList2 too */
3726 if (FAILED(IUnknown_QueryInterface(unk_src, &IID_IImageList,
3727 (void **) &src)))
3728 return E_FAIL;
3729
3730 if (ImageList_Copy(imgl, dst_index, (HIMAGELIST) src, src_index, flags))
3731 ret = S_OK;
3732 else
3733 ret = E_FAIL;
3734
3735 IImageList_Release(src);
3736 return ret;
3737}
3738
3740 IUnknown *punk2, int i2, int dx, int dy, REFIID riid, void **ppv)
3741{
3742 HIMAGELIST imgl = impl_from_IImageList2(iface);
3743 IImageList *iml2 = NULL;
3744 HIMAGELIST merged;
3745 HRESULT ret = E_FAIL;
3746
3747 TRACE("(%p)->(%d %p %d %d %d %s %p)\n", iface, i1, punk2, i2, dx, dy, debugstr_guid(riid), ppv);
3748
3749#ifdef __REACTOS__
3750 /* Make sure that the second image list uses the same implementation with the first */
3751 if (!is_valid2((HIMAGELIST)punk2))
3752 return E_FAIL;
3753#endif
3754
3755 /* TODO: Add test for IID_ImageList2 too */
3756 if (FAILED(IUnknown_QueryInterface(punk2, &IID_IImageList,
3757 (void **) &iml2)))
3758 return E_FAIL;
3759
3760 merged = ImageList_Merge(imgl, i1, (HIMAGELIST) iml2, i2, dx, dy);
3761
3762 /* Get the interface for the new image list */
3763 if (merged)
3764 {
3766 ImageList_Destroy(merged);
3767 }
3768
3769 IImageList_Release(iml2);
3770 return ret;
3771}
3772
3774{
3775 HIMAGELIST imgl = impl_from_IImageList2(iface);
3776 HIMAGELIST clone;
3777 HRESULT ret = E_FAIL;
3778
3779 TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
3780
3781 clone = ImageList_Duplicate(imgl);
3782
3783 /* Get the interface for the new image list */
3784 if (clone)
3785 {
3787 ImageList_Destroy(clone);
3788 }
3789
3790 return ret;
3791}
3792
3794 RECT *prc)
3795{
3796 HIMAGELIST imgl = impl_from_IImageList2(iface);
3798
3799 if (!prc)
3800 return E_FAIL;
3801
3802 if (!ImageList_GetImageInfo(imgl, i, &info))
3803 return E_FAIL;
3804
3805 *prc = info.rcImage;
3806
3807 return S_OK;
3808}
3809
3811 int *cy)
3812{
3813 HIMAGELIST imgl = impl_from_IImageList2(iface);
3814 return ImageList_GetIconSize(imgl, cx, cy) ? S_OK : E_INVALIDARG;
3815}
3816
3818 int cy)
3819{
3820 HIMAGELIST imgl = impl_from_IImageList2(iface);
3821 return ImageList_SetIconSize(imgl, cx, cy) ? S_OK : E_FAIL;
3822}
3823
3825{
3826 HIMAGELIST imgl = impl_from_IImageList2(iface);
3827 *pi = ImageList_GetImageCount(imgl);
3828 return S_OK;
3829}
3830
3832{
3833 HIMAGELIST imgl = impl_from_IImageList2(iface);
3834 return ImageList_SetImageCount(imgl, count) ? S_OK : E_FAIL;
3835}
3836
3838 COLORREF *pclr)
3839{
3840 HIMAGELIST imgl = impl_from_IImageList2(iface);
3841 *pclr = ImageList_SetBkColor(imgl, clrBk);
3842 return S_OK;
3843}
3844
3846{
3847 HIMAGELIST imgl = impl_from_IImageList2(iface);
3848 *pclr = ImageList_GetBkColor(imgl);
3849 return S_OK;
3850}
3851
3853 int dxHotspot, int dyHotspot)
3854{
3855 HIMAGELIST imgl = impl_from_IImageList2(iface);
3856 return ImageList_BeginDrag(imgl, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
3857}
3858
3860{
3862 return S_OK;
3863}
3864
3866 int x, int y)
3867{
3868 return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
3869}
3870
3872{
3873 return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
3874}
3875
3877{
3878 return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
3879}
3880
3882 IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
3883{
3884 IImageList *iml2 = NULL;
3885 BOOL ret;
3886
3887 if (!punk)
3888 return E_FAIL;
3889
3890 /* TODO: Add test for IID_ImageList2 too */
3891 if (FAILED(IUnknown_QueryInterface(punk, &IID_IImageList,
3892 (void **) &iml2)))
3893 return E_FAIL;
3894
3895 ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
3896 dyHotspot);
3897
3898 IImageList_Release(iml2);
3899
3900 return ret ? S_OK : E_FAIL;
3901}
3902
3904{
3905 return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
3906}
3907
3910{
3911 HRESULT ret = E_FAIL;
3912 HIMAGELIST hNew;
3913
3914 if (!ppv)
3915 return E_FAIL;
3916
3918
3919 /* Get the interface for the new image list */
3920 if (hNew)
3921 {
3922