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 belive 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 GetObjectA (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) {
1898 BITMAPFILEHEADER bmfh;
1899 BITMAPINFOHEADER bmih;
1900 int bitsperpixel,palspace,longsperline,width,height;
1901 LPBITMAPINFOHEADER bmihc = NULL;
1903 HBITMAP hbitmap = 0;
1904 LPBYTE bits = NULL,nbits = NULL;
1905 int nbytesperline,bytesperline;
1907 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1908 (bmfh.bfType != (('M'<<8)|'B')) ||
1909 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1910 (bmih.biSize != sizeof(bmih))
1914 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1915 if (bitsperpixel<=8)
1916 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1919 width = bmih.biWidth;
1920 height = bmih.biHeight;
1921 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1922 memcpy(bmihc,&bmih,sizeof(bmih));
1923 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1924 bmihc->biSizeImage = (longsperline*height)<<2;
1926 /* read the palette right after the end of the bitmapinfoheader */
1928 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1932 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1933 if ((bitsperpixel>1) &&
1934 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1936 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1939 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1945 int i,nwidth,nheight;
1947 nwidth = width*(height/cy);
1950 if (bitsperpixel==1)
1951 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1953 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1955 /* Might be a bit excessive memory use here */
1956 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1957 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1958 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1961 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1962 /* Do not forget that windows bitmaps are bottom->top */
1963 bytesperline = longsperline*4;
1964 nbytesperline = (height/cy)*bytesperline;
1965 for (i=0;i<height;i++) {
1967 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1968 bits+bytesperline*(height-1-i),
1972 bmihc->biWidth = nwidth;
1973 bmihc->biHeight = nheight;
1974 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1976 LocalFree((HLOCAL)nbits);
1977 LocalFree((HLOCAL)bits);
1981 if (xdc) ReleaseDC(0,xdc);
1982 if (bmihc) LocalFree((HLOCAL)bmihc);
1985 DeleteObject(hbitmap);
1992 /*************************************************************************
1993 * ImageList_Read [COMCTL32.@]
1995 * Reads an image list from a stream.
1998 * pstm [I] pointer to a stream
2001 * Success: handle to image list
2004 * The format is like this:
2005 * ILHEAD ilheadstruct;
2007 * for the color image part:
2008 * BITMAPFILEHEADER bmfh;
2009 * BITMAPINFOHEADER bmih;
2010 * only if it has a palette:
2011 * RGBQUAD rgbs[nr_of_paletted_colors];
2013 * BYTE colorbits[imagesize];
2015 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2016 * BITMAPFILEHEADER bmfh_mask;
2017 * BITMAPINFOHEADER bmih_mask;
2018 * only if it has a palette (it usually does not):
2019 * RGBQUAD rgbs[nr_of_paletted_colors];
2021 * BYTE maskbits[imagesize];
2023 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2024 * _read_bitmap needs to convert them.
2026 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2030 HBITMAP hbmColor=0,hbmMask=0;
2033 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2035 if (ilHead.usMagic != (('L' << 8) | 'I'))
2037 if (ilHead.usVersion != 0x101) /* probably version? */
2041 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2042 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2043 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2044 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2045 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2046 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2047 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2048 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2049 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2050 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2053 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2056 if (ilHead.flags & ILC_MASK) {
2057 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2059 DeleteObject(hbmColor);
2064 himl = ImageList_Create (
2072 DeleteObject(hbmColor);
2073 DeleteObject(hbmMask);
2076 himl->hbmImage = hbmColor;
2077 himl->hbmMask = hbmMask;
2078 himl->cCurImage = ilHead.cCurImage;
2079 himl->cMaxImage = ilHead.cMaxImage;
2081 ImageList_SetBkColor(himl,ilHead.bkcolor);
2083 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2088 /*************************************************************************
2089 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2092 * himl [I] image list handle
2101 ImageList_Remove (HIMAGELIST himl, INT i)
2103 HBITMAP hbmNewImage, hbmNewMask;
2107 TRACE("(himl=%p i=%d)\n", himl, i);
2109 if (!is_valid(himl)) {
2110 ERR("Invalid image list handle!\n");
2114 if ((i < -1) || (i >= himl->cCurImage)) {
2115 ERR("index out of range! %d\n", i);
2121 if (himl->cCurImage == 0) {
2122 /* remove all on empty ImageList is allowed */
2123 TRACE("remove all on empty ImageList!\n");
2127 himl->cMaxImage = himl->cInitial + himl->cGrow;
2128 himl->cCurImage = 0;
2129 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2130 himl->nOvlIdx[nCount] = -1;
2132 DeleteObject (himl->hbmImage);
2134 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2135 1, himl->uBitsPixel, NULL);
2137 if (himl->hbmMask) {
2138 DeleteObject (himl->hbmMask);
2140 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2145 /* delete one image */
2146 TRACE("Remove single image! %d\n", i);
2148 /* create new bitmap(s) */
2149 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2151 TRACE(" - Number of images: %d / %d (Old/New)\n",
2152 himl->cCurImage, himl->cCurImage - 1);
2153 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2154 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2157 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2160 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2162 hbmNewMask = 0; /* Just to keep compiler happy! */
2164 hdcSrc = CreateCompatibleDC (0);
2165 hdcDst = CreateCompatibleDC (0);
2167 /* copy all images and masks prior to the "removed" image */
2169 TRACE("Pre image copy: Copy %d images\n", i);
2171 SelectObject (hdcSrc, himl->hbmImage);
2172 SelectObject (hdcDst, hbmNewImage);
2173 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2174 hdcSrc, 0, 0, SRCCOPY);
2176 if (himl->hbmMask) {
2177 SelectObject (hdcSrc, himl->hbmMask);
2178 SelectObject (hdcDst, hbmNewMask);
2179 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2180 hdcSrc, 0, 0, SRCCOPY);
2184 /* copy all images and masks behind the removed image */
2185 if (i < himl->cCurImage - 1) {
2186 TRACE("Post image copy!\n");
2187 SelectObject (hdcSrc, himl->hbmImage);
2188 SelectObject (hdcDst, hbmNewImage);
2189 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2190 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2192 if (himl->hbmMask) {
2193 SelectObject (hdcSrc, himl->hbmMask);
2194 SelectObject (hdcDst, hbmNewMask);
2195 BitBlt (hdcDst, i * himl->cx, 0,
2196 (himl->cCurImage - i - 1) * himl->cx,
2197 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2204 /* delete old images and insert new ones */
2205 DeleteObject (himl->hbmImage);
2206 himl->hbmImage = hbmNewImage;
2207 if (himl->hbmMask) {
2208 DeleteObject (himl->hbmMask);
2209 himl->hbmMask = hbmNewMask;
2213 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2220 /*************************************************************************
2221 * ImageList_Replace [COMCTL32.@]
2223 * Replaces an image in an image list with a new image.
2226 * himl [I] handle to image list
2228 * hbmImage [I] handle to image bitmap
2229 * hbmMask [I] handle to mask bitmap. Can be NULL.
2237 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2240 HDC hdcImageList, hdcImage;
2243 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2245 if (!is_valid(himl)) {
2246 ERR("Invalid image list handle!\n");
2250 if ((i >= himl->cMaxImage) || (i < 0)) {
2251 ERR("Invalid image index!\n");
2255 hdcImageList = CreateCompatibleDC (0);
2256 hdcImage = CreateCompatibleDC (0);
2257 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2260 SelectObject (hdcImageList, himl->hbmImage);
2261 SelectObject (hdcImage, hbmImage);
2263 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2264 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2269 SelectObject (hdcImageList, himl->hbmMask);
2270 SelectObject (hdcImage, hbmMask);
2272 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2273 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2276 /* Remove the background from the image
2278 SelectObject (hdcImageList, himl->hbmImage);
2279 StretchBlt (hdcImageList,
2280 i*himl->cx, 0, himl->cx, himl->cy,
2282 0, 0, bmp.bmWidth, bmp.bmHeight,
2283 0x220326); /* NOTSRCAND */
2286 DeleteDC (hdcImage);
2287 DeleteDC (hdcImageList);
2293 /*************************************************************************
2294 * ImageList_ReplaceIcon [COMCTL32.@]
2296 * Replaces an image in an image list using an icon.
2299 * himl [I] handle to image list
2301 * hIcon [I] handle to icon
2304 * Success: index of the replaced image
2309 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2311 HDC hdcImageList, hdcImage;
2314 HBITMAP hbmOldSrc, hbmOldDst;
2318 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2320 if (!is_valid(himl))
2322 if ((i >= himl->cMaxImage) || (i < -1))
2325 hBestFitIcon = CopyImage(
2328 LR_COPYFROMRESOURCE);
2330 GetIconInfo (hBestFitIcon, &ii);
2331 if (ii.hbmMask == 0)
2333 if (ii.hbmColor == 0)
2335 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2338 if (himl->cCurImage + 1 > himl->cMaxImage)
2339 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2341 nIndex = himl->cCurImage;
2347 hdcImageList = CreateCompatibleDC (0);
2348 TRACE("hdcImageList=%p!\n", hdcImageList);
2349 if (hdcImageList == 0)
2350 ERR("invalid hdcImageList!\n");
2352 hdcImage = CreateCompatibleDC (0);
2353 TRACE("hdcImage=%p!\n", hdcImage);
2355 ERR("invalid hdcImage!\n");
2357 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2358 SetTextColor( hdcImageList, RGB(0,0,0));
2359 SetBkColor( hdcImageList, RGB(255,255,255));
2360 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2361 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2362 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2364 if (himl->hbmMask) {
2365 SelectObject (hdcImageList, himl->hbmMask);
2366 SelectObject (hdcImage, ii.hbmMask);
2367 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2368 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2371 SelectObject (hdcImage, hbmOldSrc);
2372 SelectObject (hdcImageList, hbmOldDst);
2375 DestroyIcon(hBestFitIcon);
2377 DeleteDC (hdcImageList);
2379 DeleteDC (hdcImage);
2381 DeleteObject (ii.hbmColor);
2383 DeleteObject (ii.hbmMask);
2389 /*************************************************************************
2390 * ImageList_SetBkColor [COMCTL32.@]
2392 * Sets the background color of an image list.
2395 * himl [I] handle to image list
2396 * clrBk [I] background color
2399 * Success: previous background color
2404 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2408 if (!is_valid(himl))
2411 clrOldBk = himl->clrBk;
2412 himl->clrBk = clrBk;
2417 /*************************************************************************
2418 * ImageList_SetDragCursorImage [COMCTL32.@]
2420 * Combines the specified image with the current drag image
2423 * himlDrag [I] handle to drag image list
2424 * iDrag [I] drag image index
2425 * dxHotspot [I] X position of the hot spot
2426 * dyHotspot [I] Y position of the hot spot
2433 * When this function is called and the drag image is visible, a
2434 * short flickering occurs but this matches the Win9x behavior. It is
2435 * possible to fix the flickering using code like in ImageList_DragMove.
2439 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2440 INT dxHotspot, INT dyHotspot)
2442 HIMAGELIST himlTemp;
2446 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2449 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2450 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2452 visible = InternalDrag.bShow;
2454 /* Calculate the offset between the origin of the old image and the
2455 * origin of the second image.
2456 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2457 * hotspot) to the origin of the second image.
2458 * See M$DN for details */
2459 if(InternalDrag.bHSPending) {
2462 InternalDrag.bHSPending = FALSE;
2464 dx = InternalDrag.dxHotspot - dxHotspot;
2465 dy = InternalDrag.dyHotspot - dyHotspot;
2467 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2470 /* hide the drag image */
2471 ImageList_DragShowNolock(FALSE);
2473 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2474 (InternalDrag.himl->cy != himlTemp->cy)) {
2475 /* the size of the drag image changed, invalidate the buffer */
2476 DeleteObject(InternalDrag.hbmBg);
2477 InternalDrag.hbmBg = 0;
2480 ImageList_Destroy (InternalDrag.himl);
2481 InternalDrag.himl = himlTemp;
2483 /* update the InternalDragOffset, if the origin of the
2484 * DragImage was changed by ImageList_Merge. */
2486 InternalDrag.dxHotspot = dxHotspot;
2488 InternalDrag.dyHotspot = dyHotspot;
2491 /* show the drag image */
2492 ImageList_DragShowNolock(TRUE);
2499 /*************************************************************************
2500 * ImageList_SetFilter [COMCTL32.@]
2502 * Sets a filter (or does something completely different)!!???
2503 * It removes 12 Bytes from the stack (3 Parameters).
2506 * himl [I] SHOULD be a handle to image list
2507 * i [I] COULD be an index?
2512 * Failure: FALSE ???
2515 * This is an UNDOCUMENTED function!!!!
2520 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2522 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2528 /*************************************************************************
2529 * ImageList_SetFlags [COMCTL32.@]
2536 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2538 FIXME("(%p %08lx):empty stub\n", himl, flags);
2543 /*************************************************************************
2544 * ImageList_SetIconSize [COMCTL32.@]
2546 * Sets the image size of the bitmap and deletes all images.
2549 * himl [I] handle to image list
2550 * cx [I] image width
2551 * cy [I] image height
2559 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2563 if (!is_valid(himl))
2566 /* remove all images */
2567 himl->cMaxImage = himl->cInitial + himl->cGrow;
2568 himl->cCurImage = 0;
2572 /* initialize overlay mask indices */
2573 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2574 himl->nOvlIdx[nCount] = -1;
2576 DeleteObject (himl->hbmImage);
2578 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2579 1, himl->uBitsPixel, NULL);
2581 if (himl->hbmMask) {
2582 DeleteObject (himl->hbmMask);
2584 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2592 /*************************************************************************
2593 * ImageList_SetImageCount [COMCTL32.@]
2595 * Resizes an image list to the specified number of images.
2598 * himl [I] handle to image list
2599 * iImageCount [I] number of images in the image list
2607 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2609 HDC hdcImageList, hdcBitmap;
2610 HBITMAP hbmNewBitmap;
2611 INT nNewCount, nCopyCount;
2613 TRACE("%p %d\n",himl,iImageCount);
2615 if (!is_valid(himl))
2617 if (himl->cCurImage >= iImageCount)
2619 if (himl->cMaxImage > iImageCount)
2621 himl->cCurImage = iImageCount;
2625 nNewCount = iImageCount + himl->cGrow;
2626 nCopyCount = min(himl->cCurImage, iImageCount);
2628 hdcImageList = CreateCompatibleDC (0);
2629 hdcBitmap = CreateCompatibleDC (0);
2631 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2632 1, himl->uBitsPixel, NULL);
2633 if (hbmNewBitmap != 0)
2635 SelectObject (hdcImageList, himl->hbmImage);
2636 SelectObject (hdcBitmap, hbmNewBitmap);
2639 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2640 hdcImageList, 0, 0, SRCCOPY);
2642 /* delete 'empty' image space */
2643 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2644 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2645 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2646 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2648 DeleteObject (himl->hbmImage);
2649 himl->hbmImage = hbmNewBitmap;
2652 ERR("Could not create new image bitmap !\n");
2656 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2658 if (hbmNewBitmap != 0)
2660 SelectObject (hdcImageList, himl->hbmMask);
2661 SelectObject (hdcBitmap, hbmNewBitmap);
2664 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2665 hdcImageList, 0, 0, SRCCOPY);
2667 /* delete 'empty' image space */
2668 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2669 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2670 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2671 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2673 DeleteObject (himl->hbmMask);
2674 himl->hbmMask = hbmNewBitmap;
2677 ERR("Could not create new mask bitmap!\n");
2680 DeleteDC (hdcImageList);
2681 DeleteDC (hdcBitmap);
2683 /* Update max image count and current image count */
2684 himl->cMaxImage = nNewCount;
2685 himl->cCurImage = iImageCount;
2691 /*************************************************************************
2692 * ImageList_SetOverlayImage [COMCTL32.@]
2694 * Assigns an overlay mask index to an existing image in an image list.
2697 * himl [I] handle to image list
2698 * iImage [I] image index
2699 * iOverlay [I] overlay mask index
2707 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2709 if (!is_valid(himl))
2711 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2713 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2715 himl->nOvlIdx[iOverlay - 1] = iImage;
2721 /* helper for ImageList_Write - write bitmap to pstm
2722 * currently everything is written as 24 bit RGB, except masks
2725 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2727 LPBITMAPFILEHEADER bmfh;
2728 LPBITMAPINFOHEADER bmih;
2729 LPBYTE data, lpBits, lpBitsOrg;
2731 INT bitCount, sizeImage, offBits, totalSize;
2732 INT nwidth, nheight, nsizeImage, icount;
2734 BOOL result = FALSE;
2738 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2740 /* XXX is this always correct? */
2741 icount = bm.bmWidth / cx;
2743 nheight = cy * ((icount+3)>>2);
2745 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2746 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2747 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2749 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2751 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2752 offBits = totalSize;
2753 totalSize += nsizeImage;
2755 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2756 bmfh = (LPBITMAPFILEHEADER)data;
2757 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2758 lpBits = data + offBits;
2760 /* setup BITMAPFILEHEADER */
2761 bmfh->bfType = (('M' << 8) | 'B');
2763 bmfh->bfReserved1 = 0;
2764 bmfh->bfReserved2 = 0;
2765 bmfh->bfOffBits = offBits;
2767 /* setup BITMAPINFOHEADER */
2768 bmih->biSize = sizeof(BITMAPINFOHEADER);
2769 bmih->biWidth = bm.bmWidth;
2770 bmih->biHeight = bm.bmHeight;
2772 bmih->biBitCount = bitCount;
2773 bmih->biCompression = BI_RGB;
2774 bmih->biSizeImage = nsizeImage;
2775 bmih->biXPelsPerMeter = 0;
2776 bmih->biYPelsPerMeter = 0;
2777 bmih->biClrUsed = 0;
2778 bmih->biClrImportant = 0;
2780 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2781 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2782 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2786 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2787 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2789 for(i = 0; i < nheight; i++) {
2790 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2791 int noff = (nbpl * (nheight-1-i));
2792 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2796 bmih->biWidth = nwidth;
2797 bmih->biHeight = nheight;
2801 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2802 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2803 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2806 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2813 LocalFree((HLOCAL)lpBitsOrg);
2819 /*************************************************************************
2820 * ImageList_Write [COMCTL32.@]
2822 * Writes an image list to a stream.
2825 * himl [I] handle to image list
2826 * pstm [O] Pointer to a stream.
2837 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2842 if (!is_valid(himl))
2845 ilHead.usMagic = (('L' << 8) | 'I');
2846 ilHead.usVersion = 0x101;
2847 ilHead.cCurImage = himl->cCurImage;
2848 ilHead.cMaxImage = himl->cMaxImage;
2849 ilHead.cGrow = himl->cGrow;
2850 ilHead.cx = himl->cx;
2851 ilHead.cy = himl->cy;
2852 ilHead.bkcolor = himl->clrBk;
2853 ilHead.flags = himl->flags;
2854 for(i = 0; i < 4; i++) {
2855 ilHead.ovls[i] = himl->nOvlIdx[i];
2858 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2861 /* write the bitmap */
2862 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2865 /* write the mask if we have one */
2866 if(himl->flags & ILC_MASK) {
2867 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))