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=%x hbmmask=%x\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, hOldBitmapMask, hOldBitmapTemp;
200 hdcMask = CreateCompatibleDC (0);
201 hdcTemp = CreateCompatibleDC(0);
202 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
203 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
206 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
211 SelectObject(hdcTemp, hOldBitmapTemp);
214 /* Remove the background from the image
217 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
220 0x220326); /* NOTSRCAND */
222 SelectObject(hdcMask, hOldBitmapMask);
226 SelectObject(hdcImage, hOldBitmapImage);
227 SelectObject(hdcBitmap, hOldBitmap);
231 nFirstIndex = himl->cCurImage;
232 himl->cCurImage += nImageCount;
238 /*************************************************************************
239 * ImageList_AddIcon [COMCTL32.@]
241 * Adds an icon to an image list.
244 * himl [I] handle to image list
245 * hIcon [I] handle to icon
248 * Success: index of the new image
253 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
255 return ImageList_ReplaceIcon (himl, -1, hIcon);
259 /*************************************************************************
260 * ImageList_AddMasked [COMCTL32.@]
262 * Adds an image or images to an image list and creates a mask from the
263 * specified bitmap using the mask color.
266 * himl [I] handle to image list.
267 * hBitmap [I] handle to bitmap
268 * clrMask [I] mask color.
271 * Success: Index of the first new image.
276 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
278 HDC hdcImage, hdcMask, hdcBitmap;
279 INT nIndex, nImageCount, nMaskXOffset=0;
281 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
282 HBITMAP hMaskBitmap=0;
285 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
289 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
292 nImageCount = bmp.bmWidth / himl->cx;
294 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
296 nIndex = himl->cCurImage;
297 himl->cCurImage += nImageCount;
299 hdcMask = CreateCompatibleDC (0);
300 hdcImage = CreateCompatibleDC(0);
301 hdcBitmap = CreateCompatibleDC(0);
304 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
305 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
308 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
309 nMaskXOffset = nIndex * himl->cx;
314 Create a temp Mask so we can remove the background of
315 the Image (Windows does this even if there is no mask)
317 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
318 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
321 /* create monochrome image to the mask bitmap */
322 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
323 GetPixel (hdcBitmap, 0, 0);
324 SetBkColor (hdcBitmap, bkColor);
326 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
330 SetBkColor(hdcBitmap, RGB(255,255,255));
331 /*Remove the background from the image
334 WINDOWS BUG ALERT!!!!!!
335 The statement below should not be done in common practice
336 but this is how ImageList_AddMasked works in Windows.
337 It overwrites the original bitmap passed, this was discovered
338 by using the same bitmap to iterate the different styles
339 on windows where it failed (BUT ImageList_Add is OK)
340 This is here in case some apps rely on this bug
343 0, 0, bmp.bmWidth, bmp.bmHeight,
346 0x220326); /* NOTSRCAND */
347 /* Copy result to the imagelist
350 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
356 SelectObject(hdcMask,hOldBitmapMask);
357 SelectObject(hdcImage, hOldBitmapImage);
358 SelectObject(hdcBitmap, hOldBitmap);
364 DeleteObject(hMaskBitmap);
371 /*************************************************************************
372 * ImageList_BeginDrag [COMCTL32.@]
374 * Creates a temporary image list that contains one image. It will be used
378 * himlTrack [I] handle to the source image list
379 * iTrack [I] index of the drag image in the source image list
380 * dxHotspot [I] X position of the hot spot of the drag image
381 * dyHotspot [I] Y position of the hot spot of the drag image
389 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
390 INT dxHotspot, INT dyHotspot)
395 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
396 dxHotspot, dyHotspot);
398 if (himlTrack == NULL)
401 if (InternalDrag.himl)
402 ImageList_EndDrag ();
407 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
408 if (InternalDrag.himl == NULL) {
409 WARN("Error creating drag image list!\n");
413 InternalDrag.dxHotspot = dxHotspot;
414 InternalDrag.dyHotspot = dyHotspot;
416 hdcSrc = CreateCompatibleDC (0);
417 hdcDst = CreateCompatibleDC (0);
420 SelectObject (hdcSrc, himlTrack->hbmImage);
421 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
422 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
425 SelectObject (hdcSrc, himlTrack->hbmMask);
426 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
427 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
432 InternalDrag.himl->cCurImage = 1;
433 InternalDrag.bHSPending = TRUE;
439 /*************************************************************************
440 * ImageList_Copy [COMCTL32.@]
442 * Copies an image of the source image list to an image of the
443 * destination image list. Images can be copied or swapped.
446 * himlDst [I] handle to the destination image list
447 * iDst [I] destination image index.
448 * himlSrc [I] handle to the source image list
449 * iSrc [I] source image index
450 * uFlags [I] flags for the copy operation
457 * Copying from one image list to another is possible. The original
458 * implementation just copies or swaps within one image list.
459 * Could this feature become a bug??? ;-)
463 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
464 INT iSrc, INT uFlags)
468 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
470 if ((himlSrc == NULL) || (himlDst == NULL))
472 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
474 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
477 hdcSrc = CreateCompatibleDC (0);
478 if (himlDst == himlSrc)
481 hdcDst = CreateCompatibleDC (0);
483 if (uFlags & ILCF_SWAP) {
485 HBITMAP hbmTempImage, hbmTempMask;
487 /* create temporary bitmaps */
488 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
489 himlSrc->uBitsPixel, NULL);
490 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
493 /* copy (and stretch) destination to temporary bitmaps.(save) */
495 SelectObject (hdcSrc, himlDst->hbmImage);
496 SelectObject (hdcDst, hbmTempImage);
497 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
498 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
501 SelectObject (hdcSrc, himlDst->hbmMask);
502 SelectObject (hdcDst, hbmTempMask);
503 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
504 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
507 /* copy (and stretch) source to destination */
509 SelectObject (hdcSrc, himlSrc->hbmImage);
510 SelectObject (hdcDst, himlDst->hbmImage);
511 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
512 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
515 SelectObject (hdcSrc, himlSrc->hbmMask);
516 SelectObject (hdcDst, himlDst->hbmMask);
517 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
518 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
521 /* copy (without stretching) temporary bitmaps to source (restore) */
523 SelectObject (hdcSrc, hbmTempImage);
524 SelectObject (hdcDst, himlSrc->hbmImage);
525 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
526 hdcSrc, 0, 0, SRCCOPY);
528 SelectObject (hdcSrc, hbmTempMask);
529 SelectObject (hdcDst, himlSrc->hbmMask);
530 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
531 hdcSrc, 0, 0, SRCCOPY);
533 /* delete temporary bitmaps */
534 DeleteObject (hbmTempMask);
535 DeleteObject (hbmTempImage);
539 SelectObject (hdcSrc, himlSrc->hbmImage);
540 if (himlSrc == himlDst)
543 SelectObject (hdcDst, himlDst->hbmImage);
544 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
545 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
549 SelectObject (hdcSrc, himlSrc->hbmMask);
550 if (himlSrc == himlDst)
553 SelectObject (hdcDst, himlDst->hbmMask);
554 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
555 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
560 if (himlSrc != himlDst)
567 /*************************************************************************
568 * ImageList_Create [COMCTL32.@] Creates a new image list.
571 * cx [I] image height
573 * flags [I] creation flags
574 * cInitial [I] initial number of images in the image list
575 * cGrow [I] number of images by which image list grows
578 * Success: Handle to the created image list
583 ImageList_Create (INT cx, INT cy, UINT flags,
584 INT cInitial, INT cGrow)
590 static WORD aBitBlend25[] =
591 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
593 static WORD aBitBlend50[] =
594 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
596 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
598 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
605 himl->cMaxImage = cInitial + cGrow;
606 himl->cInitial = cInitial;
609 himl->clrFg = CLR_DEFAULT;
610 himl->clrBk = CLR_NONE;
612 /* initialize overlay mask indices */
613 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
614 himl->nOvlIdx[nCount] = -1;
616 hdc = CreateCompatibleDC (0);
617 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
620 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
622 if (himl->cMaxImage > 0) {
624 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
625 1, himl->uBitsPixel, NULL);
626 if (himl->hbmImage == 0) {
627 ERR("Error creating image bitmap!\n");
634 if ( (himl->flags & ILC_MASK)) {
635 int images = himl->cMaxImage;
639 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
641 if (himl->hbmMask == 0) {
642 ERR("Error creating mask bitmap!\n");
644 DeleteObject (himl->hbmImage);
651 /* create blending brushes */
652 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
653 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
654 DeleteObject (hbmTemp);
656 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
657 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
658 DeleteObject (hbmTemp);
660 TRACE("created imagelist %p\n", himl);
665 /*************************************************************************
666 * ImageList_Destroy [COMCTL32.@]
668 * Destroys an image list.
671 * himl [I] handle to image list
679 ImageList_Destroy (HIMAGELIST himl)
684 /* delete image bitmaps */
686 DeleteObject (himl->hbmImage);
688 DeleteObject (himl->hbmMask);
690 /* delete blending brushes */
691 if (himl->hbrBlend25)
692 DeleteObject (himl->hbrBlend25);
693 if (himl->hbrBlend50)
694 DeleteObject (himl->hbrBlend50);
696 COMCTL32_Free (himl);
702 /*************************************************************************
703 * ImageList_DragEnter [COMCTL32.@]
705 * Locks window update and displays the drag image at the given position.
708 * hwndLock [I] handle of the window that owns the drag image.
709 * x [I] X position of the drag image.
710 * y [I] Y position of the drag image.
717 * The position of the drag image is relative to the window, not
722 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
724 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
726 if (InternalDrag.himl == NULL)
730 InternalDrag.hwnd = hwndLock;
732 InternalDrag.hwnd = GetDesktopWindow ();
737 /* draw the drag image and save the background */
738 if (!ImageList_DragShowNolock(TRUE)) {
746 /*************************************************************************
747 * ImageList_DragLeave [COMCTL32.@]
749 * Unlocks window update and hides the drag image.
752 * hwndLock [I] handle of the window that owns the drag image.
760 ImageList_DragLeave (HWND hwndLock)
762 /* As we don't save drag info in the window this can lead to problems if
763 an app does not supply the same window as DragEnter */
765 InternalDrag.hwnd = hwndLock;
767 InternalDrag.hwnd = GetDesktopWindow (); */
769 hwndLock = GetDesktopWindow();
770 if(InternalDrag.hwnd != hwndLock)
771 FIXME("DragLeave hWnd != DragEnter hWnd\n");
773 ImageList_DragShowNolock (FALSE);
779 /*************************************************************************
780 * ImageList_InternalDragDraw [Internal]
782 * Draws the drag image.
785 * hdc [I] device context to draw into.
786 * x [I] X position of the drag image.
787 * y [I] Y position of the drag image.
794 * The position of the drag image is relative to the window, not
800 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
802 IMAGELISTDRAWPARAMS imldp;
804 ZeroMemory (&imldp, sizeof(imldp));
805 imldp.cbSize = sizeof(imldp);
806 imldp.himl = InternalDrag.himl;
811 imldp.rgbBk = CLR_DEFAULT;
812 imldp.rgbFg = CLR_DEFAULT;
813 imldp.fStyle = ILD_NORMAL;
814 imldp.fState = ILS_ALPHA;
817 /* FIXME: instead of using the alpha blending, we should
818 * create a 50% mask, and draw it semitransparantly that way */
819 ImageList_DrawIndirect (&imldp);
822 /*************************************************************************
823 * ImageList_DragMove [COMCTL32.@]
825 * Moves the drag image.
828 * x [I] X position of the drag image.
829 * y [I] Y position of the drag image.
836 * The position of the drag image is relative to the window, not
840 * The drag image should be drawn semitransparent.
844 ImageList_DragMove (INT x, INT y)
846 TRACE("(x=%d y=%d)\n", x, y);
848 if (!InternalDrag.himl) {
852 /* draw/update the drag image */
853 if (InternalDrag.bShow) {
857 HBITMAP hbmOffScreen;
858 INT origNewX, origNewY;
859 INT origOldX, origOldY;
860 INT origRegX, origRegY;
861 INT sizeRegX, sizeRegY;
864 /* calculate the update region */
865 origNewX = x - InternalDrag.dxHotspot;
866 origNewY = y - InternalDrag.dyHotspot;
867 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
868 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
869 origRegX = min(origNewX, origOldX);
870 origRegY = min(origNewY, origOldY);
871 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
872 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
874 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
875 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
876 hdcOffScreen = CreateCompatibleDC(hdcDrag);
877 hdcBg = CreateCompatibleDC(hdcDrag);
879 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
880 SelectObject(hdcOffScreen, hbmOffScreen);
881 SelectObject(hdcBg, InternalDrag.hbmBg);
883 /* get the actual background of the update region */
884 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
885 origRegX, origRegY, SRCCOPY);
886 /* erase the old image */
887 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
888 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
890 /* save the background */
891 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
892 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
894 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
895 origNewY - origRegY);
896 /* draw the update region to the screen */
897 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
898 hdcOffScreen, 0, 0, SRCCOPY);
901 DeleteDC(hdcOffScreen);
902 DeleteObject(hbmOffScreen);
903 ReleaseDC(InternalDrag.hwnd, hdcDrag);
906 /* update the image position */
914 /*************************************************************************
915 * ImageList_DragShowNolock [COMCTL32.@]
917 * Shows or hides the drag image.
920 * bShow [I] TRUE shows the drag image, FALSE hides it.
927 * The drag image should be drawn semitransparent.
931 ImageList_DragShowNolock (BOOL bShow)
937 TRACE("bShow=0x%X!\n", bShow);
939 /* DragImage is already visible/hidden */
940 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
944 /* position of the origin of the DragImage */
945 x = InternalDrag.x - InternalDrag.dxHotspot;
946 y = InternalDrag.y - InternalDrag.dyHotspot;
948 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
949 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
954 hdcBg = CreateCompatibleDC(hdcDrag);
955 if (!InternalDrag.hbmBg) {
956 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
957 InternalDrag.himl->cx, InternalDrag.himl->cy);
959 SelectObject(hdcBg, InternalDrag.hbmBg);
962 /* save the background */
963 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
964 hdcDrag, x, y, SRCCOPY);
966 ImageList_InternalDragDraw(hdcDrag, x, y);
969 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
970 hdcBg, 0, 0, SRCCOPY);
973 InternalDrag.bShow = !InternalDrag.bShow;
976 ReleaseDC (InternalDrag.hwnd, hdcDrag);
981 /*************************************************************************
982 * ImageList_Draw [COMCTL32.@] Draws an image.
985 * himl [I] handle to image list
987 * hdc [I] handle to device context
990 * fStyle [I] drawing flags
1001 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1003 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1004 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1008 /*************************************************************************
1009 * ImageList_DrawEx [COMCTL32.@]
1011 * Draws an image and allows to use extended drawing features.
1014 * himl [I] handle to image list
1016 * hdc [I] handle to device context
1021 * rgbBk [I] background color
1022 * rgbFg [I] foreground color
1023 * fStyle [I] drawing flags
1030 * Calls ImageList_DrawIndirect.
1033 * ImageList_DrawIndirect.
1037 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1038 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1041 IMAGELISTDRAWPARAMS imldp;
1043 ZeroMemory (&imldp, sizeof(imldp));
1044 imldp.cbSize = sizeof(imldp);
1052 imldp.rgbBk = rgbBk;
1053 imldp.rgbFg = rgbFg;
1054 imldp.fStyle = fStyle;
1056 return ImageList_DrawIndirect (&imldp);
1060 /*************************************************************************
1061 * ImageList_DrawIndirect [COMCTL32.@]
1063 * Draws an image using ...
1066 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1074 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1076 INT cx, cy, nOvlIdx;
1077 DWORD fState, dwRop;
1079 COLORREF clrBk, oldImageBk, oldImageFg;
1080 HDC hImageDC, hImageListDC, hMaskListDC;
1081 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1082 BOOL bIsTransparent, bBlend, bResult = FALSE;
1083 const HIMAGELIST himl = pimldp->himl;
1084 const INT lx = himl->cx * pimldp->i + pimldp->xBitmap;
1085 const INT ly = pimldp->yBitmap;
1087 if (!pimldp || !himl) return FALSE;
1088 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1090 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1091 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1092 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1093 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1094 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1095 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1096 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1098 TRACE("hbmMask(0x%08x) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1099 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1101 /* we will use these DCs to access the images and masks in the ImageList */
1102 hImageListDC = CreateCompatibleDC(0);
1103 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1105 /* these will accumulate the image and mask for the image we're drawing */
1106 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1107 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1108 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1110 /* Create a compatible DC. */
1111 if (!hImageListDC || !hImageDC || !hImageBmp ||
1112 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1115 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1116 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1117 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1120 * To obtain a transparent look, background color should be set
1121 * to white and foreground color to black when blting the
1124 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1125 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1128 * Draw the initial image
1130 if(fStyle & ILD_MASK) {
1131 if (himl->hbmMask) {
1132 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1134 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1135 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1136 SelectObject(hImageDC, hOldBrush);
1138 } else if (himl->hbmMask && !bIsTransparent) {
1139 /* blend the image with the needed solid background */
1140 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1141 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1142 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1143 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1144 DeleteObject (SelectObject (hImageDC, hOldBrush));
1146 /* start off with the image, if we have a mask, we'll use it later */
1147 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1150 /* Time for blending, if required */
1152 HBRUSH hBlendBrush, hOldBrush;
1153 COLORREF clrBlend = pimldp->rgbFg;
1154 HDC hBlendMaskDC = hImageListDC;
1157 /* Create the blend Mask */
1158 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1159 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1160 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1161 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1162 SelectObject(hBlendMaskDC, hOldBrush);
1164 /* Modify the blend mask if an Image Mask exist */
1166 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1167 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1170 /* now apply blend to the current image given the BlendMask */
1171 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1172 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1173 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1174 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1175 DeleteObject(SelectObject(hImageDC, hOldBrush));
1176 SelectObject(hBlendMaskDC, hOldBitmap);
1179 /* Now do the overlay image, if any */
1180 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1181 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1182 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1183 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1184 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1185 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1186 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1187 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1191 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1192 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1193 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1194 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1196 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1197 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1198 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1200 /* now copy the image to the screen */
1202 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1203 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1204 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1205 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1206 SetBkColor(pimldp->hdcDst, oldDstBk);
1207 SetTextColor(pimldp->hdcDst, oldDstFg);
1210 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1211 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1215 /* cleanup the mess */
1216 SetBkColor(hImageDC, oldImageBk);
1217 SetTextColor(hImageDC, oldImageFg);
1218 SelectObject(hImageDC, hOldImageBmp);
1219 SelectObject(hImageListDC, hOldImageListBmp);
1220 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1222 DeleteObject(hBlendMaskBmp);
1223 DeleteObject(hImageBmp);
1224 DeleteObject(hImageDC);
1225 DeleteObject(hImageListDC);
1226 DeleteObject(hMaskListDC);
1232 /*************************************************************************
1233 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1236 * himlSrc [I] source image list handle
1239 * Success: Handle of duplicated image list.
1244 ImageList_Duplicate (HIMAGELIST himlSrc)
1249 if (himlSrc == NULL) {
1250 ERR("Invalid image list handle!\n");
1254 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1255 himlSrc->cInitial, himlSrc->cGrow);
1259 hdcSrc = CreateCompatibleDC (0);
1260 hdcDst = CreateCompatibleDC (0);
1261 SelectObject (hdcSrc, himlSrc->hbmImage);
1262 SelectObject (hdcDst, himlDst->hbmImage);
1263 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1264 hdcSrc, 0, 0, SRCCOPY);
1266 if (himlDst->hbmMask)
1268 SelectObject (hdcSrc, himlSrc->hbmMask);
1269 SelectObject (hdcDst, himlDst->hbmMask);
1270 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1271 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1277 himlDst->cCurImage = himlSrc->cCurImage;
1278 himlDst->cMaxImage = himlSrc->cMaxImage;
1284 /*************************************************************************
1285 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1287 * Finishes a drag operation.
1298 ImageList_EndDrag (void)
1300 /* cleanup the InternalDrag struct */
1301 InternalDrag.hwnd = 0;
1302 ImageList_Destroy (InternalDrag.himl);
1303 InternalDrag.himl = 0;
1306 InternalDrag.dxHotspot = 0;
1307 InternalDrag.dyHotspot = 0;
1308 InternalDrag.bShow = FALSE;
1309 DeleteObject(InternalDrag.hbmBg);
1310 InternalDrag.hbmBg = 0;
1311 InternalDrag.bHSPending = FALSE;
1317 /*************************************************************************
1318 * ImageList_GetBkColor [COMCTL32.@]
1320 * Returns the background color of an image list.
1323 * himl [I] Image list handle.
1326 * Success: background color
1331 ImageList_GetBkColor (HIMAGELIST himl)
1333 return himl ? himl->clrBk : CLR_NONE;
1337 /*************************************************************************
1338 * ImageList_GetDragImage [COMCTL32.@]
1340 * Returns the handle to the internal drag image list.
1343 * ppt [O] Pointer to the drag position. Can be NULL.
1344 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1347 * Success: Handle of the drag image list.
1352 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1354 if (InternalDrag.himl) {
1356 ppt->x = InternalDrag.x;
1357 ppt->y = InternalDrag.y;
1360 pptHotspot->x = InternalDrag.dxHotspot;
1361 pptHotspot->y = InternalDrag.dyHotspot;
1363 return (InternalDrag.himl);
1370 /*************************************************************************
1371 * ImageList_GetFlags [COMCTL32.@]
1378 ImageList_GetFlags(HIMAGELIST himl)
1380 FIXME("(%p):empty stub\n", himl);
1385 /*************************************************************************
1386 * ImageList_GetIcon [COMCTL32.@]
1388 * Creates an icon from a masked image of an image list.
1391 * himl [I] handle to image list
1393 * flags [I] drawing style flags
1396 * Success: icon handle
1401 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1405 HBITMAP hOldDstBitmap;
1408 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1410 hdcDst = CreateCompatibleDC(0);
1415 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1416 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1417 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1420 SelectObject (hdcDst, himl->hbmImage);
1421 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1422 SelectObject (hdcDst, ii.hbmColor);
1423 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1426 * CreateIconIndirect requires us to deselect the bitmaps from
1427 * the DCs before calling
1429 SelectObject(hdcDst, hOldDstBitmap);
1431 hIcon = CreateIconIndirect (&ii);
1433 DeleteObject (ii.hbmMask);
1434 DeleteObject (ii.hbmColor);
1441 /*************************************************************************
1442 * ImageList_GetIconSize [COMCTL32.@]
1444 * Retrieves the size of an image in an image list.
1447 * himl [I] handle to image list
1448 * cx [O] pointer to the image width.
1449 * cy [O] pointer to the image height.
1456 * All images in an image list have the same size.
1460 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1464 if ((himl->cx <= 0) || (himl->cy <= 0))
1476 /*************************************************************************
1477 * ImageList_GetImageCount [COMCTL32.@]
1479 * Returns the number of images in an image list.
1482 * himl [I] handle to image list
1485 * Success: Number of images.
1490 ImageList_GetImageCount (HIMAGELIST himl)
1495 return himl->cCurImage;
1499 /*************************************************************************
1500 * ImageList_GetImageInfo [COMCTL32.@]
1502 * Returns information about an image in an image list.
1505 * himl [I] handle to image list
1507 * pImageInfo [O] pointer to the image information
1515 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1517 if ((himl == NULL) || (pImageInfo == NULL))
1519 if ((i < 0) || (i >= himl->cCurImage))
1522 pImageInfo->hbmImage = himl->hbmImage;
1523 pImageInfo->hbmMask = himl->hbmMask;
1525 pImageInfo->rcImage.top = 0;
1526 pImageInfo->rcImage.bottom = himl->cy;
1527 pImageInfo->rcImage.left = i * himl->cx;
1528 pImageInfo->rcImage.right = (i+1) * himl->cx;
1534 /*************************************************************************
1535 * ImageList_GetImageRect [COMCTL32.@]
1537 * Retrieves the rectangle of the specified image in an image list.
1540 * himl [I] handle to image list
1542 * lpRect [O] pointer to the image rectangle
1549 * This is an UNDOCUMENTED function!!!
1553 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1555 if ((himl == NULL) || (lpRect == NULL))
1557 if ((i < 0) || (i >= himl->cCurImage))
1560 lpRect->left = i * himl->cx;
1562 lpRect->right = lpRect->left + himl->cx;
1563 lpRect->bottom = himl->cy;
1569 /*************************************************************************
1570 * ImageList_LoadImage [COMCTL32.@]
1571 * ImageList_LoadImageA [COMCTL32.@]
1573 * Creates an image list from a bitmap, icon or cursor.
1576 * hi [I] instance handle
1577 * lpbmp [I] name or id of the image
1578 * cx [I] width of each image
1579 * cGrow [I] number of images to expand
1580 * clrMask [I] mask color
1581 * uType [I] type of image to load
1582 * uFlags [I] loading flags
1585 * Success: handle to the loaded image list
1593 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1594 COLORREF clrMask, UINT uType, UINT uFlags)
1596 HIMAGELIST himl = NULL;
1600 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1602 ERR("Error loading image!\n");
1606 if (uType == IMAGE_BITMAP) {
1608 GetObjectA (handle, sizeof(BITMAP), &bmp);
1610 /* To match windows behavior, if cx is set to zero and
1611 the flag DI_DEFAULTSIZE is specified, cx becomes the
1612 system metric value for icons. If the flag is not specified
1613 the function sets the size to the height of the bitmap */
1616 if (uFlags & DI_DEFAULTSIZE)
1617 cx = GetSystemMetrics (SM_CXICON);
1622 nImageCount = bmp.bmWidth / cx;
1624 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1625 nImageCount, cGrow);
1626 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1628 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1632 GetIconInfo (handle, &ii);
1633 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1634 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1635 ILC_MASK | ILC_COLOR, 1, cGrow);
1636 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1637 DeleteObject (ii.hbmColor);
1638 DeleteObject (ii.hbmMask);
1641 DeleteObject (handle);
1647 /*************************************************************************
1648 * ImageList_LoadImageW [COMCTL32.@]
1650 * Creates an image list from a bitmap, icon or cursor.
1653 * hi [I] instance handle
1654 * lpbmp [I] name or id of the image
1655 * cx [I] width of each image
1656 * cGrow [I] number of images to expand
1657 * clrMask [I] mask color
1658 * uType [I] type of image to load
1659 * uFlags [I] loading flags
1662 * Success: handle to the loaded image list
1670 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1671 COLORREF clrMask, UINT uType, UINT uFlags)
1673 HIMAGELIST himl = NULL;
1677 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1679 ERR("Error loading image!\n");
1683 if (uType == IMAGE_BITMAP) {
1685 GetObjectA (handle, sizeof(BITMAP), &bmp);
1687 /* To match windows behavior, if cx is set to zero and
1688 the flag DI_DEFAULTSIZE is specified, cx becomes the
1689 system metric value for icons. If the flag is not specified
1690 the function sets the size to the height of the bitmap */
1693 if (uFlags & DI_DEFAULTSIZE)
1694 cx = GetSystemMetrics (SM_CXICON);
1699 nImageCount = bmp.bmWidth / cx;
1701 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1702 nImageCount, cGrow);
1703 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1705 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1709 GetIconInfo (handle, &ii);
1710 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1711 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1712 ILC_MASK | ILC_COLOR, 1, cGrow);
1713 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1714 DeleteObject (ii.hbmColor);
1715 DeleteObject (ii.hbmMask);
1718 DeleteObject (handle);
1724 /*************************************************************************
1725 * ImageList_Merge [COMCTL32.@]
1727 * Creates a new image list that contains a merged image from the specified
1728 * images of both source image lists.
1731 * himl1 [I] handle to first image list
1732 * i1 [I] first image index
1733 * himl2 [I] handle to second image list
1734 * i2 [I] second image index
1735 * dx [I] X offset of the second image relative to the first.
1736 * dy [I] Y offset of the second image relative to the first.
1739 * Success: handle of the merged image list.
1744 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1747 HIMAGELIST himlDst = NULL;
1748 HDC hdcSrcImage, hdcDstImage;
1750 INT xOff1, yOff1, xOff2, yOff2;
1753 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1756 if ((himl1 == NULL) || (himl2 == NULL))
1760 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1761 ERR("Index 1 out of range! %d\n", i1);
1765 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1766 ERR("Index 2 out of range! %d\n", i2);
1771 cxDst = max (himl1->cx, dx + himl2->cx);
1776 cxDst = max (himl2->cx, himl1->cx - dx);
1781 cxDst = max (himl1->cx, himl2->cx);
1787 cyDst = max (himl1->cy, dy + himl2->cy);
1792 cyDst = max (himl2->cy, himl1->cy - dy);
1797 cyDst = max (himl1->cy, himl2->cy);
1802 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1805 hdcSrcImage = CreateCompatibleDC (0);
1806 hdcDstImage = CreateCompatibleDC (0);
1807 nX1 = i1 * himl1->cx;
1808 nX2 = i2 * himl2->cx;
1811 SelectObject (hdcSrcImage, himl1->hbmImage);
1812 SelectObject (hdcDstImage, himlDst->hbmImage);
1813 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1814 hdcSrcImage, 0, 0, BLACKNESS);
1815 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1816 hdcSrcImage, nX1, 0, SRCCOPY);
1818 SelectObject (hdcSrcImage, himl2->hbmMask);
1819 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1820 hdcSrcImage, nX2, 0, SRCAND);
1822 SelectObject (hdcSrcImage, himl2->hbmImage);
1823 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1824 hdcSrcImage, nX2, 0, SRCPAINT);
1827 SelectObject (hdcSrcImage, himl1->hbmMask);
1828 SelectObject (hdcDstImage, himlDst->hbmMask);
1829 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1830 hdcSrcImage, 0, 0, WHITENESS);
1831 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1832 hdcSrcImage, nX1, 0, SRCCOPY);
1834 SelectObject (hdcSrcImage, himl2->hbmMask);
1835 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1836 hdcSrcImage, nX2, 0, SRCAND);
1838 DeleteDC (hdcSrcImage);
1839 DeleteDC (hdcDstImage);
1840 himlDst->cCurImage = 1;
1847 /* helper for _read_bitmap currently unused */
1849 static int may_use_dibsection(HDC hdc) {
1850 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1855 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1859 /* helper for ImageList_Read, see comments below */
1860 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1862 BITMAPFILEHEADER bmfh;
1863 BITMAPINFOHEADER bmih;
1864 int bitsperpixel,palspace,longsperline,width,height;
1865 LPBITMAPINFOHEADER bmihc = NULL;
1867 HBITMAP hbitmap = 0;
1868 LPBYTE bits = NULL,nbits = NULL;
1869 int nbytesperline,bytesperline;
1871 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1872 (bmfh.bfType != (('M'<<8)|'B')) ||
1873 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1874 (bmih.biSize != sizeof(bmih))
1878 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1879 if (bitsperpixel<=8)
1880 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1883 width = bmih.biWidth;
1884 height = bmih.biHeight;
1885 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1886 memcpy(bmihc,&bmih,sizeof(bmih));
1887 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1888 bmihc->biSizeImage = (longsperline*height)<<2;
1890 /* read the palette right after the end of the bitmapinfoheader */
1892 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1896 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1897 if ((bitsperpixel>1) &&
1898 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1900 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1903 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1909 int i,nwidth,nheight;
1911 nwidth = width*(height/cy);
1914 if (bitsperpixel==1)
1915 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1917 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1919 /* Might be a bit excessive memory use here */
1920 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1921 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1922 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1925 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1926 /* Do not forget that windows bitmaps are bottom->top */
1927 bytesperline = longsperline*4;
1928 nbytesperline = (height/cy)*bytesperline;
1929 for (i=0;i<height;i++) {
1931 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1932 bits+bytesperline*(height-1-i),
1936 bmihc->biWidth = nwidth;
1937 bmihc->biHeight = nheight;
1938 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1940 LocalFree((HLOCAL)nbits);
1941 LocalFree((HLOCAL)bits);
1945 if (xdc) ReleaseDC(0,xdc);
1946 if (bmihc) LocalFree((HLOCAL)bmihc);
1949 DeleteObject(hbitmap);
1956 /*************************************************************************
1957 * ImageList_Read [COMCTL32.@]
1959 * Reads an image list from a stream.
1962 * pstm [I] pointer to a stream
1965 * Success: handle to image list
1968 * The format is like this:
1969 * ILHEAD ilheadstruct;
1971 * for the color image part:
1972 * BITMAPFILEHEADER bmfh;
1973 * BITMAPINFOHEADER bmih;
1974 * only if it has a palette:
1975 * RGBQUAD rgbs[nr_of_paletted_colors];
1977 * BYTE colorbits[imagesize];
1979 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1980 * BITMAPFILEHEADER bmfh_mask;
1981 * BITMAPINFOHEADER bmih_mask;
1982 * only if it has a palette (it usually does not):
1983 * RGBQUAD rgbs[nr_of_paletted_colors];
1985 * BYTE maskbits[imagesize];
1987 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1988 * _read_bitmap needs to convert them.
1990 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1994 HBITMAP hbmColor=0,hbmMask=0;
1997 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1999 if (ilHead.usMagic != (('L' << 8) | 'I'))
2001 if (ilHead.usVersion != 0x101) /* probably version? */
2005 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2006 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2007 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2008 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2009 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2010 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2011 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2012 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2013 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2014 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2017 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2020 if (ilHead.flags & ILC_MASK) {
2021 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2023 DeleteObject(hbmColor);
2028 himl = ImageList_Create (
2036 DeleteObject(hbmColor);
2037 DeleteObject(hbmMask);
2040 himl->hbmImage = hbmColor;
2041 himl->hbmMask = hbmMask;
2042 himl->cCurImage = ilHead.cCurImage;
2043 himl->cMaxImage = ilHead.cMaxImage;
2045 ImageList_SetBkColor(himl,ilHead.bkcolor);
2047 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2052 /*************************************************************************
2053 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2056 * himl [I] image list handle
2065 ImageList_Remove (HIMAGELIST himl, INT i)
2067 HBITMAP hbmNewImage, hbmNewMask;
2071 TRACE("(himl=%p i=%d)\n", himl, i);
2074 ERR("Invalid image list handle!\n");
2078 if ((i < -1) || (i >= himl->cCurImage)) {
2079 ERR("index out of range! %d\n", i);
2085 if (himl->cCurImage == 0) {
2086 /* remove all on empty ImageList is allowed */
2087 TRACE("remove all on empty ImageList!\n");
2091 himl->cMaxImage = himl->cInitial + himl->cGrow;
2092 himl->cCurImage = 0;
2093 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2094 himl->nOvlIdx[nCount] = -1;
2096 DeleteObject (himl->hbmImage);
2098 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2099 1, himl->uBitsPixel, NULL);
2101 if (himl->hbmMask) {
2102 DeleteObject (himl->hbmMask);
2104 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2109 /* delete one image */
2110 TRACE("Remove single image! %d\n", i);
2112 /* create new bitmap(s) */
2113 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2115 TRACE(" - Number of images: %d / %d (Old/New)\n",
2116 himl->cCurImage, himl->cCurImage - 1);
2117 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2118 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2121 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2124 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2126 hbmNewMask = 0; /* Just to keep compiler happy! */
2128 hdcSrc = CreateCompatibleDC (0);
2129 hdcDst = CreateCompatibleDC (0);
2131 /* copy all images and masks prior to the "removed" image */
2133 TRACE("Pre image copy: Copy %d images\n", i);
2135 SelectObject (hdcSrc, himl->hbmImage);
2136 SelectObject (hdcDst, hbmNewImage);
2137 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2138 hdcSrc, 0, 0, SRCCOPY);
2140 if (himl->hbmMask) {
2141 SelectObject (hdcSrc, himl->hbmMask);
2142 SelectObject (hdcDst, hbmNewMask);
2143 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2144 hdcSrc, 0, 0, SRCCOPY);
2148 /* copy all images and masks behind the removed image */
2149 if (i < himl->cCurImage - 1) {
2150 TRACE("Post image copy!\n");
2151 SelectObject (hdcSrc, himl->hbmImage);
2152 SelectObject (hdcDst, hbmNewImage);
2153 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2154 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2156 if (himl->hbmMask) {
2157 SelectObject (hdcSrc, himl->hbmMask);
2158 SelectObject (hdcDst, hbmNewMask);
2159 BitBlt (hdcDst, i * himl->cx, 0,
2160 (himl->cCurImage - i - 1) * himl->cx,
2161 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2168 /* delete old images and insert new ones */
2169 DeleteObject (himl->hbmImage);
2170 himl->hbmImage = hbmNewImage;
2171 if (himl->hbmMask) {
2172 DeleteObject (himl->hbmMask);
2173 himl->hbmMask = hbmNewMask;
2177 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2184 /*************************************************************************
2185 * ImageList_Replace [COMCTL32.@]
2187 * Replaces an image in an image list with a new image.
2190 * himl [I] handle to image list
2192 * hbmImage [I] handle to image bitmap
2193 * hbmMask [I] handle to mask bitmap. Can be NULL.
2201 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2204 HDC hdcImageList, hdcImage;
2207 TRACE("%p %d %04x %04x\n", himl, i, hbmImage, hbmMask);
2210 ERR("Invalid image list handle!\n");
2214 if ((i >= himl->cMaxImage) || (i < 0)) {
2215 ERR("Invalid image index!\n");
2219 hdcImageList = CreateCompatibleDC (0);
2220 hdcImage = CreateCompatibleDC (0);
2221 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2224 SelectObject (hdcImageList, himl->hbmImage);
2225 SelectObject (hdcImage, hbmImage);
2227 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2228 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2233 SelectObject (hdcImageList, himl->hbmMask);
2234 SelectObject (hdcImage, hbmMask);
2236 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2237 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2240 /* Remove the background from the image
2242 SelectObject (hdcImageList, himl->hbmImage);
2243 StretchBlt (hdcImageList,
2244 i*himl->cx, 0, himl->cx, himl->cy,
2246 0, 0, bmp.bmWidth, bmp.bmHeight,
2247 0x220326); /* NOTSRCAND */
2250 DeleteDC (hdcImage);
2251 DeleteDC (hdcImageList);
2257 /*************************************************************************
2258 * ImageList_ReplaceIcon [COMCTL32.@]
2260 * Replaces an image in an image list using an icon.
2263 * himl [I] handle to image list
2265 * hIcon [I] handle to icon
2268 * Success: index of the replaced image
2273 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2275 HDC hdcImageList, hdcImage;
2278 HBITMAP hbmOldSrc, hbmOldDst;
2282 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2286 if ((i >= himl->cMaxImage) || (i < -1))
2289 hBestFitIcon = CopyImage(
2292 LR_COPYFROMRESOURCE);
2294 GetIconInfo (hBestFitIcon, &ii);
2295 if (ii.hbmMask == 0)
2297 if (ii.hbmColor == 0)
2299 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2302 if (himl->cCurImage + 1 > himl->cMaxImage)
2303 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2305 nIndex = himl->cCurImage;
2311 hdcImageList = CreateCompatibleDC (0);
2312 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2313 if (hdcImageList == 0)
2314 ERR("invalid hdcImageList!\n");
2316 hdcImage = CreateCompatibleDC (0);
2317 TRACE("hdcImage=0x%x!\n", hdcImage);
2319 ERR("invalid hdcImage!\n");
2321 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2322 SetTextColor( hdcImageList, RGB(0,0,0));
2323 SetBkColor( hdcImageList, RGB(255,255,255));
2324 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2325 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2326 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2328 if (himl->hbmMask) {
2329 SelectObject (hdcImageList, himl->hbmMask);
2330 SelectObject (hdcImage, ii.hbmMask);
2331 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2332 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2335 SelectObject (hdcImage, hbmOldSrc);
2336 SelectObject (hdcImageList, hbmOldDst);
2339 DestroyIcon(hBestFitIcon);
2341 DeleteDC (hdcImageList);
2343 DeleteDC (hdcImage);
2345 DeleteObject (ii.hbmColor);
2347 DeleteObject (ii.hbmMask);
2353 /*************************************************************************
2354 * ImageList_SetBkColor [COMCTL32.@]
2356 * Sets the background color of an image list.
2359 * himl [I] handle to image list
2360 * clrBk [I] background color
2363 * Success: previous background color
2368 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2375 clrOldBk = himl->clrBk;
2376 himl->clrBk = clrBk;
2381 /*************************************************************************
2382 * ImageList_SetDragCursorImage [COMCTL32.@]
2384 * Combines the specified image with the current drag image
2387 * himlDrag [I] handle to drag image list
2388 * iDrag [I] drag image index
2389 * dxHotspot [I] X position of the hot spot
2390 * dyHotspot [I] Y position of the hot spot
2397 * When this function is called and the drag image is visible, a
2398 * short flickering occurs but this matches the Win9x behavior. It is
2399 * possible to fix the flickering using code like in ImageList_DragMove.
2403 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2404 INT dxHotspot, INT dyHotspot)
2406 HIMAGELIST himlTemp;
2410 if (InternalDrag.himl == NULL)
2413 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2414 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2416 visible = InternalDrag.bShow;
2418 /* Calculate the offset between the origin of the old image and the
2419 * origin of the second image.
2420 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2421 * hotspot) to the origin of the second image.
2422 * See M$DN for details */
2423 if(InternalDrag.bHSPending) {
2426 InternalDrag.bHSPending = FALSE;
2428 dx = InternalDrag.dxHotspot - dxHotspot;
2429 dy = InternalDrag.dyHotspot - dyHotspot;
2431 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2434 /* hide the drag image */
2435 ImageList_DragShowNolock(FALSE);
2437 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2438 (InternalDrag.himl->cy != himlTemp->cy)) {
2439 /* the size of the drag image changed, invalidate the buffer */
2440 DeleteObject(InternalDrag.hbmBg);
2441 InternalDrag.hbmBg = 0;
2444 ImageList_Destroy (InternalDrag.himl);
2445 InternalDrag.himl = himlTemp;
2447 /* update the InternalDragOffset, if the origin of the
2448 * DragImage was changed by ImageList_Merge. */
2450 InternalDrag.dxHotspot = dxHotspot;
2452 InternalDrag.dyHotspot = dyHotspot;
2455 /* show the drag image */
2456 ImageList_DragShowNolock(TRUE);
2463 /*************************************************************************
2464 * ImageList_SetFilter [COMCTL32.@]
2466 * Sets a filter (or does something completely different)!!???
2467 * It removes 12 Bytes from the stack (3 Parameters).
2470 * himl [I] SHOULD be a handle to image list
2471 * i [I] COULD be an index?
2476 * Failure: FALSE ???
2479 * This is an UNDOCUMENTED function!!!!
2484 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2486 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2492 /*************************************************************************
2493 * ImageList_SetFlags [COMCTL32.@]
2500 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2502 FIXME("(%p %08lx):empty stub\n", himl, flags);
2507 /*************************************************************************
2508 * ImageList_SetIconSize [COMCTL32.@]
2510 * Sets the image size of the bitmap and deletes all images.
2513 * himl [I] handle to image list
2514 * cx [I] image width
2515 * cy [I] image height
2523 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2530 /* remove all images */
2531 himl->cMaxImage = himl->cInitial + himl->cGrow;
2532 himl->cCurImage = 0;
2536 /* initialize overlay mask indices */
2537 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2538 himl->nOvlIdx[nCount] = -1;
2540 DeleteObject (himl->hbmImage);
2542 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2543 1, himl->uBitsPixel, NULL);
2545 if (himl->hbmMask) {
2546 DeleteObject (himl->hbmMask);
2548 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2556 /*************************************************************************
2557 * ImageList_SetImageCount [COMCTL32.@]
2559 * Resizes an image list to the specified number of images.
2562 * himl [I] handle to image list
2563 * iImageCount [I] number of images in the image list
2571 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2573 HDC hdcImageList, hdcBitmap;
2574 HBITMAP hbmNewBitmap;
2575 INT nNewCount, nCopyCount;
2577 TRACE("%p %d\n",himl,iImageCount);
2581 if (himl->cCurImage >= iImageCount)
2583 if (himl->cMaxImage > iImageCount)
2585 himl->cCurImage = iImageCount;
2589 nNewCount = iImageCount + himl->cGrow;
2590 nCopyCount = min(himl->cCurImage, iImageCount);
2592 hdcImageList = CreateCompatibleDC (0);
2593 hdcBitmap = CreateCompatibleDC (0);
2595 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2596 1, himl->uBitsPixel, NULL);
2597 if (hbmNewBitmap != 0)
2599 SelectObject (hdcImageList, himl->hbmImage);
2600 SelectObject (hdcBitmap, hbmNewBitmap);
2603 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2604 hdcImageList, 0, 0, SRCCOPY);
2606 /* delete 'empty' image space */
2607 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2608 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2609 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2610 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2612 DeleteObject (himl->hbmImage);
2613 himl->hbmImage = hbmNewBitmap;
2616 ERR("Could not create new image bitmap !\n");
2620 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2622 if (hbmNewBitmap != 0)
2624 SelectObject (hdcImageList, himl->hbmMask);
2625 SelectObject (hdcBitmap, hbmNewBitmap);
2628 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2629 hdcImageList, 0, 0, SRCCOPY);
2631 /* delete 'empty' image space */
2632 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2633 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2634 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2635 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2637 DeleteObject (himl->hbmMask);
2638 himl->hbmMask = hbmNewBitmap;
2641 ERR("Could not create new mask bitmap!\n");
2644 DeleteDC (hdcImageList);
2645 DeleteDC (hdcBitmap);
2647 /* Update max image count and current image count */
2648 himl->cMaxImage = nNewCount;
2649 himl->cCurImage = iImageCount;
2655 /*************************************************************************
2656 * ImageList_SetOverlayImage [COMCTL32.@]
2658 * Assigns an overlay mask index to an existing image in an image list.
2661 * himl [I] handle to image list
2662 * iImage [I] image index
2663 * iOverlay [I] overlay mask index
2671 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2675 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2677 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2679 himl->nOvlIdx[iOverlay - 1] = iImage;
2685 /* helper for ImageList_Write - write bitmap to pstm
2686 * currently everything is written as 24 bit RGB, except masks
2689 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2691 LPBITMAPFILEHEADER bmfh;
2692 LPBITMAPINFOHEADER bmih;
2693 LPBYTE data, lpBits, lpBitsOrg;
2695 INT bitCount, sizeImage, offBits, totalSize;
2696 INT nwidth, nheight, nsizeImage, icount;
2698 BOOL result = FALSE;
2702 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2704 /* XXX is this always correct? */
2705 icount = bm.bmWidth / cx;
2707 nheight = cy * ((icount+3)>>2);
2709 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2710 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2711 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2713 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2715 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2716 offBits = totalSize;
2717 totalSize += nsizeImage;
2719 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2720 bmfh = (LPBITMAPFILEHEADER)data;
2721 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2722 lpBits = data + offBits;
2724 /* setup BITMAPFILEHEADER */
2725 bmfh->bfType = (('M' << 8) | 'B');
2727 bmfh->bfReserved1 = 0;
2728 bmfh->bfReserved2 = 0;
2729 bmfh->bfOffBits = offBits;
2731 /* setup BITMAPINFOHEADER */
2732 bmih->biSize = sizeof(BITMAPINFOHEADER);
2733 bmih->biWidth = bm.bmWidth;
2734 bmih->biHeight = bm.bmHeight;
2736 bmih->biBitCount = bitCount;
2737 bmih->biCompression = BI_RGB;
2738 bmih->biSizeImage = nsizeImage;
2739 bmih->biXPelsPerMeter = 0;
2740 bmih->biYPelsPerMeter = 0;
2741 bmih->biClrUsed = 0;
2742 bmih->biClrImportant = 0;
2744 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2745 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2746 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2750 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2751 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2753 for(i = 0; i < nheight; i++) {
2754 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2755 int noff = (nbpl * (nheight-1-i));
2756 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2760 bmih->biWidth = nwidth;
2761 bmih->biHeight = nheight;
2765 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2766 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2767 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2770 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2777 LocalFree((HLOCAL)lpBitsOrg);
2783 /*************************************************************************
2784 * ImageList_Write [COMCTL32.@]
2786 * Writes an image list to a stream.
2789 * himl [I] handle to image list
2790 * pstm [O] Pointer to a stream.
2801 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2809 ilHead.usMagic = (('L' << 8) | 'I');
2810 ilHead.usVersion = 0x101;
2811 ilHead.cCurImage = himl->cCurImage;
2812 ilHead.cMaxImage = himl->cMaxImage;
2813 ilHead.cGrow = himl->cGrow;
2814 ilHead.cx = himl->cx;
2815 ilHead.cy = himl->cy;
2816 ilHead.bkcolor = himl->clrBk;
2817 ilHead.flags = himl->flags;
2818 for(i = 0; i < 4; i++) {
2819 ilHead.ovls[i] = himl->nOvlIdx[i];
2822 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2825 /* write the bitmap */
2826 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2829 /* write the mask if we have one */
2830 if(himl->flags & ILC_MASK) {
2831 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))