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...
48 #include "wine/obj_base.h"
49 #include "wine/obj_storage.h"
51 #include "imagelist.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
57 #define MAX_OVERLAYIMAGE 15
59 /* internal image list data used for Drag & Drop operations */
64 /* position of the drag image relative to the window */
67 /* offset of the hotspot relative to the origin of the image */
70 /* is the drag image visible */
72 /* saved background */
77 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
81 /*************************************************************************
82 * IMAGELIST_InternalExpandBitmaps [Internal]
84 * Expands the bitmaps of an image list by the given number of images.
87 * himl [I] handle to image list
88 * nImageCount [I] number of images to add
94 * This function can NOT be used to reduce the number of images.
97 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
99 HDC hdcImageList, hdcBitmap;
100 HBITMAP hbmNewBitmap;
101 INT nNewWidth, nNewCount;
103 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
107 if (cy == 0) cy = himl->cy;
108 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
109 nNewWidth = nNewCount * himl->cx;
111 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
112 hdcImageList = CreateCompatibleDC (0);
113 hdcBitmap = CreateCompatibleDC (0);
116 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
117 if (hbmNewBitmap == 0)
118 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
120 SelectObject (hdcImageList, himl->hbmImage);
121 SelectObject (hdcBitmap, hbmNewBitmap);
122 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
123 hdcImageList, 0, 0, SRCCOPY);
125 DeleteObject (himl->hbmImage);
126 himl->hbmImage = hbmNewBitmap;
130 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
132 if (hbmNewBitmap == 0)
133 ERR("creating new mask bitmap!\n");
135 SelectObject (hdcImageList, himl->hbmMask);
136 SelectObject (hdcBitmap, hbmNewBitmap);
137 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
138 hdcImageList, 0, 0, SRCCOPY);
139 DeleteObject (himl->hbmMask);
140 himl->hbmMask = hbmNewBitmap;
143 himl->cMaxImage = nNewCount;
145 DeleteDC (hdcImageList);
146 DeleteDC (hdcBitmap);
150 /*************************************************************************
151 * ImageList_Add [COMCTL32.@]
153 * Add an image or images to an image list.
156 * himl [I] handle to image list
157 * hbmImage [I] handle to image bitmap
158 * hbmMask [I] handle to mask bitmap
161 * Success: Index of the first new image.
166 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
168 HDC hdcImage, hdcBitmap;
169 INT nFirstIndex, nImageCount;
172 HBITMAP hOldBitmapImage, hOldBitmap;
174 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
175 if (!himl || !hbmImage)
178 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
179 nImageCount = bmp.bmWidth / himl->cx;
181 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
183 nStartX = himl->cCurImage * himl->cx;
185 hdcImage = CreateCompatibleDC(0);
186 hdcBitmap = CreateCompatibleDC(0);
188 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
189 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
191 /* Copy result to the imagelist
193 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
194 hdcBitmap, 0, 0, SRCCOPY);
198 HDC hdcMask, hdcTemp;
199 HBITMAP hOldBitmapMask, hOldBitmapTemp;
201 hdcMask = CreateCompatibleDC (0);
202 hdcTemp = CreateCompatibleDC(0);
203 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
204 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
207 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
212 SelectObject(hdcTemp, hOldBitmapTemp);
215 /* Remove the background from the image
218 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
221 0x220326); /* NOTSRCAND */
223 SelectObject(hdcMask, hOldBitmapMask);
227 SelectObject(hdcImage, hOldBitmapImage);
228 SelectObject(hdcBitmap, hOldBitmap);
232 nFirstIndex = himl->cCurImage;
233 himl->cCurImage += nImageCount;
239 /*************************************************************************
240 * ImageList_AddIcon [COMCTL32.@]
242 * Adds an icon to an image list.
245 * himl [I] handle to image list
246 * hIcon [I] handle to icon
249 * Success: index of the new image
254 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
256 return ImageList_ReplaceIcon (himl, -1, hIcon);
260 /*************************************************************************
261 * ImageList_AddMasked [COMCTL32.@]
263 * Adds an image or images to an image list and creates a mask from the
264 * specified bitmap using the mask color.
267 * himl [I] handle to image list.
268 * hBitmap [I] handle to bitmap
269 * clrMask [I] mask color.
272 * Success: Index of the first new image.
277 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
279 HDC hdcImage, hdcMask, hdcBitmap;
280 INT nIndex, nImageCount, nMaskXOffset=0;
282 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
283 HBITMAP hMaskBitmap=0;
286 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
290 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
293 nImageCount = bmp.bmWidth / himl->cx;
295 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
297 nIndex = himl->cCurImage;
298 himl->cCurImage += nImageCount;
300 hdcMask = CreateCompatibleDC (0);
301 hdcImage = CreateCompatibleDC(0);
302 hdcBitmap = CreateCompatibleDC(0);
305 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
306 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
309 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
310 nMaskXOffset = nIndex * himl->cx;
315 Create a temp Mask so we can remove the background of
316 the Image (Windows does this even if there is no mask)
318 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
319 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
322 /* create monochrome image to the mask bitmap */
323 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
324 GetPixel (hdcBitmap, 0, 0);
325 SetBkColor (hdcBitmap, bkColor);
327 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
331 SetBkColor(hdcBitmap, RGB(255,255,255));
332 /*Remove the background from the image
335 WINDOWS BUG ALERT!!!!!!
336 The statement below should not be done in common practice
337 but this is how ImageList_AddMasked works in Windows.
338 It overwrites the original bitmap passed, this was discovered
339 by using the same bitmap to iterate the different styles
340 on windows where it failed (BUT ImageList_Add is OK)
341 This is here in case some apps rely on this bug
344 0, 0, bmp.bmWidth, bmp.bmHeight,
347 0x220326); /* NOTSRCAND */
348 /* Copy result to the imagelist
351 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
357 SelectObject(hdcMask,hOldBitmapMask);
358 SelectObject(hdcImage, hOldBitmapImage);
359 SelectObject(hdcBitmap, hOldBitmap);
365 DeleteObject(hMaskBitmap);
372 /*************************************************************************
373 * ImageList_BeginDrag [COMCTL32.@]
375 * Creates a temporary image list that contains one image. It will be used
379 * himlTrack [I] handle to the source image list
380 * iTrack [I] index of the drag image in the source image list
381 * dxHotspot [I] X position of the hot spot of the drag image
382 * dyHotspot [I] Y position of the hot spot of the drag image
390 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
391 INT dxHotspot, INT dyHotspot)
396 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
397 dxHotspot, dyHotspot);
399 if (himlTrack == NULL)
402 if (InternalDrag.himl)
403 ImageList_EndDrag ();
408 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
409 if (InternalDrag.himl == NULL) {
410 WARN("Error creating drag image list!\n");
414 InternalDrag.dxHotspot = dxHotspot;
415 InternalDrag.dyHotspot = dyHotspot;
417 hdcSrc = CreateCompatibleDC (0);
418 hdcDst = CreateCompatibleDC (0);
421 SelectObject (hdcSrc, himlTrack->hbmImage);
422 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
423 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
426 SelectObject (hdcSrc, himlTrack->hbmMask);
427 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
428 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
433 InternalDrag.himl->cCurImage = 1;
434 InternalDrag.bHSPending = TRUE;
440 /*************************************************************************
441 * ImageList_Copy [COMCTL32.@]
443 * Copies an image of the source image list to an image of the
444 * destination image list. Images can be copied or swapped.
447 * himlDst [I] handle to the destination image list
448 * iDst [I] destination image index.
449 * himlSrc [I] handle to the source image list
450 * iSrc [I] source image index
451 * uFlags [I] flags for the copy operation
458 * Copying from one image list to another is possible. The original
459 * implementation just copies or swaps within one image list.
460 * Could this feature become a bug??? ;-)
464 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
465 INT iSrc, INT uFlags)
469 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
471 if ((himlSrc == NULL) || (himlDst == NULL))
473 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
475 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
478 hdcSrc = CreateCompatibleDC (0);
479 if (himlDst == himlSrc)
482 hdcDst = CreateCompatibleDC (0);
484 if (uFlags & ILCF_SWAP) {
486 HBITMAP hbmTempImage, hbmTempMask;
488 /* create temporary bitmaps */
489 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
490 himlSrc->uBitsPixel, NULL);
491 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
494 /* copy (and stretch) destination to temporary bitmaps.(save) */
496 SelectObject (hdcSrc, himlDst->hbmImage);
497 SelectObject (hdcDst, hbmTempImage);
498 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
499 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
502 SelectObject (hdcSrc, himlDst->hbmMask);
503 SelectObject (hdcDst, hbmTempMask);
504 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
505 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
508 /* copy (and stretch) source to destination */
510 SelectObject (hdcSrc, himlSrc->hbmImage);
511 SelectObject (hdcDst, himlDst->hbmImage);
512 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
513 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
516 SelectObject (hdcSrc, himlSrc->hbmMask);
517 SelectObject (hdcDst, himlDst->hbmMask);
518 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
519 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
522 /* copy (without stretching) temporary bitmaps to source (restore) */
524 SelectObject (hdcSrc, hbmTempImage);
525 SelectObject (hdcDst, himlSrc->hbmImage);
526 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
527 hdcSrc, 0, 0, SRCCOPY);
529 SelectObject (hdcSrc, hbmTempMask);
530 SelectObject (hdcDst, himlSrc->hbmMask);
531 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
532 hdcSrc, 0, 0, SRCCOPY);
534 /* delete temporary bitmaps */
535 DeleteObject (hbmTempMask);
536 DeleteObject (hbmTempImage);
540 SelectObject (hdcSrc, himlSrc->hbmImage);
541 if (himlSrc == himlDst)
544 SelectObject (hdcDst, himlDst->hbmImage);
545 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
546 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
550 SelectObject (hdcSrc, himlSrc->hbmMask);
551 if (himlSrc == himlDst)
554 SelectObject (hdcDst, himlDst->hbmMask);
555 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
556 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
561 if (himlSrc != himlDst)
568 /*************************************************************************
569 * ImageList_Create [COMCTL32.@] Creates a new image list.
572 * cx [I] image height
574 * flags [I] creation flags
575 * cInitial [I] initial number of images in the image list
576 * cGrow [I] number of images by which image list grows
579 * Success: Handle to the created image list
584 ImageList_Create (INT cx, INT cy, UINT flags,
585 INT cInitial, INT cGrow)
591 static WORD aBitBlend25[] =
592 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
594 static WORD aBitBlend50[] =
595 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
597 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
599 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
606 himl->cMaxImage = cInitial + cGrow;
607 himl->cInitial = cInitial;
610 himl->clrFg = CLR_DEFAULT;
611 himl->clrBk = CLR_NONE;
613 /* initialize overlay mask indices */
614 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
615 himl->nOvlIdx[nCount] = -1;
617 hdc = CreateCompatibleDC (0);
618 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
621 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
623 if (himl->cMaxImage > 0) {
625 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
626 1, himl->uBitsPixel, NULL);
627 if (himl->hbmImage == 0) {
628 ERR("Error creating image bitmap!\n");
635 if ( (himl->flags & ILC_MASK)) {
636 int images = himl->cMaxImage;
640 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
642 if (himl->hbmMask == 0) {
643 ERR("Error creating mask bitmap!\n");
645 DeleteObject (himl->hbmImage);
652 /* create blending brushes */
653 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
654 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
655 DeleteObject (hbmTemp);
657 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
658 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
659 DeleteObject (hbmTemp);
661 TRACE("created imagelist %p\n", himl);
666 /*************************************************************************
667 * ImageList_Destroy [COMCTL32.@]
669 * Destroys an image list.
672 * himl [I] handle to image list
680 ImageList_Destroy (HIMAGELIST himl)
685 /* delete image bitmaps */
687 DeleteObject (himl->hbmImage);
689 DeleteObject (himl->hbmMask);
691 /* delete blending brushes */
692 if (himl->hbrBlend25)
693 DeleteObject (himl->hbrBlend25);
694 if (himl->hbrBlend50)
695 DeleteObject (himl->hbrBlend50);
697 ZeroMemory(himl, sizeof(*himl));
698 COMCTL32_Free (himl);
704 /*************************************************************************
705 * ImageList_DragEnter [COMCTL32.@]
707 * Locks window update and displays the drag image at the given position.
710 * hwndLock [I] handle of the window that owns the drag image.
711 * x [I] X position of the drag image.
712 * y [I] Y position of the drag image.
719 * The position of the drag image is relative to the window, not
724 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
726 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
728 if (InternalDrag.himl == NULL)
732 InternalDrag.hwnd = hwndLock;
734 InternalDrag.hwnd = GetDesktopWindow ();
739 /* draw the drag image and save the background */
740 if (!ImageList_DragShowNolock(TRUE)) {
748 /*************************************************************************
749 * ImageList_DragLeave [COMCTL32.@]
751 * Unlocks window update and hides the drag image.
754 * hwndLock [I] handle of the window that owns the drag image.
762 ImageList_DragLeave (HWND hwndLock)
764 /* As we don't save drag info in the window this can lead to problems if
765 an app does not supply the same window as DragEnter */
767 InternalDrag.hwnd = hwndLock;
769 InternalDrag.hwnd = GetDesktopWindow (); */
771 hwndLock = GetDesktopWindow();
772 if(InternalDrag.hwnd != hwndLock)
773 FIXME("DragLeave hWnd != DragEnter hWnd\n");
775 ImageList_DragShowNolock (FALSE);
781 /*************************************************************************
782 * ImageList_InternalDragDraw [Internal]
784 * Draws the drag image.
787 * hdc [I] device context to draw into.
788 * x [I] X position of the drag image.
789 * y [I] Y position of the drag image.
796 * The position of the drag image is relative to the window, not
802 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
804 IMAGELISTDRAWPARAMS imldp;
806 ZeroMemory (&imldp, sizeof(imldp));
807 imldp.cbSize = sizeof(imldp);
808 imldp.himl = InternalDrag.himl;
813 imldp.rgbBk = CLR_DEFAULT;
814 imldp.rgbFg = CLR_DEFAULT;
815 imldp.fStyle = ILD_NORMAL;
816 imldp.fState = ILS_ALPHA;
819 /* FIXME: instead of using the alpha blending, we should
820 * create a 50% mask, and draw it semitransparantly that way */
821 ImageList_DrawIndirect (&imldp);
824 /*************************************************************************
825 * ImageList_DragMove [COMCTL32.@]
827 * Moves the drag image.
830 * x [I] X position of the drag image.
831 * y [I] Y position of the drag image.
838 * The position of the drag image is relative to the window, not
842 * The drag image should be drawn semitransparent.
846 ImageList_DragMove (INT x, INT y)
848 TRACE("(x=%d y=%d)\n", x, y);
850 if (!InternalDrag.himl) {
854 /* draw/update the drag image */
855 if (InternalDrag.bShow) {
859 HBITMAP hbmOffScreen;
860 INT origNewX, origNewY;
861 INT origOldX, origOldY;
862 INT origRegX, origRegY;
863 INT sizeRegX, sizeRegY;
866 /* calculate the update region */
867 origNewX = x - InternalDrag.dxHotspot;
868 origNewY = y - InternalDrag.dyHotspot;
869 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
870 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
871 origRegX = min(origNewX, origOldX);
872 origRegY = min(origNewY, origOldY);
873 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
874 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
876 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
877 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
878 hdcOffScreen = CreateCompatibleDC(hdcDrag);
879 hdcBg = CreateCompatibleDC(hdcDrag);
881 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
882 SelectObject(hdcOffScreen, hbmOffScreen);
883 SelectObject(hdcBg, InternalDrag.hbmBg);
885 /* get the actual background of the update region */
886 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
887 origRegX, origRegY, SRCCOPY);
888 /* erase the old image */
889 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
890 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
892 /* save the background */
893 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
894 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
896 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
897 origNewY - origRegY);
898 /* draw the update region to the screen */
899 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
900 hdcOffScreen, 0, 0, SRCCOPY);
903 DeleteDC(hdcOffScreen);
904 DeleteObject(hbmOffScreen);
905 ReleaseDC(InternalDrag.hwnd, hdcDrag);
908 /* update the image position */
916 /*************************************************************************
917 * ImageList_DragShowNolock [COMCTL32.@]
919 * Shows or hides the drag image.
922 * bShow [I] TRUE shows the drag image, FALSE hides it.
929 * The drag image should be drawn semitransparent.
933 ImageList_DragShowNolock (BOOL bShow)
939 TRACE("bShow=0x%X!\n", bShow);
941 /* DragImage is already visible/hidden */
942 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
946 /* position of the origin of the DragImage */
947 x = InternalDrag.x - InternalDrag.dxHotspot;
948 y = InternalDrag.y - InternalDrag.dyHotspot;
950 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
951 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
956 hdcBg = CreateCompatibleDC(hdcDrag);
957 if (!InternalDrag.hbmBg) {
958 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
959 InternalDrag.himl->cx, InternalDrag.himl->cy);
961 SelectObject(hdcBg, InternalDrag.hbmBg);
964 /* save the background */
965 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
966 hdcDrag, x, y, SRCCOPY);
968 ImageList_InternalDragDraw(hdcDrag, x, y);
971 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
972 hdcBg, 0, 0, SRCCOPY);
975 InternalDrag.bShow = !InternalDrag.bShow;
978 ReleaseDC (InternalDrag.hwnd, hdcDrag);
983 /*************************************************************************
984 * ImageList_Draw [COMCTL32.@] Draws an image.
987 * himl [I] handle to image list
989 * hdc [I] handle to device context
992 * fStyle [I] drawing flags
1003 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1005 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1006 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1010 /*************************************************************************
1011 * ImageList_DrawEx [COMCTL32.@]
1013 * Draws an image and allows to use extended drawing features.
1016 * himl [I] handle to image list
1018 * hdc [I] handle to device context
1023 * rgbBk [I] background color
1024 * rgbFg [I] foreground color
1025 * fStyle [I] drawing flags
1032 * Calls ImageList_DrawIndirect.
1035 * ImageList_DrawIndirect.
1039 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1040 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1043 IMAGELISTDRAWPARAMS imldp;
1045 ZeroMemory (&imldp, sizeof(imldp));
1046 imldp.cbSize = sizeof(imldp);
1054 imldp.rgbBk = rgbBk;
1055 imldp.rgbFg = rgbFg;
1056 imldp.fStyle = fStyle;
1058 return ImageList_DrawIndirect (&imldp);
1062 /*************************************************************************
1063 * ImageList_DrawIndirect [COMCTL32.@]
1065 * Draws an image using ...
1068 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1076 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1078 INT cx, cy, lx, ly, nOvlIdx;
1079 DWORD fState, dwRop;
1081 COLORREF clrBk, oldImageBk, oldImageFg;
1082 HDC hImageDC, hImageListDC, hMaskListDC;
1083 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1084 BOOL bIsTransparent, bBlend, bResult = FALSE;
1087 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1088 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1090 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1091 ly = pimldp->yBitmap;
1093 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1094 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1095 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1096 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1097 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1098 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1099 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1101 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1102 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1104 /* we will use these DCs to access the images and masks in the ImageList */
1105 hImageListDC = CreateCompatibleDC(0);
1106 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1108 /* these will accumulate the image and mask for the image we're drawing */
1109 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1110 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1111 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1113 /* Create a compatible DC. */
1114 if (!hImageListDC || !hImageDC || !hImageBmp ||
1115 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1118 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1119 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1120 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1123 * To obtain a transparent look, background color should be set
1124 * to white and foreground color to black when blting the
1127 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1128 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1131 * Draw the initial image
1133 if(fStyle & ILD_MASK) {
1134 if (himl->hbmMask) {
1135 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1137 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1138 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1139 SelectObject(hImageDC, hOldBrush);
1141 } else if (himl->hbmMask && !bIsTransparent) {
1142 /* blend the image with the needed solid background */
1143 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1144 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1145 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1146 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1147 DeleteObject (SelectObject (hImageDC, hOldBrush));
1149 /* start off with the image, if we have a mask, we'll use it later */
1150 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1153 /* Time for blending, if required */
1155 HBRUSH hBlendBrush, hOldBrush;
1156 COLORREF clrBlend = pimldp->rgbFg;
1157 HDC hBlendMaskDC = hImageListDC;
1160 /* Create the blend Mask */
1161 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1162 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1163 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1164 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1165 SelectObject(hBlendMaskDC, hOldBrush);
1167 /* Modify the blend mask if an Image Mask exist */
1169 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1170 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1173 /* now apply blend to the current image given the BlendMask */
1174 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1175 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1176 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1177 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1178 DeleteObject(SelectObject(hImageDC, hOldBrush));
1179 SelectObject(hBlendMaskDC, hOldBitmap);
1182 /* Now do the overlay image, if any */
1183 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1184 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1185 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1186 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1187 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1188 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1189 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1190 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1194 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1195 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1196 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1197 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1199 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1200 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1201 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1203 /* now copy the image to the screen */
1205 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1206 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1207 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1208 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1209 SetBkColor(pimldp->hdcDst, oldDstBk);
1210 SetTextColor(pimldp->hdcDst, oldDstFg);
1213 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1214 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1218 /* cleanup the mess */
1219 SetBkColor(hImageDC, oldImageBk);
1220 SetTextColor(hImageDC, oldImageFg);
1221 SelectObject(hImageDC, hOldImageBmp);
1222 SelectObject(hImageListDC, hOldImageListBmp);
1223 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1225 DeleteObject(hBlendMaskBmp);
1226 DeleteObject(hImageBmp);
1228 DeleteDC(hImageListDC);
1229 DeleteDC(hMaskListDC);
1235 /*************************************************************************
1236 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1239 * himlSrc [I] source image list handle
1242 * Success: Handle of duplicated image list.
1247 ImageList_Duplicate (HIMAGELIST himlSrc)
1252 if (himlSrc == NULL) {
1253 ERR("Invalid image list handle!\n");
1257 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1258 himlSrc->cInitial, himlSrc->cGrow);
1262 hdcSrc = CreateCompatibleDC (0);
1263 hdcDst = CreateCompatibleDC (0);
1264 SelectObject (hdcSrc, himlSrc->hbmImage);
1265 SelectObject (hdcDst, himlDst->hbmImage);
1266 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1267 hdcSrc, 0, 0, SRCCOPY);
1269 if (himlDst->hbmMask)
1271 SelectObject (hdcSrc, himlSrc->hbmMask);
1272 SelectObject (hdcDst, himlDst->hbmMask);
1273 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1274 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1280 himlDst->cCurImage = himlSrc->cCurImage;
1281 himlDst->cMaxImage = himlSrc->cMaxImage;
1287 /*************************************************************************
1288 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1290 * Finishes a drag operation.
1301 ImageList_EndDrag (void)
1303 /* cleanup the InternalDrag struct */
1304 InternalDrag.hwnd = 0;
1305 ImageList_Destroy (InternalDrag.himl);
1306 InternalDrag.himl = 0;
1309 InternalDrag.dxHotspot = 0;
1310 InternalDrag.dyHotspot = 0;
1311 InternalDrag.bShow = FALSE;
1312 DeleteObject(InternalDrag.hbmBg);
1313 InternalDrag.hbmBg = 0;
1314 InternalDrag.bHSPending = FALSE;
1320 /*************************************************************************
1321 * ImageList_GetBkColor [COMCTL32.@]
1323 * Returns the background color of an image list.
1326 * himl [I] Image list handle.
1329 * Success: background color
1334 ImageList_GetBkColor (HIMAGELIST himl)
1336 return himl ? himl->clrBk : CLR_NONE;
1340 /*************************************************************************
1341 * ImageList_GetDragImage [COMCTL32.@]
1343 * Returns the handle to the internal drag image list.
1346 * ppt [O] Pointer to the drag position. Can be NULL.
1347 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1350 * Success: Handle of the drag image list.
1355 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1357 if (InternalDrag.himl) {
1359 ppt->x = InternalDrag.x;
1360 ppt->y = InternalDrag.y;
1363 pptHotspot->x = InternalDrag.dxHotspot;
1364 pptHotspot->y = InternalDrag.dyHotspot;
1366 return (InternalDrag.himl);
1373 /*************************************************************************
1374 * ImageList_GetFlags [COMCTL32.@]
1381 ImageList_GetFlags(HIMAGELIST himl)
1383 FIXME("(%p):empty stub\n", himl);
1388 /*************************************************************************
1389 * ImageList_GetIcon [COMCTL32.@]
1391 * Creates an icon from a masked image of an image list.
1394 * himl [I] handle to image list
1396 * flags [I] drawing style flags
1399 * Success: icon handle
1404 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1408 HBITMAP hOldDstBitmap;
1411 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1413 hdcDst = CreateCompatibleDC(0);
1418 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1419 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1420 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1423 SelectObject (hdcDst, himl->hbmImage);
1424 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1425 SelectObject (hdcDst, ii.hbmColor);
1426 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1429 * CreateIconIndirect requires us to deselect the bitmaps from
1430 * the DCs before calling
1432 SelectObject(hdcDst, hOldDstBitmap);
1434 hIcon = CreateIconIndirect (&ii);
1436 DeleteObject (ii.hbmMask);
1437 DeleteObject (ii.hbmColor);
1444 /*************************************************************************
1445 * ImageList_GetIconSize [COMCTL32.@]
1447 * Retrieves the size of an image in an image list.
1450 * himl [I] handle to image list
1451 * cx [O] pointer to the image width.
1452 * cy [O] pointer to the image height.
1459 * All images in an image list have the same size.
1463 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1467 if ((himl->cx <= 0) || (himl->cy <= 0))
1479 /*************************************************************************
1480 * ImageList_GetImageCount [COMCTL32.@]
1482 * Returns the number of images in an image list.
1485 * himl [I] handle to image list
1488 * Success: Number of images.
1493 ImageList_GetImageCount (HIMAGELIST himl)
1498 return himl->cCurImage;
1502 /*************************************************************************
1503 * ImageList_GetImageInfo [COMCTL32.@]
1505 * Returns information about an image in an image list.
1508 * himl [I] handle to image list
1510 * pImageInfo [O] pointer to the image information
1518 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1520 if ((himl == NULL) || (pImageInfo == NULL))
1522 if ((i < 0) || (i >= himl->cCurImage))
1525 pImageInfo->hbmImage = himl->hbmImage;
1526 pImageInfo->hbmMask = himl->hbmMask;
1528 pImageInfo->rcImage.top = 0;
1529 pImageInfo->rcImage.bottom = himl->cy;
1530 pImageInfo->rcImage.left = i * himl->cx;
1531 pImageInfo->rcImage.right = (i+1) * himl->cx;
1537 /*************************************************************************
1538 * ImageList_GetImageRect [COMCTL32.@]
1540 * Retrieves the rectangle of the specified image in an image list.
1543 * himl [I] handle to image list
1545 * lpRect [O] pointer to the image rectangle
1552 * This is an UNDOCUMENTED function!!!
1556 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1558 if ((himl == NULL) || (lpRect == NULL))
1560 if ((i < 0) || (i >= himl->cCurImage))
1563 lpRect->left = i * himl->cx;
1565 lpRect->right = lpRect->left + himl->cx;
1566 lpRect->bottom = himl->cy;
1572 /*************************************************************************
1573 * ImageList_LoadImage [COMCTL32.@]
1574 * ImageList_LoadImageA [COMCTL32.@]
1576 * Creates an image list from a bitmap, icon or cursor.
1579 * hi [I] instance handle
1580 * lpbmp [I] name or id of the image
1581 * cx [I] width of each image
1582 * cGrow [I] number of images to expand
1583 * clrMask [I] mask color
1584 * uType [I] type of image to load
1585 * uFlags [I] loading flags
1588 * Success: handle to the loaded image list
1596 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1597 COLORREF clrMask, UINT uType, UINT uFlags)
1599 HIMAGELIST himl = NULL;
1603 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1605 ERR("Error loading image!\n");
1609 if (uType == IMAGE_BITMAP) {
1611 GetObjectA (handle, sizeof(BITMAP), &bmp);
1613 /* To match windows behavior, if cx is set to zero and
1614 the flag DI_DEFAULTSIZE is specified, cx becomes the
1615 system metric value for icons. If the flag is not specified
1616 the function sets the size to the height of the bitmap */
1619 if (uFlags & DI_DEFAULTSIZE)
1620 cx = GetSystemMetrics (SM_CXICON);
1625 nImageCount = bmp.bmWidth / cx;
1627 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1628 nImageCount, cGrow);
1629 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1631 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1635 GetIconInfo (handle, &ii);
1636 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1637 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1638 ILC_MASK | ILC_COLOR, 1, cGrow);
1639 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1640 DeleteObject (ii.hbmColor);
1641 DeleteObject (ii.hbmMask);
1644 DeleteObject (handle);
1650 /*************************************************************************
1651 * ImageList_LoadImageW [COMCTL32.@]
1653 * Creates an image list from a bitmap, icon or cursor.
1656 * hi [I] instance handle
1657 * lpbmp [I] name or id of the image
1658 * cx [I] width of each image
1659 * cGrow [I] number of images to expand
1660 * clrMask [I] mask color
1661 * uType [I] type of image to load
1662 * uFlags [I] loading flags
1665 * Success: handle to the loaded image list
1673 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1674 COLORREF clrMask, UINT uType, UINT uFlags)
1676 HIMAGELIST himl = NULL;
1680 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1682 ERR("Error loading image!\n");
1686 if (uType == IMAGE_BITMAP) {
1688 GetObjectA (handle, sizeof(BITMAP), &bmp);
1690 /* To match windows behavior, if cx is set to zero and
1691 the flag DI_DEFAULTSIZE is specified, cx becomes the
1692 system metric value for icons. If the flag is not specified
1693 the function sets the size to the height of the bitmap */
1696 if (uFlags & DI_DEFAULTSIZE)
1697 cx = GetSystemMetrics (SM_CXICON);
1702 nImageCount = bmp.bmWidth / cx;
1704 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1705 nImageCount, cGrow);
1706 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1708 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1712 GetIconInfo (handle, &ii);
1713 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1714 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1715 ILC_MASK | ILC_COLOR, 1, cGrow);
1716 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1717 DeleteObject (ii.hbmColor);
1718 DeleteObject (ii.hbmMask);
1721 DeleteObject (handle);
1727 /*************************************************************************
1728 * ImageList_Merge [COMCTL32.@]
1730 * Creates a new image list that contains a merged image from the specified
1731 * images of both source image lists.
1734 * himl1 [I] handle to first image list
1735 * i1 [I] first image index
1736 * himl2 [I] handle to second image list
1737 * i2 [I] second image index
1738 * dx [I] X offset of the second image relative to the first.
1739 * dy [I] Y offset of the second image relative to the first.
1742 * Success: handle of the merged image list.
1747 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1750 HIMAGELIST himlDst = NULL;
1751 HDC hdcSrcImage, hdcDstImage;
1753 INT xOff1, yOff1, xOff2, yOff2;
1756 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1759 if ((himl1 == NULL) || (himl2 == NULL))
1763 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1764 ERR("Index 1 out of range! %d\n", i1);
1768 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1769 ERR("Index 2 out of range! %d\n", i2);
1774 cxDst = max (himl1->cx, dx + himl2->cx);
1779 cxDst = max (himl2->cx, himl1->cx - dx);
1784 cxDst = max (himl1->cx, himl2->cx);
1790 cyDst = max (himl1->cy, dy + himl2->cy);
1795 cyDst = max (himl2->cy, himl1->cy - dy);
1800 cyDst = max (himl1->cy, himl2->cy);
1805 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1808 hdcSrcImage = CreateCompatibleDC (0);
1809 hdcDstImage = CreateCompatibleDC (0);
1810 nX1 = i1 * himl1->cx;
1811 nX2 = i2 * himl2->cx;
1814 SelectObject (hdcSrcImage, himl1->hbmImage);
1815 SelectObject (hdcDstImage, himlDst->hbmImage);
1816 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1817 hdcSrcImage, 0, 0, BLACKNESS);
1818 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1819 hdcSrcImage, nX1, 0, SRCCOPY);
1821 SelectObject (hdcSrcImage, himl2->hbmMask);
1822 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1823 hdcSrcImage, nX2, 0, SRCAND);
1825 SelectObject (hdcSrcImage, himl2->hbmImage);
1826 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1827 hdcSrcImage, nX2, 0, SRCPAINT);
1830 SelectObject (hdcSrcImage, himl1->hbmMask);
1831 SelectObject (hdcDstImage, himlDst->hbmMask);
1832 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1833 hdcSrcImage, 0, 0, WHITENESS);
1834 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1835 hdcSrcImage, nX1, 0, SRCCOPY);
1837 SelectObject (hdcSrcImage, himl2->hbmMask);
1838 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1839 hdcSrcImage, nX2, 0, SRCAND);
1841 DeleteDC (hdcSrcImage);
1842 DeleteDC (hdcDstImage);
1843 himlDst->cCurImage = 1;
1850 /* helper for _read_bitmap currently unused */
1852 static int may_use_dibsection(HDC hdc) {
1853 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1858 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1862 /* helper for ImageList_Read, see comments below */
1863 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1865 BITMAPFILEHEADER bmfh;
1866 BITMAPINFOHEADER bmih;
1867 int bitsperpixel,palspace,longsperline,width,height;
1868 LPBITMAPINFOHEADER bmihc = NULL;
1870 HBITMAP hbitmap = 0;
1871 LPBYTE bits = NULL,nbits = NULL;
1872 int nbytesperline,bytesperline;
1874 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1875 (bmfh.bfType != (('M'<<8)|'B')) ||
1876 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1877 (bmih.biSize != sizeof(bmih))
1881 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1882 if (bitsperpixel<=8)
1883 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1886 width = bmih.biWidth;
1887 height = bmih.biHeight;
1888 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1889 memcpy(bmihc,&bmih,sizeof(bmih));
1890 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1891 bmihc->biSizeImage = (longsperline*height)<<2;
1893 /* read the palette right after the end of the bitmapinfoheader */
1895 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1899 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1900 if ((bitsperpixel>1) &&
1901 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1903 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1906 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1912 int i,nwidth,nheight;
1914 nwidth = width*(height/cy);
1917 if (bitsperpixel==1)
1918 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1920 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1922 /* Might be a bit excessive memory use here */
1923 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1924 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1925 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1928 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1929 /* Do not forget that windows bitmaps are bottom->top */
1930 bytesperline = longsperline*4;
1931 nbytesperline = (height/cy)*bytesperline;
1932 for (i=0;i<height;i++) {
1934 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1935 bits+bytesperline*(height-1-i),
1939 bmihc->biWidth = nwidth;
1940 bmihc->biHeight = nheight;
1941 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1943 LocalFree((HLOCAL)nbits);
1944 LocalFree((HLOCAL)bits);
1948 if (xdc) ReleaseDC(0,xdc);
1949 if (bmihc) LocalFree((HLOCAL)bmihc);
1952 DeleteObject(hbitmap);
1959 /*************************************************************************
1960 * ImageList_Read [COMCTL32.@]
1962 * Reads an image list from a stream.
1965 * pstm [I] pointer to a stream
1968 * Success: handle to image list
1971 * The format is like this:
1972 * ILHEAD ilheadstruct;
1974 * for the color image part:
1975 * BITMAPFILEHEADER bmfh;
1976 * BITMAPINFOHEADER bmih;
1977 * only if it has a palette:
1978 * RGBQUAD rgbs[nr_of_paletted_colors];
1980 * BYTE colorbits[imagesize];
1982 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1983 * BITMAPFILEHEADER bmfh_mask;
1984 * BITMAPINFOHEADER bmih_mask;
1985 * only if it has a palette (it usually does not):
1986 * RGBQUAD rgbs[nr_of_paletted_colors];
1988 * BYTE maskbits[imagesize];
1990 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1991 * _read_bitmap needs to convert them.
1993 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1997 HBITMAP hbmColor=0,hbmMask=0;
2000 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2002 if (ilHead.usMagic != (('L' << 8) | 'I'))
2004 if (ilHead.usVersion != 0x101) /* probably version? */
2008 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2009 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2010 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2011 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2012 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2013 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2014 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2015 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2016 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2017 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2020 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2023 if (ilHead.flags & ILC_MASK) {
2024 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2026 DeleteObject(hbmColor);
2031 himl = ImageList_Create (
2039 DeleteObject(hbmColor);
2040 DeleteObject(hbmMask);
2043 himl->hbmImage = hbmColor;
2044 himl->hbmMask = hbmMask;
2045 himl->cCurImage = ilHead.cCurImage;
2046 himl->cMaxImage = ilHead.cMaxImage;
2048 ImageList_SetBkColor(himl,ilHead.bkcolor);
2050 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2055 /*************************************************************************
2056 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2059 * himl [I] image list handle
2068 ImageList_Remove (HIMAGELIST himl, INT i)
2070 HBITMAP hbmNewImage, hbmNewMask;
2074 TRACE("(himl=%p i=%d)\n", himl, i);
2077 ERR("Invalid image list handle!\n");
2081 if ((i < -1) || (i >= himl->cCurImage)) {
2082 ERR("index out of range! %d\n", i);
2088 if (himl->cCurImage == 0) {
2089 /* remove all on empty ImageList is allowed */
2090 TRACE("remove all on empty ImageList!\n");
2094 himl->cMaxImage = himl->cInitial + himl->cGrow;
2095 himl->cCurImage = 0;
2096 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2097 himl->nOvlIdx[nCount] = -1;
2099 DeleteObject (himl->hbmImage);
2101 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2102 1, himl->uBitsPixel, NULL);
2104 if (himl->hbmMask) {
2105 DeleteObject (himl->hbmMask);
2107 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2112 /* delete one image */
2113 TRACE("Remove single image! %d\n", i);
2115 /* create new bitmap(s) */
2116 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2118 TRACE(" - Number of images: %d / %d (Old/New)\n",
2119 himl->cCurImage, himl->cCurImage - 1);
2120 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2121 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2124 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2127 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2129 hbmNewMask = 0; /* Just to keep compiler happy! */
2131 hdcSrc = CreateCompatibleDC (0);
2132 hdcDst = CreateCompatibleDC (0);
2134 /* copy all images and masks prior to the "removed" image */
2136 TRACE("Pre image copy: Copy %d images\n", i);
2138 SelectObject (hdcSrc, himl->hbmImage);
2139 SelectObject (hdcDst, hbmNewImage);
2140 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2141 hdcSrc, 0, 0, SRCCOPY);
2143 if (himl->hbmMask) {
2144 SelectObject (hdcSrc, himl->hbmMask);
2145 SelectObject (hdcDst, hbmNewMask);
2146 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2147 hdcSrc, 0, 0, SRCCOPY);
2151 /* copy all images and masks behind the removed image */
2152 if (i < himl->cCurImage - 1) {
2153 TRACE("Post image copy!\n");
2154 SelectObject (hdcSrc, himl->hbmImage);
2155 SelectObject (hdcDst, hbmNewImage);
2156 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2157 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2159 if (himl->hbmMask) {
2160 SelectObject (hdcSrc, himl->hbmMask);
2161 SelectObject (hdcDst, hbmNewMask);
2162 BitBlt (hdcDst, i * himl->cx, 0,
2163 (himl->cCurImage - i - 1) * himl->cx,
2164 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2171 /* delete old images and insert new ones */
2172 DeleteObject (himl->hbmImage);
2173 himl->hbmImage = hbmNewImage;
2174 if (himl->hbmMask) {
2175 DeleteObject (himl->hbmMask);
2176 himl->hbmMask = hbmNewMask;
2180 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2187 /*************************************************************************
2188 * ImageList_Replace [COMCTL32.@]
2190 * Replaces an image in an image list with a new image.
2193 * himl [I] handle to image list
2195 * hbmImage [I] handle to image bitmap
2196 * hbmMask [I] handle to mask bitmap. Can be NULL.
2204 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2207 HDC hdcImageList, hdcImage;
2210 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2213 ERR("Invalid image list handle!\n");
2217 if ((i >= himl->cMaxImage) || (i < 0)) {
2218 ERR("Invalid image index!\n");
2222 hdcImageList = CreateCompatibleDC (0);
2223 hdcImage = CreateCompatibleDC (0);
2224 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2227 SelectObject (hdcImageList, himl->hbmImage);
2228 SelectObject (hdcImage, hbmImage);
2230 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2231 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2236 SelectObject (hdcImageList, himl->hbmMask);
2237 SelectObject (hdcImage, hbmMask);
2239 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2240 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2243 /* Remove the background from the image
2245 SelectObject (hdcImageList, himl->hbmImage);
2246 StretchBlt (hdcImageList,
2247 i*himl->cx, 0, himl->cx, himl->cy,
2249 0, 0, bmp.bmWidth, bmp.bmHeight,
2250 0x220326); /* NOTSRCAND */
2253 DeleteDC (hdcImage);
2254 DeleteDC (hdcImageList);
2260 /*************************************************************************
2261 * ImageList_ReplaceIcon [COMCTL32.@]
2263 * Replaces an image in an image list using an icon.
2266 * himl [I] handle to image list
2268 * hIcon [I] handle to icon
2271 * Success: index of the replaced image
2276 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2278 HDC hdcImageList, hdcImage;
2281 HBITMAP hbmOldSrc, hbmOldDst;
2285 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2289 if ((i >= himl->cMaxImage) || (i < -1))
2292 hBestFitIcon = CopyImage(
2295 LR_COPYFROMRESOURCE);
2297 GetIconInfo (hBestFitIcon, &ii);
2298 if (ii.hbmMask == 0)
2300 if (ii.hbmColor == 0)
2302 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2305 if (himl->cCurImage + 1 > himl->cMaxImage)
2306 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2308 nIndex = himl->cCurImage;
2314 hdcImageList = CreateCompatibleDC (0);
2315 TRACE("hdcImageList=%p!\n", hdcImageList);
2316 if (hdcImageList == 0)
2317 ERR("invalid hdcImageList!\n");
2319 hdcImage = CreateCompatibleDC (0);
2320 TRACE("hdcImage=%p!\n", hdcImage);
2322 ERR("invalid hdcImage!\n");
2324 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2325 SetTextColor( hdcImageList, RGB(0,0,0));
2326 SetBkColor( hdcImageList, RGB(255,255,255));
2327 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2328 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2329 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2331 if (himl->hbmMask) {
2332 SelectObject (hdcImageList, himl->hbmMask);
2333 SelectObject (hdcImage, ii.hbmMask);
2334 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2335 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2338 SelectObject (hdcImage, hbmOldSrc);
2339 SelectObject (hdcImageList, hbmOldDst);
2342 DestroyIcon(hBestFitIcon);
2344 DeleteDC (hdcImageList);
2346 DeleteDC (hdcImage);
2348 DeleteObject (ii.hbmColor);
2350 DeleteObject (ii.hbmMask);
2356 /*************************************************************************
2357 * ImageList_SetBkColor [COMCTL32.@]
2359 * Sets the background color of an image list.
2362 * himl [I] handle to image list
2363 * clrBk [I] background color
2366 * Success: previous background color
2371 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2378 clrOldBk = himl->clrBk;
2379 himl->clrBk = clrBk;
2384 /*************************************************************************
2385 * ImageList_SetDragCursorImage [COMCTL32.@]
2387 * Combines the specified image with the current drag image
2390 * himlDrag [I] handle to drag image list
2391 * iDrag [I] drag image index
2392 * dxHotspot [I] X position of the hot spot
2393 * dyHotspot [I] Y position of the hot spot
2400 * When this function is called and the drag image is visible, a
2401 * short flickering occurs but this matches the Win9x behavior. It is
2402 * possible to fix the flickering using code like in ImageList_DragMove.
2406 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2407 INT dxHotspot, INT dyHotspot)
2409 HIMAGELIST himlTemp;
2413 if (InternalDrag.himl == NULL)
2416 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2417 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2419 visible = InternalDrag.bShow;
2421 /* Calculate the offset between the origin of the old image and the
2422 * origin of the second image.
2423 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2424 * hotspot) to the origin of the second image.
2425 * See M$DN for details */
2426 if(InternalDrag.bHSPending) {
2429 InternalDrag.bHSPending = FALSE;
2431 dx = InternalDrag.dxHotspot - dxHotspot;
2432 dy = InternalDrag.dyHotspot - dyHotspot;
2434 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2437 /* hide the drag image */
2438 ImageList_DragShowNolock(FALSE);
2440 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2441 (InternalDrag.himl->cy != himlTemp->cy)) {
2442 /* the size of the drag image changed, invalidate the buffer */
2443 DeleteObject(InternalDrag.hbmBg);
2444 InternalDrag.hbmBg = 0;
2447 ImageList_Destroy (InternalDrag.himl);
2448 InternalDrag.himl = himlTemp;
2450 /* update the InternalDragOffset, if the origin of the
2451 * DragImage was changed by ImageList_Merge. */
2453 InternalDrag.dxHotspot = dxHotspot;
2455 InternalDrag.dyHotspot = dyHotspot;
2458 /* show the drag image */
2459 ImageList_DragShowNolock(TRUE);
2466 /*************************************************************************
2467 * ImageList_SetFilter [COMCTL32.@]
2469 * Sets a filter (or does something completely different)!!???
2470 * It removes 12 Bytes from the stack (3 Parameters).
2473 * himl [I] SHOULD be a handle to image list
2474 * i [I] COULD be an index?
2479 * Failure: FALSE ???
2482 * This is an UNDOCUMENTED function!!!!
2487 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2489 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2495 /*************************************************************************
2496 * ImageList_SetFlags [COMCTL32.@]
2503 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2505 FIXME("(%p %08lx):empty stub\n", himl, flags);
2510 /*************************************************************************
2511 * ImageList_SetIconSize [COMCTL32.@]
2513 * Sets the image size of the bitmap and deletes all images.
2516 * himl [I] handle to image list
2517 * cx [I] image width
2518 * cy [I] image height
2526 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2533 /* remove all images */
2534 himl->cMaxImage = himl->cInitial + himl->cGrow;
2535 himl->cCurImage = 0;
2539 /* initialize overlay mask indices */
2540 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2541 himl->nOvlIdx[nCount] = -1;
2543 DeleteObject (himl->hbmImage);
2545 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2546 1, himl->uBitsPixel, NULL);
2548 if (himl->hbmMask) {
2549 DeleteObject (himl->hbmMask);
2551 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2559 /*************************************************************************
2560 * ImageList_SetImageCount [COMCTL32.@]
2562 * Resizes an image list to the specified number of images.
2565 * himl [I] handle to image list
2566 * iImageCount [I] number of images in the image list
2574 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2576 HDC hdcImageList, hdcBitmap;
2577 HBITMAP hbmNewBitmap;
2578 INT nNewCount, nCopyCount;
2580 TRACE("%p %d\n",himl,iImageCount);
2584 if (himl->cCurImage >= iImageCount)
2586 if (himl->cMaxImage > iImageCount)
2588 himl->cCurImage = iImageCount;
2592 nNewCount = iImageCount + himl->cGrow;
2593 nCopyCount = min(himl->cCurImage, iImageCount);
2595 hdcImageList = CreateCompatibleDC (0);
2596 hdcBitmap = CreateCompatibleDC (0);
2598 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2599 1, himl->uBitsPixel, NULL);
2600 if (hbmNewBitmap != 0)
2602 SelectObject (hdcImageList, himl->hbmImage);
2603 SelectObject (hdcBitmap, hbmNewBitmap);
2606 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2607 hdcImageList, 0, 0, SRCCOPY);
2609 /* delete 'empty' image space */
2610 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2611 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2612 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2613 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2615 DeleteObject (himl->hbmImage);
2616 himl->hbmImage = hbmNewBitmap;
2619 ERR("Could not create new image bitmap !\n");
2623 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2625 if (hbmNewBitmap != 0)
2627 SelectObject (hdcImageList, himl->hbmMask);
2628 SelectObject (hdcBitmap, hbmNewBitmap);
2631 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2632 hdcImageList, 0, 0, SRCCOPY);
2634 /* delete 'empty' image space */
2635 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2636 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2637 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2638 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2640 DeleteObject (himl->hbmMask);
2641 himl->hbmMask = hbmNewBitmap;
2644 ERR("Could not create new mask bitmap!\n");
2647 DeleteDC (hdcImageList);
2648 DeleteDC (hdcBitmap);
2650 /* Update max image count and current image count */
2651 himl->cMaxImage = nNewCount;
2652 himl->cCurImage = iImageCount;
2658 /*************************************************************************
2659 * ImageList_SetOverlayImage [COMCTL32.@]
2661 * Assigns an overlay mask index to an existing image in an image list.
2664 * himl [I] handle to image list
2665 * iImage [I] image index
2666 * iOverlay [I] overlay mask index
2674 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2678 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2680 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2682 himl->nOvlIdx[iOverlay - 1] = iImage;
2688 /* helper for ImageList_Write - write bitmap to pstm
2689 * currently everything is written as 24 bit RGB, except masks
2692 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2694 LPBITMAPFILEHEADER bmfh;
2695 LPBITMAPINFOHEADER bmih;
2696 LPBYTE data, lpBits, lpBitsOrg;
2698 INT bitCount, sizeImage, offBits, totalSize;
2699 INT nwidth, nheight, nsizeImage, icount;
2701 BOOL result = FALSE;
2705 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2707 /* XXX is this always correct? */
2708 icount = bm.bmWidth / cx;
2710 nheight = cy * ((icount+3)>>2);
2712 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2713 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2714 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2716 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2718 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2719 offBits = totalSize;
2720 totalSize += nsizeImage;
2722 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2723 bmfh = (LPBITMAPFILEHEADER)data;
2724 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2725 lpBits = data + offBits;
2727 /* setup BITMAPFILEHEADER */
2728 bmfh->bfType = (('M' << 8) | 'B');
2730 bmfh->bfReserved1 = 0;
2731 bmfh->bfReserved2 = 0;
2732 bmfh->bfOffBits = offBits;
2734 /* setup BITMAPINFOHEADER */
2735 bmih->biSize = sizeof(BITMAPINFOHEADER);
2736 bmih->biWidth = bm.bmWidth;
2737 bmih->biHeight = bm.bmHeight;
2739 bmih->biBitCount = bitCount;
2740 bmih->biCompression = BI_RGB;
2741 bmih->biSizeImage = nsizeImage;
2742 bmih->biXPelsPerMeter = 0;
2743 bmih->biYPelsPerMeter = 0;
2744 bmih->biClrUsed = 0;
2745 bmih->biClrImportant = 0;
2747 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2748 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2749 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2753 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2754 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2756 for(i = 0; i < nheight; i++) {
2757 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2758 int noff = (nbpl * (nheight-1-i));
2759 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2763 bmih->biWidth = nwidth;
2764 bmih->biHeight = nheight;
2768 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2769 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2770 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2773 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2780 LocalFree((HLOCAL)lpBitsOrg);
2786 /*************************************************************************
2787 * ImageList_Write [COMCTL32.@]
2789 * Writes an image list to a stream.
2792 * himl [I] handle to image list
2793 * pstm [O] Pointer to a stream.
2804 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2812 ilHead.usMagic = (('L' << 8) | 'I');
2813 ilHead.usVersion = 0x101;
2814 ilHead.cCurImage = himl->cCurImage;
2815 ilHead.cMaxImage = himl->cMaxImage;
2816 ilHead.cGrow = himl->cGrow;
2817 ilHead.cx = himl->cx;
2818 ilHead.cy = himl->cy;
2819 ilHead.bkcolor = himl->clrBk;
2820 ilHead.flags = himl->flags;
2821 for(i = 0; i < 4; i++) {
2822 ilHead.ovls[i] = himl->nOvlIdx[i];
2825 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2828 /* write the bitmap */
2829 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2832 /* write the mask if we have one */
2833 if(himl->flags & ILC_MASK) {
2834 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))