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...
55 #include "imagelist.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
61 #define MAX_OVERLAYIMAGE 15
63 /* internal image list data used for Drag & Drop operations */
68 /* position of the drag image relative to the window */
71 /* offset of the hotspot relative to the origin of the image */
74 /* is the drag image visible */
76 /* saved background */
81 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
84 static inline BOOL is_valid(HIMAGELIST himl)
86 return himl && himl->magic == IMAGELIST_MAGIC;
90 /*************************************************************************
91 * IMAGELIST_InternalExpandBitmaps [Internal]
93 * Expands the bitmaps of an image list by the given number of images.
96 * himl [I] handle to image list
97 * nImageCount [I] number of images to add
103 * This function can NOT be used to reduce the number of images.
106 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
109 HBITMAP hbmNewBitmap, hbmNull;
110 INT nNewWidth, nNewCount;
112 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
116 if (cy == 0) cy = himl->cy;
117 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
118 nNewWidth = nNewCount * himl->cx;
120 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
121 hdcBitmap = CreateCompatibleDC (0);
124 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
125 if (hbmNewBitmap == 0)
126 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
128 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
129 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
130 himl->hdcImage, 0, 0, SRCCOPY);
132 SelectObject (hdcBitmap, hbmNull);
133 SelectObject (himl->hdcImage, hbmNewBitmap);
134 DeleteObject (himl->hbmImage);
135 himl->hbmImage = hbmNewBitmap;
139 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
141 if (hbmNewBitmap == 0)
142 ERR("creating new mask bitmap!\n");
144 SelectObject (hdcBitmap, hbmNewBitmap);
145 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
146 himl->hdcMask, 0, 0, SRCCOPY);
147 SelectObject (hdcBitmap, hbmNull);
148 SelectObject (himl->hdcMask, hbmNewBitmap);
149 DeleteObject (himl->hbmMask);
150 himl->hbmMask = hbmNewBitmap;
153 himl->cMaxImage = nNewCount;
155 DeleteDC (hdcBitmap);
159 /*************************************************************************
160 * ImageList_Add [COMCTL32.@]
162 * Add an image or images to an image list.
165 * himl [I] handle to image list
166 * hbmImage [I] handle to image bitmap
167 * hbmMask [I] handle to mask bitmap
170 * Success: Index of the first new image.
175 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
178 INT nFirstIndex, nImageCount;
183 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
187 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
188 nImageCount = bmp.bmWidth / himl->cx;
190 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
192 nStartX = himl->cCurImage * himl->cx;
194 hdcBitmap = CreateCompatibleDC(0);
196 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
198 /* Copy result to the imagelist
200 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
201 hdcBitmap, 0, 0, SRCCOPY);
206 HBITMAP hOldBitmapTemp;
208 hdcTemp = CreateCompatibleDC(0);
209 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
211 BitBlt (himl->hdcMask,
212 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
217 SelectObject(hdcTemp, hOldBitmapTemp);
220 /* Remove the background from the image
222 BitBlt (himl->hdcImage,
223 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
226 0x220326); /* NOTSRCAND */
229 SelectObject(hdcBitmap, hOldBitmap);
232 nFirstIndex = himl->cCurImage;
233 himl->cCurImage += nImageCount;
239 /*************************************************************************
240 * ImageList_AddIcon [COMCTL32.@]
242 * Adds an icon to an image list.
245 * himl [I] handle to image list
246 * hIcon [I] handle to icon
249 * Success: index of the new image
252 #undef ImageList_AddIcon
253 INT WINAPI 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 hdcMask, hdcBitmap;
279 INT nIndex, nImageCount, nMaskXOffset=0;
282 HBITMAP hMaskBitmap=0;
285 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
289 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
293 nImageCount = bmp.bmWidth / himl->cx;
297 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
299 nIndex = himl->cCurImage;
300 himl->cCurImage += nImageCount;
302 hdcBitmap = CreateCompatibleDC(0);
305 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
308 hdcMask = himl->hdcMask;
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 hdcMask = CreateCompatibleDC(0);
318 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
319 SelectObject(hdcMask, hMaskBitmap);
322 /* create monochrome image to the mask bitmap */
323 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
324 GetPixel (hdcBitmap, 0, 0);
325 SetBkColor (hdcBitmap, bkColor);
327 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
331 SetBkColor(hdcBitmap, RGB(255,255,255));
332 /*Remove the background from the image
335 WINDOWS BUG ALERT!!!!!!
336 The statement below should not be done in common practice
337 but this is how ImageList_AddMasked works in Windows.
338 It overwrites the original bitmap passed, this was discovered
339 by using the same bitmap to iterate the different styles
340 on windows where it failed (BUT ImageList_Add is OK)
341 This is here in case some apps rely on this bug
344 0, 0, bmp.bmWidth, bmp.bmHeight,
347 0x220326); /* NOTSRCAND */
348 /* Copy result to the imagelist
350 BitBlt (himl->hdcImage,
351 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
357 SelectObject(hdcBitmap, hOldBitmap);
361 DeleteObject(hMaskBitmap);
369 /*************************************************************************
370 * ImageList_BeginDrag [COMCTL32.@]
372 * Creates a temporary image list that contains one image. It will be used
376 * himlTrack [I] handle to the source image list
377 * iTrack [I] index of the drag image in the source image list
378 * dxHotspot [I] X position of the hot spot of the drag image
379 * dyHotspot [I] Y position of the hot spot of the drag image
387 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
388 INT dxHotspot, INT dyHotspot)
392 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
393 dxHotspot, dyHotspot);
395 if (!is_valid(himlTrack))
398 if (InternalDrag.himl)
399 ImageList_EndDrag ();
404 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
405 if (InternalDrag.himl == NULL) {
406 WARN("Error creating drag image list!\n");
410 InternalDrag.dxHotspot = dxHotspot;
411 InternalDrag.dyHotspot = dyHotspot;
414 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
417 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
419 InternalDrag.himl->cCurImage = 1;
420 InternalDrag.bHSPending = TRUE;
426 /*************************************************************************
427 * ImageList_Copy [COMCTL32.@]
429 * Copies an image of the source image list to an image of the
430 * destination image list. Images can be copied or swapped.
433 * himlDst [I] handle to the destination image list
434 * iDst [I] destination image index.
435 * himlSrc [I] handle to the source image list
436 * iSrc [I] source image index
437 * uFlags [I] flags for the copy operation
444 * Copying from one image list to another is possible. The original
445 * implementation just copies or swaps within one image list.
446 * Could this feature become a bug??? ;-)
450 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
451 INT iSrc, UINT uFlags)
453 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
455 if (!is_valid(himlSrc) || !is_valid(himlDst))
457 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
459 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
462 if (uFlags & ILCF_SWAP) {
465 HBITMAP hbmTempImage, hbmTempMask;
467 hdcBmp = CreateCompatibleDC (0);
469 /* create temporary bitmaps */
470 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
471 himlSrc->uBitsPixel, NULL);
472 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
475 /* copy (and stretch) destination to temporary bitmaps.(save) */
477 SelectObject (hdcBmp, hbmTempImage);
478 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
479 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
482 SelectObject (hdcBmp, hbmTempMask);
483 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
484 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
487 /* copy (and stretch) source to destination */
489 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
490 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
493 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
494 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
497 /* copy (without stretching) temporary bitmaps to source (restore) */
499 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
500 hdcBmp, 0, 0, SRCCOPY);
503 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
504 hdcBmp, 0, 0, SRCCOPY);
505 /* delete temporary bitmaps */
506 DeleteObject (hbmTempMask);
507 DeleteObject (hbmTempImage);
512 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
513 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
517 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
518 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
526 /*************************************************************************
527 * ImageList_Create [COMCTL32.@] Creates a new image list.
530 * cx [I] image height
532 * flags [I] creation flags
533 * cInitial [I] initial number of images in the image list
534 * cGrow [I] number of images by which image list grows
537 * Success: Handle to the created image list
542 ImageList_Create (INT cx, INT cy, UINT flags,
543 INT cInitial, INT cGrow)
548 static WORD aBitBlend25[] =
549 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
551 static WORD aBitBlend50[] =
552 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
554 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
556 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
560 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
562 himl->magic = IMAGELIST_MAGIC;
566 himl->cMaxImage = cInitial + cGrow;
567 himl->cInitial = cInitial;
569 himl->clrFg = CLR_DEFAULT;
570 himl->clrBk = CLR_NONE;
572 /* initialize overlay mask indices */
573 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
574 himl->nOvlIdx[nCount] = -1;
576 /* Create Image & Mask DCs */
577 himl->hdcImage = CreateCompatibleDC (0);
580 if (himl->flags & ILC_MASK){
581 himl->hdcMask = CreateCompatibleDC(0);
586 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
588 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
590 if (himl->cMaxImage > 0) {
592 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
593 1, himl->uBitsPixel, NULL);
594 if (himl->hbmImage == 0) {
595 ERR("Error creating image bitmap!\n");
598 SelectObject(himl->hdcImage, himl->hbmImage);
601 if (himl->flags & ILC_MASK) {
603 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
605 if (himl->hbmMask == 0) {
606 ERR("Error creating mask bitmap!\n");
609 SelectObject(himl->hdcMask, himl->hbmMask);
612 /* create blending brushes */
613 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
614 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
615 DeleteObject (hbmTemp);
617 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
618 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
619 DeleteObject (hbmTemp);
621 TRACE("created imagelist %p\n", himl);
625 if (himl) ImageList_Destroy(himl);
630 /*************************************************************************
631 * ImageList_Destroy [COMCTL32.@]
633 * Destroys an image list.
636 * himl [I] handle to image list
644 ImageList_Destroy (HIMAGELIST himl)
649 /* delete image bitmaps */
651 DeleteObject (himl->hbmImage);
653 DeleteObject (himl->hbmMask);
655 /* delete image & mask DCs */
657 DeleteDC(himl->hdcImage);
659 DeleteDC(himl->hdcMask);
661 /* delete blending brushes */
662 if (himl->hbrBlend25)
663 DeleteObject (himl->hbrBlend25);
664 if (himl->hbrBlend50)
665 DeleteObject (himl->hbrBlend50);
667 ZeroMemory(himl, sizeof(*himl));
674 /*************************************************************************
675 * ImageList_DragEnter [COMCTL32.@]
677 * Locks window update and displays the drag image at the given position.
680 * hwndLock [I] handle of the window that owns the drag image.
681 * x [I] X position of the drag image.
682 * y [I] Y position of the drag image.
689 * The position of the drag image is relative to the window, not
694 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
696 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
698 if (!is_valid(InternalDrag.himl))
702 InternalDrag.hwnd = hwndLock;
704 InternalDrag.hwnd = GetDesktopWindow ();
709 /* draw the drag image and save the background */
710 if (!ImageList_DragShowNolock(TRUE)) {
718 /*************************************************************************
719 * ImageList_DragLeave [COMCTL32.@]
721 * Unlocks window update and hides the drag image.
724 * hwndLock [I] handle of the window that owns the drag image.
732 ImageList_DragLeave (HWND hwndLock)
734 /* As we don't save drag info in the window this can lead to problems if
735 an app does not supply the same window as DragEnter */
737 InternalDrag.hwnd = hwndLock;
739 InternalDrag.hwnd = GetDesktopWindow (); */
741 hwndLock = GetDesktopWindow();
742 if(InternalDrag.hwnd != hwndLock)
743 FIXME("DragLeave hWnd != DragEnter hWnd\n");
745 ImageList_DragShowNolock (FALSE);
751 /*************************************************************************
752 * ImageList_InternalDragDraw [Internal]
754 * Draws the drag image.
757 * hdc [I] device context to draw into.
758 * x [I] X position of the drag image.
759 * y [I] Y position of the drag image.
766 * The position of the drag image is relative to the window, not
772 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
774 IMAGELISTDRAWPARAMS imldp;
776 ZeroMemory (&imldp, sizeof(imldp));
777 imldp.cbSize = sizeof(imldp);
778 imldp.himl = InternalDrag.himl;
783 imldp.rgbBk = CLR_DEFAULT;
784 imldp.rgbFg = CLR_DEFAULT;
785 imldp.fStyle = ILD_NORMAL;
786 imldp.fState = ILS_ALPHA;
789 /* FIXME: instead of using the alpha blending, we should
790 * create a 50% mask, and draw it semitransparantly that way */
791 ImageList_DrawIndirect (&imldp);
794 /*************************************************************************
795 * ImageList_DragMove [COMCTL32.@]
797 * Moves the drag image.
800 * x [I] X position of the drag image.
801 * y [I] Y position of the drag image.
808 * The position of the drag image is relative to the window, not
812 * The drag image should be drawn semitransparent.
816 ImageList_DragMove (INT x, INT y)
818 TRACE("(x=%d y=%d)\n", x, y);
820 if (!is_valid(InternalDrag.himl))
823 /* draw/update the drag image */
824 if (InternalDrag.bShow) {
828 HBITMAP hbmOffScreen;
829 INT origNewX, origNewY;
830 INT origOldX, origOldY;
831 INT origRegX, origRegY;
832 INT sizeRegX, sizeRegY;
835 /* calculate the update region */
836 origNewX = x - InternalDrag.dxHotspot;
837 origNewY = y - InternalDrag.dyHotspot;
838 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
839 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
840 origRegX = min(origNewX, origOldX);
841 origRegY = min(origNewY, origOldY);
842 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
843 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
845 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
846 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
847 hdcOffScreen = CreateCompatibleDC(hdcDrag);
848 hdcBg = CreateCompatibleDC(hdcDrag);
850 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
851 SelectObject(hdcOffScreen, hbmOffScreen);
852 SelectObject(hdcBg, InternalDrag.hbmBg);
854 /* get the actual background of the update region */
855 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
856 origRegX, origRegY, SRCCOPY);
857 /* erase the old image */
858 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
859 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
861 /* save the background */
862 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
863 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
865 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
866 origNewY - origRegY);
867 /* draw the update region to the screen */
868 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
869 hdcOffScreen, 0, 0, SRCCOPY);
872 DeleteDC(hdcOffScreen);
873 DeleteObject(hbmOffScreen);
874 ReleaseDC(InternalDrag.hwnd, hdcDrag);
877 /* update the image position */
885 /*************************************************************************
886 * ImageList_DragShowNolock [COMCTL32.@]
888 * Shows or hides the drag image.
891 * bShow [I] TRUE shows the drag image, FALSE hides it.
898 * The drag image should be drawn semitransparent.
902 ImageList_DragShowNolock (BOOL bShow)
908 if (!is_valid(InternalDrag.himl))
911 TRACE("bShow=0x%X!\n", bShow);
913 /* DragImage is already visible/hidden */
914 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
918 /* position of the origin of the DragImage */
919 x = InternalDrag.x - InternalDrag.dxHotspot;
920 y = InternalDrag.y - InternalDrag.dyHotspot;
922 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
923 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
928 hdcBg = CreateCompatibleDC(hdcDrag);
929 if (!InternalDrag.hbmBg) {
930 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
931 InternalDrag.himl->cx, InternalDrag.himl->cy);
933 SelectObject(hdcBg, InternalDrag.hbmBg);
936 /* save the background */
937 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
938 hdcDrag, x, y, SRCCOPY);
940 ImageList_InternalDragDraw(hdcDrag, x, y);
943 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
944 hdcBg, 0, 0, SRCCOPY);
947 InternalDrag.bShow = !InternalDrag.bShow;
950 ReleaseDC (InternalDrag.hwnd, hdcDrag);
955 /*************************************************************************
956 * ImageList_Draw [COMCTL32.@] Draws an image.
959 * himl [I] handle to image list
961 * hdc [I] handle to device context
964 * fStyle [I] drawing flags
975 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
977 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
978 CLR_DEFAULT, CLR_DEFAULT, fStyle);
982 /*************************************************************************
983 * ImageList_DrawEx [COMCTL32.@]
985 * Draws an image and allows to use extended drawing features.
988 * himl [I] handle to image list
990 * hdc [I] handle to device context
995 * rgbBk [I] background color
996 * rgbFg [I] foreground color
997 * fStyle [I] drawing flags
1004 * Calls ImageList_DrawIndirect.
1007 * ImageList_DrawIndirect.
1011 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1012 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1015 IMAGELISTDRAWPARAMS imldp;
1017 ZeroMemory (&imldp, sizeof(imldp));
1018 imldp.cbSize = sizeof(imldp);
1026 imldp.rgbBk = rgbBk;
1027 imldp.rgbFg = rgbFg;
1028 imldp.fStyle = fStyle;
1030 return ImageList_DrawIndirect (&imldp);
1034 /*************************************************************************
1035 * ImageList_DrawIndirect [COMCTL32.@]
1037 * Draws an image using ...
1040 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1048 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1050 INT cx, cy, lx, ly, nOvlIdx;
1051 DWORD fState, dwRop;
1053 COLORREF clrBk, oldImageBk, oldImageFg;
1054 HDC hImageDC, hImageListDC, hMaskListDC;
1055 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1056 BOOL bIsTransparent, bBlend, bResult = FALSE;
1059 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1060 if (!is_valid(himl)) return FALSE;
1061 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1063 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1064 ly = pimldp->yBitmap;
1066 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1067 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1068 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1069 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1070 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1071 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1072 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1074 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1075 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1077 /* we will use these DCs to access the images and masks in the ImageList */
1078 hImageListDC = himl->hdcImage;
1079 hMaskListDC = himl->hdcMask;
1081 /* these will accumulate the image and mask for the image we're drawing */
1082 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1083 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1084 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1086 /* Create a compatible DC. */
1087 if (!hImageListDC || !hImageDC || !hImageBmp ||
1088 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1091 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1094 * To obtain a transparent look, background color should be set
1095 * to white and foreground color to black when blting the
1098 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1099 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1102 * Draw the initial image
1104 if(fStyle & ILD_MASK) {
1105 if (himl->hbmMask) {
1106 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1108 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1109 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1110 SelectObject(hImageDC, hOldBrush);
1112 } else if (himl->hbmMask && !bIsTransparent) {
1113 /* blend the image with the needed solid background */
1114 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1115 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1116 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1117 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1118 DeleteObject (SelectObject (hImageDC, hOldBrush));
1120 /* start off with the image, if we have a mask, we'll use it later */
1121 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1124 /* Time for blending, if required */
1126 HBRUSH hBlendBrush, hOldBrush;
1127 COLORREF clrBlend = pimldp->rgbFg;
1128 HDC hBlendMaskDC = hImageListDC;
1131 /* Create the blend Mask */
1132 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1133 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1134 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1135 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1136 SelectObject(hBlendMaskDC, hOldBrush);
1138 /* Modify the blend mask if an Image Mask exist */
1140 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1141 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1144 /* now apply blend to the current image given the BlendMask */
1145 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1146 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1147 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1148 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1149 DeleteObject(SelectObject(hImageDC, hOldBrush));
1150 SelectObject(hBlendMaskDC, hOldBitmap);
1153 /* Now do the overlay image, if any */
1154 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1155 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1156 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1157 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1158 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1159 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1160 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1161 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1165 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1166 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1167 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1168 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1170 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1171 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1172 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1174 /* now copy the image to the screen */
1176 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1177 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1178 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1179 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1180 SetBkColor(pimldp->hdcDst, oldDstBk);
1181 SetTextColor(pimldp->hdcDst, oldDstFg);
1184 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1185 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1189 /* cleanup the mess */
1190 SetBkColor(hImageDC, oldImageBk);
1191 SetTextColor(hImageDC, oldImageFg);
1192 SelectObject(hImageDC, hOldImageBmp);
1194 DeleteObject(hBlendMaskBmp);
1195 DeleteObject(hImageBmp);
1202 /*************************************************************************
1203 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1206 * himlSrc [I] source image list handle
1209 * Success: Handle of duplicated image list.
1214 ImageList_Duplicate (HIMAGELIST himlSrc)
1218 if (!is_valid(himlSrc)) {
1219 ERR("Invalid image list handle!\n");
1223 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1224 himlSrc->cInitial, himlSrc->cGrow);
1228 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1229 himlSrc->hdcImage, 0, 0, SRCCOPY);
1231 if (himlDst->hbmMask)
1232 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1233 himlSrc->hdcMask, 0, 0, SRCCOPY);
1235 himlDst->cCurImage = himlSrc->cCurImage;
1236 himlDst->cMaxImage = himlSrc->cMaxImage;
1242 /*************************************************************************
1243 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1245 * Finishes a drag operation.
1256 ImageList_EndDrag (void)
1258 /* cleanup the InternalDrag struct */
1259 InternalDrag.hwnd = 0;
1260 ImageList_Destroy (InternalDrag.himl);
1261 InternalDrag.himl = 0;
1264 InternalDrag.dxHotspot = 0;
1265 InternalDrag.dyHotspot = 0;
1266 InternalDrag.bShow = FALSE;
1267 DeleteObject(InternalDrag.hbmBg);
1268 InternalDrag.hbmBg = 0;
1269 InternalDrag.bHSPending = FALSE;
1273 /*************************************************************************
1274 * ImageList_GetBkColor [COMCTL32.@]
1276 * Returns the background color of an image list.
1279 * himl [I] Image list handle.
1282 * Success: background color
1287 ImageList_GetBkColor (HIMAGELIST himl)
1289 return himl ? himl->clrBk : CLR_NONE;
1293 /*************************************************************************
1294 * ImageList_GetDragImage [COMCTL32.@]
1296 * Returns the handle to the internal drag image list.
1299 * ppt [O] Pointer to the drag position. Can be NULL.
1300 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1303 * Success: Handle of the drag image list.
1308 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1310 if (is_valid(InternalDrag.himl)) {
1312 ppt->x = InternalDrag.x;
1313 ppt->y = InternalDrag.y;
1316 pptHotspot->x = InternalDrag.dxHotspot;
1317 pptHotspot->y = InternalDrag.dyHotspot;
1319 return (InternalDrag.himl);
1326 /*************************************************************************
1327 * ImageList_GetFlags [COMCTL32.@]
1334 ImageList_GetFlags(HIMAGELIST himl)
1336 FIXME("(%p):empty stub\n", himl);
1341 /*************************************************************************
1342 * ImageList_GetIcon [COMCTL32.@]
1344 * Creates an icon from a masked image of an image list.
1347 * himl [I] handle to image list
1349 * flags [I] drawing style flags
1352 * Success: icon handle
1357 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1361 HBITMAP hOldDstBitmap;
1364 TRACE("%p %d %d\n", himl, i, fStyle);
1365 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1367 hdcDst = CreateCompatibleDC(0);
1374 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1375 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1376 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1377 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1380 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1381 SelectObject (hdcDst, ii.hbmColor);
1382 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1383 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1386 * CreateIconIndirect requires us to deselect the bitmaps from
1387 * the DCs before calling
1389 SelectObject(hdcDst, hOldDstBitmap);
1391 hIcon = CreateIconIndirect (&ii);
1393 DeleteObject (ii.hbmMask);
1394 DeleteObject (ii.hbmColor);
1401 /*************************************************************************
1402 * ImageList_GetIconSize [COMCTL32.@]
1404 * Retrieves the size of an image in an image list.
1407 * himl [I] handle to image list
1408 * cx [O] pointer to the image width.
1409 * cy [O] pointer to the image height.
1416 * All images in an image list have the same size.
1420 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1422 if (!is_valid(himl))
1424 if ((himl->cx <= 0) || (himl->cy <= 0))
1436 /*************************************************************************
1437 * ImageList_GetImageCount [COMCTL32.@]
1439 * Returns the number of images in an image list.
1442 * himl [I] handle to image list
1445 * Success: Number of images.
1450 ImageList_GetImageCount (HIMAGELIST himl)
1452 if (!is_valid(himl))
1455 return himl->cCurImage;
1459 /*************************************************************************
1460 * ImageList_GetImageInfo [COMCTL32.@]
1462 * Returns information about an image in an image list.
1465 * himl [I] handle to image list
1467 * pImageInfo [O] pointer to the image information
1475 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1477 if (!is_valid(himl) || (pImageInfo == NULL))
1479 if ((i < 0) || (i >= himl->cCurImage))
1482 pImageInfo->hbmImage = himl->hbmImage;
1483 pImageInfo->hbmMask = himl->hbmMask;
1485 pImageInfo->rcImage.top = 0;
1486 pImageInfo->rcImage.bottom = himl->cy;
1487 pImageInfo->rcImage.left = i * himl->cx;
1488 pImageInfo->rcImage.right = (i+1) * himl->cx;
1494 /*************************************************************************
1495 * ImageList_GetImageRect [COMCTL32.@]
1497 * Retrieves the rectangle of the specified image in an image list.
1500 * himl [I] handle to image list
1502 * lpRect [O] pointer to the image rectangle
1509 * This is an UNDOCUMENTED function!!!
1513 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1515 if (!is_valid(himl) || (lpRect == NULL))
1517 if ((i < 0) || (i >= himl->cCurImage))
1520 lpRect->left = i * himl->cx;
1522 lpRect->right = lpRect->left + himl->cx;
1523 lpRect->bottom = himl->cy;
1529 /*************************************************************************
1530 * ImageList_LoadImage [COMCTL32.@]
1531 * ImageList_LoadImageA [COMCTL32.@]
1533 * Creates an image list from a bitmap, icon or cursor.
1536 * hi [I] instance handle
1537 * lpbmp [I] name or id of the image
1538 * cx [I] width of each image
1539 * cGrow [I] number of images to expand
1540 * clrMask [I] mask color
1541 * uType [I] type of image to load
1542 * uFlags [I] loading flags
1545 * Success: handle to the loaded image list
1553 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1554 COLORREF clrMask, UINT uType, UINT uFlags)
1556 HIMAGELIST himl = NULL;
1560 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1562 ERR("Error loading image!\n");
1566 if (uType == IMAGE_BITMAP) {
1568 GetObjectA (handle, sizeof(BITMAP), &bmp);
1570 /* To match windows behavior, if cx is set to zero and
1571 the flag DI_DEFAULTSIZE is specified, cx becomes the
1572 system metric value for icons. If the flag is not specified
1573 the function sets the size to the height of the bitmap */
1576 if (uFlags & DI_DEFAULTSIZE)
1577 cx = GetSystemMetrics (SM_CXICON);
1582 nImageCount = bmp.bmWidth / cx;
1584 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1585 nImageCount, cGrow);
1587 DeleteObject (handle);
1590 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1592 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1596 GetIconInfo (handle, &ii);
1597 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1598 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1599 ILC_MASK | ILC_COLOR, 1, cGrow);
1601 DeleteObject (ii.hbmColor);
1602 DeleteObject (ii.hbmMask);
1603 DeleteObject (handle);
1606 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1607 DeleteObject (ii.hbmColor);
1608 DeleteObject (ii.hbmMask);
1611 DeleteObject (handle);
1617 /*************************************************************************
1618 * ImageList_LoadImageW [COMCTL32.@]
1620 * Creates an image list from a bitmap, icon or cursor.
1623 * hi [I] instance handle
1624 * lpbmp [I] name or id of the image
1625 * cx [I] width of each image
1626 * cGrow [I] number of images to expand
1627 * clrMask [I] mask color
1628 * uType [I] type of image to load
1629 * uFlags [I] loading flags
1632 * Success: handle to the loaded image list
1640 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1641 COLORREF clrMask, UINT uType, UINT uFlags)
1643 HIMAGELIST himl = NULL;
1647 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1649 ERR("Error loading image!\n");
1653 if (uType == IMAGE_BITMAP) {
1655 GetObjectW (handle, sizeof(BITMAP), &bmp);
1657 /* To match windows behavior, if cx is set to zero and
1658 the flag DI_DEFAULTSIZE is specified, cx becomes the
1659 system metric value for icons. If the flag is not specified
1660 the function sets the size to the height of the bitmap */
1663 if (uFlags & DI_DEFAULTSIZE)
1664 cx = GetSystemMetrics (SM_CXICON);
1669 nImageCount = bmp.bmWidth / cx;
1671 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1672 nImageCount, cGrow);
1674 DeleteObject (handle);
1677 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1679 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1683 GetIconInfo (handle, &ii);
1684 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1685 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1686 ILC_MASK | ILC_COLOR, 1, cGrow);
1688 DeleteObject (ii.hbmColor);
1689 DeleteObject (ii.hbmMask);
1690 DeleteObject (handle);
1693 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1694 DeleteObject (ii.hbmColor);
1695 DeleteObject (ii.hbmMask);
1698 DeleteObject (handle);
1704 /*************************************************************************
1705 * ImageList_Merge [COMCTL32.@]
1707 * Creates a new image list that contains a merged image from the specified
1708 * images of both source image lists.
1711 * himl1 [I] handle to first image list
1712 * i1 [I] first image index
1713 * himl2 [I] handle to second image list
1714 * i2 [I] second image index
1715 * dx [I] X offset of the second image relative to the first.
1716 * dy [I] Y offset of the second image relative to the first.
1719 * Success: handle of the merged image list.
1724 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1727 HIMAGELIST himlDst = NULL;
1729 INT xOff1, yOff1, xOff2, yOff2;
1732 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1735 if (!is_valid(himl1) || !is_valid(himl2))
1739 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1740 ERR("Index 1 out of range! %d\n", i1);
1744 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1745 ERR("Index 2 out of range! %d\n", i2);
1750 cxDst = max (himl1->cx, dx + himl2->cx);
1755 cxDst = max (himl2->cx, himl1->cx - dx);
1760 cxDst = max (himl1->cx, himl2->cx);
1766 cyDst = max (himl1->cy, dy + himl2->cy);
1771 cyDst = max (himl2->cy, himl1->cy - dy);
1776 cyDst = max (himl1->cy, himl2->cy);
1781 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1786 nX1 = i1 * himl1->cx;
1787 nX2 = i2 * himl2->cx;
1790 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1791 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1792 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1793 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1796 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1797 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1798 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1800 himlDst->cCurImage = 1;
1807 /* helper for _read_bitmap currently unused */
1809 static int may_use_dibsection(HDC hdc) {
1810 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1815 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1819 /* helper for ImageList_Read, see comments below */
1820 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1821 HDC xdc = 0, hBitmapDC =0;
1822 BITMAPFILEHEADER bmfh;
1823 BITMAPINFOHEADER bmih;
1824 int bitsperpixel,palspace,longsperline,width,height;
1825 LPBITMAPINFOHEADER bmihc = NULL;
1827 HBITMAP hbitmap = 0, hDIB = 0;
1830 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1831 (bmfh.bfType != (('M'<<8)|'B')) ||
1832 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1833 (bmih.biSize != sizeof(bmih))
1837 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1838 if (bitsperpixel<=8)
1839 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1842 width = bmih.biWidth;
1843 height = bmih.biHeight;
1844 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1845 memcpy(bmihc,&bmih,sizeof(bmih));
1846 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1847 bmihc->biSizeImage = (longsperline*height)<<2;
1849 /* read the palette right after the end of the bitmapinfoheader */
1851 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1855 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1856 if ((bitsperpixel>1) &&
1857 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1859 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1862 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1868 int i,nwidth,nheight,nRows;
1870 nwidth = width*(height/cy);
1872 nRows = (height/cy);
1874 if (bitsperpixel==1)
1875 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1877 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1879 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1882 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1885 hBitmapDC = CreateCompatibleDC(0);
1886 SelectObject(hBitmapDC, hbitmap);
1888 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1889 /* Do not forget that windows bitmaps are bottom->top */
1890 TRACE("nRows=%d\n", nRows);
1891 for (i=0; i < nRows; i++){
1892 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1893 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1899 if (xdc) ReleaseDC(0,xdc);
1900 if (bmihc) LocalFree((HLOCAL)bmihc);
1901 if (hDIB) DeleteObject(hDIB);
1902 if (hBitmapDC) DeleteDC(hBitmapDC);
1905 DeleteObject(hbitmap);
1912 /*************************************************************************
1913 * ImageList_Read [COMCTL32.@]
1915 * Reads an image list from a stream.
1918 * pstm [I] pointer to a stream
1921 * Success: handle to image list
1924 * The format is like this:
1925 * ILHEAD ilheadstruct;
1927 * for the color image part:
1928 * BITMAPFILEHEADER bmfh;
1929 * BITMAPINFOHEADER bmih;
1930 * only if it has a palette:
1931 * RGBQUAD rgbs[nr_of_paletted_colors];
1933 * BYTE colorbits[imagesize];
1935 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1936 * BITMAPFILEHEADER bmfh_mask;
1937 * BITMAPINFOHEADER bmih_mask;
1938 * only if it has a palette (it usually does not):
1939 * RGBQUAD rgbs[nr_of_paletted_colors];
1941 * BYTE maskbits[imagesize];
1943 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1944 * _read_bitmap needs to convert them.
1946 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1950 HBITMAP hbmColor=0,hbmMask=0;
1953 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1955 if (ilHead.usMagic != (('L' << 8) | 'I'))
1957 if (ilHead.usVersion != 0x101) /* probably version? */
1961 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1962 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1963 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1964 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1965 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1966 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1967 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1968 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1969 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1970 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1973 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1976 if (ilHead.flags & ILC_MASK) {
1977 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1979 DeleteObject(hbmColor);
1984 himl = ImageList_Create (
1992 DeleteObject(hbmColor);
1993 DeleteObject(hbmMask);
1996 SelectObject(himl->hdcImage, hbmColor);
1997 DeleteObject(himl->hbmImage);
1998 himl->hbmImage = hbmColor;
2000 SelectObject(himl->hdcMask, hbmMask);
2001 DeleteObject(himl->hbmMask);
2002 himl->hbmMask = hbmMask;
2004 himl->cCurImage = ilHead.cCurImage;
2005 himl->cMaxImage = ilHead.cMaxImage;
2007 ImageList_SetBkColor(himl,ilHead.bkcolor);
2009 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2014 /*************************************************************************
2015 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2018 * himl [I] image list handle
2027 ImageList_Remove (HIMAGELIST himl, INT i)
2029 HBITMAP hbmNewImage, hbmNewMask;
2033 TRACE("(himl=%p i=%d)\n", himl, i);
2035 if (!is_valid(himl)) {
2036 ERR("Invalid image list handle!\n");
2040 if ((i < -1) || (i >= himl->cCurImage)) {
2041 ERR("index out of range! %d\n", i);
2047 if (himl->cCurImage == 0) {
2048 /* remove all on empty ImageList is allowed */
2049 TRACE("remove all on empty ImageList!\n");
2053 himl->cMaxImage = himl->cInitial + himl->cGrow;
2054 himl->cCurImage = 0;
2055 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2056 himl->nOvlIdx[nCount] = -1;
2058 hbmNewImage = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2059 1, himl->uBitsPixel, NULL);
2060 SelectObject (himl->hdcImage, hbmNewImage);
2061 DeleteObject (himl->hbmImage);
2062 himl->hbmImage = hbmNewImage;
2064 if (himl->hbmMask) {
2065 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2067 SelectObject (himl->hdcMask, hbmNewMask);
2068 DeleteObject (himl->hbmMask);
2069 himl->hbmMask = hbmNewMask;
2073 /* delete one image */
2074 TRACE("Remove single image! %d\n", i);
2076 /* create new bitmap(s) */
2077 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2079 TRACE(" - Number of images: %d / %d (Old/New)\n",
2080 himl->cCurImage, himl->cCurImage - 1);
2081 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2082 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2085 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2088 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2090 hbmNewMask = 0; /* Just to keep compiler happy! */
2092 hdcBmp = CreateCompatibleDC (0);
2094 /* copy all images and masks prior to the "removed" image */
2096 TRACE("Pre image copy: Copy %d images\n", i);
2098 SelectObject (hdcBmp, hbmNewImage);
2099 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2100 himl->hdcImage, 0, 0, SRCCOPY);
2102 if (himl->hbmMask) {
2103 SelectObject (hdcBmp, hbmNewMask);
2104 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2105 himl->hdcMask, 0, 0, SRCCOPY);
2109 /* copy all images and masks behind the removed image */
2110 if (i < himl->cCurImage - 1) {
2111 TRACE("Post image copy!\n");
2112 SelectObject (hdcBmp, hbmNewImage);
2113 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2114 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2116 if (himl->hbmMask) {
2117 SelectObject (hdcBmp, hbmNewMask);
2118 BitBlt (hdcBmp, i * himl->cx, 0,
2119 (himl->cCurImage - i - 1) * himl->cx,
2120 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2126 /* delete old images and insert new ones */
2127 SelectObject (himl->hdcImage, hbmNewImage);
2128 DeleteObject (himl->hbmImage);
2129 himl->hbmImage = hbmNewImage;
2130 if (himl->hbmMask) {
2131 SelectObject (himl->hdcMask, hbmNewMask);
2132 DeleteObject (himl->hbmMask);
2133 himl->hbmMask = hbmNewMask;
2137 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2144 /*************************************************************************
2145 * ImageList_Replace [COMCTL32.@]
2147 * Replaces an image in an image list with a new image.
2150 * himl [I] handle to image list
2152 * hbmImage [I] handle to image bitmap
2153 * hbmMask [I] handle to mask bitmap. Can be NULL.
2161 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2167 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2169 if (!is_valid(himl)) {
2170 ERR("Invalid image list handle!\n");
2174 if ((i >= himl->cMaxImage) || (i < 0)) {
2175 ERR("Invalid image index!\n");
2179 hdcImage = CreateCompatibleDC (0);
2180 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2183 SelectObject (hdcImage, hbmImage);
2185 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2186 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2191 SelectObject (hdcImage, hbmMask);
2193 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2194 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2197 /* Remove the background from the image
2199 StretchBlt (himl->hdcImage,
2200 i*himl->cx, 0, himl->cx, himl->cy,
2202 0, 0, bmp.bmWidth, bmp.bmHeight,
2203 0x220326); /* NOTSRCAND */
2206 DeleteDC (hdcImage);
2212 /*************************************************************************
2213 * ImageList_ReplaceIcon [COMCTL32.@]
2215 * Replaces an image in an image list using an icon.
2218 * himl [I] handle to image list
2220 * hIcon [I] handle to icon
2223 * Success: index of the replaced image
2228 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2237 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2239 if (!is_valid(himl))
2241 if ((i >= himl->cMaxImage) || (i < -1))
2244 hBestFitIcon = CopyImage(
2247 LR_COPYFROMRESOURCE);
2249 GetIconInfo (hBestFitIcon, &ii);
2250 if (ii.hbmMask == 0)
2252 if (ii.hbmColor == 0)
2254 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2257 if (himl->cCurImage + 1 > himl->cMaxImage)
2258 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2260 nIndex = himl->cCurImage;
2266 hdcImage = CreateCompatibleDC (0);
2267 TRACE("hdcImage=%p\n", hdcImage);
2269 ERR("invalid hdcImage!\n");
2271 SetTextColor(himl->hdcImage, RGB(0,0,0));
2272 SetBkColor (himl->hdcImage, RGB(255,255,255));
2273 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2275 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2276 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2278 if (himl->hbmMask) {
2279 SelectObject (hdcImage, ii.hbmMask);
2280 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2281 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2284 SelectObject (hdcImage, hbmOldSrc);
2287 DestroyIcon(hBestFitIcon);
2289 DeleteDC (hdcImage);
2291 DeleteObject (ii.hbmColor);
2293 DeleteObject (ii.hbmMask);
2299 /*************************************************************************
2300 * ImageList_SetBkColor [COMCTL32.@]
2302 * Sets the background color of an image list.
2305 * himl [I] handle to image list
2306 * clrBk [I] background color
2309 * Success: previous background color
2314 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2318 if (!is_valid(himl))
2321 clrOldBk = himl->clrBk;
2322 himl->clrBk = clrBk;
2327 /*************************************************************************
2328 * ImageList_SetDragCursorImage [COMCTL32.@]
2330 * Combines the specified image with the current drag image
2333 * himlDrag [I] handle to drag image list
2334 * iDrag [I] drag image index
2335 * dxHotspot [I] X position of the hot spot
2336 * dyHotspot [I] Y position of the hot spot
2343 * When this function is called and the drag image is visible, a
2344 * short flickering occurs but this matches the Win9x behavior. It is
2345 * possible to fix the flickering using code like in ImageList_DragMove.
2349 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2350 INT dxHotspot, INT dyHotspot)
2352 HIMAGELIST himlTemp;
2356 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2359 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2360 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2362 visible = InternalDrag.bShow;
2364 /* Calculate the offset between the origin of the old image and the
2365 * origin of the second image.
2366 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2367 * hotspot) to the origin of the second image.
2368 * See M$DN for details */
2369 if(InternalDrag.bHSPending) {
2372 InternalDrag.bHSPending = FALSE;
2374 dx = InternalDrag.dxHotspot - dxHotspot;
2375 dy = InternalDrag.dyHotspot - dyHotspot;
2377 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2380 /* hide the drag image */
2381 ImageList_DragShowNolock(FALSE);
2383 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2384 (InternalDrag.himl->cy != himlTemp->cy)) {
2385 /* the size of the drag image changed, invalidate the buffer */
2386 DeleteObject(InternalDrag.hbmBg);
2387 InternalDrag.hbmBg = 0;
2390 ImageList_Destroy (InternalDrag.himl);
2391 InternalDrag.himl = himlTemp;
2393 /* update the InternalDragOffset, if the origin of the
2394 * DragImage was changed by ImageList_Merge. */
2396 InternalDrag.dxHotspot = dxHotspot;
2398 InternalDrag.dyHotspot = dyHotspot;
2401 /* show the drag image */
2402 ImageList_DragShowNolock(TRUE);
2409 /*************************************************************************
2410 * ImageList_SetFilter [COMCTL32.@]
2412 * Sets a filter (or does something completely different)!!???
2413 * It removes 12 Bytes from the stack (3 Parameters).
2416 * himl [I] SHOULD be a handle to image list
2417 * i [I] COULD be an index?
2422 * Failure: FALSE ???
2425 * This is an UNDOCUMENTED function!!!!
2430 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2432 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2438 /*************************************************************************
2439 * ImageList_SetFlags [COMCTL32.@]
2446 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2448 FIXME("(%p %08lx):empty stub\n", himl, flags);
2453 /*************************************************************************
2454 * ImageList_SetIconSize [COMCTL32.@]
2456 * Sets the image size of the bitmap and deletes all images.
2459 * himl [I] handle to image list
2460 * cx [I] image width
2461 * cy [I] image height
2469 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2474 if (!is_valid(himl))
2477 /* remove all images */
2478 himl->cMaxImage = himl->cInitial + himl->cGrow;
2479 himl->cCurImage = 0;
2483 /* initialize overlay mask indices */
2484 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2485 himl->nOvlIdx[nCount] = -1;
2487 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2488 1, himl->uBitsPixel, NULL);
2489 SelectObject (himl->hdcImage, hbmNew);
2490 DeleteObject (himl->hbmImage);
2491 himl->hbmImage = hbmNew;
2493 if (himl->hbmMask) {
2494 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2496 SelectObject (himl->hdcMask, hbmNew);
2497 DeleteObject (himl->hbmMask);
2498 himl->hbmMask = hbmNew;
2505 /*************************************************************************
2506 * ImageList_SetImageCount [COMCTL32.@]
2508 * Resizes an image list to the specified number of images.
2511 * himl [I] handle to image list
2512 * iImageCount [I] number of images in the image list
2520 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2523 HBITMAP hbmNewBitmap;
2524 INT nNewCount, nCopyCount;
2526 TRACE("%p %d\n",himl,iImageCount);
2528 if (!is_valid(himl))
2530 if (himl->cCurImage >= iImageCount)
2532 if (himl->cMaxImage > iImageCount)
2534 himl->cCurImage = iImageCount;
2538 nNewCount = iImageCount + himl->cGrow;
2539 nCopyCount = min(himl->cCurImage, iImageCount);
2541 hdcBitmap = CreateCompatibleDC (0);
2543 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2544 1, himl->uBitsPixel, NULL);
2545 if (hbmNewBitmap != 0)
2547 SelectObject (hdcBitmap, hbmNewBitmap);
2550 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2551 himl->hdcImage, 0, 0, SRCCOPY);
2553 /* delete 'empty' image space */
2554 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2555 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2556 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2557 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2559 SelectObject (himl->hdcImage, hbmNewBitmap);
2560 DeleteObject (himl->hbmImage);
2561 himl->hbmImage = hbmNewBitmap;
2564 ERR("Could not create new image bitmap !\n");
2568 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2570 if (hbmNewBitmap != 0)
2572 SelectObject (hdcBitmap, hbmNewBitmap);
2575 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2576 himl->hdcMask, 0, 0, SRCCOPY);
2578 /* delete 'empty' image space */
2579 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2580 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2581 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2582 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2584 SelectObject (himl->hdcMask, hbmNewBitmap);
2585 DeleteObject (himl->hbmMask);
2586 himl->hbmMask = hbmNewBitmap;
2589 ERR("Could not create new mask bitmap!\n");
2592 DeleteDC (hdcBitmap);
2594 /* Update max image count and current image count */
2595 himl->cMaxImage = nNewCount;
2596 himl->cCurImage = iImageCount;
2602 /*************************************************************************
2603 * ImageList_SetOverlayImage [COMCTL32.@]
2605 * Assigns an overlay mask index to an existing image in an image list.
2608 * himl [I] handle to image list
2609 * iImage [I] image index
2610 * iOverlay [I] overlay mask index
2618 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2620 if (!is_valid(himl))
2622 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2624 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2626 himl->nOvlIdx[iOverlay - 1] = iImage;
2632 /* helper for ImageList_Write - write bitmap to pstm
2633 * currently everything is written as 24 bit RGB, except masks
2636 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2638 LPBITMAPFILEHEADER bmfh;
2639 LPBITMAPINFOHEADER bmih;
2640 LPBYTE data, lpBits, lpBitsOrg;
2642 INT bitCount, sizeImage, offBits, totalSize;
2643 INT nwidth, nheight, nsizeImage, icount;
2645 BOOL result = FALSE;
2649 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2651 /* XXX is this always correct? */
2652 icount = bm.bmWidth / cx;
2654 nheight = cy * icount;
2656 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2657 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2658 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2660 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2662 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2663 offBits = totalSize;
2664 totalSize += nsizeImage;
2666 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2667 bmfh = (LPBITMAPFILEHEADER)data;
2668 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2669 lpBits = data + offBits;
2671 /* setup BITMAPFILEHEADER */
2672 bmfh->bfType = (('M' << 8) | 'B');
2674 bmfh->bfReserved1 = 0;
2675 bmfh->bfReserved2 = 0;
2676 bmfh->bfOffBits = offBits;
2678 /* setup BITMAPINFOHEADER */
2679 bmih->biSize = sizeof(BITMAPINFOHEADER);
2680 bmih->biWidth = bm.bmWidth;
2681 bmih->biHeight = bm.bmHeight;
2683 bmih->biBitCount = bitCount;
2684 bmih->biCompression = BI_RGB;
2685 bmih->biSizeImage = sizeImage;
2686 bmih->biXPelsPerMeter = 0;
2687 bmih->biYPelsPerMeter = 0;
2688 bmih->biClrUsed = 0;
2689 bmih->biClrImportant = 0;
2691 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2692 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2693 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2697 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2698 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2700 for(i = 0; i < nheight; i++) {
2701 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2702 int noff = (nbpl * (nheight-1-i));
2703 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2707 bmih->biWidth = nwidth;
2708 bmih->biHeight = nheight;
2709 bmih->biSizeImage = nsizeImage;
2713 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2714 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2715 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2718 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2725 LocalFree((HLOCAL)lpBitsOrg);
2731 /*************************************************************************
2732 * ImageList_Write [COMCTL32.@]
2734 * Writes an image list to a stream.
2737 * himl [I] handle to image list
2738 * pstm [O] Pointer to a stream.
2749 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2754 if (!is_valid(himl))
2757 ilHead.usMagic = (('L' << 8) | 'I');
2758 ilHead.usVersion = 0x101;
2759 ilHead.cCurImage = himl->cCurImage;
2760 ilHead.cMaxImage = himl->cMaxImage;
2761 ilHead.cGrow = himl->cGrow;
2762 ilHead.cx = himl->cx;
2763 ilHead.cy = himl->cy;
2764 ilHead.bkcolor = himl->clrBk;
2765 ilHead.flags = himl->flags;
2766 for(i = 0; i < 4; i++) {
2767 ilHead.ovls[i] = himl->nOvlIdx[i];
2770 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2773 /* write the bitmap */
2774 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2777 /* write the mask if we have one */
2778 if(himl->flags & ILC_MASK) {
2779 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))