2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
7 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
8 * - Fix ImageList_GetIcon.
9 * - Fix drag functions.
10 * - Fix ImageList_Write.
11 * - Fix ImageList_SetFilter (undocumented).
12 * BTW does anybody know anything about this function???
13 * - It removes 12 Bytes from the stack (3 Parameters).
14 * - First parameter SHOULD be a HIMAGELIST.
15 * - Second parameter COULD be an index?????
16 * - Third parameter.... ?????????????????????
19 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
20 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
21 * partially imlemented, the functions mentioned above will be
22 * limited in functionality too.
25 /* This must be defined because the HIMAGELIST type is just a pointer
26 * to the _IMAGELIST data structure. But M$ does not want us to know
27 * anything about its contents. Applications just see a pointer to
28 * an empty structure. It's just to keep compatibility.
30 #define __WINE_IMAGELIST_C
33 #include "wine/obj_base.h"
34 #include "wine/obj_storage.h"
35 #include "imagelist.h"
37 #include "debugtools.h"
40 DEFAULT_DEBUG_CHANNEL(imagelist)
43 #define _MAX(a,b) (((a)>(b))?(a):(b))
44 #define _MIN(a,b) (((a)>(b))?(b):(a))
46 #define MAX_OVERLAYIMAGE 15
49 /* internal image list data used for Drag & Drop operations */
51 static HIMAGELIST himlInternalDrag = NULL;
52 static INT nInternalDragHotspotX = 0;
53 static INT nInternalDragHotspotY = 0;
55 static HWND hwndInternalDrag = 0;
56 static INT xInternalPos = 0;
57 static INT yInternalPos = 0;
59 static HDC hdcBackBuffer = 0;
60 static HBITMAP hbmBackBuffer = 0;
63 /*************************************************************************
64 * IMAGELIST_InternalExpandBitmaps [Internal]
66 * Expands the bitmaps of an image list by the given number of images.
69 * himl [I] handle to image list
70 * nImageCount [I] number of images to add
76 * This function can NOT be used to reduce the number of images.
79 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount)
81 HDC hdcImageList, hdcBitmap;
83 INT nNewWidth, nNewCount;
85 TRACE("Create expanded bitmaps!\n");
87 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
88 nNewWidth = nNewCount * himl->cx;
90 hdcImageList = CreateCompatibleDC (0);
91 hdcBitmap = CreateCompatibleDC (0);
94 CreateBitmap (nNewWidth, himl->cy, 1, himl->uBitsPixel, NULL);
95 if (hbmNewBitmap == 0)
96 ERR("creating new image bitmap!\n");
98 SelectObject (hdcImageList, himl->hbmImage);
99 SelectObject (hdcBitmap, hbmNewBitmap);
100 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, himl->cy,
101 hdcImageList, 0, 0, SRCCOPY);
103 DeleteObject (himl->hbmImage);
104 himl->hbmImage = hbmNewBitmap;
108 CreateBitmap (nNewWidth, himl->cy, 1, 1, NULL);
110 if (hbmNewBitmap == 0)
111 ERR("creating new mask bitmap!");
113 SelectObject (hdcImageList, himl->hbmMask);
114 SelectObject (hdcBitmap, hbmNewBitmap);
115 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, himl->cy,
116 hdcImageList, 0, 0, SRCCOPY);
117 DeleteObject (himl->hbmMask);
118 himl->hbmMask = hbmNewBitmap;
121 himl->cMaxImage = nNewCount;
123 DeleteDC (hdcImageList);
124 DeleteDC (hdcBitmap);
128 /*************************************************************************
129 * IMAGELIST_InternalDraw [Internal]
131 * Draws the image in the ImageList (without the mask)
134 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
135 * cx [I] the width of the image to display
136 * cy............[I] the height of the image to display
142 * This functions is used by ImageList_DrawIndirect, when it is
143 * required to draw only the Image (without the mask) to the screen.
145 * Blending and Overlays styles are accomplised by another function
148 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
153 hImageDC = CreateCompatibleDC(0);
154 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
155 BitBlt(pimldp->hdcDst,
156 pimldp->x, pimldp->y, cx, cy,
158 pimldp->himl->cx * pimldp->i, 0,
161 SelectObject(hImageDC, hOldBitmap);
166 /*************************************************************************
167 * IMAGELIST_InternalDrawMask [Internal]
169 * Draws the image in the ImageList witht the mask
172 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
173 * cx [I] the width of the image to display
174 * cy............[I] the height of the image to display
180 * This functions is used by ImageList_DrawIndirect, when it is
181 * required to draw the Image with the mask to the screen.
183 * Blending and Overlays styles are accomplised by another function.
186 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
188 HDC hMaskDC, hImageDC;
189 BOOL bUseCustomBackground, bBlendFlag;
190 HBRUSH hBrush, hOldBrush;
191 HBITMAP hOldBitmapImage, hOldBitmapMask;
192 HIMAGELIST himlLocal = pimldp->himl;
193 COLORREF oldBkColor, oldFgColor;
195 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
196 bBlendFlag = (pimldp->fStyle & ILD_BLEND50 )
197 || (pimldp->fStyle & ILD_BLEND25);
199 hImageDC = CreateCompatibleDC(0);
200 hMaskDC = CreateCompatibleDC(0);
202 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
203 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
204 /* Draw the Background for the appropriate Styles
206 if( bUseCustomBackground && (pimldp->fStyle == ILD_NORMAL
207 || (pimldp->fStyle & ILD_IMAGE)
210 hBrush = CreateSolidBrush (himlLocal->clrBk);
211 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
212 PatBlt (pimldp->hdcDst,
213 pimldp->x, pimldp->y, cx, cy,
216 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
219 /* Draw Image Transparently over the current background
221 if(pimldp->fStyle == ILD_NORMAL
222 || (pimldp->fStyle & ILD_TRANSPARENT)
223 || ((pimldp->fStyle & ILD_IMAGE) && bUseCustomBackground)
226 /* to obtain a transparent look, background color should be set
227 to white and foreground color to black when blting the
229 oldBkColor = SetBkColor(pimldp->hdcDst, RGB(0xff, 0xff, 0xff));
230 oldFgColor = SetTextColor(pimldp->hdcDst, RGB(0, 0, 0));
232 BitBlt(pimldp->hdcDst,
233 pimldp->x, pimldp->y, cx, cy,
235 himlLocal->cx * pimldp->i, 0,
238 BitBlt(pimldp->hdcDst,
239 pimldp->x, pimldp->y, cx, cy,
241 himlLocal->cx * pimldp->i, 0,
244 SetBkColor(pimldp->hdcDst, oldBkColor);
245 SetTextColor(pimldp->hdcDst, oldFgColor);
247 /* Draw the image when no Background is specified
249 else if((pimldp->fStyle & ILD_IMAGE) && !bUseCustomBackground)
251 BitBlt(pimldp->hdcDst,
252 pimldp->x, pimldp->y, cx, cy,
254 himlLocal->cx * pimldp->i, 0,
257 /* Draw the mask with or without a background
259 else if(pimldp->fStyle & ILD_MASK)
261 BitBlt(pimldp->hdcDst,
262 pimldp->x, pimldp->y, cx, cy,
264 himlLocal->cx * pimldp->i, 0,
265 bUseCustomBackground ? SRCCOPY : SRCAND);
267 SelectObject(hImageDC, hOldBitmapImage);
268 SelectObject(hMaskDC, hOldBitmapMask);
273 /*************************************************************************
274 * IMAGELIST_InternalDrawBlend [Internal]
276 * Draws the Blend over the current image
279 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
280 * cx [I] the width of the image to display
281 * cy............[I] the height of the image to display
287 * This functions is used by ImageList_DrawIndirect, when it is
288 * required to add the blend to the current image.
292 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
295 HDC hBlendMaskDC,hMaskDC;
296 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
297 HBITMAP hBlendMaskBitmap, hOldBitmap;
298 COLORREF clrBlend, OldTextColor, OldBkColor;
299 HIMAGELIST himlLocal = pimldp->himl;
301 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
302 if (!(pimldp->rgbFg == CLR_DEFAULT))
304 clrBlend = pimldp->rgbFg;
306 /* Create the blend Mask
308 hBlendMaskDC = CreateCompatibleDC(0);
309 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
310 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
312 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
313 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
315 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
316 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
317 SelectObject(hBlendMaskDC, hOldBrush);
319 /* Modify the blend mask if an Image Mask exist
321 if(pimldp->himl->hbmMask != 0)
323 HBITMAP hOldMaskBitmap;
324 hMaskDC = CreateCompatibleDC(0);
325 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
330 himlLocal->cx * pimldp->i,0,
331 0x220326); /* NOTSRCAND */
339 SelectObject(hMaskDC, hOldMaskBitmap);
343 /* Apply blend to the current image given the BlendMask
345 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
346 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
347 hBlendColorBrush = CreateSolidBrush(clrBlend);
348 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
350 BitBlt (pimldp->hdcDst,
351 pimldp->x, pimldp->y, cx, cy,
354 0xB8074A); /* PSDPxax */
356 SelectObject(pimldp->hdcDst, hOldBrush);
357 SetTextColor(pimldp->hdcDst, OldTextColor);
358 SetBkColor(pimldp->hdcDst, OldBkColor);
359 SelectObject(hBlendMaskDC, hOldBitmap);
360 DeleteDC(hBlendMaskDC);
361 DeleteObject(hBlendMaskBitmap);
362 DeleteObject(hBlendColorBrush);
365 /*************************************************************************
366 * IMAGELIST_InternalDrawOverlay [Internal]
368 * Draws the overlay image
371 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
372 * cx [I] the width of the image to display
373 * cy............[I] the height of the image to display
379 * This functions is used by ImageList_DrawIndirect, when it is
380 * required to draw the overlay
385 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
391 nOvlIdx = (pimldp->fStyle & 0x0700) >> 8;
392 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
394 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
395 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
397 hImageDC = CreateCompatibleDC(0);
398 if (pimldp->himl->hbmMask)
400 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
401 pimldp->himl->hbmMask);
403 BitBlt (pimldp->hdcDst,
404 pimldp->x, pimldp->y, cx, cy,
405 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
408 SelectObject(hImageDC, hOldBitmap);
410 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
411 pimldp->himl->hbmImage);
413 BitBlt (pimldp->hdcDst,
414 pimldp->x, pimldp->y, cx, cy,
416 pimldp->himl->cx * nOvlIdx, 0,
419 SelectObject(hImageDC, hOldBitmap);
429 /*************************************************************************
430 * ImageList_Add [COMCTL32.39]
432 * Add an image or images to an image list.
435 * himl [I] handle to image list
436 * hbmImage [I] handle to image bitmap
437 * hbmMask [I] handle to mask bitmap
440 * Success: Index of the first new image.
445 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
447 HDC hdcImage, hdcBitmap;
448 INT nFirstIndex, nImageCount;
451 HBITMAP hOldBitmapImage, hOldBitmap;
453 if (!himl || !hbmImage)
456 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
457 nImageCount = bmp.bmWidth / himl->cx;
459 if (himl->cCurImage + nImageCount >= himl->cMaxImage)
460 IMAGELIST_InternalExpandBitmaps (himl, nImageCount);
462 nStartX = himl->cCurImage * himl->cx;
464 hdcImage = CreateCompatibleDC(0);
465 hdcBitmap = CreateCompatibleDC(0);
467 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
468 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
470 /* Copy result to the imagelist
472 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, himl->cy,
473 hdcBitmap, 0, 0, SRCCOPY);
477 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
479 hdcMask = CreateCompatibleDC (0);
480 hdcTemp = CreateCompatibleDC(0);
481 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
482 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
485 nStartX, 0, bmp.bmWidth, himl->cy,
490 SelectObject(hdcTemp, hOldBitmapTemp);
493 /* Remove the background from the image
496 nStartX, 0, bmp.bmWidth, himl->cy,
499 0x220326); /* NOTSRCAND */
501 SelectObject(hdcMask, hOldBitmapMask);
505 SelectObject(hdcImage, hOldBitmapImage);
506 SelectObject(hdcBitmap, hOldBitmap);
510 nFirstIndex = himl->cCurImage;
511 himl->cCurImage += nImageCount;
517 /*************************************************************************
518 * ImageList_AddIcon [COMCTL32.40]
520 * Adds an icon to an image list.
523 * himl [I] handle to image list
524 * hIcon [I] handle to icon
527 * Success: index of the new image
532 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
534 return ImageList_ReplaceIcon (himl, -1, hIcon);
538 /*************************************************************************
539 * ImageList_AddMasked [COMCTL32.41]
541 * Adds an image or images to an image list and creates a mask from the
542 * specified bitmap using the mask color.
545 * himl [I] handle to image list.
546 * hBitmap [I] handle to bitmap
547 * clrMask [I] mask color.
550 * Success: Index of the first new image.
555 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
557 HDC hdcImage, hdcMask, hdcBitmap;
558 INT nIndex, nImageCount, nMaskXOffset=0;
560 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
561 HBITMAP hMaskBitmap=0;
567 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
570 nImageCount = bmp.bmWidth / himl->cx;
572 if (himl->cCurImage + nImageCount >= himl->cMaxImage)
574 IMAGELIST_InternalExpandBitmaps (himl, nImageCount);
577 nIndex = himl->cCurImage;
578 himl->cCurImage += nImageCount;
580 hdcMask = CreateCompatibleDC (0);
581 hdcImage = CreateCompatibleDC(0);
582 hdcBitmap = CreateCompatibleDC(0);
585 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
586 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
589 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
590 nMaskXOffset = nIndex * himl->cx;
595 Create a temp Mask so we can remove the background of
596 the Image (Windows does this even if there is no mask)
598 hMaskBitmap = CreateBitmap(bmp.bmWidth, himl->cy, 1, 1, NULL);
599 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
602 /* create monochrome image to the mask bitmap */
603 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
604 GetPixel (hdcBitmap, 0, 0);
605 SetBkColor (hdcBitmap, bkColor);
607 nMaskXOffset, 0, bmp.bmWidth, himl->cy,
611 SetBkColor(hdcBitmap, RGB(255,255,255));
612 /*Remove the background from the image
615 WINDOWS BUG ALERT!!!!!!
616 The statement below should not be done in common practice
617 but this is how ImageList_AddMasked works in Windows.
618 It overwrites the original bitmap passed, this was discovered
619 by using the same bitmap to itterated the different styles
620 on windows where it failed (BUT ImageList_Add is OK)
621 This is here in case some apps really on this bug
624 0, 0, bmp.bmWidth, himl->cy,
627 0x220326); /* NOTSRCAND */
628 /* Copy result to the imagelist
631 nIndex * himl->cx, 0, bmp.bmWidth, himl->cy,
637 SelectObject(hdcMask,hOldBitmapMask);
638 SelectObject(hdcImage, hOldBitmapImage);
639 SelectObject(hdcBitmap, hOldBitmap);
645 DeleteObject(hMaskBitmap);
652 /*************************************************************************
653 * ImageList_BeginDrag [COMCTL32.42]
655 * Creates a temporary image list that contains one image. It will be used
659 * himlTrack [I] handle to the source image list
660 * iTrack [I] index of the drag image in the source image list
661 * dxHotspot [I] X position of the hot spot of the drag image
662 * dyHotspot [I] Y position of the hot spot of the drag image
670 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
671 INT dxHotspot, INT dyHotspot)
675 FIXME("partially implemented!\n");
677 if (himlTrack == NULL)
680 if (himlInternalDrag)
681 ImageList_EndDrag ();
684 ImageList_Create (himlTrack->cx, himlTrack->cy,
685 himlTrack->flags, 1, 1);
686 if (himlInternalDrag == NULL) {
687 ERR("Error creating drag image list!\n");
691 nInternalDragHotspotX = dxHotspot;
692 nInternalDragHotspotY = dyHotspot;
694 hdcSrc = CreateCompatibleDC (0);
695 hdcDst = CreateCompatibleDC (0);
698 SelectObject (hdcSrc, himlTrack->hbmImage);
699 SelectObject (hdcDst, himlInternalDrag->hbmImage);
700 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
701 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
704 SelectObject (hdcSrc, himlTrack->hbmMask);
705 SelectObject (hdcDst, himlInternalDrag->hbmMask);
706 StretchBlt (hdcDst, 0, 0, himlInternalDrag->cx, himlInternalDrag->cy, hdcSrc,
707 iTrack * himlTrack->cx, 0, himlTrack->cx, himlTrack->cy, SRCCOPY);
712 himlInternalDrag->cCurImage = 1;
718 /*************************************************************************
719 * ImageList_Copy [COMCTL32.43]
721 * Copies an image of the source image list to an image of the
722 * destination image list. Images can be copied or swapped.
725 * himlDst [I] handle to the destination image list
726 * iDst [I] destination image index.
727 * himlSrc [I] handle to the source image list
728 * iSrc [I] source image index
729 * uFlags [I] flags for the copy operation
736 * Copying from one image list to another is possible. The original
737 * implementation just copies or swapps within one image list.
738 * Could this feature become a bug??? ;-)
742 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
743 INT iSrc, INT uFlags)
747 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
749 if ((himlSrc == NULL) || (himlDst == NULL))
751 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
753 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
756 hdcSrc = CreateCompatibleDC (0);
757 if (himlDst == himlSrc)
760 hdcDst = CreateCompatibleDC (0);
762 if (uFlags & ILCF_SWAP) {
764 HBITMAP hbmTempImage, hbmTempMask;
766 /* create temporary bitmaps */
767 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
768 himlSrc->uBitsPixel, NULL);
769 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
772 /* copy (and stretch) destination to temporary bitmaps.(save) */
774 SelectObject (hdcSrc, himlDst->hbmImage);
775 SelectObject (hdcDst, hbmTempImage);
776 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
777 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
780 SelectObject (hdcSrc, himlDst->hbmMask);
781 SelectObject (hdcDst, hbmTempMask);
782 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
783 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
786 /* copy (and stretch) source to destination */
788 SelectObject (hdcSrc, himlSrc->hbmImage);
789 SelectObject (hdcDst, himlDst->hbmImage);
790 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
791 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
794 SelectObject (hdcSrc, himlSrc->hbmMask);
795 SelectObject (hdcDst, himlDst->hbmMask);
796 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
797 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
800 /* copy (without stretching) temporary bitmaps to source (restore) */
802 SelectObject (hdcSrc, hbmTempImage);
803 SelectObject (hdcDst, himlSrc->hbmImage);
804 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
805 hdcSrc, 0, 0, SRCCOPY);
807 SelectObject (hdcSrc, hbmTempMask);
808 SelectObject (hdcDst, himlSrc->hbmMask);
809 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
810 hdcSrc, 0, 0, SRCCOPY);
812 /* delete temporary bitmaps */
813 DeleteObject (hbmTempMask);
814 DeleteObject (hbmTempImage);
818 SelectObject (hdcSrc, himlSrc->hbmImage);
819 if (himlSrc == himlDst)
822 SelectObject (hdcDst, himlDst->hbmImage);
823 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
824 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
828 SelectObject (hdcSrc, himlSrc->hbmMask);
829 if (himlSrc == himlDst)
832 SelectObject (hdcDst, himlDst->hbmMask);
833 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
834 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
839 if (himlSrc != himlDst)
846 /*************************************************************************
847 * ImageList_Create [COMCTL32.44] Creates a new image list.
850 * cx [I] image height
852 * flags [I] creation flags
853 * cInitial [I] initial number of images in the image list
854 * cGrow [I] number of images by which image list grows
857 * Success: Handle to the created image list
862 ImageList_Create (INT cx, INT cy, UINT flags,
863 INT cInitial, INT cGrow)
869 static WORD aBitBlend25[] =
870 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
872 static WORD aBitBlend50[] =
873 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
875 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
877 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
884 himl->cMaxImage = cInitial + cGrow;
885 himl->cInitial = cInitial;
888 himl->clrFg = CLR_DEFAULT;
889 himl->clrBk = CLR_NONE;
891 /* initialize overlay mask indices */
892 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
893 himl->nOvlIdx[nCount] = -1;
895 hdc = CreateCompatibleDC (0);
896 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
899 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
901 if (himl->cMaxImage > 0) {
903 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
904 1, himl->uBitsPixel, NULL);
905 if (himl->hbmImage == 0) {
906 ERR("Error creating image bitmap!\n");
913 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
914 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
916 if (himl->hbmMask == 0) {
917 ERR("Error creating mask bitmap!\n");
919 DeleteObject (himl->hbmImage);
926 /* create blending brushes */
927 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
928 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
929 DeleteObject (hbmTemp);
931 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
932 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
933 DeleteObject (hbmTemp);
939 /*************************************************************************
940 * ImageList_Destroy [COMCTL32.45]
942 * Destroys an image list.
945 * himl [I] handle to image list
953 ImageList_Destroy (HIMAGELIST himl)
958 /* delete image bitmaps */
960 DeleteObject (himl->hbmImage);
962 DeleteObject (himl->hbmMask);
964 /* delete blending brushes */
965 if (himl->hbrBlend25)
966 DeleteObject (himl->hbrBlend25);
967 if (himl->hbrBlend50)
968 DeleteObject (himl->hbrBlend50);
970 COMCTL32_Free (himl);
976 /*************************************************************************
977 * ImageList_DragEnter [COMCTL32.46]
979 * Locks window update and displays the drag image at the given position.
982 * hwndLock [I] handle of the window that owns the drag image.
983 * x [I] X position of the drag image.
984 * y [I] Y position of the drag image.
991 * The position of the drag image is relative to the window, not
996 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
998 if (himlInternalDrag == NULL)
1002 hwndInternalDrag = hwndLock;
1004 hwndInternalDrag = GetDesktopWindow ();
1009 hdcBackBuffer = CreateCompatibleDC (0);
1010 hbmBackBuffer = CreateCompatibleBitmap (hdcBackBuffer,
1011 himlInternalDrag->cx, himlInternalDrag->cy);
1013 ImageList_DragShowNolock (TRUE);
1019 /*************************************************************************
1020 * ImageList_DragLeave [COMCTL32.47]
1022 * Unlocks window update and hides the drag image.
1025 * hwndLock [I] handle of the window that owns the drag image.
1033 ImageList_DragLeave (HWND hwndLock)
1036 hwndInternalDrag = hwndLock;
1038 hwndInternalDrag = GetDesktopWindow ();
1040 ImageList_DragShowNolock (FALSE);
1042 DeleteDC (hdcBackBuffer);
1043 DeleteObject (hbmBackBuffer);
1049 /*************************************************************************
1050 * ImageList_DragMove [COMCTL32.48]
1052 * Moves the drag image.
1055 * x [I] X position of the drag image.
1056 * y [I] Y position of the drag image.
1063 * The position of the drag image is relative to the window, not
1068 ImageList_DragMove (INT x, INT y)
1070 ImageList_DragShowNolock (FALSE);
1075 ImageList_DragShowNolock (TRUE);
1081 /*************************************************************************
1082 * ImageList_DragShowNolock [COMCTL32.49]
1084 * Shows or hides the drag image.
1087 * bShow [I] TRUE shows the drag image, FALSE hides it.
1098 ImageList_DragShowNolock (BOOL bShow)
1102 FIXME("semi-stub!\n");
1103 TRACE("bShow=0x%X!\n", bShow);
1105 hdcDrag = GetDCEx (hwndInternalDrag, 0,
1106 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1109 /* show drag image */
1111 /* save background */
1113 /* draw drag image */
1117 /* hide drag image */
1119 /* restore background */
1123 ReleaseDC (hwndInternalDrag, hdcDrag);
1129 /*************************************************************************
1130 * ImageList_Draw [COMCTL32.50] Draws an image.
1133 * himl [I] handle to image list
1135 * hdc [I] handle to device context
1138 * fStyle [I] drawing flags
1145 * Calls ImageList_DrawIndirect.
1148 * ImageList_DrawIndirect.
1152 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1153 INT x, INT y, UINT fStyle)
1155 IMAGELISTDRAWPARAMS imldp;
1157 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1167 imldp.rgbBk = CLR_DEFAULT;
1168 imldp.rgbFg = CLR_DEFAULT;
1169 imldp.fStyle = fStyle;
1172 return ImageList_DrawIndirect (&imldp);
1176 /*************************************************************************
1177 * ImageList_DrawEx [COMCTL32.51]
1179 * Draws an image and allows to use extended drawing features.
1182 * himl [I] handle to image list
1184 * hdc [I] handle to device context
1187 * xOffs [I] X offset
1188 * yOffs [I] Y offset
1189 * rgbBk [I] background color
1190 * rgbFg [I] foreground color
1191 * fStyle [I] drawing flags
1198 * Calls ImageList_DrawIndirect.
1201 * ImageList_DrawIndirect.
1205 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1206 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1209 IMAGELISTDRAWPARAMS imldp;
1211 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1221 imldp.rgbBk = rgbBk;
1222 imldp.rgbFg = rgbFg;
1223 imldp.fStyle = fStyle;
1226 return ImageList_DrawIndirect (&imldp);
1230 /*************************************************************************
1231 * ImageList_DrawIndirect [COMCTL32.52]
1233 * Draws an image using ...
1236 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1244 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1248 Do some Error Checking
1252 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1254 if (pimldp->himl == NULL)
1256 if ((pimldp->i < 0) || (pimldp->i > pimldp->himl->cCurImage)) {
1257 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage);
1261 Get the Height and Width to display
1263 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1264 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1268 if(pimldp->himl->hbmMask != 0)
1270 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1274 IMAGELIST_InternalDraw(pimldp, cx, cy);
1277 Apply the blend if needed to the Image
1279 if((pimldp->fStyle & ILD_BLEND50)
1280 || (pimldp->fStyle & ILD_BLEND25))
1282 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1285 Apply the Overlay if needed
1287 if (pimldp->fStyle & 0x0700)
1289 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1296 /*************************************************************************
1297 * ImageList_Duplicate [COMCTL32.53] Duplicates an image list.
1300 * himlSrc [I] source image list handle
1303 * Success: Handle of duplicated image list.
1308 ImageList_Duplicate (HIMAGELIST himlSrc)
1313 if (himlSrc == NULL) {
1314 ERR("Invalid image list handle!\n");
1318 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1319 himlSrc->cInitial, himlSrc->cGrow);
1323 hdcSrc = CreateCompatibleDC (0);
1324 hdcDst = CreateCompatibleDC (0);
1325 SelectObject (hdcSrc, himlSrc->hbmImage);
1326 SelectObject (hdcDst, himlDst->hbmImage);
1327 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1328 hdcSrc, 0, 0, SRCCOPY);
1330 if (himlDst->hbmMask)
1332 SelectObject (hdcSrc, himlSrc->hbmMask);
1333 SelectObject (hdcDst, himlDst->hbmMask);
1334 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1335 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1341 himlDst->cCurImage = himlSrc->cCurImage;
1342 himlDst->cMaxImage = himlSrc->cMaxImage;
1348 /*************************************************************************
1349 * ImageList_EndDrag [COMCTL32.54] Finishes a drag operation.
1351 * Finishes a drag operation.
1365 ImageList_EndDrag (void)
1367 FIXME("semi-stub!\n");
1369 if (himlInternalDrag)
1372 ImageList_Destroy (himlInternalDrag);
1373 himlInternalDrag = NULL;
1375 nInternalDragHotspotX = 0;
1376 nInternalDragHotspotY = 0;
1384 /*************************************************************************
1385 * ImageList_GetBkColor [COMCTL32.55]
1387 * Returns the background color of an image list.
1390 * himl [I] Image list handle.
1393 * Success: background color
1398 ImageList_GetBkColor (HIMAGELIST himl)
1407 /*************************************************************************
1408 * ImageList_GetDragImage [COMCTL32.56]
1410 * Returns the handle to the internal drag image list.
1413 * ppt [O] Pointer to the drag position. Can be NULL.
1414 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1417 * Success: Handle of the drag image list.
1425 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1427 FIXME("semi-stub!\n");
1429 if (himlInternalDrag)
1430 return (himlInternalDrag);
1436 /*************************************************************************
1437 * ImageList_GetIcon [COMCTL32.57]
1439 * Creates an icon from a masked image of an image list.
1442 * himl [I] handle to image list
1444 * flags [I] drawing style flags
1447 * Success: icon handle
1452 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1456 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1459 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1460 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1464 hdcSrc = CreateCompatibleDC(0);
1465 hdcDst = CreateCompatibleDC(0);
1468 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1471 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1472 if (himl->hbmMask) {
1473 SelectObject (hdcSrc, himl->hbmMask);
1474 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1475 hdcSrc, i * himl->cx, 0, SRCCOPY);
1478 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1481 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1482 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1483 SelectObject (hdcDst, ii.hbmColor);
1484 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1485 hdcSrc, i * himl->cx, 0, SRCCOPY);
1488 * CreateIconIndirect requires us to deselect the bitmaps from
1489 * the DCs before calling
1491 SelectObject(hdcSrc, hOldSrcBitmap);
1492 SelectObject(hdcDst, hOldDstBitmap);
1494 hIcon = CreateIconIndirect (&ii);
1498 DeleteObject (ii.hbmMask);
1499 DeleteObject (ii.hbmColor);
1505 /*************************************************************************
1506 * ImageList_GetIconSize [COMCTL32.58]
1508 * Retrieves the size of an image in an image list.
1511 * himl [I] handle to image list
1512 * cx [O] pointer to the image width.
1513 * cy [O] pointer to the image height.
1520 * All images in an image list have the same size.
1524 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1528 if ((himl->cx <= 0) || (himl->cy <= 0))
1540 /*************************************************************************
1541 * ImageList_GetImageCount [COMCTL32.59]
1543 * Returns the number of images in an image list.
1546 * himl [I] handle to image list
1549 * Success: Number of images.
1554 ImageList_GetImageCount (HIMAGELIST himl)
1559 return himl->cCurImage;
1563 /*************************************************************************
1564 * ImageList_GetImageInfo [COMCTL32.60]
1566 * Returns information about an image in an image list.
1569 * himl [I] handle to image list
1571 * pImageInfo [O] pointer to the image information
1579 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1581 if ((himl == NULL) || (pImageInfo == NULL))
1583 if ((i < 0) || (i >= himl->cCurImage))
1586 pImageInfo->hbmImage = himl->hbmImage;
1587 pImageInfo->hbmMask = himl->hbmMask;
1589 pImageInfo->rcImage.top = 0;
1590 pImageInfo->rcImage.bottom = himl->cy;
1591 pImageInfo->rcImage.left = i * himl->cx;
1592 pImageInfo->rcImage.right = (i+1) * himl->cx;
1598 /*************************************************************************
1599 * ImageList_GetImageRect [COMCTL32.61]
1601 * Retrieves the rectangle of the specified image in an image list.
1604 * himl [I] handle to image list
1606 * lpRect [O] pointer to the image rectangle
1613 * This is an UNDOCUMENTED function!!!
1617 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1619 if ((himl == NULL) || (lpRect == NULL))
1621 if ((i < 0) || (i >= himl->cCurImage))
1624 lpRect->left = i * himl->cx;
1626 lpRect->right = lpRect->left + himl->cx;
1627 lpRect->bottom = himl->cy;
1633 /*************************************************************************
1634 * ImageList_LoadImage32A [COMCTL32.63][COMCTL32.62]
1636 * Creates an image list from a bitmap, icon or cursor.
1639 * hi [I] instance handle
1640 * lpbmp [I] name or id of the image
1641 * cx [I] width of each image
1642 * cGrow [I] number of images to expand
1643 * clrMask [I] mask color
1644 * uType [I] type of image to load
1645 * uFlags [I] loading flags
1648 * Success: handle to the loaded image list
1656 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1657 COLORREF clrMask, UINT uType, UINT uFlags)
1659 HIMAGELIST himl = NULL;
1663 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1665 ERR("Error loading image!\n");
1669 if (uType == IMAGE_BITMAP) {
1671 GetObjectA (handle, sizeof(BITMAP), &bmp);
1673 /* To match windows behavior, if cx is set to zero and
1674 the flag DI_DEFAULTSIZE is specified, cx becomes the
1675 system metric value for icons. If the flag is not specified
1676 the function sets the size to the height of the bitmap */
1679 if (uFlags & DI_DEFAULTSIZE)
1680 cx = GetSystemMetrics (SM_CXICON);
1685 nImageCount = bmp.bmWidth / cx;
1687 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1688 nImageCount, cGrow);
1689 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1691 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1695 GetIconInfo (handle, &ii);
1696 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1697 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1698 ILC_MASK | ILC_COLOR, 1, cGrow);
1699 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1700 DeleteObject (ii.hbmColor);
1701 DeleteObject (ii.hbmMask);
1704 DeleteObject (handle);
1710 /*************************************************************************
1711 * ImageList_LoadImage32W [COMCTL32.64]
1713 * Creates an image list from a bitmap, icon or cursor.
1716 * hi [I] instance handle
1717 * lpbmp [I] name or id of the image
1718 * cx [I] width of each image
1719 * cGrow [I] number of images to expand
1720 * clrMask [I] mask color
1721 * uType [I] type of image to load
1722 * uFlags [I] loading flags
1725 * Success: handle to the loaded image list
1733 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1734 COLORREF clrMask, UINT uType, UINT uFlags)
1736 HIMAGELIST himl = NULL;
1740 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1742 ERR("Error loading image!\n");
1746 if (uType == IMAGE_BITMAP) {
1748 GetObjectA (handle, sizeof(BITMAP), &bmp);
1749 nImageCount = bmp.bmWidth / cx;
1751 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1752 nImageCount, cGrow);
1753 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1755 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1759 GetIconInfo (handle, &ii);
1760 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1761 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1762 ILC_MASK | ILC_COLOR, 1, cGrow);
1763 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1764 DeleteObject (ii.hbmColor);
1765 DeleteObject (ii.hbmMask);
1768 DeleteObject (handle);
1774 /*************************************************************************
1775 * ImageList_Merge [COMCTL32.65]
1777 * Creates a new image list that contains a merged image from the specified
1778 * images of both source image lists.
1781 * himl1 [I] handle to first image list
1782 * i1 [I] first image index
1783 * himl2 [I] handle to second image list
1784 * i2 [I] second image index
1785 * dx [I] X offset of the second image relative to the first.
1786 * dy [I] Y offset of the second image relative to the first.
1789 * Success: handle of the merged image list.
1794 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1797 HIMAGELIST himlDst = NULL;
1798 HDC hdcSrcImage, hdcDstImage;
1800 INT xOff1, yOff1, xOff2, yOff2;
1803 if ((himl1 == NULL) || (himl2 == NULL))
1807 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1808 ERR("Index 1 out of range! %d\n", i1);
1812 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1813 ERR("Index 2 out of range! %d\n", i2);
1818 cxDst = _MAX (himl1->cx, dx + himl2->cx);
1823 cxDst = _MAX (himl2->cx, himl1->cx - dx);
1828 cxDst = _MAX (himl1->cx, himl2->cx);
1834 cyDst = _MAX (himl1->cy, dy + himl2->cy);
1839 cyDst = _MAX (himl2->cy, himl1->cy - dy);
1844 cyDst = _MAX (himl1->cy, himl2->cy);
1849 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1852 hdcSrcImage = CreateCompatibleDC (0);
1853 hdcDstImage = CreateCompatibleDC (0);
1854 nX1 = i1 * himl1->cx;
1855 nX2 = i2 * himl2->cx;
1858 SelectObject (hdcSrcImage, himl1->hbmImage);
1859 SelectObject (hdcDstImage, himlDst->hbmImage);
1860 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1861 hdcSrcImage, 0, 0, BLACKNESS);
1862 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1863 hdcSrcImage, nX1, 0, SRCCOPY);
1865 SelectObject (hdcSrcImage, himl2->hbmMask);
1866 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1867 hdcSrcImage, nX2, 0, SRCAND);
1869 SelectObject (hdcSrcImage, himl2->hbmImage);
1870 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1871 hdcSrcImage, nX2, 0, SRCPAINT);
1874 SelectObject (hdcSrcImage, himl1->hbmMask);
1875 SelectObject (hdcDstImage, himlDst->hbmMask);
1876 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1877 hdcSrcImage, 0, 0, WHITENESS);
1878 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1879 hdcSrcImage, nX1, 0, SRCCOPY);
1881 SelectObject (hdcSrcImage, himl2->hbmMask);
1882 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1883 hdcSrcImage, nX2, 0, SRCAND);
1885 DeleteDC (hdcSrcImage);
1886 DeleteDC (hdcDstImage);
1893 /* helper for _read_bitmap currently unused */
1894 static int may_use_dibsection(HDC hdc) {
1895 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1900 return GetDeviceCaps(hdc,94) & 0x10;
1903 /* helper for ImageList_Read, see comments below */
1904 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1906 BITMAPFILEHEADER bmfh;
1907 BITMAPINFOHEADER bmih;
1908 int bitsperpixel,palspace,longsperline,width,height;
1909 LPBITMAPINFOHEADER bmihc = NULL;
1911 HBITMAP hbitmap = 0;
1912 LPBYTE bits = NULL,nbits = NULL;
1913 int nbytesperline,bytesperline;
1915 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1916 (bmfh.bfType != (('M'<<8)|'B')) ||
1917 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1918 (bmih.biSize != sizeof(bmih))
1922 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1923 if (bitsperpixel<=8)
1924 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1927 width = bmih.biWidth;
1928 height = bmih.biHeight;
1929 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1930 memcpy(bmihc,&bmih,sizeof(bmih));
1931 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1932 bmihc->biSizeImage = (longsperline*height)<<2;
1934 /* read the palette right after the end of the bitmapinfoheader */
1936 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1940 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1941 if ((bitsperpixel>1) &&
1942 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1944 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1947 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1953 int i,nwidth,nheight;
1955 nwidth = width*(height/cy);
1958 if (bitsperpixel==1)
1959 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1961 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1963 /* Might be a bit excessive memory use here */
1964 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1965 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1966 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1969 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1970 /* Do not forget that windows bitmaps are bottom->top */
1971 bytesperline = longsperline*4;
1972 nbytesperline = (height/cy)*bytesperline;
1973 for (i=0;i<height;i++) {
1975 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1976 bits+bytesperline*(height-1-i),
1980 bmihc->biWidth = nwidth;
1981 bmihc->biHeight = nheight;
1982 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1984 LocalFree((HLOCAL)nbits);
1985 LocalFree((HLOCAL)bits);
1989 if (xdc) ReleaseDC(0,xdc);
1990 if (bmihc) LocalFree((HLOCAL)bmihc);
1993 DeleteObject(hbitmap);
2000 /*************************************************************************
2001 * ImageList_Read [COMCTL32.66]
2003 * Reads an image list from a stream.
2006 * pstm [I] pointer to a stream
2009 * Success: handle to image list
2012 * The format is like this:
2013 * ILHEAD ilheadstruct;
2015 * for the color image part:
2016 * BITMAPFILEHEADER bmfh;
2017 * BITMAPINFOHEADER bmih;
2018 * only if it has a palette:
2019 * RGBQUAD rgbs[nr_of_paletted_colors];
2021 * BYTE colorbits[imagesize];
2023 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2024 * BITMAPFILEHEADER bmfh_mask;
2025 * BITMAPINFOHEADER bmih_mask;
2026 * only if it has a palette (it usually does not):
2027 * RGBQUAD rgbs[nr_of_paletted_colors];
2029 * BYTE maskbits[imagesize];
2031 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2032 * _read_bitmap needs to convert them.
2034 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2038 HBITMAP hbmColor=0,hbmMask=0;
2041 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2043 if (ilHead.usMagic != (('L' << 8) | 'I'))
2045 if (ilHead.usVersion != 0x101) /* probably version? */
2049 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2050 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2051 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2052 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2053 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2054 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2055 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2056 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2057 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2058 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2061 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2064 if (ilHead.flags & ILC_MASK) {
2065 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2067 DeleteObject(hbmColor);
2072 himl = ImageList_Create (
2080 DeleteObject(hbmColor);
2081 DeleteObject(hbmMask);
2084 himl->hbmImage = hbmColor;
2085 himl->hbmMask = hbmMask;
2086 himl->cCurImage = ilHead.cCurImage;
2087 himl->cMaxImage = ilHead.cMaxImage;
2089 ImageList_SetBkColor(himl,ilHead.bkcolor);
2091 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2096 /*************************************************************************
2097 * ImageList_Remove [COMCTL32.67] Removes an image from an image list
2100 * himl [I] image list handle
2109 ImageList_Remove (HIMAGELIST himl, INT i)
2111 HBITMAP hbmNewImage, hbmNewMask;
2115 if ((i < -1) || (i >= himl->cCurImage)) {
2116 ERR("index out of range! %d\n", i);
2120 if (himl->cCurImage == 0) {
2121 ERR("image list is already empty!\n");
2127 TRACE("remove all!\n");
2129 himl->cMaxImage = himl->cInitial + himl->cGrow;
2130 himl->cCurImage = 0;
2131 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2132 himl->nOvlIdx[nCount] = -1;
2134 DeleteObject (himl->hbmImage);
2136 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2137 1, himl->uBitsPixel, NULL);
2139 if (himl->hbmMask) {
2140 DeleteObject (himl->hbmMask);
2142 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2147 /* delete one image */
2148 TRACE("Remove single image! %d\n", i);
2150 /* create new bitmap(s) */
2151 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2153 TRACE(" - Number of images: %d / %d (Old/New)\n",
2154 himl->cCurImage, himl->cCurImage - 1);
2155 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2156 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2159 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2162 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2164 hbmNewMask = 0; /* Just to keep compiler happy! */
2166 hdcSrc = CreateCompatibleDC (0);
2167 hdcDst = CreateCompatibleDC (0);
2169 /* copy all images and masks prior to the "removed" image */
2171 TRACE("Pre image copy: Copy %d images\n", i);
2173 SelectObject (hdcSrc, himl->hbmImage);
2174 SelectObject (hdcDst, hbmNewImage);
2175 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2176 hdcSrc, 0, 0, SRCCOPY);
2178 if (himl->hbmMask) {
2179 SelectObject (hdcSrc, himl->hbmMask);
2180 SelectObject (hdcDst, hbmNewMask);
2181 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2182 hdcSrc, 0, 0, SRCCOPY);
2186 /* copy all images and masks behind the removed image */
2187 if (i < himl->cCurImage - 1) {
2188 TRACE("Post image copy!\n");
2189 SelectObject (hdcSrc, himl->hbmImage);
2190 SelectObject (hdcDst, hbmNewImage);
2191 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2192 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2194 if (himl->hbmMask) {
2195 SelectObject (hdcSrc, himl->hbmMask);
2196 SelectObject (hdcDst, hbmNewMask);
2197 BitBlt (hdcDst, i * himl->cx, 0,
2198 (himl->cCurImage - i - 1) * himl->cx,
2199 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2206 /* delete old images and insert new ones */
2207 DeleteObject (himl->hbmImage);
2208 himl->hbmImage = hbmNewImage;
2209 if (himl->hbmMask) {
2210 DeleteObject (himl->hbmMask);
2211 himl->hbmMask = hbmNewMask;
2215 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2222 /*************************************************************************
2223 * ImageList_Replace [COMCTL32.68]
2225 * Replaces an image in an image list with a new image.
2228 * himl [I] handle to image list
2230 * hbmImage [I] handle to image bitmap
2231 * hbmMask [I] handle to mask bitmap. Can be NULL.
2239 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2242 HDC hdcImageList, hdcImage;
2246 ERR("Invalid image list handle!\n");
2250 if ((i >= himl->cCurImage) || (i < 0)) {
2251 ERR("Invalid image index!\n");
2255 hdcImageList = CreateCompatibleDC (0);
2256 hdcImage = CreateCompatibleDC (0);
2257 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2260 SelectObject (hdcImageList, himl->hbmImage);
2261 SelectObject (hdcImage, hbmImage);
2263 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2264 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2269 SelectObject (hdcImageList, himl->hbmMask);
2270 SelectObject (hdcImage, hbmMask);
2272 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2273 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2276 DeleteDC (hdcImage);
2277 DeleteDC (hdcImageList);
2283 /*************************************************************************
2284 * ImageList_ReplaceIcon [COMCTL32.69]
2286 * Replaces an image in an image list using an icon.
2289 * himl [I] handle to image list
2291 * hIcon [I] handle to icon
2294 * Success: index of the replaced image
2299 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2301 HDC hdcImageList, hdcImage;
2304 HBITMAP hbmOldSrc, hbmOldDst;
2308 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2312 if ((i >= himl->cCurImage) || (i < -1))
2315 hBestFitIcon = CopyImage(
2318 LR_COPYFROMRESOURCE);
2320 GetIconInfo (hBestFitIcon, &ii);
2321 if (ii.hbmMask == 0)
2323 if (ii.hbmColor == 0)
2325 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2328 if (himl->cCurImage + 1 >= himl->cMaxImage)
2329 IMAGELIST_InternalExpandBitmaps (himl, 1);
2331 nIndex = himl->cCurImage;
2337 hdcImageList = CreateCompatibleDC (0);
2338 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2339 if (hdcImageList == 0)
2340 ERR("invalid hdcImageList!\n");
2342 hdcImage = CreateCompatibleDC (0);
2343 TRACE("hdcImage=0x%x!\n", hdcImage);
2345 ERR("invalid hdcImage!\n");
2347 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2348 SetTextColor( hdcImageList, RGB(0,0,0));
2349 SetBkColor( hdcImageList, RGB(255,255,255));
2350 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2351 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2352 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2354 if (himl->hbmMask) {
2355 SelectObject (hdcImageList, himl->hbmMask);
2356 SelectObject (hdcImage, ii.hbmMask);
2357 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2358 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2361 SelectObject (hdcImage, hbmOldSrc);
2362 SelectObject (hdcImageList, hbmOldDst);
2365 DestroyIcon(hBestFitIcon);
2367 DeleteDC (hdcImageList);
2369 DeleteDC (hdcImage);
2371 DeleteObject (ii.hbmColor);
2373 DeleteObject (ii.hbmMask);
2379 /*************************************************************************
2380 * ImageList_SetBkColor [COMCTL32.70]
2382 * Sets the background color of an image list.
2385 * himl [I] handle to image list
2386 * clrBk [I] background color
2389 * Success: previous background color
2394 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2401 clrOldBk = himl->clrBk;
2402 himl->clrBk = clrBk;
2407 /*************************************************************************
2408 * ImageList_SetDragCursorImage [COMCTL32.75]
2410 * Combines the specified image with the current drag image
2413 * himlDrag [I] handle to drag image list
2414 * iDrag [I] drag image index
2415 * dxHotspot [I] X position of the hot spot
2416 * dyHotspot [I] Y position of the hot spot
2427 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2428 INT dxHotspot, INT dyHotspot)
2430 HIMAGELIST himlTemp;
2432 FIXME("semi-stub!\n");
2434 if (himlInternalDrag == NULL)
2437 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2438 dxHotspot, dyHotspot, nInternalDragHotspotX, nInternalDragHotspotY);
2440 himlTemp = ImageList_Merge (himlInternalDrag, 0, himlDrag, iDrag,
2441 dxHotspot, dyHotspot);
2443 ImageList_Destroy (himlInternalDrag);
2444 himlInternalDrag = himlTemp;
2446 nInternalDragHotspotX = dxHotspot;
2447 nInternalDragHotspotY = dyHotspot;
2453 /*************************************************************************
2454 * ImageList_SetFilter [COMCTL32.76]
2456 * Sets a filter (or does something completely different)!!???
2459 * himl [I] handle to image list
2465 * Failure: FALSE ???
2468 * This is an UNDOCUMENTED function!!!!
2473 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2475 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2482 /*************************************************************************
2483 * ImageList_SetIconSize [COMCTL32.77]
2485 * Sets the image size of the bitmap and deletes all images.
2488 * himl [I] handle to image list
2489 * cx [I] image width
2490 * cy [I] image height
2498 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2505 /* remove all images*/
2506 himl->cMaxImage = himl->cInitial + himl->cGrow;
2507 himl->cCurImage = 0;
2511 /* initialize overlay mask indices */
2512 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2513 himl->nOvlIdx[nCount] = -1;
2515 DeleteObject (himl->hbmImage);
2517 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2518 1, himl->uBitsPixel, NULL);
2520 if (himl->hbmMask) {
2521 DeleteObject (himl->hbmMask);
2523 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2531 /*************************************************************************
2532 * ImageList_SetImageCount [COMCTL32.78]
2534 * Resizes an image list to the specified number of images.
2537 * himl [I] handle to image list
2538 * iImageCount [I] number of images in the image list
2546 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2548 HDC hdcImageList, hdcBitmap;
2549 HBITMAP hbmNewBitmap;
2550 INT nNewCount, nCopyCount;
2554 if (himl->cCurImage >= iImageCount)
2556 if (himl->cMaxImage > iImageCount)
2559 nNewCount = iImageCount + himl->cGrow;
2560 nCopyCount = _MIN(himl->cCurImage, iImageCount);
2562 hdcImageList = CreateCompatibleDC (0);
2563 hdcBitmap = CreateCompatibleDC (0);
2565 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2566 1, himl->uBitsPixel, NULL);
2567 if (hbmNewBitmap != 0)
2569 SelectObject (hdcImageList, himl->hbmImage);
2570 SelectObject (hdcBitmap, hbmNewBitmap);
2573 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2574 hdcImageList, 0, 0, SRCCOPY);
2576 /* delete 'empty' image space */
2577 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2578 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2579 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2580 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2582 DeleteObject (himl->hbmImage);
2583 himl->hbmImage = hbmNewBitmap;
2586 ERR("Could not create new image bitmap !\n");
2590 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2592 if (hbmNewBitmap != 0)
2594 SelectObject (hdcImageList, himl->hbmMask);
2595 SelectObject (hdcBitmap, hbmNewBitmap);
2598 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2599 hdcImageList, 0, 0, SRCCOPY);
2601 /* delete 'empty' image space */
2602 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2603 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2604 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2605 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2607 DeleteObject (himl->hbmMask);
2608 himl->hbmMask = hbmNewBitmap;
2611 ERR("Could not create new mask bitmap!\n");
2614 DeleteDC (hdcImageList);
2615 DeleteDC (hdcBitmap);
2617 /* Update max image count and current image count */
2618 himl->cMaxImage = nNewCount;
2619 if (himl->cCurImage > nCopyCount)
2620 himl->cCurImage = nCopyCount;
2626 /*************************************************************************
2627 * ImageList_SetOverlayImage [COMCTL32.79]
2629 * Assigns an overlay mask index to an existing image in an image list.
2632 * himl [I] handle to image list
2633 * iImage [I] image index
2634 * iOverlay [I] overlay mask index
2642 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2646 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2648 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2650 himl->nOvlIdx[iOverlay - 1] = iImage;
2655 /*************************************************************************
2656 * ImageList_Write [COMCTL32.80]
2658 * Writes an image list to a stream.
2661 * himl [I] handle to image list
2662 * pstm [O] Pointer to a stream.
2669 * This function can not be implemented yet, because
2670 * IStream32::Write is not implemented.
2677 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2682 FIXME("empty stub!\n");