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...
54 #include "imagelist.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
60 #define MAX_OVERLAYIMAGE 15
62 /* internal image list data used for Drag & Drop operations */
67 /* position of the drag image relative to the window */
70 /* offset of the hotspot relative to the origin of the image */
73 /* is the drag image visible */
75 /* saved background */
80 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
83 static inline BOOL is_valid(HIMAGELIST himl)
85 return himl && himl->magic == IMAGELIST_MAGIC;
89 /*************************************************************************
90 * IMAGELIST_InternalExpandBitmaps [Internal]
92 * Expands the bitmaps of an image list by the given number of images.
95 * himl [I] handle to image list
96 * nImageCount [I] number of images to add
102 * This function can NOT be used to reduce the number of images.
105 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
108 HBITMAP hbmNewBitmap, hbmNull;
109 INT nNewWidth, nNewCount;
111 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
115 if (cy == 0) cy = himl->cy;
116 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
117 nNewWidth = nNewCount * himl->cx;
119 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
120 hdcBitmap = CreateCompatibleDC (0);
123 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
124 if (hbmNewBitmap == 0)
125 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
127 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
128 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
129 himl->hdcImage, 0, 0, SRCCOPY);
131 SelectObject (hdcBitmap, hbmNull);
132 SelectObject (himl->hdcImage, hbmNewBitmap);
133 DeleteObject (himl->hbmImage);
134 himl->hbmImage = hbmNewBitmap;
138 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
140 if (hbmNewBitmap == 0)
141 ERR("creating new mask bitmap!\n");
143 SelectObject (hdcBitmap, hbmNewBitmap);
144 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
145 himl->hdcMask, 0, 0, SRCCOPY);
146 SelectObject (hdcBitmap, hbmNull);
147 SelectObject (himl->hdcMask, hbmNewBitmap);
148 DeleteObject (himl->hbmMask);
149 himl->hbmMask = hbmNewBitmap;
152 himl->cMaxImage = nNewCount;
154 DeleteDC (hdcBitmap);
158 /*************************************************************************
159 * ImageList_Add [COMCTL32.@]
161 * Add an image or images to an image list.
164 * himl [I] handle to image list
165 * hbmImage [I] handle to image bitmap
166 * hbmMask [I] handle to mask bitmap
169 * Success: Index of the first new image.
174 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
177 INT nFirstIndex, nImageCount;
182 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
186 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
187 nImageCount = bmp.bmWidth / himl->cx;
189 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
191 nStartX = himl->cCurImage * himl->cx;
193 hdcBitmap = CreateCompatibleDC(0);
195 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
197 /* Copy result to the imagelist
199 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
200 hdcBitmap, 0, 0, SRCCOPY);
205 HBITMAP hOldBitmapTemp;
207 hdcTemp = CreateCompatibleDC(0);
208 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
210 BitBlt (himl->hdcMask,
211 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
216 SelectObject(hdcTemp, hOldBitmapTemp);
219 /* Remove the background from the image
221 BitBlt (himl->hdcImage,
222 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
225 0x220326); /* NOTSRCAND */
228 SelectObject(hdcBitmap, hOldBitmap);
231 nFirstIndex = himl->cCurImage;
232 himl->cCurImage += nImageCount;
238 /*************************************************************************
239 * ImageList_AddIcon [COMCTL32.@]
241 * Adds an icon to an image list.
244 * himl [I] handle to image list
245 * hIcon [I] handle to icon
248 * Success: index of the new image
251 #undef ImageList_AddIcon
252 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
254 return ImageList_ReplaceIcon (himl, -1, hIcon);
258 /*************************************************************************
259 * ImageList_AddMasked [COMCTL32.@]
261 * Adds an image or images to an image list and creates a mask from the
262 * specified bitmap using the mask color.
265 * himl [I] handle to image list.
266 * hBitmap [I] handle to bitmap
267 * clrMask [I] mask color.
270 * Success: Index of the first new image.
275 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
277 HDC hdcMask, hdcBitmap;
278 INT nIndex, nImageCount, nMaskXOffset=0;
281 HBITMAP hMaskBitmap=0;
284 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
288 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
292 nImageCount = bmp.bmWidth / himl->cx;
296 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
298 nIndex = himl->cCurImage;
299 himl->cCurImage += nImageCount;
301 hdcBitmap = CreateCompatibleDC(0);
304 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
307 hdcMask = himl->hdcMask;
308 nMaskXOffset = nIndex * himl->cx;
313 Create a temp Mask so we can remove the background of
314 the Image (Windows does this even if there is no mask)
316 hdcMask = CreateCompatibleDC(0);
317 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
318 SelectObject(hdcMask, hMaskBitmap);
321 /* create monochrome image to the mask bitmap */
322 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
323 GetPixel (hdcBitmap, 0, 0);
324 SetBkColor (hdcBitmap, bkColor);
326 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
330 SetBkColor(hdcBitmap, RGB(255,255,255));
331 /*Remove the background from the image
334 WINDOWS BUG ALERT!!!!!!
335 The statement below should not be done in common practice
336 but this is how ImageList_AddMasked works in Windows.
337 It overwrites the original bitmap passed, this was discovered
338 by using the same bitmap to iterate the different styles
339 on windows where it failed (BUT ImageList_Add is OK)
340 This is here in case some apps rely on this bug
343 0, 0, bmp.bmWidth, bmp.bmHeight,
346 0x220326); /* NOTSRCAND */
347 /* Copy result to the imagelist
349 BitBlt (himl->hdcImage,
350 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
356 SelectObject(hdcBitmap, hOldBitmap);
360 DeleteObject(hMaskBitmap);
368 /*************************************************************************
369 * ImageList_BeginDrag [COMCTL32.@]
371 * Creates a temporary image list that contains one image. It will be used
375 * himlTrack [I] handle to the source image list
376 * iTrack [I] index of the drag image in the source image list
377 * dxHotspot [I] X position of the hot spot of the drag image
378 * dyHotspot [I] Y position of the hot spot of the drag image
386 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
387 INT dxHotspot, INT dyHotspot)
391 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
392 dxHotspot, dyHotspot);
394 if (!is_valid(himlTrack))
397 if (InternalDrag.himl)
398 ImageList_EndDrag ();
403 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
404 if (InternalDrag.himl == NULL) {
405 WARN("Error creating drag image list!\n");
409 InternalDrag.dxHotspot = dxHotspot;
410 InternalDrag.dyHotspot = dyHotspot;
413 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
416 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
418 InternalDrag.himl->cCurImage = 1;
419 InternalDrag.bHSPending = TRUE;
425 /*************************************************************************
426 * ImageList_Copy [COMCTL32.@]
428 * Copies an image of the source image list to an image of the
429 * destination image list. Images can be copied or swapped.
432 * himlDst [I] handle to the destination image list
433 * iDst [I] destination image index.
434 * himlSrc [I] handle to the source image list
435 * iSrc [I] source image index
436 * uFlags [I] flags for the copy operation
443 * Copying from one image list to another is possible. The original
444 * implementation just copies or swaps within one image list.
445 * Could this feature become a bug??? ;-)
449 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
450 INT iSrc, UINT uFlags)
452 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
454 if (!is_valid(himlSrc) || !is_valid(himlDst))
456 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
458 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
461 if (uFlags & ILCF_SWAP) {
464 HBITMAP hbmTempImage, hbmTempMask;
466 hdcBmp = CreateCompatibleDC (0);
468 /* create temporary bitmaps */
469 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
470 himlSrc->uBitsPixel, NULL);
471 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
474 /* copy (and stretch) destination to temporary bitmaps.(save) */
476 SelectObject (hdcBmp, hbmTempImage);
477 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
478 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
481 SelectObject (hdcBmp, hbmTempMask);
482 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
483 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
486 /* copy (and stretch) source to destination */
488 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
489 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
492 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
493 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
496 /* copy (without stretching) temporary bitmaps to source (restore) */
498 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
499 hdcBmp, 0, 0, SRCCOPY);
502 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
503 hdcBmp, 0, 0, SRCCOPY);
504 /* delete temporary bitmaps */
505 DeleteObject (hbmTempMask);
506 DeleteObject (hbmTempImage);
511 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
512 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
516 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
517 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
525 /*************************************************************************
526 * ImageList_Create [COMCTL32.@] Creates a new image list.
529 * cx [I] image height
531 * flags [I] creation flags
532 * cInitial [I] initial number of images in the image list
533 * cGrow [I] number of images by which image list grows
536 * Success: Handle to the created image list
541 ImageList_Create (INT cx, INT cy, UINT flags,
542 INT cInitial, INT cGrow)
547 static WORD aBitBlend25[] =
548 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
550 static WORD aBitBlend50[] =
551 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
553 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
555 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
559 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
561 himl->magic = IMAGELIST_MAGIC;
565 himl->cMaxImage = cInitial + cGrow;
566 himl->cInitial = cInitial;
568 himl->clrFg = CLR_DEFAULT;
569 himl->clrBk = CLR_NONE;
571 /* initialize overlay mask indices */
572 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
573 himl->nOvlIdx[nCount] = -1;
575 /* Create Image & Mask DCs */
576 himl->hdcImage = CreateCompatibleDC (0);
579 if (himl->flags & ILC_MASK){
580 himl->hdcMask = CreateCompatibleDC(0);
585 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
587 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
589 if (himl->cMaxImage > 0) {
591 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
592 1, himl->uBitsPixel, NULL);
593 if (himl->hbmImage == 0) {
594 ERR("Error creating image bitmap!\n");
597 SelectObject(himl->hdcImage, himl->hbmImage);
600 if (himl->flags & ILC_MASK) {
602 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
604 if (himl->hbmMask == 0) {
605 ERR("Error creating mask bitmap!\n");
608 SelectObject(himl->hdcMask, himl->hbmMask);
611 /* create blending brushes */
612 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
613 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
614 DeleteObject (hbmTemp);
616 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
617 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
618 DeleteObject (hbmTemp);
620 TRACE("created imagelist %p\n", himl);
624 if (himl) ImageList_Destroy(himl);
629 /*************************************************************************
630 * ImageList_Destroy [COMCTL32.@]
632 * Destroys an image list.
635 * himl [I] handle to image list
643 ImageList_Destroy (HIMAGELIST himl)
648 /* delete image bitmaps */
650 DeleteObject (himl->hbmImage);
652 DeleteObject (himl->hbmMask);
654 /* delete image & mask DCs */
656 DeleteDC(himl->hdcImage);
658 DeleteDC(himl->hdcMask);
660 /* delete blending brushes */
661 if (himl->hbrBlend25)
662 DeleteObject (himl->hbrBlend25);
663 if (himl->hbrBlend50)
664 DeleteObject (himl->hbrBlend50);
666 ZeroMemory(himl, sizeof(*himl));
667 COMCTL32_Free (himl);
673 /*************************************************************************
674 * ImageList_DragEnter [COMCTL32.@]
676 * Locks window update and displays the drag image at the given position.
679 * hwndLock [I] handle of the window that owns the drag image.
680 * x [I] X position of the drag image.
681 * y [I] Y position of the drag image.
688 * The position of the drag image is relative to the window, not
693 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
695 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
697 if (!is_valid(InternalDrag.himl))
701 InternalDrag.hwnd = hwndLock;
703 InternalDrag.hwnd = GetDesktopWindow ();
708 /* draw the drag image and save the background */
709 if (!ImageList_DragShowNolock(TRUE)) {
717 /*************************************************************************
718 * ImageList_DragLeave [COMCTL32.@]
720 * Unlocks window update and hides the drag image.
723 * hwndLock [I] handle of the window that owns the drag image.
731 ImageList_DragLeave (HWND hwndLock)
733 /* As we don't save drag info in the window this can lead to problems if
734 an app does not supply the same window as DragEnter */
736 InternalDrag.hwnd = hwndLock;
738 InternalDrag.hwnd = GetDesktopWindow (); */
740 hwndLock = GetDesktopWindow();
741 if(InternalDrag.hwnd != hwndLock)
742 FIXME("DragLeave hWnd != DragEnter hWnd\n");
744 ImageList_DragShowNolock (FALSE);
750 /*************************************************************************
751 * ImageList_InternalDragDraw [Internal]
753 * Draws the drag image.
756 * hdc [I] device context to draw into.
757 * x [I] X position of the drag image.
758 * y [I] Y position of the drag image.
765 * The position of the drag image is relative to the window, not
771 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
773 IMAGELISTDRAWPARAMS imldp;
775 ZeroMemory (&imldp, sizeof(imldp));
776 imldp.cbSize = sizeof(imldp);
777 imldp.himl = InternalDrag.himl;
782 imldp.rgbBk = CLR_DEFAULT;
783 imldp.rgbFg = CLR_DEFAULT;
784 imldp.fStyle = ILD_NORMAL;
785 imldp.fState = ILS_ALPHA;
788 /* FIXME: instead of using the alpha blending, we should
789 * create a 50% mask, and draw it semitransparantly that way */
790 ImageList_DrawIndirect (&imldp);
793 /*************************************************************************
794 * ImageList_DragMove [COMCTL32.@]
796 * Moves the drag image.
799 * x [I] X position of the drag image.
800 * y [I] Y position of the drag image.
807 * The position of the drag image is relative to the window, not
811 * The drag image should be drawn semitransparent.
815 ImageList_DragMove (INT x, INT y)
817 TRACE("(x=%d y=%d)\n", x, y);
819 if (!is_valid(InternalDrag.himl))
822 /* draw/update the drag image */
823 if (InternalDrag.bShow) {
827 HBITMAP hbmOffScreen;
828 INT origNewX, origNewY;
829 INT origOldX, origOldY;
830 INT origRegX, origRegY;
831 INT sizeRegX, sizeRegY;
834 /* calculate the update region */
835 origNewX = x - InternalDrag.dxHotspot;
836 origNewY = y - InternalDrag.dyHotspot;
837 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
838 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
839 origRegX = min(origNewX, origOldX);
840 origRegY = min(origNewY, origOldY);
841 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
842 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
844 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
845 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
846 hdcOffScreen = CreateCompatibleDC(hdcDrag);
847 hdcBg = CreateCompatibleDC(hdcDrag);
849 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
850 SelectObject(hdcOffScreen, hbmOffScreen);
851 SelectObject(hdcBg, InternalDrag.hbmBg);
853 /* get the actual background of the update region */
854 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
855 origRegX, origRegY, SRCCOPY);
856 /* erase the old image */
857 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
858 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
860 /* save the background */
861 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
862 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
864 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
865 origNewY - origRegY);
866 /* draw the update region to the screen */
867 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
868 hdcOffScreen, 0, 0, SRCCOPY);
871 DeleteDC(hdcOffScreen);
872 DeleteObject(hbmOffScreen);
873 ReleaseDC(InternalDrag.hwnd, hdcDrag);
876 /* update the image position */
884 /*************************************************************************
885 * ImageList_DragShowNolock [COMCTL32.@]
887 * Shows or hides the drag image.
890 * bShow [I] TRUE shows the drag image, FALSE hides it.
897 * The drag image should be drawn semitransparent.
901 ImageList_DragShowNolock (BOOL bShow)
907 if (!is_valid(InternalDrag.himl))
910 TRACE("bShow=0x%X!\n", bShow);
912 /* DragImage is already visible/hidden */
913 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
917 /* position of the origin of the DragImage */
918 x = InternalDrag.x - InternalDrag.dxHotspot;
919 y = InternalDrag.y - InternalDrag.dyHotspot;
921 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
922 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
927 hdcBg = CreateCompatibleDC(hdcDrag);
928 if (!InternalDrag.hbmBg) {
929 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
930 InternalDrag.himl->cx, InternalDrag.himl->cy);
932 SelectObject(hdcBg, InternalDrag.hbmBg);
935 /* save the background */
936 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
937 hdcDrag, x, y, SRCCOPY);
939 ImageList_InternalDragDraw(hdcDrag, x, y);
942 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
943 hdcBg, 0, 0, SRCCOPY);
946 InternalDrag.bShow = !InternalDrag.bShow;
949 ReleaseDC (InternalDrag.hwnd, hdcDrag);
954 /*************************************************************************
955 * ImageList_Draw [COMCTL32.@] Draws an image.
958 * himl [I] handle to image list
960 * hdc [I] handle to device context
963 * fStyle [I] drawing flags
974 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
976 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
977 CLR_DEFAULT, CLR_DEFAULT, fStyle);
981 /*************************************************************************
982 * ImageList_DrawEx [COMCTL32.@]
984 * Draws an image and allows to use extended drawing features.
987 * himl [I] handle to image list
989 * hdc [I] handle to device context
994 * rgbBk [I] background color
995 * rgbFg [I] foreground color
996 * fStyle [I] drawing flags
1003 * Calls ImageList_DrawIndirect.
1006 * ImageList_DrawIndirect.
1010 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1011 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1014 IMAGELISTDRAWPARAMS imldp;
1016 ZeroMemory (&imldp, sizeof(imldp));
1017 imldp.cbSize = sizeof(imldp);
1025 imldp.rgbBk = rgbBk;
1026 imldp.rgbFg = rgbFg;
1027 imldp.fStyle = fStyle;
1029 return ImageList_DrawIndirect (&imldp);
1033 /*************************************************************************
1034 * ImageList_DrawIndirect [COMCTL32.@]
1036 * Draws an image using ...
1039 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1047 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1049 INT cx, cy, lx, ly, nOvlIdx;
1050 DWORD fState, dwRop;
1052 COLORREF clrBk, oldImageBk, oldImageFg;
1053 HDC hImageDC, hImageListDC, hMaskListDC;
1054 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1055 BOOL bIsTransparent, bBlend, bResult = FALSE;
1058 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1059 if (!is_valid(himl)) return FALSE;
1060 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1062 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1063 ly = pimldp->yBitmap;
1065 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1066 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1067 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1068 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1069 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1070 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1071 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1073 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1074 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1076 /* we will use these DCs to access the images and masks in the ImageList */
1077 hImageListDC = himl->hdcImage;
1078 hMaskListDC = himl->hdcMask;
1080 /* these will accumulate the image and mask for the image we're drawing */
1081 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1082 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1083 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1085 /* Create a compatible DC. */
1086 if (!hImageListDC || !hImageDC || !hImageBmp ||
1087 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1090 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1093 * To obtain a transparent look, background color should be set
1094 * to white and foreground color to black when blting the
1097 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1098 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1101 * Draw the initial image
1103 if(fStyle & ILD_MASK) {
1104 if (himl->hbmMask) {
1105 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1107 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1108 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1109 SelectObject(hImageDC, hOldBrush);
1111 } else if (himl->hbmMask && !bIsTransparent) {
1112 /* blend the image with the needed solid background */
1113 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1114 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1115 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1116 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1117 DeleteObject (SelectObject (hImageDC, hOldBrush));
1119 /* start off with the image, if we have a mask, we'll use it later */
1120 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1123 /* Time for blending, if required */
1125 HBRUSH hBlendBrush, hOldBrush;
1126 COLORREF clrBlend = pimldp->rgbFg;
1127 HDC hBlendMaskDC = hImageListDC;
1130 /* Create the blend Mask */
1131 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1132 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1133 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1134 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1135 SelectObject(hBlendMaskDC, hOldBrush);
1137 /* Modify the blend mask if an Image Mask exist */
1139 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1140 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1143 /* now apply blend to the current image given the BlendMask */
1144 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1145 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1146 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1147 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1148 DeleteObject(SelectObject(hImageDC, hOldBrush));
1149 SelectObject(hBlendMaskDC, hOldBitmap);
1152 /* Now do the overlay image, if any */
1153 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1154 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1155 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1156 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1157 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1158 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1159 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1160 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1164 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1165 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1166 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1167 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1169 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1170 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1171 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1173 /* now copy the image to the screen */
1175 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1176 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1177 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1178 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1179 SetBkColor(pimldp->hdcDst, oldDstBk);
1180 SetTextColor(pimldp->hdcDst, oldDstFg);
1183 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1184 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1188 /* cleanup the mess */
1189 SetBkColor(hImageDC, oldImageBk);
1190 SetTextColor(hImageDC, oldImageFg);
1191 SelectObject(hImageDC, hOldImageBmp);
1193 DeleteObject(hBlendMaskBmp);
1194 DeleteObject(hImageBmp);
1201 /*************************************************************************
1202 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1205 * himlSrc [I] source image list handle
1208 * Success: Handle of duplicated image list.
1213 ImageList_Duplicate (HIMAGELIST himlSrc)
1217 if (!is_valid(himlSrc)) {
1218 ERR("Invalid image list handle!\n");
1222 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1223 himlSrc->cInitial, himlSrc->cGrow);
1227 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1228 himlSrc->hdcImage, 0, 0, SRCCOPY);
1230 if (himlDst->hbmMask)
1231 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1232 himlSrc->hdcMask, 0, 0, SRCCOPY);
1234 himlDst->cCurImage = himlSrc->cCurImage;
1235 himlDst->cMaxImage = himlSrc->cMaxImage;
1241 /*************************************************************************
1242 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1244 * Finishes a drag operation.
1255 ImageList_EndDrag (void)
1257 /* cleanup the InternalDrag struct */
1258 InternalDrag.hwnd = 0;
1259 ImageList_Destroy (InternalDrag.himl);
1260 InternalDrag.himl = 0;
1263 InternalDrag.dxHotspot = 0;
1264 InternalDrag.dyHotspot = 0;
1265 InternalDrag.bShow = FALSE;
1266 DeleteObject(InternalDrag.hbmBg);
1267 InternalDrag.hbmBg = 0;
1268 InternalDrag.bHSPending = FALSE;
1272 /*************************************************************************
1273 * ImageList_GetBkColor [COMCTL32.@]
1275 * Returns the background color of an image list.
1278 * himl [I] Image list handle.
1281 * Success: background color
1286 ImageList_GetBkColor (HIMAGELIST himl)
1288 return himl ? himl->clrBk : CLR_NONE;
1292 /*************************************************************************
1293 * ImageList_GetDragImage [COMCTL32.@]
1295 * Returns the handle to the internal drag image list.
1298 * ppt [O] Pointer to the drag position. Can be NULL.
1299 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1302 * Success: Handle of the drag image list.
1307 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1309 if (is_valid(InternalDrag.himl)) {
1311 ppt->x = InternalDrag.x;
1312 ppt->y = InternalDrag.y;
1315 pptHotspot->x = InternalDrag.dxHotspot;
1316 pptHotspot->y = InternalDrag.dyHotspot;
1318 return (InternalDrag.himl);
1325 /*************************************************************************
1326 * ImageList_GetFlags [COMCTL32.@]
1333 ImageList_GetFlags(HIMAGELIST himl)
1335 FIXME("(%p):empty stub\n", himl);
1340 /*************************************************************************
1341 * ImageList_GetIcon [COMCTL32.@]
1343 * Creates an icon from a masked image of an image list.
1346 * himl [I] handle to image list
1348 * flags [I] drawing style flags
1351 * Success: icon handle
1356 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1360 HBITMAP hOldDstBitmap;
1363 TRACE("%p %d %d\n", himl, i, fStyle);
1364 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1366 hdcDst = CreateCompatibleDC(0);
1373 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1374 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1375 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1376 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1379 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1380 SelectObject (hdcDst, ii.hbmColor);
1381 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1382 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1385 * CreateIconIndirect requires us to deselect the bitmaps from
1386 * the DCs before calling
1388 SelectObject(hdcDst, hOldDstBitmap);
1390 hIcon = CreateIconIndirect (&ii);
1392 DeleteObject (ii.hbmMask);
1393 DeleteObject (ii.hbmColor);
1400 /*************************************************************************
1401 * ImageList_GetIconSize [COMCTL32.@]
1403 * Retrieves the size of an image in an image list.
1406 * himl [I] handle to image list
1407 * cx [O] pointer to the image width.
1408 * cy [O] pointer to the image height.
1415 * All images in an image list have the same size.
1419 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1421 if (!is_valid(himl))
1423 if ((himl->cx <= 0) || (himl->cy <= 0))
1435 /*************************************************************************
1436 * ImageList_GetImageCount [COMCTL32.@]
1438 * Returns the number of images in an image list.
1441 * himl [I] handle to image list
1444 * Success: Number of images.
1449 ImageList_GetImageCount (HIMAGELIST himl)
1451 if (!is_valid(himl))
1454 return himl->cCurImage;
1458 /*************************************************************************
1459 * ImageList_GetImageInfo [COMCTL32.@]
1461 * Returns information about an image in an image list.
1464 * himl [I] handle to image list
1466 * pImageInfo [O] pointer to the image information
1474 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1476 if (!is_valid(himl) || (pImageInfo == NULL))
1478 if ((i < 0) || (i >= himl->cCurImage))
1481 pImageInfo->hbmImage = himl->hbmImage;
1482 pImageInfo->hbmMask = himl->hbmMask;
1484 pImageInfo->rcImage.top = 0;
1485 pImageInfo->rcImage.bottom = himl->cy;
1486 pImageInfo->rcImage.left = i * himl->cx;
1487 pImageInfo->rcImage.right = (i+1) * himl->cx;
1493 /*************************************************************************
1494 * ImageList_GetImageRect [COMCTL32.@]
1496 * Retrieves the rectangle of the specified image in an image list.
1499 * himl [I] handle to image list
1501 * lpRect [O] pointer to the image rectangle
1508 * This is an UNDOCUMENTED function!!!
1512 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1514 if (!is_valid(himl) || (lpRect == NULL))
1516 if ((i < 0) || (i >= himl->cCurImage))
1519 lpRect->left = i * himl->cx;
1521 lpRect->right = lpRect->left + himl->cx;
1522 lpRect->bottom = himl->cy;
1528 /*************************************************************************
1529 * ImageList_LoadImage [COMCTL32.@]
1530 * ImageList_LoadImageA [COMCTL32.@]
1532 * Creates an image list from a bitmap, icon or cursor.
1535 * hi [I] instance handle
1536 * lpbmp [I] name or id of the image
1537 * cx [I] width of each image
1538 * cGrow [I] number of images to expand
1539 * clrMask [I] mask color
1540 * uType [I] type of image to load
1541 * uFlags [I] loading flags
1544 * Success: handle to the loaded image list
1552 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1553 COLORREF clrMask, UINT uType, UINT uFlags)
1555 HIMAGELIST himl = NULL;
1559 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1561 ERR("Error loading image!\n");
1565 if (uType == IMAGE_BITMAP) {
1567 GetObjectA (handle, sizeof(BITMAP), &bmp);
1569 /* To match windows behavior, if cx is set to zero and
1570 the flag DI_DEFAULTSIZE is specified, cx becomes the
1571 system metric value for icons. If the flag is not specified
1572 the function sets the size to the height of the bitmap */
1575 if (uFlags & DI_DEFAULTSIZE)
1576 cx = GetSystemMetrics (SM_CXICON);
1581 nImageCount = bmp.bmWidth / cx;
1583 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1584 nImageCount, cGrow);
1586 DeleteObject (handle);
1589 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1591 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1595 GetIconInfo (handle, &ii);
1596 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1597 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1598 ILC_MASK | ILC_COLOR, 1, cGrow);
1600 DeleteObject (ii.hbmColor);
1601 DeleteObject (ii.hbmMask);
1602 DeleteObject (handle);
1605 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1606 DeleteObject (ii.hbmColor);
1607 DeleteObject (ii.hbmMask);
1610 DeleteObject (handle);
1616 /*************************************************************************
1617 * ImageList_LoadImageW [COMCTL32.@]
1619 * Creates an image list from a bitmap, icon or cursor.
1622 * hi [I] instance handle
1623 * lpbmp [I] name or id of the image
1624 * cx [I] width of each image
1625 * cGrow [I] number of images to expand
1626 * clrMask [I] mask color
1627 * uType [I] type of image to load
1628 * uFlags [I] loading flags
1631 * Success: handle to the loaded image list
1639 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1640 COLORREF clrMask, UINT uType, UINT uFlags)
1642 HIMAGELIST himl = NULL;
1646 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1648 ERR("Error loading image!\n");
1652 if (uType == IMAGE_BITMAP) {
1654 GetObjectA (handle, sizeof(BITMAP), &bmp);
1656 /* To match windows behavior, if cx is set to zero and
1657 the flag DI_DEFAULTSIZE is specified, cx becomes the
1658 system metric value for icons. If the flag is not specified
1659 the function sets the size to the height of the bitmap */
1662 if (uFlags & DI_DEFAULTSIZE)
1663 cx = GetSystemMetrics (SM_CXICON);
1668 nImageCount = bmp.bmWidth / cx;
1670 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1671 nImageCount, cGrow);
1673 DeleteObject (handle);
1676 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1678 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1682 GetIconInfo (handle, &ii);
1683 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1684 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1685 ILC_MASK | ILC_COLOR, 1, cGrow);
1687 DeleteObject (ii.hbmColor);
1688 DeleteObject (ii.hbmMask);
1689 DeleteObject (handle);
1692 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1693 DeleteObject (ii.hbmColor);
1694 DeleteObject (ii.hbmMask);
1697 DeleteObject (handle);
1703 /*************************************************************************
1704 * ImageList_Merge [COMCTL32.@]
1706 * Creates a new image list that contains a merged image from the specified
1707 * images of both source image lists.
1710 * himl1 [I] handle to first image list
1711 * i1 [I] first image index
1712 * himl2 [I] handle to second image list
1713 * i2 [I] second image index
1714 * dx [I] X offset of the second image relative to the first.
1715 * dy [I] Y offset of the second image relative to the first.
1718 * Success: handle of the merged image list.
1723 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1726 HIMAGELIST himlDst = NULL;
1728 INT xOff1, yOff1, xOff2, yOff2;
1731 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1734 if (!is_valid(himl1) || !is_valid(himl2))
1738 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1739 ERR("Index 1 out of range! %d\n", i1);
1743 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1744 ERR("Index 2 out of range! %d\n", i2);
1749 cxDst = max (himl1->cx, dx + himl2->cx);
1754 cxDst = max (himl2->cx, himl1->cx - dx);
1759 cxDst = max (himl1->cx, himl2->cx);
1765 cyDst = max (himl1->cy, dy + himl2->cy);
1770 cyDst = max (himl2->cy, himl1->cy - dy);
1775 cyDst = max (himl1->cy, himl2->cy);
1780 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1785 nX1 = i1 * himl1->cx;
1786 nX2 = i2 * himl2->cx;
1789 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1790 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1791 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1792 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1795 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1796 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1797 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1799 himlDst->cCurImage = 1;
1806 /* helper for _read_bitmap currently unused */
1808 static int may_use_dibsection(HDC hdc) {
1809 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1814 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1818 /* helper for ImageList_Read, see comments below */
1819 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1820 HDC xdc = 0, hBitmapDC =0;
1821 BITMAPFILEHEADER bmfh;
1822 BITMAPINFOHEADER bmih;
1823 int bitsperpixel,palspace,longsperline,width,height;
1824 LPBITMAPINFOHEADER bmihc = NULL;
1826 HBITMAP hbitmap = 0, hDIB = 0;
1829 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1830 (bmfh.bfType != (('M'<<8)|'B')) ||
1831 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1832 (bmih.biSize != sizeof(bmih))
1836 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1837 if (bitsperpixel<=8)
1838 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1841 width = bmih.biWidth;
1842 height = bmih.biHeight;
1843 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1844 memcpy(bmihc,&bmih,sizeof(bmih));
1845 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1846 bmihc->biSizeImage = (longsperline*height)<<2;
1848 /* read the palette right after the end of the bitmapinfoheader */
1850 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1854 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1855 if ((bitsperpixel>1) &&
1856 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1858 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1861 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1867 int i,nwidth,nheight,nRows;
1869 nwidth = width*(height/cy);
1871 nRows = (height/cy);
1873 if (bitsperpixel==1)
1874 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1876 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1878 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1881 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1884 hBitmapDC = CreateCompatibleDC(0);
1885 SelectObject(hBitmapDC, hbitmap);
1887 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1888 /* Do not forget that windows bitmaps are bottom->top */
1889 TRACE("nRows=%d\n", nRows);
1890 for (i=0; i < nRows; i++){
1891 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1892 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1898 if (xdc) ReleaseDC(0,xdc);
1899 if (bmihc) LocalFree((HLOCAL)bmihc);
1900 if (hDIB) DeleteObject(hDIB);
1901 if (hBitmapDC) DeleteDC(hBitmapDC);
1904 DeleteObject(hbitmap);
1911 /*************************************************************************
1912 * ImageList_Read [COMCTL32.@]
1914 * Reads an image list from a stream.
1917 * pstm [I] pointer to a stream
1920 * Success: handle to image list
1923 * The format is like this:
1924 * ILHEAD ilheadstruct;
1926 * for the color image part:
1927 * BITMAPFILEHEADER bmfh;
1928 * BITMAPINFOHEADER bmih;
1929 * only if it has a palette:
1930 * RGBQUAD rgbs[nr_of_paletted_colors];
1932 * BYTE colorbits[imagesize];
1934 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1935 * BITMAPFILEHEADER bmfh_mask;
1936 * BITMAPINFOHEADER bmih_mask;
1937 * only if it has a palette (it usually does not):
1938 * RGBQUAD rgbs[nr_of_paletted_colors];
1940 * BYTE maskbits[imagesize];
1942 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1943 * _read_bitmap needs to convert them.
1945 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1949 HBITMAP hbmColor=0,hbmMask=0;
1952 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1954 if (ilHead.usMagic != (('L' << 8) | 'I'))
1956 if (ilHead.usVersion != 0x101) /* probably version? */
1960 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1961 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1962 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1963 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1964 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1965 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1966 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1967 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1968 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1969 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1972 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1975 if (ilHead.flags & ILC_MASK) {
1976 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1978 DeleteObject(hbmColor);
1983 himl = ImageList_Create (
1991 DeleteObject(hbmColor);
1992 DeleteObject(hbmMask);
1995 SelectObject(himl->hdcImage, hbmColor);
1996 DeleteObject(himl->hbmImage);
1997 himl->hbmImage = hbmColor;
1999 SelectObject(himl->hdcMask, hbmMask);
2000 DeleteObject(himl->hbmMask);
2001 himl->hbmMask = hbmMask;
2003 himl->cCurImage = ilHead.cCurImage;
2004 himl->cMaxImage = ilHead.cMaxImage;
2006 ImageList_SetBkColor(himl,ilHead.bkcolor);
2008 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2013 /*************************************************************************
2014 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2017 * himl [I] image list handle
2026 ImageList_Remove (HIMAGELIST himl, INT i)
2028 HBITMAP hbmNewImage, hbmNewMask;
2032 TRACE("(himl=%p i=%d)\n", himl, i);
2034 if (!is_valid(himl)) {
2035 ERR("Invalid image list handle!\n");
2039 if ((i < -1) || (i >= himl->cCurImage)) {
2040 ERR("index out of range! %d\n", i);
2046 if (himl->cCurImage == 0) {
2047 /* remove all on empty ImageList is allowed */
2048 TRACE("remove all on empty ImageList!\n");
2052 himl->cMaxImage = himl->cInitial + himl->cGrow;
2053 himl->cCurImage = 0;
2054 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2055 himl->nOvlIdx[nCount] = -1;
2057 hbmNewImage = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2058 1, himl->uBitsPixel, NULL);
2059 SelectObject (himl->hdcImage, hbmNewImage);
2060 DeleteObject (himl->hbmImage);
2061 himl->hbmImage = hbmNewImage;
2063 if (himl->hbmMask) {
2064 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2066 SelectObject (himl->hdcMask, hbmNewMask);
2067 DeleteObject (himl->hbmMask);
2068 himl->hbmMask = hbmNewMask;
2072 /* delete one image */
2073 TRACE("Remove single image! %d\n", i);
2075 /* create new bitmap(s) */
2076 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2078 TRACE(" - Number of images: %d / %d (Old/New)\n",
2079 himl->cCurImage, himl->cCurImage - 1);
2080 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2081 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2084 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2087 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2089 hbmNewMask = 0; /* Just to keep compiler happy! */
2091 hdcBmp = CreateCompatibleDC (0);
2093 /* copy all images and masks prior to the "removed" image */
2095 TRACE("Pre image copy: Copy %d images\n", i);
2097 SelectObject (hdcBmp, hbmNewImage);
2098 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2099 himl->hdcImage, 0, 0, SRCCOPY);
2101 if (himl->hbmMask) {
2102 SelectObject (hdcBmp, hbmNewMask);
2103 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2104 himl->hdcMask, 0, 0, SRCCOPY);
2108 /* copy all images and masks behind the removed image */
2109 if (i < himl->cCurImage - 1) {
2110 TRACE("Post image copy!\n");
2111 SelectObject (hdcBmp, hbmNewImage);
2112 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2113 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2115 if (himl->hbmMask) {
2116 SelectObject (hdcBmp, hbmNewMask);
2117 BitBlt (hdcBmp, i * himl->cx, 0,
2118 (himl->cCurImage - i - 1) * himl->cx,
2119 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2125 /* delete old images and insert new ones */
2126 SelectObject (himl->hdcImage, hbmNewImage);
2127 DeleteObject (himl->hbmImage);
2128 himl->hbmImage = hbmNewImage;
2129 if (himl->hbmMask) {
2130 SelectObject (himl->hdcMask, hbmNewMask);
2131 DeleteObject (himl->hbmMask);
2132 himl->hbmMask = hbmNewMask;
2136 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2143 /*************************************************************************
2144 * ImageList_Replace [COMCTL32.@]
2146 * Replaces an image in an image list with a new image.
2149 * himl [I] handle to image list
2151 * hbmImage [I] handle to image bitmap
2152 * hbmMask [I] handle to mask bitmap. Can be NULL.
2160 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2166 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2168 if (!is_valid(himl)) {
2169 ERR("Invalid image list handle!\n");
2173 if ((i >= himl->cMaxImage) || (i < 0)) {
2174 ERR("Invalid image index!\n");
2178 hdcImage = CreateCompatibleDC (0);
2179 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2182 SelectObject (hdcImage, hbmImage);
2184 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2185 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2190 SelectObject (hdcImage, hbmMask);
2192 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2193 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2196 /* Remove the background from the image
2198 StretchBlt (himl->hdcImage,
2199 i*himl->cx, 0, himl->cx, himl->cy,
2201 0, 0, bmp.bmWidth, bmp.bmHeight,
2202 0x220326); /* NOTSRCAND */
2205 DeleteDC (hdcImage);
2211 /*************************************************************************
2212 * ImageList_ReplaceIcon [COMCTL32.@]
2214 * Replaces an image in an image list using an icon.
2217 * himl [I] handle to image list
2219 * hIcon [I] handle to icon
2222 * Success: index of the replaced image
2227 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2236 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2238 if (!is_valid(himl))
2240 if ((i >= himl->cMaxImage) || (i < -1))
2243 hBestFitIcon = CopyImage(
2246 LR_COPYFROMRESOURCE);
2248 GetIconInfo (hBestFitIcon, &ii);
2249 if (ii.hbmMask == 0)
2251 if (ii.hbmColor == 0)
2253 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2256 if (himl->cCurImage + 1 > himl->cMaxImage)
2257 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2259 nIndex = himl->cCurImage;
2265 hdcImage = CreateCompatibleDC (0);
2266 TRACE("hdcImage=%p\n", hdcImage);
2268 ERR("invalid hdcImage!\n");
2270 SetTextColor(himl->hdcImage, RGB(0,0,0));
2271 SetBkColor (himl->hdcImage, RGB(255,255,255));
2272 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2274 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2275 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2277 if (himl->hbmMask) {
2278 SelectObject (hdcImage, ii.hbmMask);
2279 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2280 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2283 SelectObject (hdcImage, hbmOldSrc);
2286 DestroyIcon(hBestFitIcon);
2288 DeleteDC (hdcImage);
2290 DeleteObject (ii.hbmColor);
2292 DeleteObject (ii.hbmMask);
2298 /*************************************************************************
2299 * ImageList_SetBkColor [COMCTL32.@]
2301 * Sets the background color of an image list.
2304 * himl [I] handle to image list
2305 * clrBk [I] background color
2308 * Success: previous background color
2313 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2317 if (!is_valid(himl))
2320 clrOldBk = himl->clrBk;
2321 himl->clrBk = clrBk;
2326 /*************************************************************************
2327 * ImageList_SetDragCursorImage [COMCTL32.@]
2329 * Combines the specified image with the current drag image
2332 * himlDrag [I] handle to drag image list
2333 * iDrag [I] drag image index
2334 * dxHotspot [I] X position of the hot spot
2335 * dyHotspot [I] Y position of the hot spot
2342 * When this function is called and the drag image is visible, a
2343 * short flickering occurs but this matches the Win9x behavior. It is
2344 * possible to fix the flickering using code like in ImageList_DragMove.
2348 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2349 INT dxHotspot, INT dyHotspot)
2351 HIMAGELIST himlTemp;
2355 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2358 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2359 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2361 visible = InternalDrag.bShow;
2363 /* Calculate the offset between the origin of the old image and the
2364 * origin of the second image.
2365 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2366 * hotspot) to the origin of the second image.
2367 * See M$DN for details */
2368 if(InternalDrag.bHSPending) {
2371 InternalDrag.bHSPending = FALSE;
2373 dx = InternalDrag.dxHotspot - dxHotspot;
2374 dy = InternalDrag.dyHotspot - dyHotspot;
2376 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2379 /* hide the drag image */
2380 ImageList_DragShowNolock(FALSE);
2382 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2383 (InternalDrag.himl->cy != himlTemp->cy)) {
2384 /* the size of the drag image changed, invalidate the buffer */
2385 DeleteObject(InternalDrag.hbmBg);
2386 InternalDrag.hbmBg = 0;
2389 ImageList_Destroy (InternalDrag.himl);
2390 InternalDrag.himl = himlTemp;
2392 /* update the InternalDragOffset, if the origin of the
2393 * DragImage was changed by ImageList_Merge. */
2395 InternalDrag.dxHotspot = dxHotspot;
2397 InternalDrag.dyHotspot = dyHotspot;
2400 /* show the drag image */
2401 ImageList_DragShowNolock(TRUE);
2408 /*************************************************************************
2409 * ImageList_SetFilter [COMCTL32.@]
2411 * Sets a filter (or does something completely different)!!???
2412 * It removes 12 Bytes from the stack (3 Parameters).
2415 * himl [I] SHOULD be a handle to image list
2416 * i [I] COULD be an index?
2421 * Failure: FALSE ???
2424 * This is an UNDOCUMENTED function!!!!
2429 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2431 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2437 /*************************************************************************
2438 * ImageList_SetFlags [COMCTL32.@]
2445 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2447 FIXME("(%p %08lx):empty stub\n", himl, flags);
2452 /*************************************************************************
2453 * ImageList_SetIconSize [COMCTL32.@]
2455 * Sets the image size of the bitmap and deletes all images.
2458 * himl [I] handle to image list
2459 * cx [I] image width
2460 * cy [I] image height
2468 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2473 if (!is_valid(himl))
2476 /* remove all images */
2477 himl->cMaxImage = himl->cInitial + himl->cGrow;
2478 himl->cCurImage = 0;
2482 /* initialize overlay mask indices */
2483 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2484 himl->nOvlIdx[nCount] = -1;
2486 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2487 1, himl->uBitsPixel, NULL);
2488 SelectObject (himl->hdcImage, hbmNew);
2489 DeleteObject (himl->hbmImage);
2490 himl->hbmImage = hbmNew;
2492 if (himl->hbmMask) {
2493 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2495 SelectObject (himl->hdcMask, hbmNew);
2496 DeleteObject (himl->hbmMask);
2497 himl->hbmMask = hbmNew;
2504 /*************************************************************************
2505 * ImageList_SetImageCount [COMCTL32.@]
2507 * Resizes an image list to the specified number of images.
2510 * himl [I] handle to image list
2511 * iImageCount [I] number of images in the image list
2519 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2522 HBITMAP hbmNewBitmap;
2523 INT nNewCount, nCopyCount;
2525 TRACE("%p %d\n",himl,iImageCount);
2527 if (!is_valid(himl))
2529 if (himl->cCurImage >= iImageCount)
2531 if (himl->cMaxImage > iImageCount)
2533 himl->cCurImage = iImageCount;
2537 nNewCount = iImageCount + himl->cGrow;
2538 nCopyCount = min(himl->cCurImage, iImageCount);
2540 hdcBitmap = CreateCompatibleDC (0);
2542 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2543 1, himl->uBitsPixel, NULL);
2544 if (hbmNewBitmap != 0)
2546 SelectObject (hdcBitmap, hbmNewBitmap);
2549 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2550 himl->hdcImage, 0, 0, SRCCOPY);
2552 /* delete 'empty' image space */
2553 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2554 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2555 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2556 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2558 SelectObject (himl->hdcImage, hbmNewBitmap);
2559 DeleteObject (himl->hbmImage);
2560 himl->hbmImage = hbmNewBitmap;
2563 ERR("Could not create new image bitmap !\n");
2567 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2569 if (hbmNewBitmap != 0)
2571 SelectObject (hdcBitmap, hbmNewBitmap);
2574 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2575 himl->hdcMask, 0, 0, SRCCOPY);
2577 /* delete 'empty' image space */
2578 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2579 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2580 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2581 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2583 SelectObject (himl->hdcMask, hbmNewBitmap);
2584 DeleteObject (himl->hbmMask);
2585 himl->hbmMask = hbmNewBitmap;
2588 ERR("Could not create new mask bitmap!\n");
2591 DeleteDC (hdcBitmap);
2593 /* Update max image count and current image count */
2594 himl->cMaxImage = nNewCount;
2595 himl->cCurImage = iImageCount;
2601 /*************************************************************************
2602 * ImageList_SetOverlayImage [COMCTL32.@]
2604 * Assigns an overlay mask index to an existing image in an image list.
2607 * himl [I] handle to image list
2608 * iImage [I] image index
2609 * iOverlay [I] overlay mask index
2617 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2619 if (!is_valid(himl))
2621 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2623 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2625 himl->nOvlIdx[iOverlay - 1] = iImage;
2631 /* helper for ImageList_Write - write bitmap to pstm
2632 * currently everything is written as 24 bit RGB, except masks
2635 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2637 LPBITMAPFILEHEADER bmfh;
2638 LPBITMAPINFOHEADER bmih;
2639 LPBYTE data, lpBits, lpBitsOrg;
2641 INT bitCount, sizeImage, offBits, totalSize;
2642 INT nwidth, nheight, nsizeImage, icount;
2644 BOOL result = FALSE;
2648 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2650 /* XXX is this always correct? */
2651 icount = bm.bmWidth / cx;
2653 nheight = cy * ((icount+3)>>2);
2655 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2656 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2657 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2659 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2661 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2662 offBits = totalSize;
2663 totalSize += nsizeImage;
2665 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2666 bmfh = (LPBITMAPFILEHEADER)data;
2667 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2668 lpBits = data + offBits;
2670 /* setup BITMAPFILEHEADER */
2671 bmfh->bfType = (('M' << 8) | 'B');
2673 bmfh->bfReserved1 = 0;
2674 bmfh->bfReserved2 = 0;
2675 bmfh->bfOffBits = offBits;
2677 /* setup BITMAPINFOHEADER */
2678 bmih->biSize = sizeof(BITMAPINFOHEADER);
2679 bmih->biWidth = bm.bmWidth;
2680 bmih->biHeight = bm.bmHeight;
2682 bmih->biBitCount = bitCount;
2683 bmih->biCompression = BI_RGB;
2684 bmih->biSizeImage = nsizeImage;
2685 bmih->biXPelsPerMeter = 0;
2686 bmih->biYPelsPerMeter = 0;
2687 bmih->biClrUsed = 0;
2688 bmih->biClrImportant = 0;
2690 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2691 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2692 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2696 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2697 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2699 for(i = 0; i < nheight; i++) {
2700 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2701 int noff = (nbpl * (nheight-1-i));
2702 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2706 bmih->biWidth = nwidth;
2707 bmih->biHeight = nheight;
2711 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2712 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2713 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2716 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2723 LocalFree((HLOCAL)lpBitsOrg);
2729 /*************************************************************************
2730 * ImageList_Write [COMCTL32.@]
2732 * Writes an image list to a stream.
2735 * himl [I] handle to image list
2736 * pstm [O] Pointer to a stream.
2747 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2752 if (!is_valid(himl))
2755 ilHead.usMagic = (('L' << 8) | 'I');
2756 ilHead.usVersion = 0x101;
2757 ilHead.cCurImage = himl->cCurImage;
2758 ilHead.cMaxImage = himl->cMaxImage;
2759 ilHead.cGrow = himl->cGrow;
2760 ilHead.cx = himl->cx;
2761 ilHead.cy = himl->cy;
2762 ilHead.bkcolor = himl->clrBk;
2763 ilHead.flags = himl->flags;
2764 for(i = 0; i < 4; i++) {
2765 ilHead.ovls[i] = himl->nOvlIdx[i];
2768 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2771 /* write the bitmap */
2772 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2775 /* write the mask if we have one */
2776 if(himl->flags & ILC_MASK) {
2777 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))