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))
288 nImageCount = bmp.bmWidth / himl->cx;
292 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
294 nIndex = himl->cCurImage;
295 himl->cCurImage += nImageCount;
297 hdcBitmap = CreateCompatibleDC(0);
300 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
303 hdcMask = himl->hdcMask;
304 nMaskXOffset = nIndex * himl->cx;
309 Create a temp Mask so we can remove the background of
310 the Image (Windows does this even if there is no mask)
312 hdcMask = CreateCompatibleDC(0);
313 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
314 SelectObject(hdcMask, hMaskBitmap);
317 /* create monochrome image to the mask bitmap */
318 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
319 GetPixel (hdcBitmap, 0, 0);
320 SetBkColor (hdcBitmap, bkColor);
322 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
326 SetBkColor(hdcBitmap, RGB(255,255,255));
327 /*Remove the background from the image
330 WINDOWS BUG ALERT!!!!!!
331 The statement below should not be done in common practice
332 but this is how ImageList_AddMasked works in Windows.
333 It overwrites the original bitmap passed, this was discovered
334 by using the same bitmap to iterate the different styles
335 on windows where it failed (BUT ImageList_Add is OK)
336 This is here in case some apps rely on this bug
339 0, 0, bmp.bmWidth, bmp.bmHeight,
342 0x220326); /* NOTSRCAND */
343 /* Copy result to the imagelist
345 BitBlt (himl->hdcImage,
346 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
352 SelectObject(hdcBitmap, hOldBitmap);
356 DeleteObject(hMaskBitmap);
364 /*************************************************************************
365 * ImageList_BeginDrag [COMCTL32.@]
367 * Creates a temporary image list that contains one image. It will be used
371 * himlTrack [I] handle to the source image list
372 * iTrack [I] index of the drag image in the source image list
373 * dxHotspot [I] X position of the hot spot of the drag image
374 * dyHotspot [I] Y position of the hot spot of the drag image
382 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
383 INT dxHotspot, INT dyHotspot)
387 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
388 dxHotspot, dyHotspot);
390 if (!is_valid(himlTrack))
393 if (InternalDrag.himl)
394 ImageList_EndDrag ();
399 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
400 if (InternalDrag.himl == NULL) {
401 WARN("Error creating drag image list!\n");
405 InternalDrag.dxHotspot = dxHotspot;
406 InternalDrag.dyHotspot = dyHotspot;
409 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
412 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
414 InternalDrag.himl->cCurImage = 1;
415 InternalDrag.bHSPending = TRUE;
421 /*************************************************************************
422 * ImageList_Copy [COMCTL32.@]
424 * Copies an image of the source image list to an image of the
425 * destination image list. Images can be copied or swapped.
428 * himlDst [I] handle to the destination image list
429 * iDst [I] destination image index.
430 * himlSrc [I] handle to the source image list
431 * iSrc [I] source image index
432 * uFlags [I] flags for the copy operation
439 * Copying from one image list to another is possible. The original
440 * implementation just copies or swaps within one image list.
441 * Could this feature become a bug??? ;-)
445 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
446 INT iSrc, UINT uFlags)
448 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
450 if (!is_valid(himlSrc) || !is_valid(himlDst))
452 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
454 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
457 if (uFlags & ILCF_SWAP) {
460 HBITMAP hbmTempImage, hbmTempMask;
462 hdcBmp = CreateCompatibleDC (0);
464 /* create temporary bitmaps */
465 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
466 himlSrc->uBitsPixel, NULL);
467 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
470 /* copy (and stretch) destination to temporary bitmaps.(save) */
472 SelectObject (hdcBmp, hbmTempImage);
473 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
474 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
477 SelectObject (hdcBmp, hbmTempMask);
478 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
479 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
482 /* copy (and stretch) source to destination */
484 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
485 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
488 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
489 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
492 /* copy (without stretching) temporary bitmaps to source (restore) */
494 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
495 hdcBmp, 0, 0, SRCCOPY);
498 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
499 hdcBmp, 0, 0, SRCCOPY);
500 /* delete temporary bitmaps */
501 DeleteObject (hbmTempMask);
502 DeleteObject (hbmTempImage);
507 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
508 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
512 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
513 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
521 /*************************************************************************
522 * ImageList_Create [COMCTL32.@] Creates a new image list.
525 * cx [I] image height
527 * flags [I] creation flags
528 * cInitial [I] initial number of images in the image list
529 * cGrow [I] number of images by which image list grows
532 * Success: Handle to the created image list
537 ImageList_Create (INT cx, INT cy, UINT flags,
538 INT cInitial, INT cGrow)
543 static WORD aBitBlend25[] =
544 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
546 static WORD aBitBlend50[] =
547 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
549 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
551 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
555 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
557 himl->magic = IMAGELIST_MAGIC;
561 himl->cMaxImage = cInitial + cGrow;
562 himl->cInitial = cInitial;
564 himl->clrFg = CLR_DEFAULT;
565 himl->clrBk = CLR_NONE;
567 /* initialize overlay mask indices */
568 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
569 himl->nOvlIdx[nCount] = -1;
571 /* Create Image & Mask DCs */
572 himl->hdcImage = CreateCompatibleDC (0);
575 if (himl->flags & ILC_MASK){
576 himl->hdcMask = CreateCompatibleDC(0);
581 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
583 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
585 if (himl->cMaxImage > 0) {
587 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
588 1, himl->uBitsPixel, NULL);
589 if (himl->hbmImage == 0) {
590 ERR("Error creating image bitmap!\n");
593 SelectObject(himl->hdcImage, himl->hbmImage);
596 if (himl->flags & ILC_MASK) {
598 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
600 if (himl->hbmMask == 0) {
601 ERR("Error creating mask bitmap!\n");
604 SelectObject(himl->hdcMask, himl->hbmMask);
607 /* create blending brushes */
608 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
609 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
610 DeleteObject (hbmTemp);
612 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
613 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
614 DeleteObject (hbmTemp);
616 TRACE("created imagelist %p\n", himl);
620 if (himl) ImageList_Destroy(himl);
625 /*************************************************************************
626 * ImageList_Destroy [COMCTL32.@]
628 * Destroys an image list.
631 * himl [I] handle to image list
639 ImageList_Destroy (HIMAGELIST himl)
644 /* delete image bitmaps */
646 DeleteObject (himl->hbmImage);
648 DeleteObject (himl->hbmMask);
650 /* delete image & mask DCs */
652 DeleteDC(himl->hdcImage);
654 DeleteDC(himl->hdcMask);
656 /* delete blending brushes */
657 if (himl->hbrBlend25)
658 DeleteObject (himl->hbrBlend25);
659 if (himl->hbrBlend50)
660 DeleteObject (himl->hbrBlend50);
662 ZeroMemory(himl, sizeof(*himl));
663 COMCTL32_Free (himl);
669 /*************************************************************************
670 * ImageList_DragEnter [COMCTL32.@]
672 * Locks window update and displays the drag image at the given position.
675 * hwndLock [I] handle of the window that owns the drag image.
676 * x [I] X position of the drag image.
677 * y [I] Y position of the drag image.
684 * The position of the drag image is relative to the window, not
689 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
691 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
693 if (!is_valid(InternalDrag.himl))
697 InternalDrag.hwnd = hwndLock;
699 InternalDrag.hwnd = GetDesktopWindow ();
704 /* draw the drag image and save the background */
705 if (!ImageList_DragShowNolock(TRUE)) {
713 /*************************************************************************
714 * ImageList_DragLeave [COMCTL32.@]
716 * Unlocks window update and hides the drag image.
719 * hwndLock [I] handle of the window that owns the drag image.
727 ImageList_DragLeave (HWND hwndLock)
729 /* As we don't save drag info in the window this can lead to problems if
730 an app does not supply the same window as DragEnter */
732 InternalDrag.hwnd = hwndLock;
734 InternalDrag.hwnd = GetDesktopWindow (); */
736 hwndLock = GetDesktopWindow();
737 if(InternalDrag.hwnd != hwndLock)
738 FIXME("DragLeave hWnd != DragEnter hWnd\n");
740 ImageList_DragShowNolock (FALSE);
746 /*************************************************************************
747 * ImageList_InternalDragDraw [Internal]
749 * Draws the drag image.
752 * hdc [I] device context to draw into.
753 * x [I] X position of the drag image.
754 * y [I] Y position of the drag image.
761 * The position of the drag image is relative to the window, not
767 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
769 IMAGELISTDRAWPARAMS imldp;
771 ZeroMemory (&imldp, sizeof(imldp));
772 imldp.cbSize = sizeof(imldp);
773 imldp.himl = InternalDrag.himl;
778 imldp.rgbBk = CLR_DEFAULT;
779 imldp.rgbFg = CLR_DEFAULT;
780 imldp.fStyle = ILD_NORMAL;
781 imldp.fState = ILS_ALPHA;
784 /* FIXME: instead of using the alpha blending, we should
785 * create a 50% mask, and draw it semitransparantly that way */
786 ImageList_DrawIndirect (&imldp);
789 /*************************************************************************
790 * ImageList_DragMove [COMCTL32.@]
792 * Moves the drag image.
795 * x [I] X position of the drag image.
796 * y [I] Y position of the drag image.
803 * The position of the drag image is relative to the window, not
807 * The drag image should be drawn semitransparent.
811 ImageList_DragMove (INT x, INT y)
813 TRACE("(x=%d y=%d)\n", x, y);
815 if (!is_valid(InternalDrag.himl))
818 /* draw/update the drag image */
819 if (InternalDrag.bShow) {
823 HBITMAP hbmOffScreen;
824 INT origNewX, origNewY;
825 INT origOldX, origOldY;
826 INT origRegX, origRegY;
827 INT sizeRegX, sizeRegY;
830 /* calculate the update region */
831 origNewX = x - InternalDrag.dxHotspot;
832 origNewY = y - InternalDrag.dyHotspot;
833 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
834 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
835 origRegX = min(origNewX, origOldX);
836 origRegY = min(origNewY, origOldY);
837 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
838 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
840 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
841 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
842 hdcOffScreen = CreateCompatibleDC(hdcDrag);
843 hdcBg = CreateCompatibleDC(hdcDrag);
845 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
846 SelectObject(hdcOffScreen, hbmOffScreen);
847 SelectObject(hdcBg, InternalDrag.hbmBg);
849 /* get the actual background of the update region */
850 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
851 origRegX, origRegY, SRCCOPY);
852 /* erase the old image */
853 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
854 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
856 /* save the background */
857 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
858 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
860 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
861 origNewY - origRegY);
862 /* draw the update region to the screen */
863 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
864 hdcOffScreen, 0, 0, SRCCOPY);
867 DeleteDC(hdcOffScreen);
868 DeleteObject(hbmOffScreen);
869 ReleaseDC(InternalDrag.hwnd, hdcDrag);
872 /* update the image position */
880 /*************************************************************************
881 * ImageList_DragShowNolock [COMCTL32.@]
883 * Shows or hides the drag image.
886 * bShow [I] TRUE shows the drag image, FALSE hides it.
893 * The drag image should be drawn semitransparent.
897 ImageList_DragShowNolock (BOOL bShow)
903 if (!is_valid(InternalDrag.himl))
906 TRACE("bShow=0x%X!\n", bShow);
908 /* DragImage is already visible/hidden */
909 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
913 /* position of the origin of the DragImage */
914 x = InternalDrag.x - InternalDrag.dxHotspot;
915 y = InternalDrag.y - InternalDrag.dyHotspot;
917 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
918 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
923 hdcBg = CreateCompatibleDC(hdcDrag);
924 if (!InternalDrag.hbmBg) {
925 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
926 InternalDrag.himl->cx, InternalDrag.himl->cy);
928 SelectObject(hdcBg, InternalDrag.hbmBg);
931 /* save the background */
932 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
933 hdcDrag, x, y, SRCCOPY);
935 ImageList_InternalDragDraw(hdcDrag, x, y);
938 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
939 hdcBg, 0, 0, SRCCOPY);
942 InternalDrag.bShow = !InternalDrag.bShow;
945 ReleaseDC (InternalDrag.hwnd, hdcDrag);
950 /*************************************************************************
951 * ImageList_Draw [COMCTL32.@] Draws an image.
954 * himl [I] handle to image list
956 * hdc [I] handle to device context
959 * fStyle [I] drawing flags
970 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
972 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
973 CLR_DEFAULT, CLR_DEFAULT, fStyle);
977 /*************************************************************************
978 * ImageList_DrawEx [COMCTL32.@]
980 * Draws an image and allows to use extended drawing features.
983 * himl [I] handle to image list
985 * hdc [I] handle to device context
990 * rgbBk [I] background color
991 * rgbFg [I] foreground color
992 * fStyle [I] drawing flags
999 * Calls ImageList_DrawIndirect.
1002 * ImageList_DrawIndirect.
1006 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1007 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1010 IMAGELISTDRAWPARAMS imldp;
1012 ZeroMemory (&imldp, sizeof(imldp));
1013 imldp.cbSize = sizeof(imldp);
1021 imldp.rgbBk = rgbBk;
1022 imldp.rgbFg = rgbFg;
1023 imldp.fStyle = fStyle;
1025 return ImageList_DrawIndirect (&imldp);
1029 /*************************************************************************
1030 * ImageList_DrawIndirect [COMCTL32.@]
1032 * Draws an image using ...
1035 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1043 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1045 INT cx, cy, lx, ly, nOvlIdx;
1046 DWORD fState, dwRop;
1048 COLORREF clrBk, oldImageBk, oldImageFg;
1049 HDC hImageDC, hImageListDC, hMaskListDC;
1050 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1051 BOOL bIsTransparent, bBlend, bResult = FALSE;
1054 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1055 if (!is_valid(himl)) return FALSE;
1056 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1058 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1059 ly = pimldp->yBitmap;
1061 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1062 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1063 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1064 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1065 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1066 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1067 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1069 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1070 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1072 /* we will use these DCs to access the images and masks in the ImageList */
1073 hImageListDC = himl->hdcImage;
1074 hMaskListDC = himl->hdcMask;
1076 /* these will accumulate the image and mask for the image we're drawing */
1077 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1078 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1079 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1081 /* Create a compatible DC. */
1082 if (!hImageListDC || !hImageDC || !hImageBmp ||
1083 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1086 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1089 * To obtain a transparent look, background color should be set
1090 * to white and foreground color to black when blting the
1093 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1094 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1097 * Draw the initial image
1099 if(fStyle & ILD_MASK) {
1100 if (himl->hbmMask) {
1101 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1103 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1104 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1105 SelectObject(hImageDC, hOldBrush);
1107 } else if (himl->hbmMask && !bIsTransparent) {
1108 /* blend the image with the needed solid background */
1109 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1110 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1111 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1112 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1113 DeleteObject (SelectObject (hImageDC, hOldBrush));
1115 /* start off with the image, if we have a mask, we'll use it later */
1116 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1119 /* Time for blending, if required */
1121 HBRUSH hBlendBrush, hOldBrush;
1122 COLORREF clrBlend = pimldp->rgbFg;
1123 HDC hBlendMaskDC = hImageListDC;
1126 /* Create the blend Mask */
1127 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1128 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1129 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1130 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1131 SelectObject(hBlendMaskDC, hOldBrush);
1133 /* Modify the blend mask if an Image Mask exist */
1135 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1136 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1139 /* now apply blend to the current image given the BlendMask */
1140 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1141 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1142 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1143 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1144 DeleteObject(SelectObject(hImageDC, hOldBrush));
1145 SelectObject(hBlendMaskDC, hOldBitmap);
1148 /* Now do the overlay image, if any */
1149 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1150 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1151 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1152 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1153 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1154 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1155 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1156 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1160 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1161 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1162 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1163 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1165 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1166 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1167 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1169 /* now copy the image to the screen */
1171 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1172 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1173 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1174 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1175 SetBkColor(pimldp->hdcDst, oldDstBk);
1176 SetTextColor(pimldp->hdcDst, oldDstFg);
1179 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1180 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1184 /* cleanup the mess */
1185 SetBkColor(hImageDC, oldImageBk);
1186 SetTextColor(hImageDC, oldImageFg);
1187 SelectObject(hImageDC, hOldImageBmp);
1189 DeleteObject(hBlendMaskBmp);
1190 DeleteObject(hImageBmp);
1197 /*************************************************************************
1198 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1201 * himlSrc [I] source image list handle
1204 * Success: Handle of duplicated image list.
1209 ImageList_Duplicate (HIMAGELIST himlSrc)
1213 if (!is_valid(himlSrc)) {
1214 ERR("Invalid image list handle!\n");
1218 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1219 himlSrc->cInitial, himlSrc->cGrow);
1223 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1224 himlSrc->hdcImage, 0, 0, SRCCOPY);
1226 if (himlDst->hbmMask)
1227 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1228 himlSrc->hdcMask, 0, 0, SRCCOPY);
1230 himlDst->cCurImage = himlSrc->cCurImage;
1231 himlDst->cMaxImage = himlSrc->cMaxImage;
1237 /*************************************************************************
1238 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1240 * Finishes a drag operation.
1251 ImageList_EndDrag (void)
1253 /* cleanup the InternalDrag struct */
1254 InternalDrag.hwnd = 0;
1255 ImageList_Destroy (InternalDrag.himl);
1256 InternalDrag.himl = 0;
1259 InternalDrag.dxHotspot = 0;
1260 InternalDrag.dyHotspot = 0;
1261 InternalDrag.bShow = FALSE;
1262 DeleteObject(InternalDrag.hbmBg);
1263 InternalDrag.hbmBg = 0;
1264 InternalDrag.bHSPending = FALSE;
1268 /*************************************************************************
1269 * ImageList_GetBkColor [COMCTL32.@]
1271 * Returns the background color of an image list.
1274 * himl [I] Image list handle.
1277 * Success: background color
1282 ImageList_GetBkColor (HIMAGELIST himl)
1284 return himl ? himl->clrBk : CLR_NONE;
1288 /*************************************************************************
1289 * ImageList_GetDragImage [COMCTL32.@]
1291 * Returns the handle to the internal drag image list.
1294 * ppt [O] Pointer to the drag position. Can be NULL.
1295 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1298 * Success: Handle of the drag image list.
1303 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1305 if (is_valid(InternalDrag.himl)) {
1307 ppt->x = InternalDrag.x;
1308 ppt->y = InternalDrag.y;
1311 pptHotspot->x = InternalDrag.dxHotspot;
1312 pptHotspot->y = InternalDrag.dyHotspot;
1314 return (InternalDrag.himl);
1321 /*************************************************************************
1322 * ImageList_GetFlags [COMCTL32.@]
1329 ImageList_GetFlags(HIMAGELIST himl)
1331 FIXME("(%p):empty stub\n", himl);
1336 /*************************************************************************
1337 * ImageList_GetIcon [COMCTL32.@]
1339 * Creates an icon from a masked image of an image list.
1342 * himl [I] handle to image list
1344 * flags [I] drawing style flags
1347 * Success: icon handle
1352 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1356 HBITMAP hOldDstBitmap;
1359 TRACE("%p %d %d\n", himl, i, fStyle);
1360 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1362 hdcDst = CreateCompatibleDC(0);
1369 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1370 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1371 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1372 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1375 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1376 SelectObject (hdcDst, ii.hbmColor);
1377 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1378 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1381 * CreateIconIndirect requires us to deselect the bitmaps from
1382 * the DCs before calling
1384 SelectObject(hdcDst, hOldDstBitmap);
1386 hIcon = CreateIconIndirect (&ii);
1388 DeleteObject (ii.hbmMask);
1389 DeleteObject (ii.hbmColor);
1396 /*************************************************************************
1397 * ImageList_GetIconSize [COMCTL32.@]
1399 * Retrieves the size of an image in an image list.
1402 * himl [I] handle to image list
1403 * cx [O] pointer to the image width.
1404 * cy [O] pointer to the image height.
1411 * All images in an image list have the same size.
1415 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1417 if (!is_valid(himl))
1419 if ((himl->cx <= 0) || (himl->cy <= 0))
1431 /*************************************************************************
1432 * ImageList_GetImageCount [COMCTL32.@]
1434 * Returns the number of images in an image list.
1437 * himl [I] handle to image list
1440 * Success: Number of images.
1445 ImageList_GetImageCount (HIMAGELIST himl)
1447 if (!is_valid(himl))
1450 return himl->cCurImage;
1454 /*************************************************************************
1455 * ImageList_GetImageInfo [COMCTL32.@]
1457 * Returns information about an image in an image list.
1460 * himl [I] handle to image list
1462 * pImageInfo [O] pointer to the image information
1470 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1472 if (!is_valid(himl) || (pImageInfo == NULL))
1474 if ((i < 0) || (i >= himl->cCurImage))
1477 pImageInfo->hbmImage = himl->hbmImage;
1478 pImageInfo->hbmMask = himl->hbmMask;
1480 pImageInfo->rcImage.top = 0;
1481 pImageInfo->rcImage.bottom = himl->cy;
1482 pImageInfo->rcImage.left = i * himl->cx;
1483 pImageInfo->rcImage.right = (i+1) * himl->cx;
1489 /*************************************************************************
1490 * ImageList_GetImageRect [COMCTL32.@]
1492 * Retrieves the rectangle of the specified image in an image list.
1495 * himl [I] handle to image list
1497 * lpRect [O] pointer to the image rectangle
1504 * This is an UNDOCUMENTED function!!!
1508 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1510 if (!is_valid(himl) || (lpRect == NULL))
1512 if ((i < 0) || (i >= himl->cCurImage))
1515 lpRect->left = i * himl->cx;
1517 lpRect->right = lpRect->left + himl->cx;
1518 lpRect->bottom = himl->cy;
1524 /*************************************************************************
1525 * ImageList_LoadImage [COMCTL32.@]
1526 * ImageList_LoadImageA [COMCTL32.@]
1528 * Creates an image list from a bitmap, icon or cursor.
1531 * hi [I] instance handle
1532 * lpbmp [I] name or id of the image
1533 * cx [I] width of each image
1534 * cGrow [I] number of images to expand
1535 * clrMask [I] mask color
1536 * uType [I] type of image to load
1537 * uFlags [I] loading flags
1540 * Success: handle to the loaded image list
1548 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1549 COLORREF clrMask, UINT uType, UINT uFlags)
1551 HIMAGELIST himl = NULL;
1555 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1557 ERR("Error loading image!\n");
1561 if (uType == IMAGE_BITMAP) {
1563 GetObjectA (handle, sizeof(BITMAP), &bmp);
1565 /* To match windows behavior, if cx is set to zero and
1566 the flag DI_DEFAULTSIZE is specified, cx becomes the
1567 system metric value for icons. If the flag is not specified
1568 the function sets the size to the height of the bitmap */
1571 if (uFlags & DI_DEFAULTSIZE)
1572 cx = GetSystemMetrics (SM_CXICON);
1577 nImageCount = bmp.bmWidth / cx;
1579 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1580 nImageCount, cGrow);
1582 DeleteObject (handle);
1585 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1587 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1591 GetIconInfo (handle, &ii);
1592 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1593 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1594 ILC_MASK | ILC_COLOR, 1, cGrow);
1596 DeleteObject (ii.hbmColor);
1597 DeleteObject (ii.hbmMask);
1598 DeleteObject (handle);
1601 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1602 DeleteObject (ii.hbmColor);
1603 DeleteObject (ii.hbmMask);
1606 DeleteObject (handle);
1612 /*************************************************************************
1613 * ImageList_LoadImageW [COMCTL32.@]
1615 * Creates an image list from a bitmap, icon or cursor.
1618 * hi [I] instance handle
1619 * lpbmp [I] name or id of the image
1620 * cx [I] width of each image
1621 * cGrow [I] number of images to expand
1622 * clrMask [I] mask color
1623 * uType [I] type of image to load
1624 * uFlags [I] loading flags
1627 * Success: handle to the loaded image list
1635 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1636 COLORREF clrMask, UINT uType, UINT uFlags)
1638 HIMAGELIST himl = NULL;
1642 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1644 ERR("Error loading image!\n");
1648 if (uType == IMAGE_BITMAP) {
1650 GetObjectA (handle, sizeof(BITMAP), &bmp);
1652 /* To match windows behavior, if cx is set to zero and
1653 the flag DI_DEFAULTSIZE is specified, cx becomes the
1654 system metric value for icons. If the flag is not specified
1655 the function sets the size to the height of the bitmap */
1658 if (uFlags & DI_DEFAULTSIZE)
1659 cx = GetSystemMetrics (SM_CXICON);
1664 nImageCount = bmp.bmWidth / cx;
1666 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1667 nImageCount, cGrow);
1669 DeleteObject (handle);
1672 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1674 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1678 GetIconInfo (handle, &ii);
1679 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1680 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1681 ILC_MASK | ILC_COLOR, 1, cGrow);
1683 DeleteObject (ii.hbmColor);
1684 DeleteObject (ii.hbmMask);
1685 DeleteObject (handle);
1688 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1689 DeleteObject (ii.hbmColor);
1690 DeleteObject (ii.hbmMask);
1693 DeleteObject (handle);
1699 /*************************************************************************
1700 * ImageList_Merge [COMCTL32.@]
1702 * Creates a new image list that contains a merged image from the specified
1703 * images of both source image lists.
1706 * himl1 [I] handle to first image list
1707 * i1 [I] first image index
1708 * himl2 [I] handle to second image list
1709 * i2 [I] second image index
1710 * dx [I] X offset of the second image relative to the first.
1711 * dy [I] Y offset of the second image relative to the first.
1714 * Success: handle of the merged image list.
1719 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1722 HIMAGELIST himlDst = NULL;
1724 INT xOff1, yOff1, xOff2, yOff2;
1727 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1730 if (!is_valid(himl1) || !is_valid(himl2))
1734 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1735 ERR("Index 1 out of range! %d\n", i1);
1739 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1740 ERR("Index 2 out of range! %d\n", i2);
1745 cxDst = max (himl1->cx, dx + himl2->cx);
1750 cxDst = max (himl2->cx, himl1->cx - dx);
1755 cxDst = max (himl1->cx, himl2->cx);
1761 cyDst = max (himl1->cy, dy + himl2->cy);
1766 cyDst = max (himl2->cy, himl1->cy - dy);
1771 cyDst = max (himl1->cy, himl2->cy);
1776 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1781 nX1 = i1 * himl1->cx;
1782 nX2 = i2 * himl2->cx;
1785 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1786 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1787 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1788 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1791 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1792 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1793 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1795 himlDst->cCurImage = 1;
1802 /* helper for _read_bitmap currently unused */
1804 static int may_use_dibsection(HDC hdc) {
1805 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1810 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1814 /* helper for ImageList_Read, see comments below */
1815 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1816 HDC xdc = 0, hBitmapDC =0;
1817 BITMAPFILEHEADER bmfh;
1818 BITMAPINFOHEADER bmih;
1819 int bitsperpixel,palspace,longsperline,width,height;
1820 LPBITMAPINFOHEADER bmihc = NULL;
1822 HBITMAP hbitmap = 0, hDIB = 0;
1825 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1826 (bmfh.bfType != (('M'<<8)|'B')) ||
1827 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1828 (bmih.biSize != sizeof(bmih))
1832 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1833 if (bitsperpixel<=8)
1834 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1837 width = bmih.biWidth;
1838 height = bmih.biHeight;
1839 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1840 memcpy(bmihc,&bmih,sizeof(bmih));
1841 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1842 bmihc->biSizeImage = (longsperline*height)<<2;
1844 /* read the palette right after the end of the bitmapinfoheader */
1846 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1850 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1851 if ((bitsperpixel>1) &&
1852 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1854 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1857 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1863 int i,nwidth,nheight,nRows;
1865 nwidth = width*(height/cy);
1867 nRows = (height/cy);
1869 if (bitsperpixel==1)
1870 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1872 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1874 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1877 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1880 hBitmapDC = CreateCompatibleDC(0);
1881 SelectObject(hBitmapDC, hbitmap);
1883 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1884 /* Do not forget that windows bitmaps are bottom->top */
1885 TRACE("nRows=%d\n", nRows);
1886 for (i=0; i < nRows; i++){
1887 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1888 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1894 if (xdc) ReleaseDC(0,xdc);
1895 if (bmihc) LocalFree((HLOCAL)bmihc);
1896 if (hDIB) DeleteObject(hDIB);
1897 if (hBitmapDC) DeleteDC(hBitmapDC);
1900 DeleteObject(hbitmap);
1907 /*************************************************************************
1908 * ImageList_Read [COMCTL32.@]
1910 * Reads an image list from a stream.
1913 * pstm [I] pointer to a stream
1916 * Success: handle to image list
1919 * The format is like this:
1920 * ILHEAD ilheadstruct;
1922 * for the color image part:
1923 * BITMAPFILEHEADER bmfh;
1924 * BITMAPINFOHEADER bmih;
1925 * only if it has a palette:
1926 * RGBQUAD rgbs[nr_of_paletted_colors];
1928 * BYTE colorbits[imagesize];
1930 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1931 * BITMAPFILEHEADER bmfh_mask;
1932 * BITMAPINFOHEADER bmih_mask;
1933 * only if it has a palette (it usually does not):
1934 * RGBQUAD rgbs[nr_of_paletted_colors];
1936 * BYTE maskbits[imagesize];
1938 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1939 * _read_bitmap needs to convert them.
1941 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1945 HBITMAP hbmColor=0,hbmMask=0;
1948 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1950 if (ilHead.usMagic != (('L' << 8) | 'I'))
1952 if (ilHead.usVersion != 0x101) /* probably version? */
1956 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1957 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1958 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1959 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1960 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1961 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1962 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1963 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1964 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1965 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1968 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1971 if (ilHead.flags & ILC_MASK) {
1972 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1974 DeleteObject(hbmColor);
1979 himl = ImageList_Create (
1987 DeleteObject(hbmColor);
1988 DeleteObject(hbmMask);
1991 SelectObject(himl->hdcImage, hbmColor);
1992 DeleteObject(himl->hbmImage);
1993 himl->hbmImage = hbmColor;
1995 SelectObject(himl->hdcMask, hbmMask);
1996 DeleteObject(himl->hbmMask);
1997 himl->hbmMask = hbmMask;
1999 himl->cCurImage = ilHead.cCurImage;
2000 himl->cMaxImage = ilHead.cMaxImage;
2002 ImageList_SetBkColor(himl,ilHead.bkcolor);
2004 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2009 /*************************************************************************
2010 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2013 * himl [I] image list handle
2022 ImageList_Remove (HIMAGELIST himl, INT i)
2024 HBITMAP hbmNewImage, hbmNewMask;
2028 TRACE("(himl=%p i=%d)\n", himl, i);
2030 if (!is_valid(himl)) {
2031 ERR("Invalid image list handle!\n");
2035 if ((i < -1) || (i >= himl->cCurImage)) {
2036 ERR("index out of range! %d\n", i);
2042 if (himl->cCurImage == 0) {
2043 /* remove all on empty ImageList is allowed */
2044 TRACE("remove all on empty ImageList!\n");
2048 himl->cMaxImage = himl->cInitial + himl->cGrow;
2049 himl->cCurImage = 0;
2050 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2051 himl->nOvlIdx[nCount] = -1;
2053 hbmNewImage = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2054 1, himl->uBitsPixel, NULL);
2055 SelectObject (himl->hdcImage, hbmNewImage);
2056 DeleteObject (himl->hbmImage);
2057 himl->hbmImage = hbmNewImage;
2059 if (himl->hbmMask) {
2060 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2062 SelectObject (himl->hdcMask, hbmNewMask);
2063 DeleteObject (himl->hbmMask);
2064 himl->hbmMask = hbmNewMask;
2068 /* delete one image */
2069 TRACE("Remove single image! %d\n", i);
2071 /* create new bitmap(s) */
2072 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2074 TRACE(" - Number of images: %d / %d (Old/New)\n",
2075 himl->cCurImage, himl->cCurImage - 1);
2076 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2077 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2080 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2083 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2085 hbmNewMask = 0; /* Just to keep compiler happy! */
2087 hdcBmp = CreateCompatibleDC (0);
2089 /* copy all images and masks prior to the "removed" image */
2091 TRACE("Pre image copy: Copy %d images\n", i);
2093 SelectObject (hdcBmp, hbmNewImage);
2094 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2095 himl->hdcImage, 0, 0, SRCCOPY);
2097 if (himl->hbmMask) {
2098 SelectObject (hdcBmp, hbmNewMask);
2099 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2100 himl->hdcMask, 0, 0, SRCCOPY);
2104 /* copy all images and masks behind the removed image */
2105 if (i < himl->cCurImage - 1) {
2106 TRACE("Post image copy!\n");
2107 SelectObject (hdcBmp, hbmNewImage);
2108 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2109 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2111 if (himl->hbmMask) {
2112 SelectObject (hdcBmp, hbmNewMask);
2113 BitBlt (hdcBmp, i * himl->cx, 0,
2114 (himl->cCurImage - i - 1) * himl->cx,
2115 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2121 /* delete old images and insert new ones */
2122 SelectObject (himl->hdcImage, hbmNewImage);
2123 DeleteObject (himl->hbmImage);
2124 himl->hbmImage = hbmNewImage;
2125 if (himl->hbmMask) {
2126 SelectObject (himl->hdcMask, hbmNewMask);
2127 DeleteObject (himl->hbmMask);
2128 himl->hbmMask = hbmNewMask;
2132 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2139 /*************************************************************************
2140 * ImageList_Replace [COMCTL32.@]
2142 * Replaces an image in an image list with a new image.
2145 * himl [I] handle to image list
2147 * hbmImage [I] handle to image bitmap
2148 * hbmMask [I] handle to mask bitmap. Can be NULL.
2156 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2162 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2164 if (!is_valid(himl)) {
2165 ERR("Invalid image list handle!\n");
2169 if ((i >= himl->cMaxImage) || (i < 0)) {
2170 ERR("Invalid image index!\n");
2174 hdcImage = CreateCompatibleDC (0);
2175 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2178 SelectObject (hdcImage, hbmImage);
2180 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2181 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2186 SelectObject (hdcImage, hbmMask);
2188 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2189 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2192 /* Remove the background from the image
2194 StretchBlt (himl->hdcImage,
2195 i*himl->cx, 0, himl->cx, himl->cy,
2197 0, 0, bmp.bmWidth, bmp.bmHeight,
2198 0x220326); /* NOTSRCAND */
2201 DeleteDC (hdcImage);
2207 /*************************************************************************
2208 * ImageList_ReplaceIcon [COMCTL32.@]
2210 * Replaces an image in an image list using an icon.
2213 * himl [I] handle to image list
2215 * hIcon [I] handle to icon
2218 * Success: index of the replaced image
2223 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2232 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2234 if (!is_valid(himl))
2236 if ((i >= himl->cMaxImage) || (i < -1))
2239 hBestFitIcon = CopyImage(
2242 LR_COPYFROMRESOURCE);
2244 GetIconInfo (hBestFitIcon, &ii);
2245 if (ii.hbmMask == 0)
2247 if (ii.hbmColor == 0)
2249 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2252 if (himl->cCurImage + 1 > himl->cMaxImage)
2253 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2255 nIndex = himl->cCurImage;
2261 hdcImage = CreateCompatibleDC (0);
2262 TRACE("hdcImage=%p\n", hdcImage);
2264 ERR("invalid hdcImage!\n");
2266 SetTextColor(himl->hdcImage, RGB(0,0,0));
2267 SetBkColor (himl->hdcImage, RGB(255,255,255));
2268 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2270 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2271 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2273 if (himl->hbmMask) {
2274 SelectObject (hdcImage, ii.hbmMask);
2275 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2276 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2279 SelectObject (hdcImage, hbmOldSrc);
2282 DestroyIcon(hBestFitIcon);
2284 DeleteDC (hdcImage);
2286 DeleteObject (ii.hbmColor);
2288 DeleteObject (ii.hbmMask);
2294 /*************************************************************************
2295 * ImageList_SetBkColor [COMCTL32.@]
2297 * Sets the background color of an image list.
2300 * himl [I] handle to image list
2301 * clrBk [I] background color
2304 * Success: previous background color
2309 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2313 if (!is_valid(himl))
2316 clrOldBk = himl->clrBk;
2317 himl->clrBk = clrBk;
2322 /*************************************************************************
2323 * ImageList_SetDragCursorImage [COMCTL32.@]
2325 * Combines the specified image with the current drag image
2328 * himlDrag [I] handle to drag image list
2329 * iDrag [I] drag image index
2330 * dxHotspot [I] X position of the hot spot
2331 * dyHotspot [I] Y position of the hot spot
2338 * When this function is called and the drag image is visible, a
2339 * short flickering occurs but this matches the Win9x behavior. It is
2340 * possible to fix the flickering using code like in ImageList_DragMove.
2344 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2345 INT dxHotspot, INT dyHotspot)
2347 HIMAGELIST himlTemp;
2351 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2354 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2355 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2357 visible = InternalDrag.bShow;
2359 /* Calculate the offset between the origin of the old image and the
2360 * origin of the second image.
2361 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2362 * hotspot) to the origin of the second image.
2363 * See M$DN for details */
2364 if(InternalDrag.bHSPending) {
2367 InternalDrag.bHSPending = FALSE;
2369 dx = InternalDrag.dxHotspot - dxHotspot;
2370 dy = InternalDrag.dyHotspot - dyHotspot;
2372 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2375 /* hide the drag image */
2376 ImageList_DragShowNolock(FALSE);
2378 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2379 (InternalDrag.himl->cy != himlTemp->cy)) {
2380 /* the size of the drag image changed, invalidate the buffer */
2381 DeleteObject(InternalDrag.hbmBg);
2382 InternalDrag.hbmBg = 0;
2385 ImageList_Destroy (InternalDrag.himl);
2386 InternalDrag.himl = himlTemp;
2388 /* update the InternalDragOffset, if the origin of the
2389 * DragImage was changed by ImageList_Merge. */
2391 InternalDrag.dxHotspot = dxHotspot;
2393 InternalDrag.dyHotspot = dyHotspot;
2396 /* show the drag image */
2397 ImageList_DragShowNolock(TRUE);
2404 /*************************************************************************
2405 * ImageList_SetFilter [COMCTL32.@]
2407 * Sets a filter (or does something completely different)!!???
2408 * It removes 12 Bytes from the stack (3 Parameters).
2411 * himl [I] SHOULD be a handle to image list
2412 * i [I] COULD be an index?
2417 * Failure: FALSE ???
2420 * This is an UNDOCUMENTED function!!!!
2425 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2427 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2433 /*************************************************************************
2434 * ImageList_SetFlags [COMCTL32.@]
2441 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2443 FIXME("(%p %08lx):empty stub\n", himl, flags);
2448 /*************************************************************************
2449 * ImageList_SetIconSize [COMCTL32.@]
2451 * Sets the image size of the bitmap and deletes all images.
2454 * himl [I] handle to image list
2455 * cx [I] image width
2456 * cy [I] image height
2464 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2469 if (!is_valid(himl))
2472 /* remove all images */
2473 himl->cMaxImage = himl->cInitial + himl->cGrow;
2474 himl->cCurImage = 0;
2478 /* initialize overlay mask indices */
2479 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2480 himl->nOvlIdx[nCount] = -1;
2482 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2483 1, himl->uBitsPixel, NULL);
2484 SelectObject (himl->hdcImage, hbmNew);
2485 DeleteObject (himl->hbmImage);
2486 himl->hbmImage = hbmNew;
2488 if (himl->hbmMask) {
2489 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2491 SelectObject (himl->hdcMask, hbmNew);
2492 DeleteObject (himl->hbmMask);
2493 himl->hbmMask = hbmNew;
2500 /*************************************************************************
2501 * ImageList_SetImageCount [COMCTL32.@]
2503 * Resizes an image list to the specified number of images.
2506 * himl [I] handle to image list
2507 * iImageCount [I] number of images in the image list
2515 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2518 HBITMAP hbmNewBitmap;
2519 INT nNewCount, nCopyCount;
2521 TRACE("%p %d\n",himl,iImageCount);
2523 if (!is_valid(himl))
2525 if (himl->cCurImage >= iImageCount)
2527 if (himl->cMaxImage > iImageCount)
2529 himl->cCurImage = iImageCount;
2533 nNewCount = iImageCount + himl->cGrow;
2534 nCopyCount = min(himl->cCurImage, iImageCount);
2536 hdcBitmap = CreateCompatibleDC (0);
2538 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2539 1, himl->uBitsPixel, NULL);
2540 if (hbmNewBitmap != 0)
2542 SelectObject (hdcBitmap, hbmNewBitmap);
2545 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2546 himl->hdcImage, 0, 0, SRCCOPY);
2548 /* delete 'empty' image space */
2549 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2550 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2551 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2552 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2554 SelectObject (himl->hdcImage, hbmNewBitmap);
2555 DeleteObject (himl->hbmImage);
2556 himl->hbmImage = hbmNewBitmap;
2559 ERR("Could not create new image bitmap !\n");
2563 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2565 if (hbmNewBitmap != 0)
2567 SelectObject (hdcBitmap, hbmNewBitmap);
2570 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2571 himl->hdcMask, 0, 0, SRCCOPY);
2573 /* delete 'empty' image space */
2574 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2575 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2576 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2577 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2579 SelectObject (himl->hdcMask, hbmNewBitmap);
2580 DeleteObject (himl->hbmMask);
2581 himl->hbmMask = hbmNewBitmap;
2584 ERR("Could not create new mask bitmap!\n");
2587 DeleteDC (hdcBitmap);
2589 /* Update max image count and current image count */
2590 himl->cMaxImage = nNewCount;
2591 himl->cCurImage = iImageCount;
2597 /*************************************************************************
2598 * ImageList_SetOverlayImage [COMCTL32.@]
2600 * Assigns an overlay mask index to an existing image in an image list.
2603 * himl [I] handle to image list
2604 * iImage [I] image index
2605 * iOverlay [I] overlay mask index
2613 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2615 if (!is_valid(himl))
2617 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2619 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2621 himl->nOvlIdx[iOverlay - 1] = iImage;
2627 /* helper for ImageList_Write - write bitmap to pstm
2628 * currently everything is written as 24 bit RGB, except masks
2631 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2633 LPBITMAPFILEHEADER bmfh;
2634 LPBITMAPINFOHEADER bmih;
2635 LPBYTE data, lpBits, lpBitsOrg;
2637 INT bitCount, sizeImage, offBits, totalSize;
2638 INT nwidth, nheight, nsizeImage, icount;
2640 BOOL result = FALSE;
2644 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2646 /* XXX is this always correct? */
2647 icount = bm.bmWidth / cx;
2649 nheight = cy * ((icount+3)>>2);
2651 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2652 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2653 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2655 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2657 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2658 offBits = totalSize;
2659 totalSize += nsizeImage;
2661 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2662 bmfh = (LPBITMAPFILEHEADER)data;
2663 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2664 lpBits = data + offBits;
2666 /* setup BITMAPFILEHEADER */
2667 bmfh->bfType = (('M' << 8) | 'B');
2669 bmfh->bfReserved1 = 0;
2670 bmfh->bfReserved2 = 0;
2671 bmfh->bfOffBits = offBits;
2673 /* setup BITMAPINFOHEADER */
2674 bmih->biSize = sizeof(BITMAPINFOHEADER);
2675 bmih->biWidth = bm.bmWidth;
2676 bmih->biHeight = bm.bmHeight;
2678 bmih->biBitCount = bitCount;
2679 bmih->biCompression = BI_RGB;
2680 bmih->biSizeImage = nsizeImage;
2681 bmih->biXPelsPerMeter = 0;
2682 bmih->biYPelsPerMeter = 0;
2683 bmih->biClrUsed = 0;
2684 bmih->biClrImportant = 0;
2686 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2687 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2688 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2692 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2693 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2695 for(i = 0; i < nheight; i++) {
2696 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2697 int noff = (nbpl * (nheight-1-i));
2698 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2702 bmih->biWidth = nwidth;
2703 bmih->biHeight = nheight;
2707 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2708 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2709 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2712 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2719 LocalFree((HLOCAL)lpBitsOrg);
2725 /*************************************************************************
2726 * ImageList_Write [COMCTL32.@]
2728 * Writes an image list to a stream.
2731 * himl [I] handle to image list
2732 * pstm [O] Pointer to a stream.
2743 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2748 if (!is_valid(himl))
2751 ilHead.usMagic = (('L' << 8) | 'I');
2752 ilHead.usVersion = 0x101;
2753 ilHead.cCurImage = himl->cCurImage;
2754 ilHead.cMaxImage = himl->cMaxImage;
2755 ilHead.cGrow = himl->cGrow;
2756 ilHead.cx = himl->cx;
2757 ilHead.cy = himl->cy;
2758 ilHead.bkcolor = himl->clrBk;
2759 ilHead.flags = himl->flags;
2760 for(i = 0; i < 4; i++) {
2761 ilHead.ovls[i] = himl->nOvlIdx[i];
2764 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2767 /* write the bitmap */
2768 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2771 /* write the mask if we have one */
2772 if(himl->flags & ILC_MASK) {
2773 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))