2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 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
38 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
39 * is the offset of the image position relative to the actual mouse pointer
40 * position. However the Hotspot passed to SetDragCursorImage is the
41 * offset of the mouse messages sent to the application...
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 */
76 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
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)
103 HDC hdcImageList, hdcBitmap;
104 HBITMAP hbmNewBitmap;
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 hdcImageList = CreateCompatibleDC (0);
117 hdcBitmap = CreateCompatibleDC (0);
120 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
121 if (hbmNewBitmap == 0)
122 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
124 SelectObject (hdcImageList, himl->hbmImage);
125 SelectObject (hdcBitmap, hbmNewBitmap);
126 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
127 hdcImageList, 0, 0, SRCCOPY);
129 DeleteObject (himl->hbmImage);
130 himl->hbmImage = hbmNewBitmap;
134 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
136 if (hbmNewBitmap == 0)
137 ERR("creating new mask bitmap!\n");
139 SelectObject (hdcImageList, himl->hbmMask);
140 SelectObject (hdcBitmap, hbmNewBitmap);
141 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
142 hdcImageList, 0, 0, SRCCOPY);
143 DeleteObject (himl->hbmMask);
144 himl->hbmMask = hbmNewBitmap;
147 himl->cMaxImage = nNewCount;
149 DeleteDC (hdcImageList);
150 DeleteDC (hdcBitmap);
154 /*************************************************************************
155 * ImageList_Add [COMCTL32.@]
157 * Add an image or images to an image list.
160 * himl [I] handle to image list
161 * hbmImage [I] handle to image bitmap
162 * hbmMask [I] handle to mask bitmap
165 * Success: Index of the first new image.
170 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
172 HDC hdcImage, hdcBitmap;
173 INT nFirstIndex, nImageCount;
176 HBITMAP hOldBitmapImage, hOldBitmap;
178 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
182 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
183 nImageCount = bmp.bmWidth / himl->cx;
185 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
187 nStartX = himl->cCurImage * himl->cx;
189 hdcImage = CreateCompatibleDC(0);
190 hdcBitmap = CreateCompatibleDC(0);
192 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
193 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
195 /* Copy result to the imagelist
197 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
198 hdcBitmap, 0, 0, SRCCOPY);
202 HDC hdcMask, hdcTemp;
203 HBITMAP hOldBitmapMask, hOldBitmapTemp;
205 hdcMask = CreateCompatibleDC (0);
206 hdcTemp = CreateCompatibleDC(0);
207 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
208 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
211 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
216 SelectObject(hdcTemp, hOldBitmapTemp);
219 /* Remove the background from the image
222 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
225 0x220326); /* NOTSRCAND */
227 SelectObject(hdcMask, hOldBitmapMask);
231 SelectObject(hdcImage, hOldBitmapImage);
232 SelectObject(hdcBitmap, hOldBitmap);
236 nFirstIndex = himl->cCurImage;
237 himl->cCurImage += nImageCount;
243 /*************************************************************************
244 * ImageList_AddIcon [COMCTL32.@]
246 * Adds an icon to an image list.
249 * himl [I] handle to image list
250 * hIcon [I] handle to icon
253 * Success: index of the new image
256 #undef ImageList_AddIcon
257 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
259 return ImageList_ReplaceIcon (himl, -1, hIcon);
263 /*************************************************************************
264 * ImageList_AddMasked [COMCTL32.@]
266 * Adds an image or images to an image list and creates a mask from the
267 * specified bitmap using the mask color.
270 * himl [I] handle to image list.
271 * hBitmap [I] handle to bitmap
272 * clrMask [I] mask color.
275 * Success: Index of the first new image.
280 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
282 HDC hdcImage, hdcMask, hdcBitmap;
283 INT nIndex, nImageCount, nMaskXOffset=0;
285 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
286 HBITMAP hMaskBitmap=0;
289 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
293 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
296 nImageCount = bmp.bmWidth / himl->cx;
298 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
300 nIndex = himl->cCurImage;
301 himl->cCurImage += nImageCount;
303 hdcMask = CreateCompatibleDC (0);
304 hdcImage = CreateCompatibleDC(0);
305 hdcBitmap = CreateCompatibleDC(0);
308 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
309 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
312 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
313 nMaskXOffset = nIndex * himl->cx;
318 Create a temp Mask so we can remove the background of
319 the Image (Windows does this even if there is no mask)
321 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
322 hOldBitmapMask = 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
354 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
360 SelectObject(hdcMask,hOldBitmapMask);
361 SelectObject(hdcImage, hOldBitmapImage);
362 SelectObject(hdcBitmap, hOldBitmap);
368 DeleteObject(hMaskBitmap);
375 /*************************************************************************
376 * ImageList_BeginDrag [COMCTL32.@]
378 * Creates a temporary image list that contains one image. It will be used
382 * himlTrack [I] handle to the source image list
383 * iTrack [I] index of the drag image in the source image list
384 * dxHotspot [I] X position of the hot spot of the drag image
385 * dyHotspot [I] Y position of the hot spot of the drag image
393 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
394 INT dxHotspot, INT dyHotspot)
399 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
400 dxHotspot, dyHotspot);
402 if (!is_valid(himlTrack))
405 if (InternalDrag.himl)
406 ImageList_EndDrag ();
411 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
412 if (InternalDrag.himl == NULL) {
413 WARN("Error creating drag image list!\n");
417 InternalDrag.dxHotspot = dxHotspot;
418 InternalDrag.dyHotspot = dyHotspot;
420 hdcSrc = CreateCompatibleDC (0);
421 hdcDst = CreateCompatibleDC (0);
424 SelectObject (hdcSrc, himlTrack->hbmImage);
425 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
426 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
429 SelectObject (hdcSrc, himlTrack->hbmMask);
430 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
431 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
436 InternalDrag.himl->cCurImage = 1;
437 InternalDrag.bHSPending = TRUE;
443 /*************************************************************************
444 * ImageList_Copy [COMCTL32.@]
446 * Copies an image of the source image list to an image of the
447 * destination image list. Images can be copied or swapped.
450 * himlDst [I] handle to the destination image list
451 * iDst [I] destination image index.
452 * himlSrc [I] handle to the source image list
453 * iSrc [I] source image index
454 * uFlags [I] flags for the copy operation
461 * Copying from one image list to another is possible. The original
462 * implementation just copies or swaps within one image list.
463 * Could this feature become a bug??? ;-)
467 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
468 INT iSrc, INT uFlags)
472 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
474 if (!is_valid(himlSrc) || !is_valid(himlDst))
476 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
478 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
481 hdcSrc = CreateCompatibleDC (0);
482 if (himlDst == himlSrc)
485 hdcDst = CreateCompatibleDC (0);
487 if (uFlags & ILCF_SWAP) {
489 HBITMAP hbmTempImage, hbmTempMask;
491 /* create temporary bitmaps */
492 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
493 himlSrc->uBitsPixel, NULL);
494 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
497 /* copy (and stretch) destination to temporary bitmaps.(save) */
499 SelectObject (hdcSrc, himlDst->hbmImage);
500 SelectObject (hdcDst, hbmTempImage);
501 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
502 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
505 SelectObject (hdcSrc, himlDst->hbmMask);
506 SelectObject (hdcDst, hbmTempMask);
507 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
508 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
511 /* copy (and stretch) source to destination */
513 SelectObject (hdcSrc, himlSrc->hbmImage);
514 SelectObject (hdcDst, himlDst->hbmImage);
515 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
516 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
519 SelectObject (hdcSrc, himlSrc->hbmMask);
520 SelectObject (hdcDst, himlDst->hbmMask);
521 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
522 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
525 /* copy (without stretching) temporary bitmaps to source (restore) */
527 SelectObject (hdcSrc, hbmTempImage);
528 SelectObject (hdcDst, himlSrc->hbmImage);
529 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
530 hdcSrc, 0, 0, SRCCOPY);
532 SelectObject (hdcSrc, hbmTempMask);
533 SelectObject (hdcDst, himlSrc->hbmMask);
534 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
535 hdcSrc, 0, 0, SRCCOPY);
537 /* delete temporary bitmaps */
538 DeleteObject (hbmTempMask);
539 DeleteObject (hbmTempImage);
543 SelectObject (hdcSrc, himlSrc->hbmImage);
544 if (himlSrc == himlDst)
547 SelectObject (hdcDst, himlDst->hbmImage);
548 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
549 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
553 SelectObject (hdcSrc, himlSrc->hbmMask);
554 if (himlSrc == himlDst)
557 SelectObject (hdcDst, himlDst->hbmMask);
558 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
559 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
564 if (himlSrc != himlDst)
571 /*************************************************************************
572 * ImageList_Create [COMCTL32.@] Creates a new image list.
575 * cx [I] image height
577 * flags [I] creation flags
578 * cInitial [I] initial number of images in the image list
579 * cGrow [I] number of images by which image list grows
582 * Success: Handle to the created image list
587 ImageList_Create (INT cx, INT cy, UINT flags,
588 INT cInitial, INT cGrow)
594 static WORD aBitBlend25[] =
595 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
597 static WORD aBitBlend50[] =
598 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
600 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
602 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
606 himl->magic = IMAGELIST_MAGIC;
610 himl->cMaxImage = cInitial + cGrow;
611 himl->cInitial = cInitial;
614 himl->clrFg = CLR_DEFAULT;
615 himl->clrBk = CLR_NONE;
618 himl->hbrBlend25 = 0;
619 himl->hbrBlend50 = 0;
621 /* initialize overlay mask indices */
622 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
623 himl->nOvlIdx[nCount] = -1;
625 hdc = CreateCompatibleDC (0);
626 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
629 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
631 if (himl->cMaxImage > 0) {
633 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
634 1, himl->uBitsPixel, NULL);
635 if (himl->hbmImage == 0) {
636 ERR("Error creating image bitmap!\n");
637 ImageList_Destroy(himl);
644 if ( (himl->flags & ILC_MASK)) {
645 int images = himl->cMaxImage;
649 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
651 if (himl->hbmMask == 0) {
652 ERR("Error creating mask bitmap!\n");
653 ImageList_Destroy(himl);
660 /* create blending brushes */
661 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
662 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
663 DeleteObject (hbmTemp);
665 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
666 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
667 DeleteObject (hbmTemp);
669 TRACE("created imagelist %p\n", himl);
674 /*************************************************************************
675 * ImageList_Destroy [COMCTL32.@]
677 * Destroys an image list.
680 * himl [I] handle to image list
688 ImageList_Destroy (HIMAGELIST himl)
693 /* delete image bitmaps */
695 DeleteObject (himl->hbmImage);
697 DeleteObject (himl->hbmMask);
699 /* delete blending brushes */
700 if (himl->hbrBlend25)
701 DeleteObject (himl->hbrBlend25);
702 if (himl->hbrBlend50)
703 DeleteObject (himl->hbrBlend50);
705 ZeroMemory(himl, sizeof(*himl));
706 COMCTL32_Free (himl);
712 /*************************************************************************
713 * ImageList_DragEnter [COMCTL32.@]
715 * Locks window update and displays the drag image at the given position.
718 * hwndLock [I] handle of the window that owns the drag image.
719 * x [I] X position of the drag image.
720 * y [I] Y position of the drag image.
727 * The position of the drag image is relative to the window, not
732 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
734 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
736 if (!is_valid(InternalDrag.himl))
740 InternalDrag.hwnd = hwndLock;
742 InternalDrag.hwnd = GetDesktopWindow ();
747 /* draw the drag image and save the background */
748 if (!ImageList_DragShowNolock(TRUE)) {
756 /*************************************************************************
757 * ImageList_DragLeave [COMCTL32.@]
759 * Unlocks window update and hides the drag image.
762 * hwndLock [I] handle of the window that owns the drag image.
770 ImageList_DragLeave (HWND hwndLock)
772 /* As we don't save drag info in the window this can lead to problems if
773 an app does not supply the same window as DragEnter */
775 InternalDrag.hwnd = hwndLock;
777 InternalDrag.hwnd = GetDesktopWindow (); */
779 hwndLock = GetDesktopWindow();
780 if(InternalDrag.hwnd != hwndLock)
781 FIXME("DragLeave hWnd != DragEnter hWnd\n");
783 ImageList_DragShowNolock (FALSE);
789 /*************************************************************************
790 * ImageList_InternalDragDraw [Internal]
792 * Draws the drag image.
795 * hdc [I] device context to draw into.
796 * x [I] X position of the drag image.
797 * y [I] Y position of the drag image.
804 * The position of the drag image is relative to the window, not
810 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
812 IMAGELISTDRAWPARAMS imldp;
814 ZeroMemory (&imldp, sizeof(imldp));
815 imldp.cbSize = sizeof(imldp);
816 imldp.himl = InternalDrag.himl;
821 imldp.rgbBk = CLR_DEFAULT;
822 imldp.rgbFg = CLR_DEFAULT;
823 imldp.fStyle = ILD_NORMAL;
824 imldp.fState = ILS_ALPHA;
827 /* FIXME: instead of using the alpha blending, we should
828 * create a 50% mask, and draw it semitransparantly that way */
829 ImageList_DrawIndirect (&imldp);
832 /*************************************************************************
833 * ImageList_DragMove [COMCTL32.@]
835 * Moves the drag image.
838 * x [I] X position of the drag image.
839 * y [I] Y position of the drag image.
846 * The position of the drag image is relative to the window, not
850 * The drag image should be drawn semitransparent.
854 ImageList_DragMove (INT x, INT y)
856 TRACE("(x=%d y=%d)\n", x, y);
858 if (!is_valid(InternalDrag.himl))
861 /* draw/update the drag image */
862 if (InternalDrag.bShow) {
866 HBITMAP hbmOffScreen;
867 INT origNewX, origNewY;
868 INT origOldX, origOldY;
869 INT origRegX, origRegY;
870 INT sizeRegX, sizeRegY;
873 /* calculate the update region */
874 origNewX = x - InternalDrag.dxHotspot;
875 origNewY = y - InternalDrag.dyHotspot;
876 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
877 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
878 origRegX = min(origNewX, origOldX);
879 origRegY = min(origNewY, origOldY);
880 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
881 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
883 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
884 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
885 hdcOffScreen = CreateCompatibleDC(hdcDrag);
886 hdcBg = CreateCompatibleDC(hdcDrag);
888 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
889 SelectObject(hdcOffScreen, hbmOffScreen);
890 SelectObject(hdcBg, InternalDrag.hbmBg);
892 /* get the actual background of the update region */
893 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
894 origRegX, origRegY, SRCCOPY);
895 /* erase the old image */
896 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
897 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
899 /* save the background */
900 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
901 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
903 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
904 origNewY - origRegY);
905 /* draw the update region to the screen */
906 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
907 hdcOffScreen, 0, 0, SRCCOPY);
910 DeleteDC(hdcOffScreen);
911 DeleteObject(hbmOffScreen);
912 ReleaseDC(InternalDrag.hwnd, hdcDrag);
915 /* update the image position */
923 /*************************************************************************
924 * ImageList_DragShowNolock [COMCTL32.@]
926 * Shows or hides the drag image.
929 * bShow [I] TRUE shows the drag image, FALSE hides it.
936 * The drag image should be drawn semitransparent.
940 ImageList_DragShowNolock (BOOL bShow)
946 if (!is_valid(InternalDrag.himl))
949 TRACE("bShow=0x%X!\n", bShow);
951 /* DragImage is already visible/hidden */
952 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
956 /* position of the origin of the DragImage */
957 x = InternalDrag.x - InternalDrag.dxHotspot;
958 y = InternalDrag.y - InternalDrag.dyHotspot;
960 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
961 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
966 hdcBg = CreateCompatibleDC(hdcDrag);
967 if (!InternalDrag.hbmBg) {
968 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
969 InternalDrag.himl->cx, InternalDrag.himl->cy);
971 SelectObject(hdcBg, InternalDrag.hbmBg);
974 /* save the background */
975 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
976 hdcDrag, x, y, SRCCOPY);
978 ImageList_InternalDragDraw(hdcDrag, x, y);
981 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
982 hdcBg, 0, 0, SRCCOPY);
985 InternalDrag.bShow = !InternalDrag.bShow;
988 ReleaseDC (InternalDrag.hwnd, hdcDrag);
993 /*************************************************************************
994 * ImageList_Draw [COMCTL32.@] Draws an image.
997 * himl [I] handle to image list
999 * hdc [I] handle to device context
1002 * fStyle [I] drawing flags
1013 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1015 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1016 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1020 /*************************************************************************
1021 * ImageList_DrawEx [COMCTL32.@]
1023 * Draws an image and allows to use extended drawing features.
1026 * himl [I] handle to image list
1028 * hdc [I] handle to device context
1033 * rgbBk [I] background color
1034 * rgbFg [I] foreground color
1035 * fStyle [I] drawing flags
1042 * Calls ImageList_DrawIndirect.
1045 * ImageList_DrawIndirect.
1049 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1050 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1053 IMAGELISTDRAWPARAMS imldp;
1055 ZeroMemory (&imldp, sizeof(imldp));
1056 imldp.cbSize = sizeof(imldp);
1064 imldp.rgbBk = rgbBk;
1065 imldp.rgbFg = rgbFg;
1066 imldp.fStyle = fStyle;
1068 return ImageList_DrawIndirect (&imldp);
1072 /*************************************************************************
1073 * ImageList_DrawIndirect [COMCTL32.@]
1075 * Draws an image using ...
1078 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1086 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1088 INT cx, cy, lx, ly, nOvlIdx;
1089 DWORD fState, dwRop;
1091 COLORREF clrBk, oldImageBk, oldImageFg;
1092 HDC hImageDC, hImageListDC, hMaskListDC;
1093 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1094 BOOL bIsTransparent, bBlend, bResult = FALSE;
1097 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1098 if (!is_valid(himl)) return FALSE;
1099 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1101 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1102 ly = pimldp->yBitmap;
1104 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1105 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1106 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1107 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1108 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1109 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1110 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1112 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1113 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1115 /* we will use these DCs to access the images and masks in the ImageList */
1116 hImageListDC = CreateCompatibleDC(0);
1117 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1119 /* these will accumulate the image and mask for the image we're drawing */
1120 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1121 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1122 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1124 /* Create a compatible DC. */
1125 if (!hImageListDC || !hImageDC || !hImageBmp ||
1126 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1129 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1130 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1131 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1134 * To obtain a transparent look, background color should be set
1135 * to white and foreground color to black when blting the
1138 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1139 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1142 * Draw the initial image
1144 if(fStyle & ILD_MASK) {
1145 if (himl->hbmMask) {
1146 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1148 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1149 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1150 SelectObject(hImageDC, hOldBrush);
1152 } else if (himl->hbmMask && !bIsTransparent) {
1153 /* blend the image with the needed solid background */
1154 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1155 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1156 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1157 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1158 DeleteObject (SelectObject (hImageDC, hOldBrush));
1160 /* start off with the image, if we have a mask, we'll use it later */
1161 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1164 /* Time for blending, if required */
1166 HBRUSH hBlendBrush, hOldBrush;
1167 COLORREF clrBlend = pimldp->rgbFg;
1168 HDC hBlendMaskDC = hImageListDC;
1171 /* Create the blend Mask */
1172 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1173 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1174 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1175 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1176 SelectObject(hBlendMaskDC, hOldBrush);
1178 /* Modify the blend mask if an Image Mask exist */
1180 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1181 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1184 /* now apply blend to the current image given the BlendMask */
1185 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1186 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1187 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1188 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1189 DeleteObject(SelectObject(hImageDC, hOldBrush));
1190 SelectObject(hBlendMaskDC, hOldBitmap);
1193 /* Now do the overlay image, if any */
1194 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1195 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1196 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1197 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1198 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1199 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1200 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1201 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1205 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1206 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1207 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1208 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1210 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1211 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1212 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1214 /* now copy the image to the screen */
1216 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1217 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1218 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1219 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1220 SetBkColor(pimldp->hdcDst, oldDstBk);
1221 SetTextColor(pimldp->hdcDst, oldDstFg);
1224 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1225 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1229 /* cleanup the mess */
1230 SetBkColor(hImageDC, oldImageBk);
1231 SetTextColor(hImageDC, oldImageFg);
1232 SelectObject(hImageDC, hOldImageBmp);
1233 SelectObject(hImageListDC, hOldImageListBmp);
1234 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1236 DeleteObject(hBlendMaskBmp);
1237 DeleteObject(hImageBmp);
1239 DeleteDC(hImageListDC);
1240 DeleteDC(hMaskListDC);
1246 /*************************************************************************
1247 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1250 * himlSrc [I] source image list handle
1253 * Success: Handle of duplicated image list.
1258 ImageList_Duplicate (HIMAGELIST himlSrc)
1263 if (!is_valid(himlSrc)) {
1264 ERR("Invalid image list handle!\n");
1268 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1269 himlSrc->cInitial, himlSrc->cGrow);
1273 hdcSrc = CreateCompatibleDC (0);
1274 hdcDst = CreateCompatibleDC (0);
1275 SelectObject (hdcSrc, himlSrc->hbmImage);
1276 SelectObject (hdcDst, himlDst->hbmImage);
1277 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1278 hdcSrc, 0, 0, SRCCOPY);
1280 if (himlDst->hbmMask)
1282 SelectObject (hdcSrc, himlSrc->hbmMask);
1283 SelectObject (hdcDst, himlDst->hbmMask);
1284 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1285 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1291 himlDst->cCurImage = himlSrc->cCurImage;
1292 himlDst->cMaxImage = himlSrc->cMaxImage;
1298 /*************************************************************************
1299 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1301 * Finishes a drag operation.
1312 ImageList_EndDrag (void)
1314 /* cleanup the InternalDrag struct */
1315 InternalDrag.hwnd = 0;
1316 ImageList_Destroy (InternalDrag.himl);
1317 InternalDrag.himl = 0;
1320 InternalDrag.dxHotspot = 0;
1321 InternalDrag.dyHotspot = 0;
1322 InternalDrag.bShow = FALSE;
1323 DeleteObject(InternalDrag.hbmBg);
1324 InternalDrag.hbmBg = 0;
1325 InternalDrag.bHSPending = FALSE;
1331 /*************************************************************************
1332 * ImageList_GetBkColor [COMCTL32.@]
1334 * Returns the background color of an image list.
1337 * himl [I] Image list handle.
1340 * Success: background color
1345 ImageList_GetBkColor (HIMAGELIST himl)
1347 return himl ? himl->clrBk : CLR_NONE;
1351 /*************************************************************************
1352 * ImageList_GetDragImage [COMCTL32.@]
1354 * Returns the handle to the internal drag image list.
1357 * ppt [O] Pointer to the drag position. Can be NULL.
1358 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1361 * Success: Handle of the drag image list.
1366 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1368 if (is_valid(InternalDrag.himl)) {
1370 ppt->x = InternalDrag.x;
1371 ppt->y = InternalDrag.y;
1374 pptHotspot->x = InternalDrag.dxHotspot;
1375 pptHotspot->y = InternalDrag.dyHotspot;
1377 return (InternalDrag.himl);
1384 /*************************************************************************
1385 * ImageList_GetFlags [COMCTL32.@]
1392 ImageList_GetFlags(HIMAGELIST himl)
1394 FIXME("(%p):empty stub\n", himl);
1399 /*************************************************************************
1400 * ImageList_GetIcon [COMCTL32.@]
1402 * Creates an icon from a masked image of an image list.
1405 * himl [I] handle to image list
1407 * flags [I] drawing style flags
1410 * Success: icon handle
1415 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1419 HBITMAP hOldDstBitmap;
1422 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1424 hdcDst = CreateCompatibleDC(0);
1429 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1430 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1431 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1434 SelectObject (hdcDst, himl->hbmImage);
1435 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1436 SelectObject (hdcDst, ii.hbmColor);
1437 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1440 * CreateIconIndirect requires us to deselect the bitmaps from
1441 * the DCs before calling
1443 SelectObject(hdcDst, hOldDstBitmap);
1445 hIcon = CreateIconIndirect (&ii);
1447 DeleteObject (ii.hbmMask);
1448 DeleteObject (ii.hbmColor);
1455 /*************************************************************************
1456 * ImageList_GetIconSize [COMCTL32.@]
1458 * Retrieves the size of an image in an image list.
1461 * himl [I] handle to image list
1462 * cx [O] pointer to the image width.
1463 * cy [O] pointer to the image height.
1470 * All images in an image list have the same size.
1474 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1476 if (!is_valid(himl))
1478 if ((himl->cx <= 0) || (himl->cy <= 0))
1490 /*************************************************************************
1491 * ImageList_GetImageCount [COMCTL32.@]
1493 * Returns the number of images in an image list.
1496 * himl [I] handle to image list
1499 * Success: Number of images.
1504 ImageList_GetImageCount (HIMAGELIST himl)
1506 if (!is_valid(himl))
1509 return himl->cCurImage;
1513 /*************************************************************************
1514 * ImageList_GetImageInfo [COMCTL32.@]
1516 * Returns information about an image in an image list.
1519 * himl [I] handle to image list
1521 * pImageInfo [O] pointer to the image information
1529 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1531 if (!is_valid(himl) || (pImageInfo == NULL))
1533 if ((i < 0) || (i >= himl->cCurImage))
1536 pImageInfo->hbmImage = himl->hbmImage;
1537 pImageInfo->hbmMask = himl->hbmMask;
1539 pImageInfo->rcImage.top = 0;
1540 pImageInfo->rcImage.bottom = himl->cy;
1541 pImageInfo->rcImage.left = i * himl->cx;
1542 pImageInfo->rcImage.right = (i+1) * himl->cx;
1548 /*************************************************************************
1549 * ImageList_GetImageRect [COMCTL32.@]
1551 * Retrieves the rectangle of the specified image in an image list.
1554 * himl [I] handle to image list
1556 * lpRect [O] pointer to the image rectangle
1563 * This is an UNDOCUMENTED function!!!
1567 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1569 if (!is_valid(himl) || (lpRect == NULL))
1571 if ((i < 0) || (i >= himl->cCurImage))
1574 lpRect->left = i * himl->cx;
1576 lpRect->right = lpRect->left + himl->cx;
1577 lpRect->bottom = himl->cy;
1583 /*************************************************************************
1584 * ImageList_LoadImage [COMCTL32.@]
1585 * ImageList_LoadImageA [COMCTL32.@]
1587 * Creates an image list from a bitmap, icon or cursor.
1590 * hi [I] instance handle
1591 * lpbmp [I] name or id of the image
1592 * cx [I] width of each image
1593 * cGrow [I] number of images to expand
1594 * clrMask [I] mask color
1595 * uType [I] type of image to load
1596 * uFlags [I] loading flags
1599 * Success: handle to the loaded image list
1607 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1608 COLORREF clrMask, UINT uType, UINT uFlags)
1610 HIMAGELIST himl = NULL;
1614 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1616 ERR("Error loading image!\n");
1620 if (uType == IMAGE_BITMAP) {
1622 GetObjectA (handle, sizeof(BITMAP), &bmp);
1624 /* To match windows behavior, if cx is set to zero and
1625 the flag DI_DEFAULTSIZE is specified, cx becomes the
1626 system metric value for icons. If the flag is not specified
1627 the function sets the size to the height of the bitmap */
1630 if (uFlags & DI_DEFAULTSIZE)
1631 cx = GetSystemMetrics (SM_CXICON);
1636 nImageCount = bmp.bmWidth / cx;
1638 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1639 nImageCount, cGrow);
1641 DeleteObject (handle);
1644 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1646 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1650 GetIconInfo (handle, &ii);
1651 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1652 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1653 ILC_MASK | ILC_COLOR, 1, cGrow);
1655 DeleteObject (ii.hbmColor);
1656 DeleteObject (ii.hbmMask);
1657 DeleteObject (handle);
1660 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1661 DeleteObject (ii.hbmColor);
1662 DeleteObject (ii.hbmMask);
1665 DeleteObject (handle);
1671 /*************************************************************************
1672 * ImageList_LoadImageW [COMCTL32.@]
1674 * Creates an image list from a bitmap, icon or cursor.
1677 * hi [I] instance handle
1678 * lpbmp [I] name or id of the image
1679 * cx [I] width of each image
1680 * cGrow [I] number of images to expand
1681 * clrMask [I] mask color
1682 * uType [I] type of image to load
1683 * uFlags [I] loading flags
1686 * Success: handle to the loaded image list
1694 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1695 COLORREF clrMask, UINT uType, UINT uFlags)
1697 HIMAGELIST himl = NULL;
1701 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1703 ERR("Error loading image!\n");
1707 if (uType == IMAGE_BITMAP) {
1709 GetObjectA (handle, sizeof(BITMAP), &bmp);
1711 /* To match windows behavior, if cx is set to zero and
1712 the flag DI_DEFAULTSIZE is specified, cx becomes the
1713 system metric value for icons. If the flag is not specified
1714 the function sets the size to the height of the bitmap */
1717 if (uFlags & DI_DEFAULTSIZE)
1718 cx = GetSystemMetrics (SM_CXICON);
1723 nImageCount = bmp.bmWidth / cx;
1725 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1726 nImageCount, cGrow);
1728 DeleteObject (handle);
1731 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1733 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1737 GetIconInfo (handle, &ii);
1738 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1739 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1740 ILC_MASK | ILC_COLOR, 1, cGrow);
1742 DeleteObject (ii.hbmColor);
1743 DeleteObject (ii.hbmMask);
1744 DeleteObject (handle);
1747 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1748 DeleteObject (ii.hbmColor);
1749 DeleteObject (ii.hbmMask);
1752 DeleteObject (handle);
1758 /*************************************************************************
1759 * ImageList_Merge [COMCTL32.@]
1761 * Creates a new image list that contains a merged image from the specified
1762 * images of both source image lists.
1765 * himl1 [I] handle to first image list
1766 * i1 [I] first image index
1767 * himl2 [I] handle to second image list
1768 * i2 [I] second image index
1769 * dx [I] X offset of the second image relative to the first.
1770 * dy [I] Y offset of the second image relative to the first.
1773 * Success: handle of the merged image list.
1778 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1781 HIMAGELIST himlDst = NULL;
1782 HDC hdcSrcImage, hdcDstImage;
1784 INT xOff1, yOff1, xOff2, yOff2;
1787 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1790 if (!is_valid(himl1) || !is_valid(himl2))
1794 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1795 ERR("Index 1 out of range! %d\n", i1);
1799 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1800 ERR("Index 2 out of range! %d\n", i2);
1805 cxDst = max (himl1->cx, dx + himl2->cx);
1810 cxDst = max (himl2->cx, himl1->cx - dx);
1815 cxDst = max (himl1->cx, himl2->cx);
1821 cyDst = max (himl1->cy, dy + himl2->cy);
1826 cyDst = max (himl2->cy, himl1->cy - dy);
1831 cyDst = max (himl1->cy, himl2->cy);
1836 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1841 hdcSrcImage = CreateCompatibleDC (0);
1842 hdcDstImage = CreateCompatibleDC (0);
1843 nX1 = i1 * himl1->cx;
1844 nX2 = i2 * himl2->cx;
1847 SelectObject (hdcSrcImage, himl1->hbmImage);
1848 SelectObject (hdcDstImage, himlDst->hbmImage);
1849 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1850 hdcSrcImage, 0, 0, BLACKNESS);
1851 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1852 hdcSrcImage, nX1, 0, SRCCOPY);
1854 SelectObject (hdcSrcImage, himl2->hbmMask);
1855 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1856 hdcSrcImage, nX2, 0, SRCAND);
1858 SelectObject (hdcSrcImage, himl2->hbmImage);
1859 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1860 hdcSrcImage, nX2, 0, SRCPAINT);
1863 SelectObject (hdcSrcImage, himl1->hbmMask);
1864 SelectObject (hdcDstImage, himlDst->hbmMask);
1865 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1866 hdcSrcImage, 0, 0, WHITENESS);
1867 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1868 hdcSrcImage, nX1, 0, SRCCOPY);
1870 SelectObject (hdcSrcImage, himl2->hbmMask);
1871 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1872 hdcSrcImage, nX2, 0, SRCAND);
1874 DeleteDC (hdcSrcImage);
1875 DeleteDC (hdcDstImage);
1876 himlDst->cCurImage = 1;
1883 /* helper for _read_bitmap currently unused */
1885 static int may_use_dibsection(HDC hdc) {
1886 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1891 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1895 /* helper for ImageList_Read, see comments below */
1896 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1897 HDC xdc = 0, hBitmapDC =0;
1898 BITMAPFILEHEADER bmfh;
1899 BITMAPINFOHEADER bmih;
1900 int bitsperpixel,palspace,longsperline,width,height;
1901 LPBITMAPINFOHEADER bmihc = NULL;
1903 HBITMAP hbitmap = 0, hDIB = 0;
1906 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1907 (bmfh.bfType != (('M'<<8)|'B')) ||
1908 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1909 (bmih.biSize != sizeof(bmih))
1913 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1914 if (bitsperpixel<=8)
1915 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1918 width = bmih.biWidth;
1919 height = bmih.biHeight;
1920 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1921 memcpy(bmihc,&bmih,sizeof(bmih));
1922 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1923 bmihc->biSizeImage = (longsperline*height)<<2;
1925 /* read the palette right after the end of the bitmapinfoheader */
1927 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1931 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1932 if ((bitsperpixel>1) &&
1933 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1935 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1938 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1944 int i,nwidth,nheight,nRows;
1946 nwidth = width*(height/cy);
1948 nRows = (height/cy);
1950 if (bitsperpixel==1)
1951 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1953 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1955 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1958 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1961 hBitmapDC = CreateCompatibleDC(0);
1962 SelectObject(hBitmapDC, hbitmap);
1964 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1965 /* Do not forget that windows bitmaps are bottom->top */
1966 TRACE("nRows=%d\n", nRows);
1967 for (i=0; i < nRows; i++){
1968 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1969 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1975 if (xdc) ReleaseDC(0,xdc);
1976 if (bmihc) LocalFree((HLOCAL)bmihc);
1977 if (hDIB) DeleteObject(hDIB);
1978 if (hBitmapDC) DeleteDC(hBitmapDC);
1981 DeleteObject(hbitmap);
1988 /*************************************************************************
1989 * ImageList_Read [COMCTL32.@]
1991 * Reads an image list from a stream.
1994 * pstm [I] pointer to a stream
1997 * Success: handle to image list
2000 * The format is like this:
2001 * ILHEAD ilheadstruct;
2003 * for the color image part:
2004 * BITMAPFILEHEADER bmfh;
2005 * BITMAPINFOHEADER bmih;
2006 * only if it has a palette:
2007 * RGBQUAD rgbs[nr_of_paletted_colors];
2009 * BYTE colorbits[imagesize];
2011 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2012 * BITMAPFILEHEADER bmfh_mask;
2013 * BITMAPINFOHEADER bmih_mask;
2014 * only if it has a palette (it usually does not):
2015 * RGBQUAD rgbs[nr_of_paletted_colors];
2017 * BYTE maskbits[imagesize];
2019 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2020 * _read_bitmap needs to convert them.
2022 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2026 HBITMAP hbmColor=0,hbmMask=0;
2029 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2031 if (ilHead.usMagic != (('L' << 8) | 'I'))
2033 if (ilHead.usVersion != 0x101) /* probably version? */
2037 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2038 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2039 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2040 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2041 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2042 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2043 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2044 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2045 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2046 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2049 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2052 if (ilHead.flags & ILC_MASK) {
2053 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2055 DeleteObject(hbmColor);
2060 himl = ImageList_Create (
2068 DeleteObject(hbmColor);
2069 DeleteObject(hbmMask);
2072 himl->hbmImage = hbmColor;
2073 himl->hbmMask = hbmMask;
2074 himl->cCurImage = ilHead.cCurImage;
2075 himl->cMaxImage = ilHead.cMaxImage;
2077 ImageList_SetBkColor(himl,ilHead.bkcolor);
2079 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2084 /*************************************************************************
2085 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2088 * himl [I] image list handle
2097 ImageList_Remove (HIMAGELIST himl, INT i)
2099 HBITMAP hbmNewImage, hbmNewMask;
2103 TRACE("(himl=%p i=%d)\n", himl, i);
2105 if (!is_valid(himl)) {
2106 ERR("Invalid image list handle!\n");
2110 if ((i < -1) || (i >= himl->cCurImage)) {
2111 ERR("index out of range! %d\n", i);
2117 if (himl->cCurImage == 0) {
2118 /* remove all on empty ImageList is allowed */
2119 TRACE("remove all on empty ImageList!\n");
2123 himl->cMaxImage = himl->cInitial + himl->cGrow;
2124 himl->cCurImage = 0;
2125 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2126 himl->nOvlIdx[nCount] = -1;
2128 DeleteObject (himl->hbmImage);
2130 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2131 1, himl->uBitsPixel, NULL);
2133 if (himl->hbmMask) {
2134 DeleteObject (himl->hbmMask);
2136 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2141 /* delete one image */
2142 TRACE("Remove single image! %d\n", i);
2144 /* create new bitmap(s) */
2145 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2147 TRACE(" - Number of images: %d / %d (Old/New)\n",
2148 himl->cCurImage, himl->cCurImage - 1);
2149 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2150 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2153 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2156 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2158 hbmNewMask = 0; /* Just to keep compiler happy! */
2160 hdcSrc = CreateCompatibleDC (0);
2161 hdcDst = CreateCompatibleDC (0);
2163 /* copy all images and masks prior to the "removed" image */
2165 TRACE("Pre image copy: Copy %d images\n", i);
2167 SelectObject (hdcSrc, himl->hbmImage);
2168 SelectObject (hdcDst, hbmNewImage);
2169 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2170 hdcSrc, 0, 0, SRCCOPY);
2172 if (himl->hbmMask) {
2173 SelectObject (hdcSrc, himl->hbmMask);
2174 SelectObject (hdcDst, hbmNewMask);
2175 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2176 hdcSrc, 0, 0, SRCCOPY);
2180 /* copy all images and masks behind the removed image */
2181 if (i < himl->cCurImage - 1) {
2182 TRACE("Post image copy!\n");
2183 SelectObject (hdcSrc, himl->hbmImage);
2184 SelectObject (hdcDst, hbmNewImage);
2185 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2186 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2188 if (himl->hbmMask) {
2189 SelectObject (hdcSrc, himl->hbmMask);
2190 SelectObject (hdcDst, hbmNewMask);
2191 BitBlt (hdcDst, i * himl->cx, 0,
2192 (himl->cCurImage - i - 1) * himl->cx,
2193 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2200 /* delete old images and insert new ones */
2201 DeleteObject (himl->hbmImage);
2202 himl->hbmImage = hbmNewImage;
2203 if (himl->hbmMask) {
2204 DeleteObject (himl->hbmMask);
2205 himl->hbmMask = hbmNewMask;
2209 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2216 /*************************************************************************
2217 * ImageList_Replace [COMCTL32.@]
2219 * Replaces an image in an image list with a new image.
2222 * himl [I] handle to image list
2224 * hbmImage [I] handle to image bitmap
2225 * hbmMask [I] handle to mask bitmap. Can be NULL.
2233 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2236 HDC hdcImageList, hdcImage;
2239 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2241 if (!is_valid(himl)) {
2242 ERR("Invalid image list handle!\n");
2246 if ((i >= himl->cMaxImage) || (i < 0)) {
2247 ERR("Invalid image index!\n");
2251 hdcImageList = CreateCompatibleDC (0);
2252 hdcImage = CreateCompatibleDC (0);
2253 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2256 SelectObject (hdcImageList, himl->hbmImage);
2257 SelectObject (hdcImage, hbmImage);
2259 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2260 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2265 SelectObject (hdcImageList, himl->hbmMask);
2266 SelectObject (hdcImage, hbmMask);
2268 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2269 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2272 /* Remove the background from the image
2274 SelectObject (hdcImageList, himl->hbmImage);
2275 StretchBlt (hdcImageList,
2276 i*himl->cx, 0, himl->cx, himl->cy,
2278 0, 0, bmp.bmWidth, bmp.bmHeight,
2279 0x220326); /* NOTSRCAND */
2282 DeleteDC (hdcImage);
2283 DeleteDC (hdcImageList);
2289 /*************************************************************************
2290 * ImageList_ReplaceIcon [COMCTL32.@]
2292 * Replaces an image in an image list using an icon.
2295 * himl [I] handle to image list
2297 * hIcon [I] handle to icon
2300 * Success: index of the replaced image
2305 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2307 HDC hdcImageList, hdcImage;
2310 HBITMAP hbmOldSrc, hbmOldDst;
2314 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2316 if (!is_valid(himl))
2318 if ((i >= himl->cMaxImage) || (i < -1))
2321 hBestFitIcon = CopyImage(
2324 LR_COPYFROMRESOURCE);
2326 GetIconInfo (hBestFitIcon, &ii);
2327 if (ii.hbmMask == 0)
2329 if (ii.hbmColor == 0)
2331 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2334 if (himl->cCurImage + 1 > himl->cMaxImage)
2335 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2337 nIndex = himl->cCurImage;
2343 hdcImageList = CreateCompatibleDC (0);
2344 TRACE("hdcImageList=%p!\n", hdcImageList);
2345 if (hdcImageList == 0)
2346 ERR("invalid hdcImageList!\n");
2348 hdcImage = CreateCompatibleDC (0);
2349 TRACE("hdcImage=%p!\n", hdcImage);
2351 ERR("invalid hdcImage!\n");
2353 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2354 SetTextColor( hdcImageList, RGB(0,0,0));
2355 SetBkColor( hdcImageList, RGB(255,255,255));
2356 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2357 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2358 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2360 if (himl->hbmMask) {
2361 SelectObject (hdcImageList, himl->hbmMask);
2362 SelectObject (hdcImage, ii.hbmMask);
2363 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2364 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2367 SelectObject (hdcImage, hbmOldSrc);
2368 SelectObject (hdcImageList, hbmOldDst);
2371 DestroyIcon(hBestFitIcon);
2373 DeleteDC (hdcImageList);
2375 DeleteDC (hdcImage);
2377 DeleteObject (ii.hbmColor);
2379 DeleteObject (ii.hbmMask);
2385 /*************************************************************************
2386 * ImageList_SetBkColor [COMCTL32.@]
2388 * Sets the background color of an image list.
2391 * himl [I] handle to image list
2392 * clrBk [I] background color
2395 * Success: previous background color
2400 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2404 if (!is_valid(himl))
2407 clrOldBk = himl->clrBk;
2408 himl->clrBk = clrBk;
2413 /*************************************************************************
2414 * ImageList_SetDragCursorImage [COMCTL32.@]
2416 * Combines the specified image with the current drag image
2419 * himlDrag [I] handle to drag image list
2420 * iDrag [I] drag image index
2421 * dxHotspot [I] X position of the hot spot
2422 * dyHotspot [I] Y position of the hot spot
2429 * When this function is called and the drag image is visible, a
2430 * short flickering occurs but this matches the Win9x behavior. It is
2431 * possible to fix the flickering using code like in ImageList_DragMove.
2435 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2436 INT dxHotspot, INT dyHotspot)
2438 HIMAGELIST himlTemp;
2442 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2445 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2446 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2448 visible = InternalDrag.bShow;
2450 /* Calculate the offset between the origin of the old image and the
2451 * origin of the second image.
2452 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2453 * hotspot) to the origin of the second image.
2454 * See M$DN for details */
2455 if(InternalDrag.bHSPending) {
2458 InternalDrag.bHSPending = FALSE;
2460 dx = InternalDrag.dxHotspot - dxHotspot;
2461 dy = InternalDrag.dyHotspot - dyHotspot;
2463 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2466 /* hide the drag image */
2467 ImageList_DragShowNolock(FALSE);
2469 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2470 (InternalDrag.himl->cy != himlTemp->cy)) {
2471 /* the size of the drag image changed, invalidate the buffer */
2472 DeleteObject(InternalDrag.hbmBg);
2473 InternalDrag.hbmBg = 0;
2476 ImageList_Destroy (InternalDrag.himl);
2477 InternalDrag.himl = himlTemp;
2479 /* update the InternalDragOffset, if the origin of the
2480 * DragImage was changed by ImageList_Merge. */
2482 InternalDrag.dxHotspot = dxHotspot;
2484 InternalDrag.dyHotspot = dyHotspot;
2487 /* show the drag image */
2488 ImageList_DragShowNolock(TRUE);
2495 /*************************************************************************
2496 * ImageList_SetFilter [COMCTL32.@]
2498 * Sets a filter (or does something completely different)!!???
2499 * It removes 12 Bytes from the stack (3 Parameters).
2502 * himl [I] SHOULD be a handle to image list
2503 * i [I] COULD be an index?
2508 * Failure: FALSE ???
2511 * This is an UNDOCUMENTED function!!!!
2516 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2518 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2524 /*************************************************************************
2525 * ImageList_SetFlags [COMCTL32.@]
2532 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2534 FIXME("(%p %08lx):empty stub\n", himl, flags);
2539 /*************************************************************************
2540 * ImageList_SetIconSize [COMCTL32.@]
2542 * Sets the image size of the bitmap and deletes all images.
2545 * himl [I] handle to image list
2546 * cx [I] image width
2547 * cy [I] image height
2555 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2559 if (!is_valid(himl))
2562 /* remove all images */
2563 himl->cMaxImage = himl->cInitial + himl->cGrow;
2564 himl->cCurImage = 0;
2568 /* initialize overlay mask indices */
2569 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2570 himl->nOvlIdx[nCount] = -1;
2572 DeleteObject (himl->hbmImage);
2574 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2575 1, himl->uBitsPixel, NULL);
2577 if (himl->hbmMask) {
2578 DeleteObject (himl->hbmMask);
2580 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2588 /*************************************************************************
2589 * ImageList_SetImageCount [COMCTL32.@]
2591 * Resizes an image list to the specified number of images.
2594 * himl [I] handle to image list
2595 * iImageCount [I] number of images in the image list
2603 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2605 HDC hdcImageList, hdcBitmap;
2606 HBITMAP hbmNewBitmap;
2607 INT nNewCount, nCopyCount;
2609 TRACE("%p %d\n",himl,iImageCount);
2611 if (!is_valid(himl))
2613 if (himl->cCurImage >= iImageCount)
2615 if (himl->cMaxImage > iImageCount)
2617 himl->cCurImage = iImageCount;
2621 nNewCount = iImageCount + himl->cGrow;
2622 nCopyCount = min(himl->cCurImage, iImageCount);
2624 hdcImageList = CreateCompatibleDC (0);
2625 hdcBitmap = CreateCompatibleDC (0);
2627 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2628 1, himl->uBitsPixel, NULL);
2629 if (hbmNewBitmap != 0)
2631 SelectObject (hdcImageList, himl->hbmImage);
2632 SelectObject (hdcBitmap, hbmNewBitmap);
2635 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2636 hdcImageList, 0, 0, SRCCOPY);
2638 /* delete 'empty' image space */
2639 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2640 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2641 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2642 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2644 DeleteObject (himl->hbmImage);
2645 himl->hbmImage = hbmNewBitmap;
2648 ERR("Could not create new image bitmap !\n");
2652 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2654 if (hbmNewBitmap != 0)
2656 SelectObject (hdcImageList, himl->hbmMask);
2657 SelectObject (hdcBitmap, hbmNewBitmap);
2660 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2661 hdcImageList, 0, 0, SRCCOPY);
2663 /* delete 'empty' image space */
2664 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2665 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2666 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2667 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2669 DeleteObject (himl->hbmMask);
2670 himl->hbmMask = hbmNewBitmap;
2673 ERR("Could not create new mask bitmap!\n");
2676 DeleteDC (hdcImageList);
2677 DeleteDC (hdcBitmap);
2679 /* Update max image count and current image count */
2680 himl->cMaxImage = nNewCount;
2681 himl->cCurImage = iImageCount;
2687 /*************************************************************************
2688 * ImageList_SetOverlayImage [COMCTL32.@]
2690 * Assigns an overlay mask index to an existing image in an image list.
2693 * himl [I] handle to image list
2694 * iImage [I] image index
2695 * iOverlay [I] overlay mask index
2703 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2705 if (!is_valid(himl))
2707 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2709 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2711 himl->nOvlIdx[iOverlay - 1] = iImage;
2717 /* helper for ImageList_Write - write bitmap to pstm
2718 * currently everything is written as 24 bit RGB, except masks
2721 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2723 LPBITMAPFILEHEADER bmfh;
2724 LPBITMAPINFOHEADER bmih;
2725 LPBYTE data, lpBits, lpBitsOrg;
2727 INT bitCount, sizeImage, offBits, totalSize;
2728 INT nwidth, nheight, nsizeImage, icount;
2730 BOOL result = FALSE;
2734 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2736 /* XXX is this always correct? */
2737 icount = bm.bmWidth / cx;
2739 nheight = cy * ((icount+3)>>2);
2741 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2742 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2743 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2745 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2747 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2748 offBits = totalSize;
2749 totalSize += nsizeImage;
2751 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2752 bmfh = (LPBITMAPFILEHEADER)data;
2753 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2754 lpBits = data + offBits;
2756 /* setup BITMAPFILEHEADER */
2757 bmfh->bfType = (('M' << 8) | 'B');
2759 bmfh->bfReserved1 = 0;
2760 bmfh->bfReserved2 = 0;
2761 bmfh->bfOffBits = offBits;
2763 /* setup BITMAPINFOHEADER */
2764 bmih->biSize = sizeof(BITMAPINFOHEADER);
2765 bmih->biWidth = bm.bmWidth;
2766 bmih->biHeight = bm.bmHeight;
2768 bmih->biBitCount = bitCount;
2769 bmih->biCompression = BI_RGB;
2770 bmih->biSizeImage = nsizeImage;
2771 bmih->biXPelsPerMeter = 0;
2772 bmih->biYPelsPerMeter = 0;
2773 bmih->biClrUsed = 0;
2774 bmih->biClrImportant = 0;
2776 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2777 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2778 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2782 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2783 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2785 for(i = 0; i < nheight; i++) {
2786 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2787 int noff = (nbpl * (nheight-1-i));
2788 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2792 bmih->biWidth = nwidth;
2793 bmih->biHeight = nheight;
2797 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2798 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2799 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2802 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2809 LocalFree((HLOCAL)lpBitsOrg);
2815 /*************************************************************************
2816 * ImageList_Write [COMCTL32.@]
2818 * Writes an image list to a stream.
2821 * himl [I] handle to image list
2822 * pstm [O] Pointer to a stream.
2833 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2838 if (!is_valid(himl))
2841 ilHead.usMagic = (('L' << 8) | 'I');
2842 ilHead.usVersion = 0x101;
2843 ilHead.cCurImage = himl->cCurImage;
2844 ilHead.cMaxImage = himl->cMaxImage;
2845 ilHead.cGrow = himl->cGrow;
2846 ilHead.cx = himl->cx;
2847 ilHead.cy = himl->cy;
2848 ilHead.bkcolor = himl->clrBk;
2849 ilHead.flags = himl->flags;
2850 for(i = 0; i < 4; i++) {
2851 ilHead.ovls[i] = himl->nOvlIdx[i];
2854 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2857 /* write the bitmap */
2858 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2861 /* write the mask if we have one */
2862 if(himl->flags & ILC_MASK) {
2863 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))