2 * ImageList implementation
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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we believe this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
36 * - Thread-safe locking
50 #include "imagelist.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
56 #define MAX_OVERLAYIMAGE 15
58 /* internal image list data used for Drag & Drop operations */
63 /* position of the drag image relative to the window */
66 /* offset of the hotspot relative to the origin of the image */
69 /* is the drag image visible */
71 /* saved background */
75 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
77 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
79 static inline BOOL is_valid(HIMAGELIST himl)
81 return himl && himl->magic == IMAGELIST_MAGIC;
85 /*************************************************************************
86 * IMAGELIST_InternalExpandBitmaps [Internal]
88 * Expands the bitmaps of an image list by the given number of images.
91 * himl [I] handle to image list
92 * nImageCount [I] number of images to add
98 * This function can NOT be used to reduce the number of images.
101 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
104 HBITMAP hbmNewBitmap, hbmNull;
105 INT nNewWidth, nNewCount;
107 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
111 if (cy == 0) cy = himl->cy;
112 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
113 nNewWidth = nNewCount * himl->cx;
115 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
116 hdcBitmap = CreateCompatibleDC (0);
118 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
120 if (hbmNewBitmap == 0)
121 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
125 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
126 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
127 himl->hdcImage, 0, 0, SRCCOPY);
128 SelectObject (hdcBitmap, hbmNull);
130 SelectObject (himl->hdcImage, hbmNewBitmap);
131 DeleteObject (himl->hbmImage);
132 himl->hbmImage = hbmNewBitmap;
134 if (himl->flags & ILC_MASK)
136 hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
138 if (hbmNewBitmap == 0)
139 ERR("creating new mask bitmap!\n");
143 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
144 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
145 himl->hdcMask, 0, 0, SRCCOPY);
146 SelectObject (hdcBitmap, hbmNull);
148 SelectObject (himl->hdcMask, hbmNewBitmap);
149 DeleteObject (himl->hbmMask);
150 himl->hbmMask = hbmNewBitmap;
153 himl->cMaxImage = nNewCount;
155 DeleteDC (hdcBitmap);
159 /*************************************************************************
160 * ImageList_Add [COMCTL32.@]
162 * Add an image or images to an image list.
165 * himl [I] handle to image list
166 * hbmImage [I] handle to image bitmap
167 * hbmMask [I] handle to mask bitmap
170 * Success: Index of the first new image.
175 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
178 INT nFirstIndex, nImageCount;
183 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
187 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
188 nImageCount = bmp.bmWidth / himl->cx;
190 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
192 nStartX = himl->cCurImage * himl->cx;
194 hdcBitmap = CreateCompatibleDC(0);
196 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
198 /* Copy result to the imagelist
200 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
201 hdcBitmap, 0, 0, SRCCOPY);
206 HBITMAP hOldBitmapTemp;
208 hdcTemp = CreateCompatibleDC(0);
209 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
211 BitBlt (himl->hdcMask,
212 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
217 SelectObject(hdcTemp, hOldBitmapTemp);
220 /* Remove the background from the image
222 BitBlt (himl->hdcImage,
223 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
226 0x220326); /* NOTSRCAND */
229 SelectObject(hdcBitmap, hOldBitmap);
232 nFirstIndex = himl->cCurImage;
233 himl->cCurImage += nImageCount;
239 /*************************************************************************
240 * ImageList_AddIcon [COMCTL32.@]
242 * Adds an icon to an image list.
245 * himl [I] handle to image list
246 * hIcon [I] handle to icon
249 * Success: index of the new image
252 #undef ImageList_AddIcon
253 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
255 return ImageList_ReplaceIcon (himl, -1, hIcon);
259 /*************************************************************************
260 * ImageList_AddMasked [COMCTL32.@]
262 * Adds an image or images to an image list and creates a mask from the
263 * specified bitmap using the mask color.
266 * himl [I] handle to image list.
267 * hBitmap [I] handle to bitmap
268 * clrMask [I] mask color.
271 * Success: Index of the first new image.
276 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
278 HDC hdcMask, hdcBitmap;
279 INT nIndex, nImageCount, nMaskXOffset=0;
282 HBITMAP hMaskBitmap=0;
285 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
289 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
293 nImageCount = bmp.bmWidth / himl->cx;
297 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
299 nIndex = himl->cCurImage;
300 himl->cCurImage += nImageCount;
302 hdcBitmap = CreateCompatibleDC(0);
305 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
308 hdcMask = himl->hdcMask;
309 nMaskXOffset = nIndex * himl->cx;
314 Create a temp Mask so we can remove the background of
315 the Image (Windows does this even if there is no mask)
317 hdcMask = CreateCompatibleDC(0);
318 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
319 SelectObject(hdcMask, hMaskBitmap);
322 /* create monochrome image to the mask bitmap */
323 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
324 GetPixel (hdcBitmap, 0, 0);
325 SetBkColor (hdcBitmap, bkColor);
327 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
331 SetBkColor(hdcBitmap, RGB(255,255,255));
332 /*Remove the background from the image
335 WINDOWS BUG ALERT!!!!!!
336 The statement below should not be done in common practice
337 but this is how ImageList_AddMasked works in Windows.
338 It overwrites the original bitmap passed, this was discovered
339 by using the same bitmap to iterate the different styles
340 on windows where it failed (BUT ImageList_Add is OK)
341 This is here in case some apps rely on this bug
344 0, 0, bmp.bmWidth, bmp.bmHeight,
347 0x220326); /* NOTSRCAND */
348 /* Copy result to the imagelist
350 BitBlt (himl->hdcImage,
351 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
357 SelectObject(hdcBitmap, hOldBitmap);
361 DeleteObject(hMaskBitmap);
369 /*************************************************************************
370 * ImageList_BeginDrag [COMCTL32.@]
372 * Creates a temporary image list that contains one image. It will be used
376 * himlTrack [I] handle to the source image list
377 * iTrack [I] index of the drag image in the source image list
378 * dxHotspot [I] X position of the hot spot of the drag image
379 * dyHotspot [I] Y position of the hot spot of the drag image
387 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
388 INT dxHotspot, INT dyHotspot)
392 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
393 dxHotspot, dyHotspot);
395 if (!is_valid(himlTrack))
398 if (InternalDrag.himl)
399 ImageList_EndDrag ();
404 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
405 if (InternalDrag.himl == NULL) {
406 WARN("Error creating drag image list!\n");
410 InternalDrag.dxHotspot = dxHotspot;
411 InternalDrag.dyHotspot = dyHotspot;
414 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
417 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
419 InternalDrag.himl->cCurImage = 1;
425 /*************************************************************************
426 * ImageList_Copy [COMCTL32.@]
428 * Copies an image of the source image list to an image of the
429 * destination image list. Images can be copied or swapped.
432 * himlDst [I] handle to the destination image list
433 * iDst [I] destination image index.
434 * himlSrc [I] handle to the source image list
435 * iSrc [I] source image index
436 * uFlags [I] flags for the copy operation
443 * Copying from one image list to another is possible. The original
444 * implementation just copies or swaps within one image list.
445 * Could this feature become a bug??? ;-)
449 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
450 INT iSrc, UINT uFlags)
452 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
454 if (!is_valid(himlSrc) || !is_valid(himlDst))
456 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
458 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
461 if (uFlags & ILCF_SWAP) {
464 HBITMAP hbmTempImage, hbmTempMask;
466 hdcBmp = CreateCompatibleDC (0);
468 /* create temporary bitmaps */
469 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
470 himlSrc->uBitsPixel, NULL);
471 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
474 /* copy (and stretch) destination to temporary bitmaps.(save) */
476 SelectObject (hdcBmp, hbmTempImage);
477 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
478 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
481 SelectObject (hdcBmp, hbmTempMask);
482 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
483 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
486 /* copy (and stretch) source to destination */
488 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
489 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
492 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
493 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
496 /* copy (without stretching) temporary bitmaps to source (restore) */
498 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
499 hdcBmp, 0, 0, SRCCOPY);
502 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
503 hdcBmp, 0, 0, SRCCOPY);
504 /* delete temporary bitmaps */
505 DeleteObject (hbmTempMask);
506 DeleteObject (hbmTempImage);
511 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
512 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
516 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
517 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
525 /*************************************************************************
526 * ImageList_Create [COMCTL32.@]
528 * Creates a new image list.
531 * cx [I] image height
533 * flags [I] creation flags
534 * cInitial [I] initial number of images in the image list
535 * cGrow [I] number of images by which image list grows
538 * Success: Handle to the created image list
542 ImageList_Create (INT cx, INT cy, UINT flags,
543 INT cInitial, INT cGrow)
548 UINT ilc = (flags & 0xFE);
549 static const WORD aBitBlend25[] =
550 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
552 static const WORD aBitBlend50[] =
553 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
555 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
557 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
561 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
563 himl->magic = IMAGELIST_MAGIC;
567 himl->cMaxImage = cInitial + cGrow;
568 himl->cInitial = cInitial;
570 himl->clrFg = CLR_DEFAULT;
571 himl->clrBk = CLR_NONE;
573 /* initialize overlay mask indices */
574 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
575 himl->nOvlIdx[nCount] = -1;
577 /* Create Image & Mask DCs */
578 himl->hdcImage = CreateCompatibleDC (0);
581 if (himl->flags & ILC_MASK){
582 himl->hdcMask = CreateCompatibleDC(0);
587 /* Default to ILC_COLOR4 if non of the ILC_COLOR* flags are specified */
588 if (ilc == ILC_COLOR)
591 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
592 himl->uBitsPixel = ilc;
594 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
596 if (himl->cMaxImage > 0) {
597 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy);
598 SelectObject(himl->hdcImage, himl->hbmImage);
602 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
604 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
606 if (himl->hbmMask == 0) {
607 ERR("Error creating mask bitmap!\n");
610 SelectObject(himl->hdcMask, himl->hbmMask);
613 /* create blending brushes */
614 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
615 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
616 DeleteObject (hbmTemp);
618 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
619 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
620 DeleteObject (hbmTemp);
622 TRACE("created imagelist %p\n", himl);
626 if (himl) ImageList_Destroy(himl);
631 /*************************************************************************
632 * ImageList_Destroy [COMCTL32.@]
634 * Destroys an image list.
637 * himl [I] handle to image list
645 ImageList_Destroy (HIMAGELIST himl)
650 /* delete image bitmaps */
652 DeleteObject (himl->hbmImage);
654 DeleteObject (himl->hbmMask);
656 /* delete image & mask DCs */
658 DeleteDC(himl->hdcImage);
660 DeleteDC(himl->hdcMask);
662 /* delete blending brushes */
663 if (himl->hbrBlend25)
664 DeleteObject (himl->hbrBlend25);
665 if (himl->hbrBlend50)
666 DeleteObject (himl->hbrBlend50);
668 ZeroMemory(himl, sizeof(*himl));
675 /*************************************************************************
676 * ImageList_DragEnter [COMCTL32.@]
678 * Locks window update and displays the drag image at the given position.
681 * hwndLock [I] handle of the window that owns the drag image.
682 * x [I] X position of the drag image.
683 * y [I] Y position of the drag image.
690 * The position of the drag image is relative to the window, not
695 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
697 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
699 if (!is_valid(InternalDrag.himl))
703 InternalDrag.hwnd = hwndLock;
705 InternalDrag.hwnd = GetDesktopWindow ();
710 /* draw the drag image and save the background */
711 if (!ImageList_DragShowNolock(TRUE)) {
719 /*************************************************************************
720 * ImageList_DragLeave [COMCTL32.@]
722 * Unlocks window update and hides the drag image.
725 * hwndLock [I] handle of the window that owns the drag image.
733 ImageList_DragLeave (HWND hwndLock)
735 /* As we don't save drag info in the window this can lead to problems if
736 an app does not supply the same window as DragEnter */
738 InternalDrag.hwnd = hwndLock;
740 InternalDrag.hwnd = GetDesktopWindow (); */
742 hwndLock = GetDesktopWindow();
743 if(InternalDrag.hwnd != hwndLock)
744 FIXME("DragLeave hWnd != DragEnter hWnd\n");
746 ImageList_DragShowNolock (FALSE);
752 /*************************************************************************
753 * ImageList_InternalDragDraw [Internal]
755 * Draws the drag image.
758 * hdc [I] device context to draw into.
759 * x [I] X position of the drag image.
760 * y [I] Y position of the drag image.
767 * The position of the drag image is relative to the window, not
773 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
775 IMAGELISTDRAWPARAMS imldp;
777 ZeroMemory (&imldp, sizeof(imldp));
778 imldp.cbSize = sizeof(imldp);
779 imldp.himl = InternalDrag.himl;
784 imldp.rgbBk = CLR_DEFAULT;
785 imldp.rgbFg = CLR_DEFAULT;
786 imldp.fStyle = ILD_NORMAL;
787 imldp.fState = ILS_ALPHA;
790 /* FIXME: instead of using the alpha blending, we should
791 * create a 50% mask, and draw it semitransparantly that way */
792 ImageList_DrawIndirect (&imldp);
795 /*************************************************************************
796 * ImageList_DragMove [COMCTL32.@]
798 * Moves the drag image.
801 * x [I] X position of the drag image.
802 * y [I] Y position of the drag image.
809 * The position of the drag image is relative to the window, not
813 * The drag image should be drawn semitransparent.
817 ImageList_DragMove (INT x, INT y)
819 TRACE("(x=%d y=%d)\n", x, y);
821 if (!is_valid(InternalDrag.himl))
824 /* draw/update the drag image */
825 if (InternalDrag.bShow) {
829 HBITMAP hbmOffScreen;
830 INT origNewX, origNewY;
831 INT origOldX, origOldY;
832 INT origRegX, origRegY;
833 INT sizeRegX, sizeRegY;
836 /* calculate the update region */
837 origNewX = x - InternalDrag.dxHotspot;
838 origNewY = y - InternalDrag.dyHotspot;
839 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
840 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
841 origRegX = min(origNewX, origOldX);
842 origRegY = min(origNewY, origOldY);
843 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
844 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
846 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
847 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
848 hdcOffScreen = CreateCompatibleDC(hdcDrag);
849 hdcBg = CreateCompatibleDC(hdcDrag);
851 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
852 SelectObject(hdcOffScreen, hbmOffScreen);
853 SelectObject(hdcBg, InternalDrag.hbmBg);
855 /* get the actual background of the update region */
856 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
857 origRegX, origRegY, SRCCOPY);
858 /* erase the old image */
859 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
860 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
862 /* save the background */
863 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
864 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
866 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
867 origNewY - origRegY);
868 /* draw the update region to the screen */
869 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
870 hdcOffScreen, 0, 0, SRCCOPY);
873 DeleteDC(hdcOffScreen);
874 DeleteObject(hbmOffScreen);
875 ReleaseDC(InternalDrag.hwnd, hdcDrag);
878 /* update the image position */
886 /*************************************************************************
887 * ImageList_DragShowNolock [COMCTL32.@]
889 * Shows or hides the drag image.
892 * bShow [I] TRUE shows the drag image, FALSE hides it.
899 * The drag image should be drawn semitransparent.
903 ImageList_DragShowNolock (BOOL bShow)
909 if (!is_valid(InternalDrag.himl))
912 TRACE("bShow=0x%X!\n", bShow);
914 /* DragImage is already visible/hidden */
915 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
919 /* position of the origin of the DragImage */
920 x = InternalDrag.x - InternalDrag.dxHotspot;
921 y = InternalDrag.y - InternalDrag.dyHotspot;
923 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
924 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
929 hdcBg = CreateCompatibleDC(hdcDrag);
930 if (!InternalDrag.hbmBg) {
931 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
932 InternalDrag.himl->cx, InternalDrag.himl->cy);
934 SelectObject(hdcBg, InternalDrag.hbmBg);
937 /* save the background */
938 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
939 hdcDrag, x, y, SRCCOPY);
941 ImageList_InternalDragDraw(hdcDrag, x, y);
944 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
945 hdcBg, 0, 0, SRCCOPY);
948 InternalDrag.bShow = !InternalDrag.bShow;
951 ReleaseDC (InternalDrag.hwnd, hdcDrag);
956 /*************************************************************************
957 * ImageList_Draw [COMCTL32.@]
962 * himl [I] handle to image list
964 * hdc [I] handle to device context
967 * fStyle [I] drawing flags
978 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
980 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
981 CLR_DEFAULT, CLR_DEFAULT, fStyle);
985 /*************************************************************************
986 * ImageList_DrawEx [COMCTL32.@]
988 * Draws an image and allows to use extended drawing features.
991 * himl [I] handle to image list
993 * hdc [I] handle to device context
998 * rgbBk [I] background color
999 * rgbFg [I] foreground color
1000 * fStyle [I] drawing flags
1007 * Calls ImageList_DrawIndirect.
1010 * ImageList_DrawIndirect.
1014 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1015 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1018 IMAGELISTDRAWPARAMS imldp;
1020 ZeroMemory (&imldp, sizeof(imldp));
1021 imldp.cbSize = sizeof(imldp);
1029 imldp.rgbBk = rgbBk;
1030 imldp.rgbFg = rgbFg;
1031 imldp.fStyle = fStyle;
1033 return ImageList_DrawIndirect (&imldp);
1037 /*************************************************************************
1038 * ImageList_DrawIndirect [COMCTL32.@]
1040 * Draws an image using various parameters specified in pimldp.
1043 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1051 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1053 INT cx, cy, lx, ly, nOvlIdx;
1054 DWORD fState, dwRop;
1056 COLORREF clrBk, oldImageBk, oldImageFg;
1057 HDC hImageDC, hImageListDC, hMaskListDC;
1058 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1059 BOOL bIsTransparent, bBlend, bResult = FALSE;
1062 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1063 if (!is_valid(himl)) return FALSE;
1064 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1066 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1067 ly = pimldp->yBitmap;
1069 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1070 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1071 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1072 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1073 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1074 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1075 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1077 TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1078 (DWORD)himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1080 /* we will use these DCs to access the images and masks in the ImageList */
1081 hImageListDC = himl->hdcImage;
1082 hMaskListDC = himl->hdcMask;
1084 /* these will accumulate the image and mask for the image we're drawing */
1085 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1086 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1087 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1089 /* Create a compatible DC. */
1090 if (!hImageListDC || !hImageDC || !hImageBmp ||
1091 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1094 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1097 * To obtain a transparent look, background color should be set
1098 * to white and foreground color to black when blting the
1101 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1102 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1105 * Draw the initial image
1107 if (fStyle & ILD_MASK) {
1108 if (himl->hbmMask) {
1109 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1111 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1112 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1113 SelectObject(hImageDC, hOldBrush);
1115 } else if (himl->hbmMask && !bIsTransparent) {
1116 /* blend the image with the needed solid background */
1117 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1118 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1119 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1120 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1121 DeleteObject (SelectObject (hImageDC, hOldBrush));
1123 /* start off with the image, if we have a mask, we'll use it later */
1124 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1127 /* Time for blending, if required */
1129 HBRUSH hBlendBrush, hOldBrush;
1130 COLORREF clrBlend = pimldp->rgbFg;
1131 HDC hBlendMaskDC = hImageListDC;
1134 /* Create the blend Mask */
1135 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1136 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1137 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1138 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1139 SelectObject(hBlendMaskDC, hOldBrush);
1141 /* Modify the blend mask if an Image Mask exist */
1143 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1144 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1147 /* now apply blend to the current image given the BlendMask */
1148 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1149 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1150 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1151 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1152 DeleteObject(SelectObject(hImageDC, hOldBrush));
1153 SelectObject(hBlendMaskDC, hOldBitmap);
1156 /* Now do the overlay image, if any */
1157 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1158 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1159 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1160 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1161 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1162 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1163 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1164 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1168 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1169 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1170 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1171 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1173 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1174 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1175 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1177 /* now copy the image to the screen */
1179 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1180 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1181 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1182 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1183 SetBkColor(pimldp->hdcDst, oldDstBk);
1184 SetTextColor(pimldp->hdcDst, oldDstFg);
1187 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1188 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1192 /* cleanup the mess */
1193 SetBkColor(hImageDC, oldImageBk);
1194 SetTextColor(hImageDC, oldImageFg);
1195 SelectObject(hImageDC, hOldImageBmp);
1197 DeleteObject(hBlendMaskBmp);
1198 DeleteObject(hImageBmp);
1205 /*************************************************************************
1206 * ImageList_Duplicate [COMCTL32.@]
1208 * Duplicates an image list.
1211 * himlSrc [I] source image list handle
1214 * Success: Handle of duplicated image list.
1219 ImageList_Duplicate (HIMAGELIST himlSrc)
1223 if (!is_valid(himlSrc)) {
1224 ERR("Invalid image list handle!\n");
1228 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1229 himlSrc->cInitial, himlSrc->cGrow);
1233 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1234 himlSrc->hdcImage, 0, 0, SRCCOPY);
1236 if (himlDst->hbmMask)
1237 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1238 himlSrc->hdcMask, 0, 0, SRCCOPY);
1240 himlDst->cCurImage = himlSrc->cCurImage;
1241 himlDst->cMaxImage = himlSrc->cMaxImage;
1247 /*************************************************************************
1248 * ImageList_EndDrag [COMCTL32.@]
1250 * Finishes a drag operation.
1261 ImageList_EndDrag (void)
1263 /* cleanup the InternalDrag struct */
1264 InternalDrag.hwnd = 0;
1265 ImageList_Destroy (InternalDrag.himl);
1266 InternalDrag.himl = 0;
1269 InternalDrag.dxHotspot = 0;
1270 InternalDrag.dyHotspot = 0;
1271 InternalDrag.bShow = FALSE;
1272 DeleteObject(InternalDrag.hbmBg);
1273 InternalDrag.hbmBg = 0;
1277 /*************************************************************************
1278 * ImageList_GetBkColor [COMCTL32.@]
1280 * Returns the background color of an image list.
1283 * himl [I] Image list handle.
1286 * Success: background color
1291 ImageList_GetBkColor (HIMAGELIST himl)
1293 return himl ? himl->clrBk : CLR_NONE;
1297 /*************************************************************************
1298 * ImageList_GetDragImage [COMCTL32.@]
1300 * Returns the handle to the internal drag image list.
1303 * ppt [O] Pointer to the drag position. Can be NULL.
1304 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1307 * Success: Handle of the drag image list.
1312 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1314 if (is_valid(InternalDrag.himl)) {
1316 ppt->x = InternalDrag.x;
1317 ppt->y = InternalDrag.y;
1320 pptHotspot->x = InternalDrag.dxHotspot;
1321 pptHotspot->y = InternalDrag.dyHotspot;
1323 return (InternalDrag.himl);
1330 /*************************************************************************
1331 * ImageList_GetFlags [COMCTL32.@]
1333 * Gets the flags of the specified image list.
1336 * himl [I] Handle to image list
1346 ImageList_GetFlags(HIMAGELIST himl)
1348 FIXME("(%p):empty stub\n", himl);
1353 /*************************************************************************
1354 * ImageList_GetIcon [COMCTL32.@]
1356 * Creates an icon from a masked image of an image list.
1359 * himl [I] handle to image list
1361 * flags [I] drawing style flags
1364 * Success: icon handle
1369 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1373 HBITMAP hOldDstBitmap;
1376 TRACE("%p %d %d\n", himl, i, fStyle);
1377 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1379 hdcDst = CreateCompatibleDC(0);
1386 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1387 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1388 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1389 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1392 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1393 SelectObject (hdcDst, ii.hbmColor);
1394 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1395 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1398 * CreateIconIndirect requires us to deselect the bitmaps from
1399 * the DCs before calling
1401 SelectObject(hdcDst, hOldDstBitmap);
1403 hIcon = CreateIconIndirect (&ii);
1405 DeleteObject (ii.hbmMask);
1406 DeleteObject (ii.hbmColor);
1413 /*************************************************************************
1414 * ImageList_GetIconSize [COMCTL32.@]
1416 * Retrieves the size of an image in an image list.
1419 * himl [I] handle to image list
1420 * cx [O] pointer to the image width.
1421 * cy [O] pointer to the image height.
1428 * All images in an image list have the same size.
1432 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1434 if (!is_valid(himl))
1436 if ((himl->cx <= 0) || (himl->cy <= 0))
1448 /*************************************************************************
1449 * ImageList_GetImageCount [COMCTL32.@]
1451 * Returns the number of images in an image list.
1454 * himl [I] handle to image list
1457 * Success: Number of images.
1462 ImageList_GetImageCount (HIMAGELIST himl)
1464 if (!is_valid(himl))
1467 return himl->cCurImage;
1471 /*************************************************************************
1472 * ImageList_GetImageInfo [COMCTL32.@]
1474 * Returns information about an image in an image list.
1477 * himl [I] handle to image list
1479 * pImageInfo [O] pointer to the image information
1487 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1489 if (!is_valid(himl) || (pImageInfo == NULL))
1491 if ((i < 0) || (i >= himl->cCurImage))
1494 pImageInfo->hbmImage = himl->hbmImage;
1495 pImageInfo->hbmMask = himl->hbmMask;
1497 pImageInfo->rcImage.top = 0;
1498 pImageInfo->rcImage.bottom = himl->cy;
1499 pImageInfo->rcImage.left = i * himl->cx;
1500 pImageInfo->rcImage.right = (i+1) * himl->cx;
1506 /*************************************************************************
1507 * ImageList_GetImageRect [COMCTL32.@]
1509 * Retrieves the rectangle of the specified image in an image list.
1512 * himl [I] handle to image list
1514 * lpRect [O] pointer to the image rectangle
1521 * This is an UNDOCUMENTED function!!!
1525 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1527 if (!is_valid(himl) || (lpRect == NULL))
1529 if ((i < 0) || (i >= himl->cCurImage))
1532 lpRect->left = i * himl->cx;
1534 lpRect->right = lpRect->left + himl->cx;
1535 lpRect->bottom = himl->cy;
1541 /*************************************************************************
1542 * ImageList_LoadImage [COMCTL32.@]
1543 * ImageList_LoadImageA [COMCTL32.@]
1545 * Creates an image list from a bitmap, icon or cursor.
1548 * hi [I] instance handle
1549 * lpbmp [I] name or id of the image
1550 * cx [I] width of each image
1551 * cGrow [I] number of images to expand
1552 * clrMask [I] mask color
1553 * uType [I] type of image to load
1554 * uFlags [I] loading flags
1557 * Success: handle to the loaded image list
1565 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1566 COLORREF clrMask, UINT uType, UINT uFlags)
1568 HIMAGELIST himl = NULL;
1572 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1574 ERR("Error loading image!\n");
1578 if (uType == IMAGE_BITMAP) {
1580 GetObjectA (handle, sizeof(BITMAP), &bmp);
1582 /* To match windows behavior, if cx is set to zero and
1583 the flag DI_DEFAULTSIZE is specified, cx becomes the
1584 system metric value for icons. If the flag is not specified
1585 the function sets the size to the height of the bitmap */
1588 if (uFlags & DI_DEFAULTSIZE)
1589 cx = GetSystemMetrics (SM_CXICON);
1594 nImageCount = bmp.bmWidth / cx;
1596 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1597 nImageCount, cGrow);
1599 DeleteObject (handle);
1602 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1604 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1608 GetIconInfo (handle, &ii);
1609 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1610 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1611 ILC_MASK | ILC_COLOR, 1, cGrow);
1613 DeleteObject (ii.hbmColor);
1614 DeleteObject (ii.hbmMask);
1615 DeleteObject (handle);
1618 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1619 DeleteObject (ii.hbmColor);
1620 DeleteObject (ii.hbmMask);
1623 DeleteObject (handle);
1629 /*************************************************************************
1630 * ImageList_LoadImageW [COMCTL32.@]
1632 * Creates an image list from a bitmap, icon or cursor.
1635 * hi [I] instance handle
1636 * lpbmp [I] name or id of the image
1637 * cx [I] width of each image
1638 * cGrow [I] number of images to expand
1639 * clrMask [I] mask color
1640 * uType [I] type of image to load
1641 * uFlags [I] loading flags
1644 * Success: handle to the loaded image list
1652 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1653 COLORREF clrMask, UINT uType, UINT uFlags)
1655 HIMAGELIST himl = NULL;
1659 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1661 ERR("Error loading image!\n");
1665 if (uType == IMAGE_BITMAP) {
1667 GetObjectW (handle, sizeof(BITMAP), &bmp);
1669 /* To match windows behavior, if cx is set to zero and
1670 the flag DI_DEFAULTSIZE is specified, cx becomes the
1671 system metric value for icons. If the flag is not specified
1672 the function sets the size to the height of the bitmap */
1675 if (uFlags & DI_DEFAULTSIZE)
1676 cx = GetSystemMetrics (SM_CXICON);
1681 nImageCount = bmp.bmWidth / cx;
1683 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1684 nImageCount, cGrow);
1686 DeleteObject (handle);
1689 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1691 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1695 GetIconInfo (handle, &ii);
1696 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1697 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1698 ILC_MASK | ILC_COLOR, 1, cGrow);
1700 DeleteObject (ii.hbmColor);
1701 DeleteObject (ii.hbmMask);
1702 DeleteObject (handle);
1705 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1706 DeleteObject (ii.hbmColor);
1707 DeleteObject (ii.hbmMask);
1710 DeleteObject (handle);
1716 /*************************************************************************
1717 * ImageList_Merge [COMCTL32.@]
1719 * Creates a new image list that contains a merged image from the specified
1720 * images of both source image lists.
1723 * himl1 [I] handle to first image list
1724 * i1 [I] first image index
1725 * himl2 [I] handle to second image list
1726 * i2 [I] second image index
1727 * dx [I] X offset of the second image relative to the first.
1728 * dy [I] Y offset of the second image relative to the first.
1731 * Success: handle of the merged image list.
1736 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1739 HIMAGELIST himlDst = NULL;
1741 INT xOff1, yOff1, xOff2, yOff2;
1744 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1747 if (!is_valid(himl1) || !is_valid(himl2))
1751 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1752 ERR("Index 1 out of range! %d\n", i1);
1756 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1757 ERR("Index 2 out of range! %d\n", i2);
1762 cxDst = max (himl1->cx, dx + himl2->cx);
1767 cxDst = max (himl2->cx, himl1->cx - dx);
1772 cxDst = max (himl1->cx, himl2->cx);
1778 cyDst = max (himl1->cy, dy + himl2->cy);
1783 cyDst = max (himl2->cy, himl1->cy - dy);
1788 cyDst = max (himl1->cy, himl2->cy);
1793 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1798 nX1 = i1 * himl1->cx;
1799 nX2 = i2 * himl2->cx;
1802 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1803 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1804 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1805 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1808 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1809 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1810 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1812 himlDst->cCurImage = 1;
1819 /* helper for _read_bitmap currently unused */
1821 static int may_use_dibsection(HDC hdc) {
1822 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1827 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1831 /* helper for ImageList_Read, see comments below */
1832 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1833 HDC xdc = 0, hBitmapDC =0;
1834 BITMAPFILEHEADER bmfh;
1835 BITMAPINFOHEADER bmih;
1836 int bitsperpixel,palspace,longsperline,width,height;
1837 LPBITMAPINFOHEADER bmihc = NULL;
1839 HBITMAP hbitmap = 0, hDIB = 0;
1842 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1843 (bmfh.bfType != (('M'<<8)|'B')) ||
1844 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1845 (bmih.biSize != sizeof(bmih))
1849 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1850 if (bitsperpixel<=8)
1851 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1854 width = bmih.biWidth;
1855 height = bmih.biHeight;
1856 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1857 memcpy(bmihc,&bmih,sizeof(bmih));
1858 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1859 bmihc->biSizeImage = (longsperline*height)<<2;
1861 /* read the palette right after the end of the bitmapinfoheader */
1863 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1867 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1868 if ((bitsperpixel>1) &&
1869 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1871 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1874 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1880 int i,nwidth,nheight,nRows;
1882 nwidth = width*(height/cy);
1884 nRows = (height/cy);
1886 if (bitsperpixel==1)
1887 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1889 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1891 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1894 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1897 hBitmapDC = CreateCompatibleDC(0);
1898 SelectObject(hBitmapDC, hbitmap);
1900 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1901 /* Do not forget that windows bitmaps are bottom->top */
1902 TRACE("nRows=%d\n", nRows);
1903 for (i=0; i < nRows; i++){
1904 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1905 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1911 if (xdc) ReleaseDC(0,xdc);
1912 if (bmihc) LocalFree((HLOCAL)bmihc);
1913 if (hDIB) DeleteObject(hDIB);
1914 if (hBitmapDC) DeleteDC(hBitmapDC);
1917 DeleteObject(hbitmap);
1924 /*************************************************************************
1925 * ImageList_Read [COMCTL32.@]
1927 * Reads an image list from a stream.
1930 * pstm [I] pointer to a stream
1933 * Success: handle to image list
1936 * The format is like this:
1937 * ILHEAD ilheadstruct;
1939 * for the color image part:
1940 * BITMAPFILEHEADER bmfh;
1941 * BITMAPINFOHEADER bmih;
1942 * only if it has a palette:
1943 * RGBQUAD rgbs[nr_of_paletted_colors];
1945 * BYTE colorbits[imagesize];
1947 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1948 * BITMAPFILEHEADER bmfh_mask;
1949 * BITMAPINFOHEADER bmih_mask;
1950 * only if it has a palette (it usually does not):
1951 * RGBQUAD rgbs[nr_of_paletted_colors];
1953 * BYTE maskbits[imagesize];
1955 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1956 * _read_bitmap needs to convert them.
1958 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1962 HBITMAP hbmColor=0,hbmMask=0;
1965 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1967 if (ilHead.usMagic != (('L' << 8) | 'I'))
1969 if (ilHead.usVersion != 0x101) /* probably version? */
1973 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1974 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1975 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1976 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1977 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1978 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1979 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1980 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1981 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1982 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1985 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1988 if (ilHead.flags & ILC_MASK) {
1989 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1991 DeleteObject(hbmColor);
1996 himl = ImageList_Create (
2004 DeleteObject(hbmColor);
2005 DeleteObject(hbmMask);
2008 SelectObject(himl->hdcImage, hbmColor);
2009 DeleteObject(himl->hbmImage);
2010 himl->hbmImage = hbmColor;
2012 SelectObject(himl->hdcMask, hbmMask);
2013 DeleteObject(himl->hbmMask);
2014 himl->hbmMask = hbmMask;
2016 himl->cCurImage = ilHead.cCurImage;
2017 himl->cMaxImage = ilHead.cMaxImage;
2019 ImageList_SetBkColor(himl,ilHead.bkcolor);
2021 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2026 /*************************************************************************
2027 * ImageList_Remove [COMCTL32.@]
2029 * Removes an image from an image list
2032 * himl [I] image list handle
2041 ImageList_Remove (HIMAGELIST himl, INT i)
2043 HBITMAP hbmNewImage, hbmNewMask;
2047 TRACE("(himl=%p i=%d)\n", himl, i);
2049 if (!is_valid(himl)) {
2050 ERR("Invalid image list handle!\n");
2054 if ((i < -1) || (i >= himl->cCurImage)) {
2055 TRACE("index out of range! %d\n", i);
2061 if (himl->cCurImage == 0) {
2062 /* remove all on empty ImageList is allowed */
2063 TRACE("remove all on empty ImageList!\n");
2067 himl->cMaxImage = himl->cInitial + himl->cGrow;
2068 himl->cCurImage = 0;
2069 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2070 himl->nOvlIdx[nCount] = -1;
2072 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2073 SelectObject (himl->hdcImage, hbmNewImage);
2074 DeleteObject (himl->hbmImage);
2075 himl->hbmImage = hbmNewImage;
2077 if (himl->hbmMask) {
2078 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2080 SelectObject (himl->hdcMask, hbmNewMask);
2081 DeleteObject (himl->hbmMask);
2082 himl->hbmMask = hbmNewMask;
2086 /* delete one image */
2087 TRACE("Remove single image! %d\n", i);
2089 /* create new bitmap(s) */
2090 nCount = (himl->cCurImage + himl->cGrow - 1);
2091 cxNew = nCount * himl->cx;
2093 TRACE(" - Number of images: %d / %d (Old/New)\n",
2094 himl->cCurImage, himl->cCurImage - 1);
2095 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2096 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2098 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy);
2101 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2103 hbmNewMask = 0; /* Just to keep compiler happy! */
2105 hdcBmp = CreateCompatibleDC (0);
2107 /* copy all images and masks prior to the "removed" image */
2109 TRACE("Pre image copy: Copy %d images\n", i);
2111 SelectObject (hdcBmp, hbmNewImage);
2112 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2113 himl->hdcImage, 0, 0, SRCCOPY);
2115 if (himl->hbmMask) {
2116 SelectObject (hdcBmp, hbmNewMask);
2117 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2118 himl->hdcMask, 0, 0, SRCCOPY);
2122 /* copy all images and masks behind the removed image */
2123 if (i < himl->cCurImage - 1) {
2124 TRACE("Post image copy!\n");
2125 SelectObject (hdcBmp, hbmNewImage);
2126 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2127 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2129 if (himl->hbmMask) {
2130 SelectObject (hdcBmp, hbmNewMask);
2131 BitBlt (hdcBmp, i * himl->cx, 0,
2132 (himl->cCurImage - i - 1) * himl->cx,
2133 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2139 /* delete old images and insert new ones */
2140 SelectObject (himl->hdcImage, hbmNewImage);
2141 DeleteObject (himl->hbmImage);
2142 himl->hbmImage = hbmNewImage;
2143 if (himl->hbmMask) {
2144 SelectObject (himl->hdcMask, hbmNewMask);
2145 DeleteObject (himl->hbmMask);
2146 himl->hbmMask = hbmNewMask;
2150 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2157 /*************************************************************************
2158 * ImageList_Replace [COMCTL32.@]
2160 * Replaces an image in an image list with a new image.
2163 * himl [I] handle to image list
2165 * hbmImage [I] handle to image bitmap
2166 * hbmMask [I] handle to mask bitmap. Can be NULL.
2174 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2180 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2182 if (!is_valid(himl)) {
2183 ERR("Invalid image list handle!\n");
2187 if ((i >= himl->cMaxImage) || (i < 0)) {
2188 ERR("Invalid image index!\n");
2192 hdcImage = CreateCompatibleDC (0);
2193 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2196 SelectObject (hdcImage, hbmImage);
2198 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2199 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2204 SelectObject (hdcImage, hbmMask);
2206 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2207 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2210 /* Remove the background from the image
2212 StretchBlt (himl->hdcImage,
2213 i*himl->cx, 0, himl->cx, himl->cy,
2215 0, 0, bmp.bmWidth, bmp.bmHeight,
2216 0x220326); /* NOTSRCAND */
2219 DeleteDC (hdcImage);
2225 /*************************************************************************
2226 * ImageList_ReplaceIcon [COMCTL32.@]
2228 * Replaces an image in an image list using an icon.
2231 * himl [I] handle to image list
2233 * hIcon [I] handle to icon
2236 * Success: index of the replaced image
2241 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2250 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2252 if (!is_valid(himl))
2254 if ((i >= himl->cMaxImage) || (i < -1))
2257 hBestFitIcon = CopyImage(
2260 LR_COPYFROMRESOURCE);
2262 GetIconInfo (hBestFitIcon, &ii);
2263 if (ii.hbmMask == 0)
2265 if (ii.hbmColor == 0)
2267 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2270 if (himl->cCurImage + 1 > himl->cMaxImage)
2271 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2273 nIndex = himl->cCurImage;
2279 hdcImage = CreateCompatibleDC (0);
2280 TRACE("hdcImage=%p\n", hdcImage);
2282 ERR("invalid hdcImage!\n");
2284 SetTextColor(himl->hdcImage, RGB(0,0,0));
2285 SetBkColor (himl->hdcImage, RGB(255,255,255));
2286 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2288 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2289 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2291 if (himl->hbmMask) {
2292 SelectObject (hdcImage, ii.hbmMask);
2293 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2294 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2297 SelectObject (hdcImage, hbmOldSrc);
2300 DestroyIcon(hBestFitIcon);
2302 DeleteDC (hdcImage);
2304 DeleteObject (ii.hbmColor);
2306 DeleteObject (ii.hbmMask);
2312 /*************************************************************************
2313 * ImageList_SetBkColor [COMCTL32.@]
2315 * Sets the background color of an image list.
2318 * himl [I] handle to image list
2319 * clrBk [I] background color
2322 * Success: previous background color
2327 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2331 if (!is_valid(himl))
2334 clrOldBk = himl->clrBk;
2335 himl->clrBk = clrBk;
2340 /*************************************************************************
2341 * ImageList_SetDragCursorImage [COMCTL32.@]
2343 * Combines the specified image with the current drag image
2346 * himlDrag [I] handle to drag image list
2347 * iDrag [I] drag image index
2348 * dxHotspot [I] X position of the hot spot
2349 * dyHotspot [I] Y position of the hot spot
2356 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2357 * to do with a hotspot but are only the offset of the origin of the new
2358 * image relative to the origin of the old image.
2360 * - When this function is called and the drag image is visible, a
2361 * short flickering occurs but this matches the Win9x behavior. It is
2362 * possible to fix the flickering using code like in ImageList_DragMove.
2366 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2367 INT dxHotspot, INT dyHotspot)
2369 HIMAGELIST himlTemp;
2372 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2375 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2376 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2378 visible = InternalDrag.bShow;
2380 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2381 dxHotspot, dyHotspot);
2384 /* hide the drag image */
2385 ImageList_DragShowNolock(FALSE);
2387 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2388 (InternalDrag.himl->cy != himlTemp->cy)) {
2389 /* the size of the drag image changed, invalidate the buffer */
2390 DeleteObject(InternalDrag.hbmBg);
2391 InternalDrag.hbmBg = 0;
2394 ImageList_Destroy (InternalDrag.himl);
2395 InternalDrag.himl = himlTemp;
2398 /* show the drag image */
2399 ImageList_DragShowNolock(TRUE);
2406 /*************************************************************************
2407 * ImageList_SetFilter [COMCTL32.@]
2409 * Sets a filter (or does something completely different)!!???
2410 * It removes 12 Bytes from the stack (3 Parameters).
2413 * himl [I] SHOULD be a handle to image list
2414 * i [I] COULD be an index?
2419 * Failure: FALSE ???
2422 * This is an UNDOCUMENTED function!!!!
2427 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2429 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2435 /*************************************************************************
2436 * ImageList_SetFlags [COMCTL32.@]
2438 * Sets the image list flags.
2441 * himl [I] Handle to image list
2442 * flags [I] Flags to set
2452 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2454 FIXME("(%p %08lx):empty stub\n", himl, flags);
2459 /*************************************************************************
2460 * ImageList_SetIconSize [COMCTL32.@]
2462 * Sets the image size of the bitmap and deletes all images.
2465 * himl [I] handle to image list
2466 * cx [I] image width
2467 * cy [I] image height
2475 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2480 if (!is_valid(himl))
2483 /* remove all images */
2484 himl->cMaxImage = himl->cInitial + himl->cGrow;
2485 himl->cCurImage = 0;
2489 /* initialize overlay mask indices */
2490 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2491 himl->nOvlIdx[nCount] = -1;
2493 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2494 SelectObject (himl->hdcImage, hbmNew);
2495 DeleteObject (himl->hbmImage);
2496 himl->hbmImage = hbmNew;
2498 if (himl->hbmMask) {
2499 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2501 SelectObject (himl->hdcMask, hbmNew);
2502 DeleteObject (himl->hbmMask);
2503 himl->hbmMask = hbmNew;
2510 /*************************************************************************
2511 * ImageList_SetImageCount [COMCTL32.@]
2513 * Resizes an image list to the specified number of images.
2516 * himl [I] handle to image list
2517 * iImageCount [I] number of images in the image list
2525 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2528 HBITMAP hbmNewBitmap;
2529 INT nNewCount, nCopyCount;
2531 TRACE("%p %d\n",himl,iImageCount);
2533 if (!is_valid(himl))
2535 if (himl->cCurImage >= iImageCount)
2537 if (himl->cMaxImage > iImageCount)
2539 himl->cCurImage = iImageCount;
2543 nNewCount = iImageCount + himl->cGrow;
2544 nCopyCount = min(himl->cCurImage, iImageCount);
2546 hdcBitmap = CreateCompatibleDC (0);
2548 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy);
2550 if (hbmNewBitmap != 0)
2552 SelectObject (hdcBitmap, hbmNewBitmap);
2555 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2556 himl->hdcImage, 0, 0, SRCCOPY);
2558 /* delete 'empty' image space */
2559 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2560 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2561 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2562 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2564 SelectObject (himl->hdcImage, hbmNewBitmap);
2565 DeleteObject (himl->hbmImage);
2566 himl->hbmImage = hbmNewBitmap;
2569 ERR("Could not create new image bitmap !\n");
2573 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2575 if (hbmNewBitmap != 0)
2577 SelectObject (hdcBitmap, hbmNewBitmap);
2580 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2581 himl->hdcMask, 0, 0, SRCCOPY);
2583 /* delete 'empty' image space */
2584 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2585 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2586 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2587 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2589 SelectObject (himl->hdcMask, hbmNewBitmap);
2590 DeleteObject (himl->hbmMask);
2591 himl->hbmMask = hbmNewBitmap;
2594 ERR("Could not create new mask bitmap!\n");
2597 DeleteDC (hdcBitmap);
2599 /* Update max image count and current image count */
2600 himl->cMaxImage = nNewCount;
2601 himl->cCurImage = iImageCount;
2607 /*************************************************************************
2608 * ImageList_SetOverlayImage [COMCTL32.@]
2610 * Assigns an overlay mask index to an existing image in an image list.
2613 * himl [I] handle to image list
2614 * iImage [I] image index
2615 * iOverlay [I] overlay mask index
2623 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2625 if (!is_valid(himl))
2627 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2629 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2631 himl->nOvlIdx[iOverlay - 1] = iImage;
2637 /* helper for ImageList_Write - write bitmap to pstm
2638 * currently everything is written as 24 bit RGB, except masks
2641 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2643 LPBITMAPFILEHEADER bmfh;
2644 LPBITMAPINFOHEADER bmih;
2645 LPBYTE data, lpBits, lpBitsOrg;
2647 INT bitCount, sizeImage, offBits, totalSize;
2648 INT nwidth, nheight, nsizeImage, icount;
2650 BOOL result = FALSE;
2654 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2656 /* XXX is this always correct? */
2657 icount = bm.bmWidth / cx;
2659 nheight = cy * icount;
2661 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2662 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2663 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2665 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2667 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2668 offBits = totalSize;
2669 totalSize += nsizeImage;
2671 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2672 bmfh = (LPBITMAPFILEHEADER)data;
2673 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2674 lpBits = data + offBits;
2676 /* setup BITMAPFILEHEADER */
2677 bmfh->bfType = (('M' << 8) | 'B');
2679 bmfh->bfReserved1 = 0;
2680 bmfh->bfReserved2 = 0;
2681 bmfh->bfOffBits = offBits;
2683 /* setup BITMAPINFOHEADER */
2684 bmih->biSize = sizeof(BITMAPINFOHEADER);
2685 bmih->biWidth = bm.bmWidth;
2686 bmih->biHeight = bm.bmHeight;
2688 bmih->biBitCount = bitCount;
2689 bmih->biCompression = BI_RGB;
2690 bmih->biSizeImage = sizeImage;
2691 bmih->biXPelsPerMeter = 0;
2692 bmih->biYPelsPerMeter = 0;
2693 bmih->biClrUsed = 0;
2694 bmih->biClrImportant = 0;
2696 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2697 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2698 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2702 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2703 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2705 for(i = 0; i < nheight; i++) {
2706 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2707 int noff = (nbpl * (nheight-1-i));
2708 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2712 bmih->biWidth = nwidth;
2713 bmih->biHeight = nheight;
2714 bmih->biSizeImage = nsizeImage;
2718 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2719 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2720 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2723 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2730 LocalFree((HLOCAL)lpBitsOrg);
2736 /*************************************************************************
2737 * ImageList_Write [COMCTL32.@]
2739 * Writes an image list to a stream.
2742 * himl [I] handle to image list
2743 * pstm [O] Pointer to a stream.
2754 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2759 if (!is_valid(himl))
2762 ilHead.usMagic = (('L' << 8) | 'I');
2763 ilHead.usVersion = 0x101;
2764 ilHead.cCurImage = himl->cCurImage;
2765 ilHead.cMaxImage = himl->cMaxImage;
2766 ilHead.cGrow = himl->cGrow;
2767 ilHead.cx = himl->cx;
2768 ilHead.cy = himl->cy;
2769 ilHead.bkcolor = himl->clrBk;
2770 ilHead.flags = himl->flags;
2771 for(i = 0; i < 4; i++) {
2772 ilHead.ovls[i] = himl->nOvlIdx[i];
2775 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2778 /* write the bitmap */
2779 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2782 /* write the mask if we have one */
2783 if(himl->flags & ILC_MASK) {
2784 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2792 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height)
2794 HBITMAP hbmNewBitmap;
2795 UINT ilc = (himl->flags & 0xFE);
2797 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2802 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2804 if (himl->uBitsPixel <= ILC_COLOR8)
2810 colors = 1 << himl->uBitsPixel;
2811 bmi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) +
2812 sizeof(PALETTEENTRY) * colors);
2814 pal = (LPPALETTEENTRY)bmi->bmiColors;
2815 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2817 /* Swap colors returned by GetPaletteEntries so we can use them for
2818 * CreateDIBSection call. */
2819 for (i = 0; i < colors; i++)
2821 temp = pal[i].peBlue;
2822 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2823 bmi->bmiColors[i].rgbBlue = temp;
2828 bmi = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER));
2831 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2832 bmi->bmiHeader.biWidth = width;
2833 bmi->bmiHeader.biHeight = height;
2834 bmi->bmiHeader.biPlanes = 1;
2835 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2836 bmi->bmiHeader.biCompression = BI_RGB;
2837 bmi->bmiHeader.biSizeImage = 0;
2838 bmi->bmiHeader.biXPelsPerMeter = 0;
2839 bmi->bmiHeader.biYPelsPerMeter = 0;
2840 bmi->bmiHeader.biClrUsed = 0;
2841 bmi->bmiHeader.biClrImportant = 0;
2843 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2845 HeapFree(GetProcessHeap(), 0, bmi);
2847 else /*if (ilc == ILC_COLORDDB)*/
2849 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2851 hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL);
2854 return hbmNewBitmap;