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
53 #include "imagelist.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
59 #define MAX_OVERLAYIMAGE 15
61 /* internal image list data used for Drag & Drop operations */
66 /* position of the drag image relative to the window */
69 /* offset of the hotspot relative to the origin of the image */
72 /* is the drag image visible */
74 /* saved background */
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
82 static inline BOOL is_valid(HIMAGELIST himl)
84 return himl && himl->magic == IMAGELIST_MAGIC;
88 /*************************************************************************
89 * IMAGELIST_InternalExpandBitmaps [Internal]
91 * Expands the bitmaps of an image list by the given number of images.
94 * himl [I] handle to image list
95 * nImageCount [I] number of images to add
101 * This function CANNOT be used to reduce the number of images.
104 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
107 HBITMAP hbmNewBitmap, hbmNull;
108 INT nNewWidth, nNewCount;
110 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
114 if (cy == 0) cy = himl->cy;
115 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
116 nNewWidth = nNewCount * himl->cx;
118 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
119 hdcBitmap = CreateCompatibleDC (0);
121 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
123 if (hbmNewBitmap == 0)
124 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
128 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
129 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
130 himl->hdcImage, 0, 0, SRCCOPY);
131 SelectObject (hdcBitmap, hbmNull);
133 SelectObject (himl->hdcImage, hbmNewBitmap);
134 DeleteObject (himl->hbmImage);
135 himl->hbmImage = hbmNewBitmap;
137 if (himl->flags & ILC_MASK)
139 hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
141 if (hbmNewBitmap == 0)
142 ERR("creating new mask bitmap!\n");
146 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
147 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
148 himl->hdcMask, 0, 0, SRCCOPY);
149 SelectObject (hdcBitmap, hbmNull);
151 SelectObject (himl->hdcMask, hbmNewBitmap);
152 DeleteObject (himl->hbmMask);
153 himl->hbmMask = hbmNewBitmap;
156 himl->cMaxImage = nNewCount;
158 DeleteDC (hdcBitmap);
162 /*************************************************************************
163 * ImageList_Add [COMCTL32.@]
165 * Add an image or images to an image list.
168 * himl [I] handle to image list
169 * hbmImage [I] handle to image bitmap
170 * hbmMask [I] handle to mask bitmap
173 * Success: Index of the first new image.
178 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
181 INT nFirstIndex, nImageCount;
186 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
190 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
191 nImageCount = bmp.bmWidth / himl->cx;
193 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
195 nStartX = himl->cCurImage * himl->cx;
197 hdcBitmap = CreateCompatibleDC(0);
199 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
201 /* Copy result to the imagelist
203 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
204 hdcBitmap, 0, 0, SRCCOPY);
209 HBITMAP hOldBitmapTemp;
211 hdcTemp = CreateCompatibleDC(0);
212 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
214 BitBlt (himl->hdcMask,
215 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
220 SelectObject(hdcTemp, hOldBitmapTemp);
223 /* Remove the background from the image
225 BitBlt (himl->hdcImage,
226 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
229 0x220326); /* NOTSRCAND */
232 SelectObject(hdcBitmap, hOldBitmap);
235 nFirstIndex = himl->cCurImage;
236 himl->cCurImage += nImageCount;
242 /*************************************************************************
243 * ImageList_AddIcon [COMCTL32.@]
245 * Adds an icon to an image list.
248 * himl [I] handle to image list
249 * hIcon [I] handle to icon
252 * Success: index of the new image
255 #undef ImageList_AddIcon
256 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
258 return ImageList_ReplaceIcon (himl, -1, hIcon);
262 /*************************************************************************
263 * ImageList_AddMasked [COMCTL32.@]
265 * Adds an image or images to an image list and creates a mask from the
266 * specified bitmap using the mask color.
269 * himl [I] handle to image list.
270 * hBitmap [I] handle to bitmap
271 * clrMask [I] mask color.
274 * Success: Index of the first new image.
279 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
281 HDC hdcMask, hdcBitmap;
282 INT nIndex, nImageCount, nMaskXOffset=0;
285 HBITMAP hMaskBitmap=0;
288 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
292 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
296 nImageCount = bmp.bmWidth / himl->cx;
300 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
302 nIndex = himl->cCurImage;
303 himl->cCurImage += nImageCount;
305 hdcBitmap = CreateCompatibleDC(0);
308 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
311 hdcMask = himl->hdcMask;
312 nMaskXOffset = nIndex * himl->cx;
317 Create a temp Mask so we can remove the background of
318 the Image (Windows does this even if there is no mask)
320 hdcMask = CreateCompatibleDC(0);
321 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
322 SelectObject(hdcMask, hMaskBitmap);
325 /* create monochrome image to the mask bitmap */
326 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
327 GetPixel (hdcBitmap, 0, 0);
328 SetBkColor (hdcBitmap, bkColor);
330 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
334 SetBkColor(hdcBitmap, RGB(255,255,255));
335 /*Remove the background from the image
338 WINDOWS BUG ALERT!!!!!!
339 The statement below should not be done in common practice
340 but this is how ImageList_AddMasked works in Windows.
341 It overwrites the original bitmap passed, this was discovered
342 by using the same bitmap to iterate the different styles
343 on windows where it failed (BUT ImageList_Add is OK)
344 This is here in case some apps rely on this bug
347 0, 0, bmp.bmWidth, bmp.bmHeight,
350 0x220326); /* NOTSRCAND */
351 /* Copy result to the imagelist
353 BitBlt (himl->hdcImage,
354 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
360 SelectObject(hdcBitmap, hOldBitmap);
364 DeleteObject(hMaskBitmap);
372 /*************************************************************************
373 * ImageList_BeginDrag [COMCTL32.@]
375 * Creates a temporary image list that contains one image. It will be used
379 * himlTrack [I] handle to the source image list
380 * iTrack [I] index of the drag image in the source image list
381 * dxHotspot [I] X position of the hot spot of the drag image
382 * dyHotspot [I] Y position of the hot spot of the drag image
390 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
391 INT dxHotspot, INT dyHotspot)
395 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
396 dxHotspot, dyHotspot);
398 if (!is_valid(himlTrack))
401 if (InternalDrag.himl)
402 ImageList_EndDrag ();
407 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
408 if (InternalDrag.himl == NULL) {
409 WARN("Error creating drag image list!\n");
413 InternalDrag.dxHotspot = dxHotspot;
414 InternalDrag.dyHotspot = dyHotspot;
417 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
420 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
422 InternalDrag.himl->cCurImage = 1;
428 /*************************************************************************
429 * ImageList_Copy [COMCTL32.@]
431 * Copies an image of the source image list to an image of the
432 * destination image list. Images can be copied or swapped.
435 * himlDst [I] handle to the destination image list
436 * iDst [I] destination image index.
437 * himlSrc [I] handle to the source image list
438 * iSrc [I] source image index
439 * uFlags [I] flags for the copy operation
446 * Copying from one image list to another is possible. The original
447 * implementation just copies or swaps within one image list.
448 * Could this feature become a bug??? ;-)
452 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
453 INT iSrc, UINT uFlags)
455 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
457 if (!is_valid(himlSrc) || !is_valid(himlDst))
459 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
461 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
464 if (uFlags & ILCF_SWAP) {
467 HBITMAP hbmTempImage, hbmTempMask;
469 hdcBmp = CreateCompatibleDC (0);
471 /* create temporary bitmaps */
472 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
473 himlSrc->uBitsPixel, NULL);
474 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
477 /* copy (and stretch) destination to temporary bitmaps.(save) */
479 SelectObject (hdcBmp, hbmTempImage);
480 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
481 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
484 SelectObject (hdcBmp, hbmTempMask);
485 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
486 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
489 /* copy (and stretch) source to destination */
491 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
492 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
495 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
496 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
499 /* copy (without stretching) temporary bitmaps to source (restore) */
501 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
502 hdcBmp, 0, 0, SRCCOPY);
505 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
506 hdcBmp, 0, 0, SRCCOPY);
507 /* delete temporary bitmaps */
508 DeleteObject (hbmTempMask);
509 DeleteObject (hbmTempImage);
514 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
515 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
519 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
520 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
528 /*************************************************************************
529 * ImageList_Create [COMCTL32.@]
531 * Creates a new image list.
534 * cx [I] image height
536 * flags [I] creation flags
537 * cInitial [I] initial number of images in the image list
538 * cGrow [I] number of images by which image list grows
541 * Success: Handle to the created image list
545 ImageList_Create (INT cx, INT cy, UINT flags,
546 INT cInitial, INT cGrow)
551 UINT ilc = (flags & 0xFE);
552 static const WORD aBitBlend25[] =
553 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
555 static const WORD aBitBlend50[] =
556 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
558 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
560 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
564 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
566 himl->magic = IMAGELIST_MAGIC;
570 himl->cMaxImage = cInitial + cGrow;
571 himl->cInitial = cInitial;
573 himl->clrFg = CLR_DEFAULT;
574 himl->clrBk = CLR_NONE;
576 /* initialize overlay mask indices */
577 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
578 himl->nOvlIdx[nCount] = -1;
580 /* Create Image & Mask DCs */
581 himl->hdcImage = CreateCompatibleDC (0);
584 if (himl->flags & ILC_MASK){
585 himl->hdcMask = CreateCompatibleDC(0);
590 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
591 if (ilc == ILC_COLOR)
594 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
595 himl->uBitsPixel = ilc;
597 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
599 if (himl->cMaxImage > 0) {
600 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy);
601 SelectObject(himl->hdcImage, himl->hbmImage);
605 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
607 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
609 if (himl->hbmMask == 0) {
610 ERR("Error creating mask bitmap!\n");
613 SelectObject(himl->hdcMask, himl->hbmMask);
618 /* create blending brushes */
619 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
620 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
621 DeleteObject (hbmTemp);
623 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
624 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
625 DeleteObject (hbmTemp);
627 TRACE("created imagelist %p\n", himl);
631 if (himl) ImageList_Destroy(himl);
636 /*************************************************************************
637 * ImageList_Destroy [COMCTL32.@]
639 * Destroys an image list.
642 * himl [I] handle to image list
650 ImageList_Destroy (HIMAGELIST himl)
655 /* delete image bitmaps */
657 DeleteObject (himl->hbmImage);
659 DeleteObject (himl->hbmMask);
661 /* delete image & mask DCs */
663 DeleteDC(himl->hdcImage);
665 DeleteDC(himl->hdcMask);
667 /* delete blending brushes */
668 if (himl->hbrBlend25)
669 DeleteObject (himl->hbrBlend25);
670 if (himl->hbrBlend50)
671 DeleteObject (himl->hbrBlend50);
673 ZeroMemory(himl, sizeof(*himl));
680 /*************************************************************************
681 * ImageList_DragEnter [COMCTL32.@]
683 * Locks window update and displays the drag image at the given position.
686 * hwndLock [I] handle of the window that owns the drag image.
687 * x [I] X position of the drag image.
688 * y [I] Y position of the drag image.
695 * The position of the drag image is relative to the window, not
700 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
702 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
704 if (!is_valid(InternalDrag.himl))
708 InternalDrag.hwnd = hwndLock;
710 InternalDrag.hwnd = GetDesktopWindow ();
715 /* draw the drag image and save the background */
716 if (!ImageList_DragShowNolock(TRUE)) {
724 /*************************************************************************
725 * ImageList_DragLeave [COMCTL32.@]
727 * Unlocks window update and hides the drag image.
730 * hwndLock [I] handle of the window that owns the drag image.
738 ImageList_DragLeave (HWND hwndLock)
740 /* As we don't save drag info in the window this can lead to problems if
741 an app does not supply the same window as DragEnter */
743 InternalDrag.hwnd = hwndLock;
745 InternalDrag.hwnd = GetDesktopWindow (); */
747 hwndLock = GetDesktopWindow();
748 if(InternalDrag.hwnd != hwndLock)
749 FIXME("DragLeave hWnd != DragEnter hWnd\n");
751 ImageList_DragShowNolock (FALSE);
757 /*************************************************************************
758 * ImageList_InternalDragDraw [Internal]
760 * Draws the drag image.
763 * hdc [I] device context to draw into.
764 * x [I] X position of the drag image.
765 * y [I] Y position of the drag image.
772 * The position of the drag image is relative to the window, not
778 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
780 IMAGELISTDRAWPARAMS imldp;
782 ZeroMemory (&imldp, sizeof(imldp));
783 imldp.cbSize = sizeof(imldp);
784 imldp.himl = InternalDrag.himl;
789 imldp.rgbBk = CLR_DEFAULT;
790 imldp.rgbFg = CLR_DEFAULT;
791 imldp.fStyle = ILD_NORMAL;
792 imldp.fState = ILS_ALPHA;
795 /* FIXME: instead of using the alpha blending, we should
796 * create a 50% mask, and draw it semitransparantly that way */
797 ImageList_DrawIndirect (&imldp);
800 /*************************************************************************
801 * ImageList_DragMove [COMCTL32.@]
803 * Moves the drag image.
806 * x [I] X position of the drag image.
807 * y [I] Y position of the drag image.
814 * The position of the drag image is relative to the window, not
818 * The drag image should be drawn semitransparent.
822 ImageList_DragMove (INT x, INT y)
824 TRACE("(x=%d y=%d)\n", x, y);
826 if (!is_valid(InternalDrag.himl))
829 /* draw/update the drag image */
830 if (InternalDrag.bShow) {
834 HBITMAP hbmOffScreen;
835 INT origNewX, origNewY;
836 INT origOldX, origOldY;
837 INT origRegX, origRegY;
838 INT sizeRegX, sizeRegY;
841 /* calculate the update region */
842 origNewX = x - InternalDrag.dxHotspot;
843 origNewY = y - InternalDrag.dyHotspot;
844 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
845 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
846 origRegX = min(origNewX, origOldX);
847 origRegY = min(origNewY, origOldY);
848 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
849 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
851 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
852 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
853 hdcOffScreen = CreateCompatibleDC(hdcDrag);
854 hdcBg = CreateCompatibleDC(hdcDrag);
856 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
857 SelectObject(hdcOffScreen, hbmOffScreen);
858 SelectObject(hdcBg, InternalDrag.hbmBg);
860 /* get the actual background of the update region */
861 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
862 origRegX, origRegY, SRCCOPY);
863 /* erase the old image */
864 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
865 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
867 /* save the background */
868 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
869 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
871 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
872 origNewY - origRegY);
873 /* draw the update region to the screen */
874 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
875 hdcOffScreen, 0, 0, SRCCOPY);
878 DeleteDC(hdcOffScreen);
879 DeleteObject(hbmOffScreen);
880 ReleaseDC(InternalDrag.hwnd, hdcDrag);
883 /* update the image position */
891 /*************************************************************************
892 * ImageList_DragShowNolock [COMCTL32.@]
894 * Shows or hides the drag image.
897 * bShow [I] TRUE shows the drag image, FALSE hides it.
904 * The drag image should be drawn semitransparent.
908 ImageList_DragShowNolock (BOOL bShow)
914 if (!is_valid(InternalDrag.himl))
917 TRACE("bShow=0x%X!\n", bShow);
919 /* DragImage is already visible/hidden */
920 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
924 /* position of the origin of the DragImage */
925 x = InternalDrag.x - InternalDrag.dxHotspot;
926 y = InternalDrag.y - InternalDrag.dyHotspot;
928 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
929 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
934 hdcBg = CreateCompatibleDC(hdcDrag);
935 if (!InternalDrag.hbmBg) {
936 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
937 InternalDrag.himl->cx, InternalDrag.himl->cy);
939 SelectObject(hdcBg, InternalDrag.hbmBg);
942 /* save the background */
943 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
944 hdcDrag, x, y, SRCCOPY);
946 ImageList_InternalDragDraw(hdcDrag, x, y);
949 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
950 hdcBg, 0, 0, SRCCOPY);
953 InternalDrag.bShow = !InternalDrag.bShow;
956 ReleaseDC (InternalDrag.hwnd, hdcDrag);
961 /*************************************************************************
962 * ImageList_Draw [COMCTL32.@]
967 * himl [I] handle to image list
969 * hdc [I] handle to device context
972 * fStyle [I] drawing flags
983 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
985 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
986 CLR_DEFAULT, CLR_DEFAULT, fStyle);
990 /*************************************************************************
991 * ImageList_DrawEx [COMCTL32.@]
993 * Draws an image and allows to use extended drawing features.
996 * himl [I] handle to image list
998 * hdc [I] handle to device context
1003 * rgbBk [I] background color
1004 * rgbFg [I] foreground color
1005 * fStyle [I] drawing flags
1012 * Calls ImageList_DrawIndirect.
1015 * ImageList_DrawIndirect.
1019 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1020 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1023 IMAGELISTDRAWPARAMS imldp;
1025 ZeroMemory (&imldp, sizeof(imldp));
1026 imldp.cbSize = sizeof(imldp);
1034 imldp.rgbBk = rgbBk;
1035 imldp.rgbFg = rgbFg;
1036 imldp.fStyle = fStyle;
1038 return ImageList_DrawIndirect (&imldp);
1042 /*************************************************************************
1043 * ImageList_DrawIndirect [COMCTL32.@]
1045 * Draws an image using various parameters specified in pimldp.
1048 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1056 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1058 INT cx, cy, lx, ly, nOvlIdx;
1059 DWORD fState, dwRop;
1061 COLORREF oldImageBk, oldImageFg;
1062 HDC hImageDC, hImageListDC, hMaskListDC;
1063 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1064 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1067 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1068 if (!is_valid(himl)) return FALSE;
1069 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1071 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1072 ly = pimldp->yBitmap;
1074 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1075 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1076 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1077 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1079 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1080 if( pimldp->rgbBk == CLR_NONE )
1081 bIsTransparent = TRUE;
1082 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1083 bIsTransparent = TRUE;
1084 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1085 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1087 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1088 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1090 /* we will use these DCs to access the images and masks in the ImageList */
1091 hImageListDC = himl->hdcImage;
1092 hMaskListDC = himl->hdcMask;
1094 /* these will accumulate the image and mask for the image we're drawing */
1095 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1096 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1097 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1099 /* Create a compatible DC. */
1100 if (!hImageListDC || !hImageDC || !hImageBmp ||
1101 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1104 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1107 * To obtain a transparent look, background color should be set
1108 * to white and foreground color to black when blting the
1111 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1112 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1115 * Draw the initial image
1118 if (himl->hbmMask) {
1120 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1121 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1122 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCPAINT);
1123 DeleteObject (SelectObject (hImageDC, hOldBrush));
1124 if( bIsTransparent )
1126 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1131 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1132 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1133 SelectObject(hImageDC, hOldBrush);
1136 /* blend the image with the needed solid background */
1137 COLORREF colour = RGB(0,0,0);
1140 if( !bIsTransparent )
1142 colour = pimldp->rgbBk;
1143 if( colour == CLR_DEFAULT )
1144 colour = himl->clrBk;
1145 if( colour == CLR_NONE )
1146 colour = GetBkColor(pimldp->hdcDst);
1149 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1150 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1151 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1152 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1153 DeleteObject (SelectObject (hImageDC, hOldBrush));
1156 /* Time for blending, if required */
1158 HBRUSH hBlendBrush, hOldBrush;
1159 COLORREF clrBlend = pimldp->rgbFg;
1160 HDC hBlendMaskDC = hImageListDC;
1163 /* Create the blend Mask */
1164 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1165 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1166 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1167 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1168 SelectObject(hBlendMaskDC, hOldBrush);
1170 /* Modify the blend mask if an Image Mask exist */
1172 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1173 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1176 /* now apply blend to the current image given the BlendMask */
1177 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1178 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1179 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1180 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1181 DeleteObject(SelectObject(hImageDC, hOldBrush));
1182 SelectObject(hBlendMaskDC, hOldBitmap);
1185 /* Now do the overlay image, if any */
1186 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1187 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1188 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1189 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1190 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1191 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1192 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1193 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1197 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1198 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1199 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1200 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1202 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1203 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1204 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1206 /* now copy the image to the screen */
1208 if (himl->hbmMask && bIsTransparent ) {
1209 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1210 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1211 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1212 SetBkColor(pimldp->hdcDst, oldDstBk);
1213 SetTextColor(pimldp->hdcDst, oldDstFg);
1216 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1217 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1221 /* cleanup the mess */
1222 SetBkColor(hImageDC, oldImageBk);
1223 SetTextColor(hImageDC, oldImageFg);
1224 SelectObject(hImageDC, hOldImageBmp);
1226 DeleteObject(hBlendMaskBmp);
1227 DeleteObject(hImageBmp);
1234 /*************************************************************************
1235 * ImageList_Duplicate [COMCTL32.@]
1237 * Duplicates an image list.
1240 * himlSrc [I] source image list handle
1243 * Success: Handle of duplicated image list.
1248 ImageList_Duplicate (HIMAGELIST himlSrc)
1252 if (!is_valid(himlSrc)) {
1253 ERR("Invalid image list handle!\n");
1257 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1258 himlSrc->cInitial, himlSrc->cGrow);
1262 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1263 himlSrc->hdcImage, 0, 0, SRCCOPY);
1265 if (himlDst->hbmMask)
1266 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1267 himlSrc->hdcMask, 0, 0, SRCCOPY);
1269 himlDst->cCurImage = himlSrc->cCurImage;
1270 himlDst->cMaxImage = himlSrc->cMaxImage;
1276 /*************************************************************************
1277 * ImageList_EndDrag [COMCTL32.@]
1279 * Finishes a drag operation.
1290 ImageList_EndDrag (void)
1292 /* cleanup the InternalDrag struct */
1293 InternalDrag.hwnd = 0;
1294 ImageList_Destroy (InternalDrag.himl);
1295 InternalDrag.himl = 0;
1298 InternalDrag.dxHotspot = 0;
1299 InternalDrag.dyHotspot = 0;
1300 InternalDrag.bShow = FALSE;
1301 DeleteObject(InternalDrag.hbmBg);
1302 InternalDrag.hbmBg = 0;
1306 /*************************************************************************
1307 * ImageList_GetBkColor [COMCTL32.@]
1309 * Returns the background color of an image list.
1312 * himl [I] Image list handle.
1315 * Success: background color
1320 ImageList_GetBkColor (HIMAGELIST himl)
1322 return himl ? himl->clrBk : CLR_NONE;
1326 /*************************************************************************
1327 * ImageList_GetDragImage [COMCTL32.@]
1329 * Returns the handle to the internal drag image list.
1332 * ppt [O] Pointer to the drag position. Can be NULL.
1333 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1336 * Success: Handle of the drag image list.
1341 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1343 if (is_valid(InternalDrag.himl)) {
1345 ppt->x = InternalDrag.x;
1346 ppt->y = InternalDrag.y;
1349 pptHotspot->x = InternalDrag.dxHotspot;
1350 pptHotspot->y = InternalDrag.dyHotspot;
1352 return (InternalDrag.himl);
1359 /*************************************************************************
1360 * ImageList_GetFlags [COMCTL32.@]
1362 * Gets the flags of the specified image list.
1365 * himl [I] Handle to image list
1375 ImageList_GetFlags(HIMAGELIST himl)
1377 FIXME("(%p):empty stub\n", himl);
1382 /*************************************************************************
1383 * ImageList_GetIcon [COMCTL32.@]
1385 * Creates an icon from a masked image of an image list.
1388 * himl [I] handle to image list
1390 * flags [I] drawing style flags
1393 * Success: icon handle
1398 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1402 HBITMAP hOldDstBitmap;
1405 TRACE("%p %d %d\n", himl, i, fStyle);
1406 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1412 /* create colour bitmap */
1414 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1415 ReleaseDC(0, hdcDst);
1417 hdcDst = CreateCompatibleDC(0);
1420 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1421 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1422 if (himl->hbmMask) {
1423 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1424 himl->hdcMask, i * himl->cx, 0, SRCCOPY);
1427 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1430 SelectObject (hdcDst, ii.hbmColor);
1431 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1432 himl->hdcImage, i * himl->cx, 0, SRCCOPY);
1435 * CreateIconIndirect requires us to deselect the bitmaps from
1436 * the DCs before calling
1438 SelectObject(hdcDst, hOldDstBitmap);
1440 hIcon = CreateIconIndirect (&ii);
1442 DeleteObject (ii.hbmMask);
1443 DeleteObject (ii.hbmColor);
1450 /*************************************************************************
1451 * ImageList_GetIconSize [COMCTL32.@]
1453 * Retrieves the size of an image in an image list.
1456 * himl [I] handle to image list
1457 * cx [O] pointer to the image width.
1458 * cy [O] pointer to the image height.
1465 * All images in an image list have the same size.
1469 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1471 if (!is_valid(himl))
1473 if ((himl->cx <= 0) || (himl->cy <= 0))
1485 /*************************************************************************
1486 * ImageList_GetImageCount [COMCTL32.@]
1488 * Returns the number of images in an image list.
1491 * himl [I] handle to image list
1494 * Success: Number of images.
1499 ImageList_GetImageCount (HIMAGELIST himl)
1501 if (!is_valid(himl))
1504 return himl->cCurImage;
1508 /*************************************************************************
1509 * ImageList_GetImageInfo [COMCTL32.@]
1511 * Returns information about an image in an image list.
1514 * himl [I] handle to image list
1516 * pImageInfo [O] pointer to the image information
1524 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1526 if (!is_valid(himl) || (pImageInfo == NULL))
1528 if ((i < 0) || (i >= himl->cCurImage))
1531 pImageInfo->hbmImage = himl->hbmImage;
1532 pImageInfo->hbmMask = himl->hbmMask;
1534 pImageInfo->rcImage.top = 0;
1535 pImageInfo->rcImage.bottom = himl->cy;
1536 pImageInfo->rcImage.left = i * himl->cx;
1537 pImageInfo->rcImage.right = (i+1) * himl->cx;
1543 /*************************************************************************
1544 * ImageList_GetImageRect [COMCTL32.@]
1546 * Retrieves the rectangle of the specified image in an image list.
1549 * himl [I] handle to image list
1551 * lpRect [O] pointer to the image rectangle
1558 * This is an UNDOCUMENTED function!!!
1562 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1564 if (!is_valid(himl) || (lpRect == NULL))
1566 if ((i < 0) || (i >= himl->cCurImage))
1569 lpRect->left = i * himl->cx;
1571 lpRect->right = lpRect->left + himl->cx;
1572 lpRect->bottom = himl->cy;
1578 /*************************************************************************
1579 * ImageList_LoadImage [COMCTL32.@]
1580 * ImageList_LoadImageA [COMCTL32.@]
1582 * Creates an image list from a bitmap, icon or cursor.
1584 * See ImageList_LoadImageW.
1588 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1589 COLORREF clrMask, UINT uType, UINT uFlags)
1596 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1599 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1600 lpbmpW = Alloc(len * sizeof(WCHAR));
1601 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1603 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1609 /*************************************************************************
1610 * ImageList_LoadImageW [COMCTL32.@]
1612 * Creates an image list from a bitmap, icon or cursor.
1615 * hi [I] instance handle
1616 * lpbmp [I] name or id of the image
1617 * cx [I] width of each image
1618 * cGrow [I] number of images to expand
1619 * clrMask [I] mask color
1620 * uType [I] type of image to load
1621 * uFlags [I] loading flags
1624 * Success: handle to the loaded image list
1632 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1633 COLORREF clrMask, UINT uType, UINT uFlags)
1635 HIMAGELIST himl = NULL;
1639 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1641 ERR("Error loading image!\n");
1645 if (uType == IMAGE_BITMAP) {
1647 GetObjectW (handle, sizeof(BITMAP), &bmp);
1649 /* To match windows behavior, if cx is set to zero and
1650 the flag DI_DEFAULTSIZE is specified, cx becomes the
1651 system metric value for icons. If the flag is not specified
1652 the function sets the size to the height of the bitmap */
1655 if (uFlags & DI_DEFAULTSIZE)
1656 cx = GetSystemMetrics (SM_CXICON);
1661 nImageCount = bmp.bmWidth / cx;
1663 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1664 nImageCount, cGrow);
1666 DeleteObject (handle);
1669 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1671 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1675 GetIconInfo (handle, &ii);
1676 GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1677 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1678 ILC_MASK | ILC_COLOR, 1, cGrow);
1680 DeleteObject (ii.hbmColor);
1681 DeleteObject (ii.hbmMask);
1682 DeleteObject (handle);
1685 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1686 DeleteObject (ii.hbmColor);
1687 DeleteObject (ii.hbmMask);
1690 DeleteObject (handle);
1696 /*************************************************************************
1697 * ImageList_Merge [COMCTL32.@]
1699 * Create an image list containing a merged image from two image lists.
1702 * himl1 [I] handle to first image list
1703 * i1 [I] first image index
1704 * himl2 [I] handle to second image list
1705 * i2 [I] second image index
1706 * dx [I] X offset of the second image relative to the first.
1707 * dy [I] Y offset of the second image relative to the first.
1710 * Success: The newly created image list. It contains a single image
1711 * consisting of the second image merged with the first.
1712 * Failure: NULL, if either himl1 or himl2 are invalid.
1715 * - The returned image list should be deleted by the caller using
1716 * ImageList_Destroy() when it is no longer required.
1717 * - If either i1 or i2 are not valid image indices they will be treated
1721 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1724 HIMAGELIST himlDst = NULL;
1726 INT xOff1, yOff1, xOff2, yOff2;
1729 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1732 if (!is_valid(himl1) || !is_valid(himl2))
1736 cxDst = max (himl1->cx, dx + himl2->cx);
1741 cxDst = max (himl2->cx, himl1->cx - dx);
1746 cxDst = max (himl1->cx, himl2->cx);
1752 cyDst = max (himl1->cy, dy + himl2->cy);
1757 cyDst = max (himl2->cy, himl1->cy - dy);
1762 cyDst = max (himl1->cy, himl2->cy);
1767 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1771 nX1 = i1 * himl1->cx;
1772 nX2 = i2 * himl2->cx;
1775 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1776 if (i1 >= 0 && i1 < himl1->cCurImage)
1777 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1778 if (i2 >= 0 && i2 < himl2->cCurImage)
1780 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1781 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1785 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1786 if (i1 >= 0 && i1 < himl1->cCurImage)
1787 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1788 if (i2 >= 0 && i2 < himl2->cCurImage)
1789 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1791 himlDst->cCurImage = 1;
1798 /* helper for _read_bitmap currently unused */
1800 static int may_use_dibsection(HDC hdc) {
1801 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1806 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1810 /* helper for ImageList_Read, see comments below */
1811 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1812 HDC xdc = 0, hBitmapDC =0;
1813 BITMAPFILEHEADER bmfh;
1814 BITMAPINFOHEADER bmih;
1815 int bitsperpixel,palspace,longsperline,width,height;
1816 LPBITMAPINFOHEADER bmihc = NULL;
1818 HBITMAP hbitmap = 0, hDIB = 0;
1821 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1822 (bmfh.bfType != (('M'<<8)|'B')) ||
1823 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1824 (bmih.biSize != sizeof(bmih))
1828 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1829 if (bitsperpixel<=8)
1830 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1833 width = bmih.biWidth;
1834 height = bmih.biHeight;
1835 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1836 memcpy(bmihc,&bmih,sizeof(bmih));
1837 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1838 bmihc->biSizeImage = (longsperline*height)<<2;
1840 /* read the palette right after the end of the bitmapinfoheader */
1842 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1846 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1847 if ((bitsperpixel>1) &&
1848 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1850 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1853 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1859 int i,nwidth,nheight,nRows;
1861 nwidth = width*(height/cy);
1863 nRows = (height/cy);
1865 if (bitsperpixel==1)
1866 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1868 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1870 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1873 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1876 hBitmapDC = CreateCompatibleDC(0);
1877 SelectObject(hBitmapDC, hbitmap);
1879 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1880 /* Do not forget that windows bitmaps are bottom->top */
1881 TRACE("nRows=%d\n", nRows);
1882 for (i=0; i < nRows; i++){
1883 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1884 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1890 if (xdc) ReleaseDC(0,xdc);
1891 if (bmihc) LocalFree((HLOCAL)bmihc);
1892 if (hDIB) DeleteObject(hDIB);
1893 if (hBitmapDC) DeleteDC(hBitmapDC);
1896 DeleteObject(hbitmap);
1903 /*************************************************************************
1904 * ImageList_Read [COMCTL32.@]
1906 * Reads an image list from a stream.
1909 * pstm [I] pointer to a stream
1912 * Success: handle to image list
1915 * The format is like this:
1916 * ILHEAD ilheadstruct;
1918 * for the color image part:
1919 * BITMAPFILEHEADER bmfh;
1920 * BITMAPINFOHEADER bmih;
1921 * only if it has a palette:
1922 * RGBQUAD rgbs[nr_of_paletted_colors];
1924 * BYTE colorbits[imagesize];
1926 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1927 * BITMAPFILEHEADER bmfh_mask;
1928 * BITMAPINFOHEADER bmih_mask;
1929 * only if it has a palette (it usually does not):
1930 * RGBQUAD rgbs[nr_of_paletted_colors];
1932 * BYTE maskbits[imagesize];
1934 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1935 * _read_bitmap needs to convert them.
1937 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1941 HBITMAP hbmColor=0,hbmMask=0;
1944 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1946 if (ilHead.usMagic != (('L' << 8) | 'I'))
1948 if (ilHead.usVersion != 0x101) /* probably version? */
1952 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1953 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1954 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1955 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1956 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1957 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1958 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1959 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1960 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1961 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1964 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1967 if (ilHead.flags & ILC_MASK) {
1968 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1970 DeleteObject(hbmColor);
1975 himl = ImageList_Create (
1983 DeleteObject(hbmColor);
1984 DeleteObject(hbmMask);
1987 SelectObject(himl->hdcImage, hbmColor);
1988 DeleteObject(himl->hbmImage);
1989 himl->hbmImage = hbmColor;
1991 SelectObject(himl->hdcMask, hbmMask);
1992 DeleteObject(himl->hbmMask);
1993 himl->hbmMask = hbmMask;
1995 himl->cCurImage = ilHead.cCurImage;
1996 himl->cMaxImage = ilHead.cMaxImage;
1998 ImageList_SetBkColor(himl,ilHead.bkcolor);
2000 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2005 /*************************************************************************
2006 * ImageList_Remove [COMCTL32.@]
2008 * Removes an image from an image list
2011 * himl [I] image list handle
2020 ImageList_Remove (HIMAGELIST himl, INT i)
2022 HBITMAP hbmNewImage, hbmNewMask;
2026 TRACE("(himl=%p i=%d)\n", himl, i);
2028 if (!is_valid(himl)) {
2029 ERR("Invalid image list handle!\n");
2033 if ((i < -1) || (i >= himl->cCurImage)) {
2034 TRACE("index out of range! %d\n", i);
2040 if (himl->cCurImage == 0) {
2041 /* remove all on empty ImageList is allowed */
2042 TRACE("remove all on empty ImageList!\n");
2046 himl->cMaxImage = himl->cInitial + himl->cGrow;
2047 himl->cCurImage = 0;
2048 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2049 himl->nOvlIdx[nCount] = -1;
2051 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2052 SelectObject (himl->hdcImage, hbmNewImage);
2053 DeleteObject (himl->hbmImage);
2054 himl->hbmImage = hbmNewImage;
2056 if (himl->hbmMask) {
2057 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2059 SelectObject (himl->hdcMask, hbmNewMask);
2060 DeleteObject (himl->hbmMask);
2061 himl->hbmMask = hbmNewMask;
2065 /* delete one image */
2066 TRACE("Remove single image! %d\n", i);
2068 /* create new bitmap(s) */
2069 nCount = (himl->cCurImage + himl->cGrow - 1);
2070 cxNew = nCount * himl->cx;
2072 TRACE(" - Number of images: %d / %d (Old/New)\n",
2073 himl->cCurImage, himl->cCurImage - 1);
2074 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2075 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2077 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy);
2080 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2082 hbmNewMask = 0; /* Just to keep compiler happy! */
2084 hdcBmp = CreateCompatibleDC (0);
2086 /* copy all images and masks prior to the "removed" image */
2088 TRACE("Pre image copy: Copy %d images\n", i);
2090 SelectObject (hdcBmp, hbmNewImage);
2091 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2092 himl->hdcImage, 0, 0, SRCCOPY);
2094 if (himl->hbmMask) {
2095 SelectObject (hdcBmp, hbmNewMask);
2096 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2097 himl->hdcMask, 0, 0, SRCCOPY);
2101 /* copy all images and masks behind the removed image */
2102 if (i < himl->cCurImage - 1) {
2103 TRACE("Post image copy!\n");
2104 SelectObject (hdcBmp, hbmNewImage);
2105 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2106 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2108 if (himl->hbmMask) {
2109 SelectObject (hdcBmp, hbmNewMask);
2110 BitBlt (hdcBmp, i * himl->cx, 0,
2111 (himl->cCurImage - i - 1) * himl->cx,
2112 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2118 /* delete old images and insert new ones */
2119 SelectObject (himl->hdcImage, hbmNewImage);
2120 DeleteObject (himl->hbmImage);
2121 himl->hbmImage = hbmNewImage;
2122 if (himl->hbmMask) {
2123 SelectObject (himl->hdcMask, hbmNewMask);
2124 DeleteObject (himl->hbmMask);
2125 himl->hbmMask = hbmNewMask;
2129 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2136 /*************************************************************************
2137 * ImageList_Replace [COMCTL32.@]
2139 * Replaces an image in an image list with a new image.
2142 * himl [I] handle to image list
2144 * hbmImage [I] handle to image bitmap
2145 * hbmMask [I] handle to mask bitmap. Can be NULL.
2153 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2159 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2161 if (!is_valid(himl)) {
2162 ERR("Invalid image list handle!\n");
2166 if ((i >= himl->cMaxImage) || (i < 0)) {
2167 ERR("Invalid image index!\n");
2171 hdcImage = CreateCompatibleDC (0);
2172 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2175 SelectObject (hdcImage, hbmImage);
2177 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2178 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2183 SelectObject (hdcImage, hbmMask);
2185 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2186 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2189 /* Remove the background from the image
2191 StretchBlt (himl->hdcImage,
2192 i*himl->cx, 0, himl->cx, himl->cy,
2194 0, 0, bmp.bmWidth, bmp.bmHeight,
2195 0x220326); /* NOTSRCAND */
2198 DeleteDC (hdcImage);
2204 /*************************************************************************
2205 * ImageList_ReplaceIcon [COMCTL32.@]
2207 * Replaces an image in an image list using an icon.
2210 * himl [I] handle to image list
2212 * hIcon [I] handle to icon
2215 * Success: index of the replaced image
2220 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2230 TRACE("(%p %d %p)\n", himl, i, hIcon);
2232 if (!is_valid(himl)) {
2233 ERR("invalid image list\n");
2236 if ((i >= himl->cMaxImage) || (i < -1)) {
2237 ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2241 hBestFitIcon = CopyImage(
2244 LR_COPYFROMRESOURCE);
2245 /* the above will fail if the icon wasn't loaded from a resource, so try
2246 * again without LR_COPYFROMRESOURCE flag */
2248 hBestFitIcon = CopyImage(
2255 ret = GetIconInfo (hBestFitIcon, &ii);
2257 DestroyIcon(hBestFitIcon);
2261 if (ii.hbmColor == 0)
2263 ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2265 ERR("couldn't get mask bitmap info\n");
2267 DeleteObject (ii.hbmColor);
2269 DeleteObject (ii.hbmMask);
2270 DestroyIcon(hBestFitIcon);
2275 if (himl->cCurImage + 1 > himl->cMaxImage)
2276 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2278 nIndex = himl->cCurImage;
2284 hdcImage = CreateCompatibleDC (0);
2285 TRACE("hdcImage=%p\n", hdcImage);
2287 ERR("invalid hdcImage!\n");
2289 SetTextColor(himl->hdcImage, RGB(0,0,0));
2290 SetBkColor (himl->hdcImage, RGB(255,255,255));
2291 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2293 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2294 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2296 if (himl->hbmMask) {
2297 SelectObject (hdcImage, ii.hbmMask);
2298 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2299 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2302 SelectObject (hdcImage, hbmOldSrc);
2304 DestroyIcon(hBestFitIcon);
2306 DeleteDC (hdcImage);
2308 DeleteObject (ii.hbmColor);
2310 DeleteObject (ii.hbmMask);
2312 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2317 /*************************************************************************
2318 * ImageList_SetBkColor [COMCTL32.@]
2320 * Sets the background color of an image list.
2323 * himl [I] handle to image list
2324 * clrBk [I] background color
2327 * Success: previous background color
2332 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2336 if (!is_valid(himl))
2339 clrOldBk = himl->clrBk;
2340 himl->clrBk = clrBk;
2345 /*************************************************************************
2346 * ImageList_SetDragCursorImage [COMCTL32.@]
2348 * Combines the specified image with the current drag image
2351 * himlDrag [I] handle to drag image list
2352 * iDrag [I] drag image index
2353 * dxHotspot [I] X position of the hot spot
2354 * dyHotspot [I] Y position of the hot spot
2361 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2362 * to do with a hotspot but are only the offset of the origin of the new
2363 * image relative to the origin of the old image.
2365 * - When this function is called and the drag image is visible, a
2366 * short flickering occurs but this matches the Win9x behavior. It is
2367 * possible to fix the flickering using code like in ImageList_DragMove.
2371 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2372 INT dxHotspot, INT dyHotspot)
2374 HIMAGELIST himlTemp;
2377 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2380 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2381 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2383 visible = InternalDrag.bShow;
2385 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2386 dxHotspot, dyHotspot);
2389 /* hide the drag image */
2390 ImageList_DragShowNolock(FALSE);
2392 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2393 (InternalDrag.himl->cy != himlTemp->cy)) {
2394 /* the size of the drag image changed, invalidate the buffer */
2395 DeleteObject(InternalDrag.hbmBg);
2396 InternalDrag.hbmBg = 0;
2399 ImageList_Destroy (InternalDrag.himl);
2400 InternalDrag.himl = himlTemp;
2403 /* show the drag image */
2404 ImageList_DragShowNolock(TRUE);
2411 /*************************************************************************
2412 * ImageList_SetFilter [COMCTL32.@]
2414 * Sets a filter (or does something completely different)!!???
2415 * It removes 12 Bytes from the stack (3 Parameters).
2418 * himl [I] SHOULD be a handle to image list
2419 * i [I] COULD be an index?
2424 * Failure: FALSE ???
2427 * This is an UNDOCUMENTED function!!!!
2432 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2434 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2440 /*************************************************************************
2441 * ImageList_SetFlags [COMCTL32.@]
2443 * Sets the image list flags.
2446 * himl [I] Handle to image list
2447 * flags [I] Flags to set
2457 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2459 FIXME("(%p %08lx):empty stub\n", himl, flags);
2464 /*************************************************************************
2465 * ImageList_SetIconSize [COMCTL32.@]
2467 * Sets the image size of the bitmap and deletes all images.
2470 * himl [I] handle to image list
2471 * cx [I] image width
2472 * cy [I] image height
2480 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2485 if (!is_valid(himl))
2488 /* remove all images */
2489 himl->cMaxImage = himl->cInitial + himl->cGrow;
2490 himl->cCurImage = 0;
2494 /* initialize overlay mask indices */
2495 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2496 himl->nOvlIdx[nCount] = -1;
2498 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2499 SelectObject (himl->hdcImage, hbmNew);
2500 DeleteObject (himl->hbmImage);
2501 himl->hbmImage = hbmNew;
2503 if (himl->hbmMask) {
2504 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2506 SelectObject (himl->hdcMask, hbmNew);
2507 DeleteObject (himl->hbmMask);
2508 himl->hbmMask = hbmNew;
2515 /*************************************************************************
2516 * ImageList_SetImageCount [COMCTL32.@]
2518 * Resizes an image list to the specified number of images.
2521 * himl [I] handle to image list
2522 * iImageCount [I] number of images in the image list
2530 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2533 HBITMAP hbmNewBitmap;
2534 INT nNewCount, nCopyCount;
2536 TRACE("%p %d\n",himl,iImageCount);
2538 if (!is_valid(himl))
2540 if (himl->cCurImage >= iImageCount)
2542 if (himl->cMaxImage > iImageCount)
2544 himl->cCurImage = iImageCount;
2548 nNewCount = iImageCount + himl->cGrow;
2549 nCopyCount = min(himl->cCurImage, iImageCount);
2551 hdcBitmap = CreateCompatibleDC (0);
2553 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy);
2555 if (hbmNewBitmap != 0)
2557 SelectObject (hdcBitmap, hbmNewBitmap);
2560 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2561 himl->hdcImage, 0, 0, SRCCOPY);
2563 /* delete 'empty' image space */
2564 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2565 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2566 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2567 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2569 SelectObject (himl->hdcImage, hbmNewBitmap);
2570 DeleteObject (himl->hbmImage);
2571 himl->hbmImage = hbmNewBitmap;
2574 ERR("Could not create new image bitmap !\n");
2578 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2580 if (hbmNewBitmap != 0)
2582 SelectObject (hdcBitmap, hbmNewBitmap);
2585 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2586 himl->hdcMask, 0, 0, SRCCOPY);
2588 /* delete 'empty' image space */
2589 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2590 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2591 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2592 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2594 SelectObject (himl->hdcMask, hbmNewBitmap);
2595 DeleteObject (himl->hbmMask);
2596 himl->hbmMask = hbmNewBitmap;
2599 ERR("Could not create new mask bitmap!\n");
2602 DeleteDC (hdcBitmap);
2604 /* Update max image count and current image count */
2605 himl->cMaxImage = nNewCount;
2606 himl->cCurImage = iImageCount;
2612 /*************************************************************************
2613 * ImageList_SetOverlayImage [COMCTL32.@]
2615 * Assigns an overlay mask index to an existing image in an image list.
2618 * himl [I] handle to image list
2619 * iImage [I] image index
2620 * iOverlay [I] overlay mask index
2628 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2630 if (!is_valid(himl))
2632 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2634 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2636 himl->nOvlIdx[iOverlay - 1] = iImage;
2642 /* helper for ImageList_Write - write bitmap to pstm
2643 * currently everything is written as 24 bit RGB, except masks
2646 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2648 LPBITMAPFILEHEADER bmfh;
2649 LPBITMAPINFOHEADER bmih;
2650 LPBYTE data, lpBits, lpBitsOrg;
2652 INT bitCount, sizeImage, offBits, totalSize;
2653 INT nwidth, nheight, nsizeImage, icount;
2655 BOOL result = FALSE;
2659 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2661 /* XXX is this always correct? */
2662 icount = bm.bmWidth / cx;
2664 nheight = cy * icount;
2666 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2667 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2668 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2670 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2672 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2673 offBits = totalSize;
2674 totalSize += nsizeImage;
2676 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2677 bmfh = (LPBITMAPFILEHEADER)data;
2678 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2679 lpBits = data + offBits;
2681 /* setup BITMAPFILEHEADER */
2682 bmfh->bfType = (('M' << 8) | 'B');
2684 bmfh->bfReserved1 = 0;
2685 bmfh->bfReserved2 = 0;
2686 bmfh->bfOffBits = offBits;
2688 /* setup BITMAPINFOHEADER */
2689 bmih->biSize = sizeof(BITMAPINFOHEADER);
2690 bmih->biWidth = bm.bmWidth;
2691 bmih->biHeight = bm.bmHeight;
2693 bmih->biBitCount = bitCount;
2694 bmih->biCompression = BI_RGB;
2695 bmih->biSizeImage = sizeImage;
2696 bmih->biXPelsPerMeter = 0;
2697 bmih->biYPelsPerMeter = 0;
2698 bmih->biClrUsed = 0;
2699 bmih->biClrImportant = 0;
2701 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2702 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2703 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2707 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2708 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2710 for(i = 0; i < nheight; i++) {
2711 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2712 int noff = (nbpl * (nheight-1-i));
2713 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2717 bmih->biWidth = nwidth;
2718 bmih->biHeight = nheight;
2719 bmih->biSizeImage = nsizeImage;
2723 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2724 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2725 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2728 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2735 LocalFree((HLOCAL)lpBitsOrg);
2736 LocalFree((HLOCAL)data);
2742 /*************************************************************************
2743 * ImageList_Write [COMCTL32.@]
2745 * Writes an image list to a stream.
2748 * himl [I] handle to image list
2749 * pstm [O] Pointer to a stream.
2760 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2765 if (!is_valid(himl))
2768 ilHead.usMagic = (('L' << 8) | 'I');
2769 ilHead.usVersion = 0x101;
2770 ilHead.cCurImage = himl->cCurImage;
2771 ilHead.cMaxImage = himl->cMaxImage;
2772 ilHead.cGrow = himl->cGrow;
2773 ilHead.cx = himl->cx;
2774 ilHead.cy = himl->cy;
2775 ilHead.bkcolor = himl->clrBk;
2776 ilHead.flags = himl->flags;
2777 for(i = 0; i < 4; i++) {
2778 ilHead.ovls[i] = himl->nOvlIdx[i];
2781 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2784 /* write the bitmap */
2785 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2788 /* write the mask if we have one */
2789 if(himl->flags & ILC_MASK) {
2790 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2798 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height)
2800 HBITMAP hbmNewBitmap;
2801 UINT ilc = (himl->flags & 0xFE);
2803 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2808 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2810 if (himl->uBitsPixel <= ILC_COLOR8)
2816 colors = 1 << himl->uBitsPixel;
2817 bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2818 sizeof(PALETTEENTRY) * colors);
2820 pal = (LPPALETTEENTRY)bmi->bmiColors;
2821 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2823 /* Swap colors returned by GetPaletteEntries so we can use them for
2824 * CreateDIBSection call. */
2825 for (i = 0; i < colors; i++)
2827 temp = pal[i].peBlue;
2828 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2829 bmi->bmiColors[i].rgbBlue = temp;
2834 bmi = Alloc(sizeof(BITMAPINFOHEADER));
2837 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2838 bmi->bmiHeader.biWidth = width;
2839 bmi->bmiHeader.biHeight = height;
2840 bmi->bmiHeader.biPlanes = 1;
2841 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2842 bmi->bmiHeader.biCompression = BI_RGB;
2843 bmi->bmiHeader.biSizeImage = 0;
2844 bmi->bmiHeader.biXPelsPerMeter = 0;
2845 bmi->bmiHeader.biYPelsPerMeter = 0;
2846 bmi->bmiHeader.biClrUsed = 0;
2847 bmi->bmiHeader.biClrImportant = 0;
2849 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2853 else /*if (ilc == ILC_COLORDDB)*/
2855 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2857 hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL);
2859 TRACE("returning %p\n", hbmNewBitmap);
2860 return hbmNewBitmap;
2863 /*************************************************************************
2864 * ImageList_SetColorTable [COMCTL32.@]
2866 * Sets the color table of an image list.
2869 * himl [I] Handle to the image list.
2870 * uStartIndex [I] The first index to set.
2871 * cEntries [I] Number of entries to set.
2872 * prgb [I] New color information for color table for the image list.
2875 * Success: Number of entries in the table that were set.
2879 * ImageList_Create(), SetDIBColorTable()
2883 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2885 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);