2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we believe this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
38 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
39 * is the offset of the image position relative to the actual mouse pointer
40 * position. However the Hotspot passed to SetDragCursorImage is the
41 * offset of the mouse messages sent to the application...
50 #include "imagelist.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
56 #define MAX_OVERLAYIMAGE 15
58 /* internal image list data used for Drag & Drop operations */
63 /* position of the drag image relative to the window */
66 /* offset of the hotspot relative to the origin of the image */
69 /* is the drag image visible */
71 /* saved background */
76 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
79 static inline BOOL is_valid(HIMAGELIST himl)
81 return himl && himl->magic == IMAGELIST_MAGIC;
85 /*************************************************************************
86 * IMAGELIST_InternalExpandBitmaps [Internal]
88 * Expands the bitmaps of an image list by the given number of images.
91 * himl [I] handle to image list
92 * nImageCount [I] number of images to add
98 * This function can NOT be used to reduce the number of images.
101 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
104 HBITMAP hbmNewBitmap, hbmNull;
105 INT nNewWidth, nNewCount;
107 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
111 if (cy == 0) cy = himl->cy;
112 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
113 nNewWidth = nNewCount * himl->cx;
115 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
116 hdcBitmap = CreateCompatibleDC (0);
119 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
120 if (hbmNewBitmap == 0)
121 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
123 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
124 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
125 himl->hdcImage, 0, 0, SRCCOPY);
127 SelectObject (hdcBitmap, hbmNull);
128 SelectObject (himl->hdcImage, hbmNewBitmap);
129 DeleteObject (himl->hbmImage);
130 himl->hbmImage = hbmNewBitmap;
134 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
136 if (hbmNewBitmap == 0)
137 ERR("creating new mask bitmap!\n");
139 SelectObject (hdcBitmap, hbmNewBitmap);
140 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
141 himl->hdcMask, 0, 0, SRCCOPY);
142 SelectObject (hdcBitmap, hbmNull);
143 SelectObject (himl->hdcMask, hbmNewBitmap);
144 DeleteObject (himl->hbmMask);
145 himl->hbmMask = hbmNewBitmap;
148 himl->cMaxImage = nNewCount;
150 DeleteDC (hdcBitmap);
154 /*************************************************************************
155 * ImageList_Add [COMCTL32.@]
157 * Add an image or images to an image list.
160 * himl [I] handle to image list
161 * hbmImage [I] handle to image bitmap
162 * hbmMask [I] handle to mask bitmap
165 * Success: Index of the first new image.
170 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
173 INT nFirstIndex, nImageCount;
178 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
182 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
183 nImageCount = bmp.bmWidth / himl->cx;
185 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
187 nStartX = himl->cCurImage * himl->cx;
189 hdcBitmap = CreateCompatibleDC(0);
191 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
193 /* Copy result to the imagelist
195 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
196 hdcBitmap, 0, 0, SRCCOPY);
201 HBITMAP hOldBitmapTemp;
203 hdcTemp = CreateCompatibleDC(0);
204 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
206 BitBlt (himl->hdcMask,
207 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
212 SelectObject(hdcTemp, hOldBitmapTemp);
215 /* Remove the background from the image
217 BitBlt (himl->hdcImage,
218 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
221 0x220326); /* NOTSRCAND */
224 SelectObject(hdcBitmap, hOldBitmap);
227 nFirstIndex = himl->cCurImage;
228 himl->cCurImage += nImageCount;
234 /*************************************************************************
235 * ImageList_AddIcon [COMCTL32.@]
237 * Adds an icon to an image list.
240 * himl [I] handle to image list
241 * hIcon [I] handle to icon
244 * Success: index of the new image
247 #undef ImageList_AddIcon
248 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
250 return ImageList_ReplaceIcon (himl, -1, hIcon);
254 /*************************************************************************
255 * ImageList_AddMasked [COMCTL32.@]
257 * Adds an image or images to an image list and creates a mask from the
258 * specified bitmap using the mask color.
261 * himl [I] handle to image list.
262 * hBitmap [I] handle to bitmap
263 * clrMask [I] mask color.
266 * Success: Index of the first new image.
271 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
273 HDC hdcMask, hdcBitmap;
274 INT nIndex, nImageCount, nMaskXOffset=0;
277 HBITMAP hMaskBitmap=0;
280 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
284 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
287 nImageCount = bmp.bmWidth / himl->cx;
289 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
291 nIndex = himl->cCurImage;
292 himl->cCurImage += nImageCount;
294 hdcBitmap = CreateCompatibleDC(0);
297 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
300 hdcMask = himl->hdcMask;
301 nMaskXOffset = nIndex * himl->cx;
306 Create a temp Mask so we can remove the background of
307 the Image (Windows does this even if there is no mask)
309 hdcMask = CreateCompatibleDC(0);
310 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
311 SelectObject(hdcMask, hMaskBitmap);
314 /* create monochrome image to the mask bitmap */
315 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
316 GetPixel (hdcBitmap, 0, 0);
317 SetBkColor (hdcBitmap, bkColor);
319 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
323 SetBkColor(hdcBitmap, RGB(255,255,255));
324 /*Remove the background from the image
327 WINDOWS BUG ALERT!!!!!!
328 The statement below should not be done in common practice
329 but this is how ImageList_AddMasked works in Windows.
330 It overwrites the original bitmap passed, this was discovered
331 by using the same bitmap to iterate the different styles
332 on windows where it failed (BUT ImageList_Add is OK)
333 This is here in case some apps rely on this bug
336 0, 0, bmp.bmWidth, bmp.bmHeight,
339 0x220326); /* NOTSRCAND */
340 /* Copy result to the imagelist
342 BitBlt (himl->hdcImage,
343 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
349 SelectObject(hdcBitmap, hOldBitmap);
353 DeleteObject(hMaskBitmap);
361 /*************************************************************************
362 * ImageList_BeginDrag [COMCTL32.@]
364 * Creates a temporary image list that contains one image. It will be used
368 * himlTrack [I] handle to the source image list
369 * iTrack [I] index of the drag image in the source image list
370 * dxHotspot [I] X position of the hot spot of the drag image
371 * dyHotspot [I] Y position of the hot spot of the drag image
379 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
380 INT dxHotspot, INT dyHotspot)
384 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
385 dxHotspot, dyHotspot);
387 if (!is_valid(himlTrack))
390 if (InternalDrag.himl)
391 ImageList_EndDrag ();
396 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
397 if (InternalDrag.himl == NULL) {
398 WARN("Error creating drag image list!\n");
402 InternalDrag.dxHotspot = dxHotspot;
403 InternalDrag.dyHotspot = dyHotspot;
406 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
409 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
411 InternalDrag.himl->cCurImage = 1;
412 InternalDrag.bHSPending = TRUE;
418 /*************************************************************************
419 * ImageList_Copy [COMCTL32.@]
421 * Copies an image of the source image list to an image of the
422 * destination image list. Images can be copied or swapped.
425 * himlDst [I] handle to the destination image list
426 * iDst [I] destination image index.
427 * himlSrc [I] handle to the source image list
428 * iSrc [I] source image index
429 * uFlags [I] flags for the copy operation
436 * Copying from one image list to another is possible. The original
437 * implementation just copies or swaps within one image list.
438 * Could this feature become a bug??? ;-)
442 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
443 INT iSrc, INT uFlags)
445 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
447 if (!is_valid(himlSrc) || !is_valid(himlDst))
449 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
451 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
454 if (uFlags & ILCF_SWAP) {
457 HBITMAP hbmTempImage, hbmTempMask;
459 hdcBmp = CreateCompatibleDC (0);
461 /* create temporary bitmaps */
462 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
463 himlSrc->uBitsPixel, NULL);
464 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
467 /* copy (and stretch) destination to temporary bitmaps.(save) */
469 SelectObject (hdcBmp, hbmTempImage);
470 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
471 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
474 SelectObject (hdcBmp, hbmTempMask);
475 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
476 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
479 /* copy (and stretch) source to destination */
481 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
482 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
485 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
486 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
489 /* copy (without stretching) temporary bitmaps to source (restore) */
491 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
492 hdcBmp, 0, 0, SRCCOPY);
495 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
496 hdcBmp, 0, 0, SRCCOPY);
497 /* delete temporary bitmaps */
498 DeleteObject (hbmTempMask);
499 DeleteObject (hbmTempImage);
504 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
505 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
509 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
510 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
518 /*************************************************************************
519 * ImageList_Create [COMCTL32.@] Creates a new image list.
522 * cx [I] image height
524 * flags [I] creation flags
525 * cInitial [I] initial number of images in the image list
526 * cGrow [I] number of images by which image list grows
529 * Success: Handle to the created image list
534 ImageList_Create (INT cx, INT cy, UINT flags,
535 INT cInitial, INT cGrow)
540 static WORD aBitBlend25[] =
541 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
543 static WORD aBitBlend50[] =
544 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
546 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
548 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
552 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
554 himl->magic = IMAGELIST_MAGIC;
558 himl->cMaxImage = cInitial + cGrow;
559 himl->cInitial = cInitial;
561 himl->clrFg = CLR_DEFAULT;
562 himl->clrBk = CLR_NONE;
564 /* initialize overlay mask indices */
565 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
566 himl->nOvlIdx[nCount] = -1;
568 /* Create Image & Mask DCs */
569 himl->hdcImage = CreateCompatibleDC (0);
572 if (himl->flags & ILC_MASK){
573 himl->hdcMask = CreateCompatibleDC(0);
578 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
580 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
582 if (himl->cMaxImage > 0) {
584 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
585 1, himl->uBitsPixel, NULL);
586 if (himl->hbmImage == 0) {
587 ERR("Error creating image bitmap!\n");
590 SelectObject(himl->hdcImage, himl->hbmImage);
593 if (himl->flags & ILC_MASK) {
595 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
597 if (himl->hbmMask == 0) {
598 ERR("Error creating mask bitmap!\n");
601 SelectObject(himl->hdcMask, himl->hbmMask);
604 /* create blending brushes */
605 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
606 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
607 DeleteObject (hbmTemp);
609 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
610 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
611 DeleteObject (hbmTemp);
613 TRACE("created imagelist %p\n", himl);
617 if (himl) ImageList_Destroy(himl);
622 /*************************************************************************
623 * ImageList_Destroy [COMCTL32.@]
625 * Destroys an image list.
628 * himl [I] handle to image list
636 ImageList_Destroy (HIMAGELIST himl)
641 /* delete image bitmaps */
643 DeleteObject (himl->hbmImage);
645 DeleteObject (himl->hbmMask);
647 /* delete image & mask DCs */
649 DeleteDC(himl->hdcImage);
651 DeleteDC(himl->hdcMask);
653 /* delete blending brushes */
654 if (himl->hbrBlend25)
655 DeleteObject (himl->hbrBlend25);
656 if (himl->hbrBlend50)
657 DeleteObject (himl->hbrBlend50);
659 ZeroMemory(himl, sizeof(*himl));
660 COMCTL32_Free (himl);
666 /*************************************************************************
667 * ImageList_DragEnter [COMCTL32.@]
669 * Locks window update and displays the drag image at the given position.
672 * hwndLock [I] handle of the window that owns the drag image.
673 * x [I] X position of the drag image.
674 * y [I] Y position of the drag image.
681 * The position of the drag image is relative to the window, not
686 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
688 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
690 if (!is_valid(InternalDrag.himl))
694 InternalDrag.hwnd = hwndLock;
696 InternalDrag.hwnd = GetDesktopWindow ();
701 /* draw the drag image and save the background */
702 if (!ImageList_DragShowNolock(TRUE)) {
710 /*************************************************************************
711 * ImageList_DragLeave [COMCTL32.@]
713 * Unlocks window update and hides the drag image.
716 * hwndLock [I] handle of the window that owns the drag image.
724 ImageList_DragLeave (HWND hwndLock)
726 /* As we don't save drag info in the window this can lead to problems if
727 an app does not supply the same window as DragEnter */
729 InternalDrag.hwnd = hwndLock;
731 InternalDrag.hwnd = GetDesktopWindow (); */
733 hwndLock = GetDesktopWindow();
734 if(InternalDrag.hwnd != hwndLock)
735 FIXME("DragLeave hWnd != DragEnter hWnd\n");
737 ImageList_DragShowNolock (FALSE);
743 /*************************************************************************
744 * ImageList_InternalDragDraw [Internal]
746 * Draws the drag image.
749 * hdc [I] device context to draw into.
750 * x [I] X position of the drag image.
751 * y [I] Y position of the drag image.
758 * The position of the drag image is relative to the window, not
764 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
766 IMAGELISTDRAWPARAMS imldp;
768 ZeroMemory (&imldp, sizeof(imldp));
769 imldp.cbSize = sizeof(imldp);
770 imldp.himl = InternalDrag.himl;
775 imldp.rgbBk = CLR_DEFAULT;
776 imldp.rgbFg = CLR_DEFAULT;
777 imldp.fStyle = ILD_NORMAL;
778 imldp.fState = ILS_ALPHA;
781 /* FIXME: instead of using the alpha blending, we should
782 * create a 50% mask, and draw it semitransparantly that way */
783 ImageList_DrawIndirect (&imldp);
786 /*************************************************************************
787 * ImageList_DragMove [COMCTL32.@]
789 * Moves the drag image.
792 * x [I] X position of the drag image.
793 * y [I] Y position of the drag image.
800 * The position of the drag image is relative to the window, not
804 * The drag image should be drawn semitransparent.
808 ImageList_DragMove (INT x, INT y)
810 TRACE("(x=%d y=%d)\n", x, y);
812 if (!is_valid(InternalDrag.himl))
815 /* draw/update the drag image */
816 if (InternalDrag.bShow) {
820 HBITMAP hbmOffScreen;
821 INT origNewX, origNewY;
822 INT origOldX, origOldY;
823 INT origRegX, origRegY;
824 INT sizeRegX, sizeRegY;
827 /* calculate the update region */
828 origNewX = x - InternalDrag.dxHotspot;
829 origNewY = y - InternalDrag.dyHotspot;
830 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
831 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
832 origRegX = min(origNewX, origOldX);
833 origRegY = min(origNewY, origOldY);
834 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
835 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
837 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
838 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
839 hdcOffScreen = CreateCompatibleDC(hdcDrag);
840 hdcBg = CreateCompatibleDC(hdcDrag);
842 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
843 SelectObject(hdcOffScreen, hbmOffScreen);
844 SelectObject(hdcBg, InternalDrag.hbmBg);
846 /* get the actual background of the update region */
847 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
848 origRegX, origRegY, SRCCOPY);
849 /* erase the old image */
850 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
851 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
853 /* save the background */
854 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
855 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
857 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
858 origNewY - origRegY);
859 /* draw the update region to the screen */
860 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
861 hdcOffScreen, 0, 0, SRCCOPY);
864 DeleteDC(hdcOffScreen);
865 DeleteObject(hbmOffScreen);
866 ReleaseDC(InternalDrag.hwnd, hdcDrag);
869 /* update the image position */
877 /*************************************************************************
878 * ImageList_DragShowNolock [COMCTL32.@]
880 * Shows or hides the drag image.
883 * bShow [I] TRUE shows the drag image, FALSE hides it.
890 * The drag image should be drawn semitransparent.
894 ImageList_DragShowNolock (BOOL bShow)
900 if (!is_valid(InternalDrag.himl))
903 TRACE("bShow=0x%X!\n", bShow);
905 /* DragImage is already visible/hidden */
906 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
910 /* position of the origin of the DragImage */
911 x = InternalDrag.x - InternalDrag.dxHotspot;
912 y = InternalDrag.y - InternalDrag.dyHotspot;
914 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
915 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
920 hdcBg = CreateCompatibleDC(hdcDrag);
921 if (!InternalDrag.hbmBg) {
922 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
923 InternalDrag.himl->cx, InternalDrag.himl->cy);
925 SelectObject(hdcBg, InternalDrag.hbmBg);
928 /* save the background */
929 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
930 hdcDrag, x, y, SRCCOPY);
932 ImageList_InternalDragDraw(hdcDrag, x, y);
935 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
936 hdcBg, 0, 0, SRCCOPY);
939 InternalDrag.bShow = !InternalDrag.bShow;
942 ReleaseDC (InternalDrag.hwnd, hdcDrag);
947 /*************************************************************************
948 * ImageList_Draw [COMCTL32.@] Draws an image.
951 * himl [I] handle to image list
953 * hdc [I] handle to device context
956 * fStyle [I] drawing flags
967 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
969 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
970 CLR_DEFAULT, CLR_DEFAULT, fStyle);
974 /*************************************************************************
975 * ImageList_DrawEx [COMCTL32.@]
977 * Draws an image and allows to use extended drawing features.
980 * himl [I] handle to image list
982 * hdc [I] handle to device context
987 * rgbBk [I] background color
988 * rgbFg [I] foreground color
989 * fStyle [I] drawing flags
996 * Calls ImageList_DrawIndirect.
999 * ImageList_DrawIndirect.
1003 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1004 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1007 IMAGELISTDRAWPARAMS imldp;
1009 ZeroMemory (&imldp, sizeof(imldp));
1010 imldp.cbSize = sizeof(imldp);
1018 imldp.rgbBk = rgbBk;
1019 imldp.rgbFg = rgbFg;
1020 imldp.fStyle = fStyle;
1022 return ImageList_DrawIndirect (&imldp);
1026 /*************************************************************************
1027 * ImageList_DrawIndirect [COMCTL32.@]
1029 * Draws an image using ...
1032 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1040 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1042 INT cx, cy, lx, ly, nOvlIdx;
1043 DWORD fState, dwRop;
1045 COLORREF clrBk, oldImageBk, oldImageFg;
1046 HDC hImageDC, hImageListDC, hMaskListDC;
1047 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1048 BOOL bIsTransparent, bBlend, bResult = FALSE;
1051 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1052 if (!is_valid(himl)) return FALSE;
1053 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1055 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1056 ly = pimldp->yBitmap;
1058 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1059 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1060 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1061 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1062 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1063 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1064 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1066 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1067 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1069 /* we will use these DCs to access the images and masks in the ImageList */
1070 hImageListDC = himl->hdcImage;
1071 hMaskListDC = himl->hdcMask;
1073 /* these will accumulate the image and mask for the image we're drawing */
1074 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1075 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1076 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1078 /* Create a compatible DC. */
1079 if (!hImageListDC || !hImageDC || !hImageBmp ||
1080 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1083 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1086 * To obtain a transparent look, background color should be set
1087 * to white and foreground color to black when blting the
1090 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1091 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1094 * Draw the initial image
1096 if(fStyle & ILD_MASK) {
1097 if (himl->hbmMask) {
1098 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1100 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1101 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1102 SelectObject(hImageDC, hOldBrush);
1104 } else if (himl->hbmMask && !bIsTransparent) {
1105 /* blend the image with the needed solid background */
1106 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1107 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1108 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1109 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1110 DeleteObject (SelectObject (hImageDC, hOldBrush));
1112 /* start off with the image, if we have a mask, we'll use it later */
1113 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1116 /* Time for blending, if required */
1118 HBRUSH hBlendBrush, hOldBrush;
1119 COLORREF clrBlend = pimldp->rgbFg;
1120 HDC hBlendMaskDC = hImageListDC;
1123 /* Create the blend Mask */
1124 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1125 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1126 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1127 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1128 SelectObject(hBlendMaskDC, hOldBrush);
1130 /* Modify the blend mask if an Image Mask exist */
1132 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1133 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1136 /* now apply blend to the current image given the BlendMask */
1137 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1138 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1139 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1140 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1141 DeleteObject(SelectObject(hImageDC, hOldBrush));
1142 SelectObject(hBlendMaskDC, hOldBitmap);
1145 /* Now do the overlay image, if any */
1146 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1147 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1148 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1149 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1150 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1151 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1152 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1153 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1157 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1158 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1159 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1160 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1162 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1163 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1164 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1166 /* now copy the image to the screen */
1168 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1169 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1170 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1171 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1172 SetBkColor(pimldp->hdcDst, oldDstBk);
1173 SetTextColor(pimldp->hdcDst, oldDstFg);
1176 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1177 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1181 /* cleanup the mess */
1182 SetBkColor(hImageDC, oldImageBk);
1183 SetTextColor(hImageDC, oldImageFg);
1184 SelectObject(hImageDC, hOldImageBmp);
1186 DeleteObject(hBlendMaskBmp);
1187 DeleteObject(hImageBmp);
1194 /*************************************************************************
1195 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1198 * himlSrc [I] source image list handle
1201 * Success: Handle of duplicated image list.
1206 ImageList_Duplicate (HIMAGELIST himlSrc)
1210 if (!is_valid(himlSrc)) {
1211 ERR("Invalid image list handle!\n");
1215 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1216 himlSrc->cInitial, himlSrc->cGrow);
1220 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1221 himlSrc->hdcImage, 0, 0, SRCCOPY);
1223 if (himlDst->hbmMask)
1224 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1225 himlSrc->hdcMask, 0, 0, SRCCOPY);
1227 himlDst->cCurImage = himlSrc->cCurImage;
1228 himlDst->cMaxImage = himlSrc->cMaxImage;
1234 /*************************************************************************
1235 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1237 * Finishes a drag operation.
1248 ImageList_EndDrag (void)
1250 /* cleanup the InternalDrag struct */
1251 InternalDrag.hwnd = 0;
1252 ImageList_Destroy (InternalDrag.himl);
1253 InternalDrag.himl = 0;
1256 InternalDrag.dxHotspot = 0;
1257 InternalDrag.dyHotspot = 0;
1258 InternalDrag.bShow = FALSE;
1259 DeleteObject(InternalDrag.hbmBg);
1260 InternalDrag.hbmBg = 0;
1261 InternalDrag.bHSPending = FALSE;
1267 /*************************************************************************
1268 * ImageList_GetBkColor [COMCTL32.@]
1270 * Returns the background color of an image list.
1273 * himl [I] Image list handle.
1276 * Success: background color
1281 ImageList_GetBkColor (HIMAGELIST himl)
1283 return himl ? himl->clrBk : CLR_NONE;
1287 /*************************************************************************
1288 * ImageList_GetDragImage [COMCTL32.@]
1290 * Returns the handle to the internal drag image list.
1293 * ppt [O] Pointer to the drag position. Can be NULL.
1294 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1297 * Success: Handle of the drag image list.
1302 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1304 if (is_valid(InternalDrag.himl)) {
1306 ppt->x = InternalDrag.x;
1307 ppt->y = InternalDrag.y;
1310 pptHotspot->x = InternalDrag.dxHotspot;
1311 pptHotspot->y = InternalDrag.dyHotspot;
1313 return (InternalDrag.himl);
1320 /*************************************************************************
1321 * ImageList_GetFlags [COMCTL32.@]
1328 ImageList_GetFlags(HIMAGELIST himl)
1330 FIXME("(%p):empty stub\n", himl);
1335 /*************************************************************************
1336 * ImageList_GetIcon [COMCTL32.@]
1338 * Creates an icon from a masked image of an image list.
1341 * himl [I] handle to image list
1343 * flags [I] drawing style flags
1346 * Success: icon handle
1351 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1355 HBITMAP hOldDstBitmap;
1358 TRACE("%p %d %d\n", himl, i, fStyle);
1359 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1361 hdcDst = CreateCompatibleDC(0);
1368 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1369 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1370 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1371 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1374 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1375 SelectObject (hdcDst, ii.hbmColor);
1376 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1377 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1380 * CreateIconIndirect requires us to deselect the bitmaps from
1381 * the DCs before calling
1383 SelectObject(hdcDst, hOldDstBitmap);
1385 hIcon = CreateIconIndirect (&ii);
1387 DeleteObject (ii.hbmMask);
1388 DeleteObject (ii.hbmColor);
1395 /*************************************************************************
1396 * ImageList_GetIconSize [COMCTL32.@]
1398 * Retrieves the size of an image in an image list.
1401 * himl [I] handle to image list
1402 * cx [O] pointer to the image width.
1403 * cy [O] pointer to the image height.
1410 * All images in an image list have the same size.
1414 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1416 if (!is_valid(himl))
1418 if ((himl->cx <= 0) || (himl->cy <= 0))
1430 /*************************************************************************
1431 * ImageList_GetImageCount [COMCTL32.@]
1433 * Returns the number of images in an image list.
1436 * himl [I] handle to image list
1439 * Success: Number of images.
1444 ImageList_GetImageCount (HIMAGELIST himl)
1446 if (!is_valid(himl))
1449 return himl->cCurImage;
1453 /*************************************************************************
1454 * ImageList_GetImageInfo [COMCTL32.@]
1456 * Returns information about an image in an image list.
1459 * himl [I] handle to image list
1461 * pImageInfo [O] pointer to the image information
1469 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1471 if (!is_valid(himl) || (pImageInfo == NULL))
1473 if ((i < 0) || (i >= himl->cCurImage))
1476 pImageInfo->hbmImage = himl->hbmImage;
1477 pImageInfo->hbmMask = himl->hbmMask;
1479 pImageInfo->rcImage.top = 0;
1480 pImageInfo->rcImage.bottom = himl->cy;
1481 pImageInfo->rcImage.left = i * himl->cx;
1482 pImageInfo->rcImage.right = (i+1) * himl->cx;
1488 /*************************************************************************
1489 * ImageList_GetImageRect [COMCTL32.@]
1491 * Retrieves the rectangle of the specified image in an image list.
1494 * himl [I] handle to image list
1496 * lpRect [O] pointer to the image rectangle
1503 * This is an UNDOCUMENTED function!!!
1507 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1509 if (!is_valid(himl) || (lpRect == NULL))
1511 if ((i < 0) || (i >= himl->cCurImage))
1514 lpRect->left = i * himl->cx;
1516 lpRect->right = lpRect->left + himl->cx;
1517 lpRect->bottom = himl->cy;
1523 /*************************************************************************
1524 * ImageList_LoadImage [COMCTL32.@]
1525 * ImageList_LoadImageA [COMCTL32.@]
1527 * Creates an image list from a bitmap, icon or cursor.
1530 * hi [I] instance handle
1531 * lpbmp [I] name or id of the image
1532 * cx [I] width of each image
1533 * cGrow [I] number of images to expand
1534 * clrMask [I] mask color
1535 * uType [I] type of image to load
1536 * uFlags [I] loading flags
1539 * Success: handle to the loaded image list
1547 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1548 COLORREF clrMask, UINT uType, UINT uFlags)
1550 HIMAGELIST himl = NULL;
1554 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1556 ERR("Error loading image!\n");
1560 if (uType == IMAGE_BITMAP) {
1562 GetObjectA (handle, sizeof(BITMAP), &bmp);
1564 /* To match windows behavior, if cx is set to zero and
1565 the flag DI_DEFAULTSIZE is specified, cx becomes the
1566 system metric value for icons. If the flag is not specified
1567 the function sets the size to the height of the bitmap */
1570 if (uFlags & DI_DEFAULTSIZE)
1571 cx = GetSystemMetrics (SM_CXICON);
1576 nImageCount = bmp.bmWidth / cx;
1578 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1579 nImageCount, cGrow);
1581 DeleteObject (handle);
1584 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1586 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1590 GetIconInfo (handle, &ii);
1591 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1592 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1593 ILC_MASK | ILC_COLOR, 1, cGrow);
1595 DeleteObject (ii.hbmColor);
1596 DeleteObject (ii.hbmMask);
1597 DeleteObject (handle);
1600 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1601 DeleteObject (ii.hbmColor);
1602 DeleteObject (ii.hbmMask);
1605 DeleteObject (handle);
1611 /*************************************************************************
1612 * ImageList_LoadImageW [COMCTL32.@]
1614 * Creates an image list from a bitmap, icon or cursor.
1617 * hi [I] instance handle
1618 * lpbmp [I] name or id of the image
1619 * cx [I] width of each image
1620 * cGrow [I] number of images to expand
1621 * clrMask [I] mask color
1622 * uType [I] type of image to load
1623 * uFlags [I] loading flags
1626 * Success: handle to the loaded image list
1634 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1635 COLORREF clrMask, UINT uType, UINT uFlags)
1637 HIMAGELIST himl = NULL;
1641 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1643 ERR("Error loading image!\n");
1647 if (uType == IMAGE_BITMAP) {
1649 GetObjectA (handle, sizeof(BITMAP), &bmp);
1651 /* To match windows behavior, if cx is set to zero and
1652 the flag DI_DEFAULTSIZE is specified, cx becomes the
1653 system metric value for icons. If the flag is not specified
1654 the function sets the size to the height of the bitmap */
1657 if (uFlags & DI_DEFAULTSIZE)
1658 cx = GetSystemMetrics (SM_CXICON);
1663 nImageCount = bmp.bmWidth / cx;
1665 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1666 nImageCount, cGrow);
1668 DeleteObject (handle);
1671 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1673 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1677 GetIconInfo (handle, &ii);
1678 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1679 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1680 ILC_MASK | ILC_COLOR, 1, cGrow);
1682 DeleteObject (ii.hbmColor);
1683 DeleteObject (ii.hbmMask);
1684 DeleteObject (handle);
1687 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1688 DeleteObject (ii.hbmColor);
1689 DeleteObject (ii.hbmMask);
1692 DeleteObject (handle);
1698 /*************************************************************************
1699 * ImageList_Merge [COMCTL32.@]
1701 * Creates a new image list that contains a merged image from the specified
1702 * images of both source image lists.
1705 * himl1 [I] handle to first image list
1706 * i1 [I] first image index
1707 * himl2 [I] handle to second image list
1708 * i2 [I] second image index
1709 * dx [I] X offset of the second image relative to the first.
1710 * dy [I] Y offset of the second image relative to the first.
1713 * Success: handle of the merged image list.
1718 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1721 HIMAGELIST himlDst = NULL;
1723 INT xOff1, yOff1, xOff2, yOff2;
1726 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1729 if (!is_valid(himl1) || !is_valid(himl2))
1733 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1734 ERR("Index 1 out of range! %d\n", i1);
1738 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1739 ERR("Index 2 out of range! %d\n", i2);
1744 cxDst = max (himl1->cx, dx + himl2->cx);
1749 cxDst = max (himl2->cx, himl1->cx - dx);
1754 cxDst = max (himl1->cx, himl2->cx);
1760 cyDst = max (himl1->cy, dy + himl2->cy);
1765 cyDst = max (himl2->cy, himl1->cy - dy);
1770 cyDst = max (himl1->cy, himl2->cy);
1775 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1780 nX1 = i1 * himl1->cx;
1781 nX2 = i2 * himl2->cx;
1784 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1785 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1786 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1787 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1790 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1791 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1792 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1794 himlDst->cCurImage = 1;
1801 /* helper for _read_bitmap currently unused */
1803 static int may_use_dibsection(HDC hdc) {
1804 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1809 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1813 /* helper for ImageList_Read, see comments below */
1814 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1815 HDC xdc = 0, hBitmapDC =0;
1816 BITMAPFILEHEADER bmfh;
1817 BITMAPINFOHEADER bmih;
1818 int bitsperpixel,palspace,longsperline,width,height;
1819 LPBITMAPINFOHEADER bmihc = NULL;
1821 HBITMAP hbitmap = 0, hDIB = 0;
1824 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1825 (bmfh.bfType != (('M'<<8)|'B')) ||
1826 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1827 (bmih.biSize != sizeof(bmih))
1831 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1832 if (bitsperpixel<=8)
1833 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1836 width = bmih.biWidth;
1837 height = bmih.biHeight;
1838 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1839 memcpy(bmihc,&bmih,sizeof(bmih));
1840 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1841 bmihc->biSizeImage = (longsperline*height)<<2;
1843 /* read the palette right after the end of the bitmapinfoheader */
1845 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1849 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1850 if ((bitsperpixel>1) &&
1851 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1853 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1856 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1862 int i,nwidth,nheight,nRows;
1864 nwidth = width*(height/cy);
1866 nRows = (height/cy);
1868 if (bitsperpixel==1)
1869 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1871 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1873 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1876 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1879 hBitmapDC = CreateCompatibleDC(0);
1880 SelectObject(hBitmapDC, hbitmap);
1882 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1883 /* Do not forget that windows bitmaps are bottom->top */
1884 TRACE("nRows=%d\n", nRows);
1885 for (i=0; i < nRows; i++){
1886 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1887 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1893 if (xdc) ReleaseDC(0,xdc);
1894 if (bmihc) LocalFree((HLOCAL)bmihc);
1895 if (hDIB) DeleteObject(hDIB);
1896 if (hBitmapDC) DeleteDC(hBitmapDC);
1899 DeleteObject(hbitmap);
1906 /*************************************************************************
1907 * ImageList_Read [COMCTL32.@]
1909 * Reads an image list from a stream.
1912 * pstm [I] pointer to a stream
1915 * Success: handle to image list
1918 * The format is like this:
1919 * ILHEAD ilheadstruct;
1921 * for the color image part:
1922 * BITMAPFILEHEADER bmfh;
1923 * BITMAPINFOHEADER bmih;
1924 * only if it has a palette:
1925 * RGBQUAD rgbs[nr_of_paletted_colors];
1927 * BYTE colorbits[imagesize];
1929 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1930 * BITMAPFILEHEADER bmfh_mask;
1931 * BITMAPINFOHEADER bmih_mask;
1932 * only if it has a palette (it usually does not):
1933 * RGBQUAD rgbs[nr_of_paletted_colors];
1935 * BYTE maskbits[imagesize];
1937 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1938 * _read_bitmap needs to convert them.
1940 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1944 HBITMAP hbmColor=0,hbmMask=0;
1947 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1949 if (ilHead.usMagic != (('L' << 8) | 'I'))
1951 if (ilHead.usVersion != 0x101) /* probably version? */
1955 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1956 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1957 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1958 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1959 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1960 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1961 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1962 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1963 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1964 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1967 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1970 if (ilHead.flags & ILC_MASK) {
1971 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1973 DeleteObject(hbmColor);
1978 himl = ImageList_Create (
1986 DeleteObject(hbmColor);
1987 DeleteObject(hbmMask);
1990 SelectObject(himl->hdcImage, hbmColor);
1991 DeleteObject(himl->hbmImage);
1992 himl->hbmImage = hbmColor;
1994 SelectObject(himl->hdcMask, hbmMask);
1995 DeleteObject(himl->hbmMask);
1996 himl->hbmMask = hbmMask;
1998 himl->cCurImage = ilHead.cCurImage;
1999 himl->cMaxImage = ilHead.cMaxImage;
2001 ImageList_SetBkColor(himl,ilHead.bkcolor);
2003 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2008 /*************************************************************************
2009 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2012 * himl [I] image list handle
2021 ImageList_Remove (HIMAGELIST himl, INT i)
2023 HBITMAP hbmNewImage, hbmNewMask;
2027 TRACE("(himl=%p i=%d)\n", himl, i);
2029 if (!is_valid(himl)) {
2030 ERR("Invalid image list handle!\n");
2034 if ((i < -1) || (i >= himl->cCurImage)) {
2035 ERR("index out of range! %d\n", i);
2041 if (himl->cCurImage == 0) {
2042 /* remove all on empty ImageList is allowed */
2043 TRACE("remove all on empty ImageList!\n");
2047 himl->cMaxImage = himl->cInitial + himl->cGrow;
2048 himl->cCurImage = 0;
2049 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2050 himl->nOvlIdx[nCount] = -1;
2052 hbmNewImage = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2053 1, himl->uBitsPixel, NULL);
2054 SelectObject (himl->hdcImage, hbmNewImage);
2055 DeleteObject (himl->hbmImage);
2056 himl->hbmImage = hbmNewImage;
2058 if (himl->hbmMask) {
2059 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2061 SelectObject (himl->hdcMask, hbmNewMask);
2062 DeleteObject (himl->hbmMask);
2063 himl->hbmMask = hbmNewMask;
2067 /* delete one image */
2068 TRACE("Remove single image! %d\n", i);
2070 /* create new bitmap(s) */
2071 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2073 TRACE(" - Number of images: %d / %d (Old/New)\n",
2074 himl->cCurImage, himl->cCurImage - 1);
2075 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2076 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2079 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2082 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2084 hbmNewMask = 0; /* Just to keep compiler happy! */
2086 hdcBmp = CreateCompatibleDC (0);
2088 /* copy all images and masks prior to the "removed" image */
2090 TRACE("Pre image copy: Copy %d images\n", i);
2092 SelectObject (hdcBmp, hbmNewImage);
2093 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2094 himl->hdcImage, 0, 0, SRCCOPY);
2096 if (himl->hbmMask) {
2097 SelectObject (hdcBmp, hbmNewMask);
2098 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2099 himl->hdcMask, 0, 0, SRCCOPY);
2103 /* copy all images and masks behind the removed image */
2104 if (i < himl->cCurImage - 1) {
2105 TRACE("Post image copy!\n");
2106 SelectObject (hdcBmp, hbmNewImage);
2107 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2108 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2110 if (himl->hbmMask) {
2111 SelectObject (hdcBmp, hbmNewMask);
2112 BitBlt (hdcBmp, i * himl->cx, 0,
2113 (himl->cCurImage - i - 1) * himl->cx,
2114 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2120 /* delete old images and insert new ones */
2121 SelectObject (himl->hdcImage, hbmNewImage);
2122 DeleteObject (himl->hbmImage);
2123 himl->hbmImage = hbmNewImage;
2124 if (himl->hbmMask) {
2125 SelectObject (himl->hdcMask, hbmNewMask);
2126 DeleteObject (himl->hbmMask);
2127 himl->hbmMask = hbmNewMask;
2131 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2138 /*************************************************************************
2139 * ImageList_Replace [COMCTL32.@]
2141 * Replaces an image in an image list with a new image.
2144 * himl [I] handle to image list
2146 * hbmImage [I] handle to image bitmap
2147 * hbmMask [I] handle to mask bitmap. Can be NULL.
2155 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2161 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2163 if (!is_valid(himl)) {
2164 ERR("Invalid image list handle!\n");
2168 if ((i >= himl->cMaxImage) || (i < 0)) {
2169 ERR("Invalid image index!\n");
2173 hdcImage = CreateCompatibleDC (0);
2174 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2177 SelectObject (hdcImage, hbmImage);
2179 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2180 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2185 SelectObject (hdcImage, hbmMask);
2187 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2188 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2191 /* Remove the background from the image
2193 StretchBlt (himl->hdcImage,
2194 i*himl->cx, 0, himl->cx, himl->cy,
2196 0, 0, bmp.bmWidth, bmp.bmHeight,
2197 0x220326); /* NOTSRCAND */
2200 DeleteDC (hdcImage);
2206 /*************************************************************************
2207 * ImageList_ReplaceIcon [COMCTL32.@]
2209 * Replaces an image in an image list using an icon.
2212 * himl [I] handle to image list
2214 * hIcon [I] handle to icon
2217 * Success: index of the replaced image
2222 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2231 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2233 if (!is_valid(himl))
2235 if ((i >= himl->cMaxImage) || (i < -1))
2238 hBestFitIcon = CopyImage(
2241 LR_COPYFROMRESOURCE);
2243 GetIconInfo (hBestFitIcon, &ii);
2244 if (ii.hbmMask == 0)
2246 if (ii.hbmColor == 0)
2248 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2251 if (himl->cCurImage + 1 > himl->cMaxImage)
2252 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2254 nIndex = himl->cCurImage;
2260 hdcImage = CreateCompatibleDC (0);
2261 TRACE("hdcImage=%p\n", hdcImage);
2263 ERR("invalid hdcImage!\n");
2265 SetTextColor(himl->hdcImage, RGB(0,0,0));
2266 SetBkColor (himl->hdcImage, RGB(255,255,255));
2267 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2269 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2270 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2272 if (himl->hbmMask) {
2273 SelectObject (hdcImage, ii.hbmMask);
2274 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2275 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2278 SelectObject (hdcImage, hbmOldSrc);
2281 DestroyIcon(hBestFitIcon);
2283 DeleteDC (hdcImage);
2285 DeleteObject (ii.hbmColor);
2287 DeleteObject (ii.hbmMask);
2293 /*************************************************************************
2294 * ImageList_SetBkColor [COMCTL32.@]
2296 * Sets the background color of an image list.
2299 * himl [I] handle to image list
2300 * clrBk [I] background color
2303 * Success: previous background color
2308 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2312 if (!is_valid(himl))
2315 clrOldBk = himl->clrBk;
2316 himl->clrBk = clrBk;
2321 /*************************************************************************
2322 * ImageList_SetDragCursorImage [COMCTL32.@]
2324 * Combines the specified image with the current drag image
2327 * himlDrag [I] handle to drag image list
2328 * iDrag [I] drag image index
2329 * dxHotspot [I] X position of the hot spot
2330 * dyHotspot [I] Y position of the hot spot
2337 * When this function is called and the drag image is visible, a
2338 * short flickering occurs but this matches the Win9x behavior. It is
2339 * possible to fix the flickering using code like in ImageList_DragMove.
2343 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2344 INT dxHotspot, INT dyHotspot)
2346 HIMAGELIST himlTemp;
2350 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2353 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2354 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2356 visible = InternalDrag.bShow;
2358 /* Calculate the offset between the origin of the old image and the
2359 * origin of the second image.
2360 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2361 * hotspot) to the origin of the second image.
2362 * See M$DN for details */
2363 if(InternalDrag.bHSPending) {
2366 InternalDrag.bHSPending = FALSE;
2368 dx = InternalDrag.dxHotspot - dxHotspot;
2369 dy = InternalDrag.dyHotspot - dyHotspot;
2371 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2374 /* hide the drag image */
2375 ImageList_DragShowNolock(FALSE);
2377 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2378 (InternalDrag.himl->cy != himlTemp->cy)) {
2379 /* the size of the drag image changed, invalidate the buffer */
2380 DeleteObject(InternalDrag.hbmBg);
2381 InternalDrag.hbmBg = 0;
2384 ImageList_Destroy (InternalDrag.himl);
2385 InternalDrag.himl = himlTemp;
2387 /* update the InternalDragOffset, if the origin of the
2388 * DragImage was changed by ImageList_Merge. */
2390 InternalDrag.dxHotspot = dxHotspot;
2392 InternalDrag.dyHotspot = dyHotspot;
2395 /* show the drag image */
2396 ImageList_DragShowNolock(TRUE);
2403 /*************************************************************************
2404 * ImageList_SetFilter [COMCTL32.@]
2406 * Sets a filter (or does something completely different)!!???
2407 * It removes 12 Bytes from the stack (3 Parameters).
2410 * himl [I] SHOULD be a handle to image list
2411 * i [I] COULD be an index?
2416 * Failure: FALSE ???
2419 * This is an UNDOCUMENTED function!!!!
2424 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2426 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2432 /*************************************************************************
2433 * ImageList_SetFlags [COMCTL32.@]
2440 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2442 FIXME("(%p %08lx):empty stub\n", himl, flags);
2447 /*************************************************************************
2448 * ImageList_SetIconSize [COMCTL32.@]
2450 * Sets the image size of the bitmap and deletes all images.
2453 * himl [I] handle to image list
2454 * cx [I] image width
2455 * cy [I] image height
2463 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2468 if (!is_valid(himl))
2471 /* remove all images */
2472 himl->cMaxImage = himl->cInitial + himl->cGrow;
2473 himl->cCurImage = 0;
2477 /* initialize overlay mask indices */
2478 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2479 himl->nOvlIdx[nCount] = -1;
2481 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2482 1, himl->uBitsPixel, NULL);
2483 SelectObject (himl->hdcImage, hbmNew);
2484 DeleteObject (himl->hbmImage);
2485 himl->hbmImage = hbmNew;
2487 if (himl->hbmMask) {
2488 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2490 SelectObject (himl->hdcMask, hbmNew);
2491 DeleteObject (himl->hbmMask);
2492 himl->hbmMask = hbmNew;
2499 /*************************************************************************
2500 * ImageList_SetImageCount [COMCTL32.@]
2502 * Resizes an image list to the specified number of images.
2505 * himl [I] handle to image list
2506 * iImageCount [I] number of images in the image list
2514 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2517 HBITMAP hbmNewBitmap;
2518 INT nNewCount, nCopyCount;
2520 TRACE("%p %d\n",himl,iImageCount);
2522 if (!is_valid(himl))
2524 if (himl->cCurImage >= iImageCount)
2526 if (himl->cMaxImage > iImageCount)
2528 himl->cCurImage = iImageCount;
2532 nNewCount = iImageCount + himl->cGrow;
2533 nCopyCount = min(himl->cCurImage, iImageCount);
2535 hdcBitmap = CreateCompatibleDC (0);
2537 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2538 1, himl->uBitsPixel, NULL);
2539 if (hbmNewBitmap != 0)
2541 SelectObject (hdcBitmap, hbmNewBitmap);
2544 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2545 himl->hdcImage, 0, 0, SRCCOPY);
2547 /* delete 'empty' image space */
2548 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2549 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2550 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2551 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2553 SelectObject (himl->hdcImage, hbmNewBitmap);
2554 DeleteObject (himl->hbmImage);
2555 himl->hbmImage = hbmNewBitmap;
2558 ERR("Could not create new image bitmap !\n");
2562 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2564 if (hbmNewBitmap != 0)
2566 SelectObject (hdcBitmap, hbmNewBitmap);
2569 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2570 himl->hdcMask, 0, 0, SRCCOPY);
2572 /* delete 'empty' image space */
2573 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2574 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2575 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2576 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2578 SelectObject (himl->hdcMask, hbmNewBitmap);
2579 DeleteObject (himl->hbmMask);
2580 himl->hbmMask = hbmNewBitmap;
2583 ERR("Could not create new mask bitmap!\n");
2586 DeleteDC (hdcBitmap);
2588 /* Update max image count and current image count */
2589 himl->cMaxImage = nNewCount;
2590 himl->cCurImage = iImageCount;
2596 /*************************************************************************
2597 * ImageList_SetOverlayImage [COMCTL32.@]
2599 * Assigns an overlay mask index to an existing image in an image list.
2602 * himl [I] handle to image list
2603 * iImage [I] image index
2604 * iOverlay [I] overlay mask index
2612 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2614 if (!is_valid(himl))
2616 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2618 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2620 himl->nOvlIdx[iOverlay - 1] = iImage;
2626 /* helper for ImageList_Write - write bitmap to pstm
2627 * currently everything is written as 24 bit RGB, except masks
2630 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2632 LPBITMAPFILEHEADER bmfh;
2633 LPBITMAPINFOHEADER bmih;
2634 LPBYTE data, lpBits, lpBitsOrg;
2636 INT bitCount, sizeImage, offBits, totalSize;
2637 INT nwidth, nheight, nsizeImage, icount;
2639 BOOL result = FALSE;
2643 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2645 /* XXX is this always correct? */
2646 icount = bm.bmWidth / cx;
2648 nheight = cy * ((icount+3)>>2);
2650 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2651 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2652 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2654 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2656 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2657 offBits = totalSize;
2658 totalSize += nsizeImage;
2660 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2661 bmfh = (LPBITMAPFILEHEADER)data;
2662 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2663 lpBits = data + offBits;
2665 /* setup BITMAPFILEHEADER */
2666 bmfh->bfType = (('M' << 8) | 'B');
2668 bmfh->bfReserved1 = 0;
2669 bmfh->bfReserved2 = 0;
2670 bmfh->bfOffBits = offBits;
2672 /* setup BITMAPINFOHEADER */
2673 bmih->biSize = sizeof(BITMAPINFOHEADER);
2674 bmih->biWidth = bm.bmWidth;
2675 bmih->biHeight = bm.bmHeight;
2677 bmih->biBitCount = bitCount;
2678 bmih->biCompression = BI_RGB;
2679 bmih->biSizeImage = nsizeImage;
2680 bmih->biXPelsPerMeter = 0;
2681 bmih->biYPelsPerMeter = 0;
2682 bmih->biClrUsed = 0;
2683 bmih->biClrImportant = 0;
2685 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2686 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2687 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2691 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2692 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2694 for(i = 0; i < nheight; i++) {
2695 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2696 int noff = (nbpl * (nheight-1-i));
2697 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2701 bmih->biWidth = nwidth;
2702 bmih->biHeight = nheight;
2706 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2707 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2708 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2711 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2718 LocalFree((HLOCAL)lpBitsOrg);
2724 /*************************************************************************
2725 * ImageList_Write [COMCTL32.@]
2727 * Writes an image list to a stream.
2730 * himl [I] handle to image list
2731 * pstm [O] Pointer to a stream.
2742 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2747 if (!is_valid(himl))
2750 ilHead.usMagic = (('L' << 8) | 'I');
2751 ilHead.usVersion = 0x101;
2752 ilHead.cCurImage = himl->cCurImage;
2753 ilHead.cMaxImage = himl->cMaxImage;
2754 ilHead.cGrow = himl->cGrow;
2755 ilHead.cx = himl->cx;
2756 ilHead.cy = himl->cy;
2757 ilHead.bkcolor = himl->clrBk;
2758 ilHead.flags = himl->flags;
2759 for(i = 0; i < 4; i++) {
2760 ilHead.ovls[i] = himl->nOvlIdx[i];
2763 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2766 /* write the bitmap */
2767 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2770 /* write the mask if we have one */
2771 if(himl->flags & ILC_MASK) {
2772 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))