2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001, 2004 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
36 * - Thread-safe locking
53 #include "imagelist.h"
54 #include "wine/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
59 #define MAX_OVERLAYIMAGE 15
61 /* internal image list data used for Drag & Drop operations */
66 /* position of the drag image relative to the window */
69 /* offset of the hotspot relative to the origin of the image */
72 /* is the drag image visible */
74 /* saved background */
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height);
82 static inline BOOL is_valid(HIMAGELIST himl)
84 return himl && himl->magic == IMAGELIST_MAGIC;
88 * An imagelist with N images is tiled like this:
100 static inline UINT imagelist_width( UINT count )
102 return ((count + TILE_COUNT - 1)/TILE_COUNT);
105 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
107 pt->x = (index/TILE_COUNT) * himl->cx;
108 pt->y = (index%TILE_COUNT) * himl->cy;
111 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cy, SIZE *sz )
113 sz->cx = imagelist_width( count ) * himl->cx;
114 sz->cy = cy*TILE_COUNT;
118 * imagelist_copy_images()
120 * Copies a block of count images from offset src in the list to offset dest.
121 * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
123 static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
124 UINT src, UINT count, UINT dest )
130 for ( i=0; i<TILE_COUNT; i++ )
132 imagelist_point_from_index( himl, src+i, &ptSrc );
133 imagelist_point_from_index( himl, dest+i, &ptDest );
134 sz.cx = himl->cx * imagelist_width( count - i );
137 BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
138 hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
142 /*************************************************************************
143 * IMAGELIST_InternalExpandBitmaps [Internal]
145 * Expands the bitmaps of an image list by the given number of images.
148 * himl [I] handle to image list
149 * nImageCount [I] number of images to add
155 * This function CANNOT be used to reduce the number of images.
158 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
161 HBITMAP hbmNewBitmap, hbmNull;
165 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
169 if (cy == 0) cy = himl->cy;
170 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
172 imagelist_get_bitmap_size(himl, nNewCount, cy, &sz);
174 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
175 hdcBitmap = CreateCompatibleDC (0);
177 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cy);
179 if (hbmNewBitmap == 0)
180 ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
184 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
185 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
186 himl->hdcImage, 0, 0, SRCCOPY);
187 SelectObject (hdcBitmap, hbmNull);
189 SelectObject (himl->hdcImage, hbmNewBitmap);
190 DeleteObject (himl->hbmImage);
191 himl->hbmImage = hbmNewBitmap;
193 if (himl->flags & ILC_MASK)
195 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
197 if (hbmNewBitmap == 0)
198 ERR("creating new mask bitmap!\n");
202 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
203 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
204 himl->hdcMask, 0, 0, SRCCOPY);
205 SelectObject (hdcBitmap, hbmNull);
207 SelectObject (himl->hdcMask, hbmNewBitmap);
208 DeleteObject (himl->hbmMask);
209 himl->hbmMask = hbmNewBitmap;
212 himl->cMaxImage = nNewCount;
214 DeleteDC (hdcBitmap);
218 /*************************************************************************
219 * ImageList_Add [COMCTL32.@]
221 * Add an image or images to an image list.
224 * himl [I] handle to image list
225 * hbmImage [I] handle to image bitmap
226 * hbmMask [I] handle to mask bitmap
229 * Success: Index of the first new image.
234 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
236 HDC hdcBitmap, hdcTemp;
237 INT nFirstIndex, nImageCount, i;
239 HBITMAP hOldBitmap, hOldBitmapTemp;
242 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
246 if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
249 nImageCount = bmp.bmWidth / himl->cx;
251 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
253 hdcBitmap = CreateCompatibleDC(0);
255 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
257 for (i=0; i<nImageCount; i++)
259 imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
261 /* Copy result to the imagelist
263 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
264 hdcBitmap, i*himl->cx, 0, SRCCOPY );
269 hdcTemp = CreateCompatibleDC(0);
270 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
272 BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
273 hdcTemp, i*himl->cx, 0, SRCCOPY );
275 SelectObject(hdcTemp, hOldBitmapTemp);
278 /* Remove the background from the image
280 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
281 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
284 SelectObject(hdcBitmap, hOldBitmap);
287 nFirstIndex = himl->cCurImage;
288 himl->cCurImage += nImageCount;
294 /*************************************************************************
295 * ImageList_AddIcon [COMCTL32.@]
297 * Adds an icon to an image list.
300 * himl [I] handle to image list
301 * hIcon [I] handle to icon
304 * Success: index of the new image
307 #undef ImageList_AddIcon
308 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
310 return ImageList_ReplaceIcon (himl, -1, hIcon);
314 /*************************************************************************
315 * ImageList_AddMasked [COMCTL32.@]
317 * Adds an image or images to an image list and creates a mask from the
318 * specified bitmap using the mask color.
321 * himl [I] handle to image list.
322 * hBitmap [I] handle to bitmap
323 * clrMask [I] mask color.
326 * Success: Index of the first new image.
331 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
333 HDC hdcMask, hdcBitmap;
334 INT nIndex, nImageCount;
337 HBITMAP hMaskBitmap=0;
341 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
345 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
349 nImageCount = bmp.bmWidth / himl->cx;
353 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
355 nIndex = himl->cCurImage;
356 himl->cCurImage += nImageCount;
358 hdcBitmap = CreateCompatibleDC(0);
361 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
364 hdcMask = himl->hdcMask;
365 imagelist_point_from_index( himl, nIndex, &pt );
370 Create a temp Mask so we can remove the background of
371 the Image (Windows does this even if there is no mask)
373 hdcMask = CreateCompatibleDC(0);
374 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
375 SelectObject(hdcMask, hMaskBitmap);
376 imagelist_point_from_index( himl, 0, &pt );
378 /* create monochrome image to the mask bitmap */
379 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
380 GetPixel (hdcBitmap, 0, 0);
381 SetBkColor (hdcBitmap, bkColor);
383 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
387 SetBkColor(hdcBitmap, RGB(255,255,255));
388 /*Remove the background from the image
391 WINDOWS BUG ALERT!!!!!!
392 The statement below should not be done in common practice
393 but this is how ImageList_AddMasked works in Windows.
394 It overwrites the original bitmap passed, this was discovered
395 by using the same bitmap to iterate the different styles
396 on windows where it failed (BUT ImageList_Add is OK)
397 This is here in case some apps rely on this bug
400 0, 0, bmp.bmWidth, bmp.bmHeight,
403 0x220326); /* NOTSRCAND */
404 /* Copy result to the imagelist
406 imagelist_point_from_index( himl, nIndex, &pt );
407 BitBlt (himl->hdcImage,
408 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
414 SelectObject(hdcBitmap, hOldBitmap);
418 DeleteObject(hMaskBitmap);
426 /*************************************************************************
427 * ImageList_BeginDrag [COMCTL32.@]
429 * Creates a temporary image list that contains one image. It will be used
433 * himlTrack [I] handle to the source image list
434 * iTrack [I] index of the drag image in the source image list
435 * dxHotspot [I] X position of the hot spot of the drag image
436 * dyHotspot [I] Y position of the hot spot of the drag image
444 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
445 INT dxHotspot, INT dyHotspot)
449 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
450 dxHotspot, dyHotspot);
452 if (!is_valid(himlTrack))
455 if (InternalDrag.himl)
456 ImageList_EndDrag ();
461 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
462 if (InternalDrag.himl == NULL) {
463 WARN("Error creating drag image list!\n");
467 InternalDrag.dxHotspot = dxHotspot;
468 InternalDrag.dyHotspot = dyHotspot;
471 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
474 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
476 InternalDrag.himl->cCurImage = 1;
482 /*************************************************************************
483 * ImageList_Copy [COMCTL32.@]
485 * Copies an image of the source image list to an image of the
486 * destination image list. Images can be copied or swapped.
489 * himlDst [I] handle to the destination image list
490 * iDst [I] destination image index.
491 * himlSrc [I] handle to the source image list
492 * iSrc [I] source image index
493 * uFlags [I] flags for the copy operation
500 * Copying from one image list to another is possible. The original
501 * implementation just copies or swaps within one image list.
502 * Could this feature become a bug??? ;-)
506 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
507 INT iSrc, UINT uFlags)
511 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
513 if (!is_valid(himlSrc) || !is_valid(himlDst))
515 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
517 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
520 imagelist_point_from_index( himlDst, iDst, &ptDst );
521 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
523 if (uFlags & ILCF_SWAP) {
526 HBITMAP hbmTempImage, hbmTempMask;
528 hdcBmp = CreateCompatibleDC (0);
530 /* create temporary bitmaps */
531 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
532 himlSrc->uBitsPixel, NULL);
533 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
536 /* copy (and stretch) destination to temporary bitmaps.(save) */
538 SelectObject (hdcBmp, hbmTempImage);
539 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
540 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
543 SelectObject (hdcBmp, hbmTempMask);
544 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
545 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
548 /* copy (and stretch) source to destination */
550 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
551 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
554 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
555 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
558 /* copy (without stretching) temporary bitmaps to source (restore) */
560 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
561 hdcBmp, 0, 0, SRCCOPY);
564 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
565 hdcBmp, 0, 0, SRCCOPY);
566 /* delete temporary bitmaps */
567 DeleteObject (hbmTempMask);
568 DeleteObject (hbmTempImage);
573 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
574 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
578 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
579 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
587 /*************************************************************************
588 * ImageList_Create [COMCTL32.@]
590 * Creates a new image list.
593 * cx [I] image height
595 * flags [I] creation flags
596 * cInitial [I] initial number of images in the image list
597 * cGrow [I] number of images by which image list grows
600 * Success: Handle to the created image list
604 ImageList_Create (INT cx, INT cy, UINT flags,
605 INT cInitial, INT cGrow)
610 UINT ilc = (flags & 0xFE);
611 static const WORD aBitBlend25[] =
612 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
614 static const WORD aBitBlend50[] =
615 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
617 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
619 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
623 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
625 himl->magic = IMAGELIST_MAGIC;
629 himl->cMaxImage = cInitial + cGrow;
630 himl->cInitial = cInitial;
632 himl->clrFg = CLR_DEFAULT;
633 himl->clrBk = CLR_NONE;
635 /* initialize overlay mask indices */
636 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
637 himl->nOvlIdx[nCount] = -1;
639 /* Create Image & Mask DCs */
640 himl->hdcImage = CreateCompatibleDC (0);
643 if (himl->flags & ILC_MASK){
644 himl->hdcMask = CreateCompatibleDC(0);
649 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
650 if (ilc == ILC_COLOR)
653 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
654 himl->uBitsPixel = ilc;
656 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
658 if (himl->cMaxImage > 0) {
659 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cy);
660 SelectObject(himl->hdcImage, himl->hbmImage);
664 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
667 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
668 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
669 if (himl->hbmMask == 0) {
670 ERR("Error creating mask bitmap!\n");
673 SelectObject(himl->hdcMask, himl->hbmMask);
678 /* create blending brushes */
679 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
680 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
681 DeleteObject (hbmTemp);
683 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
684 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
685 DeleteObject (hbmTemp);
687 TRACE("created imagelist %p\n", himl);
691 if (himl) ImageList_Destroy(himl);
696 /*************************************************************************
697 * ImageList_Destroy [COMCTL32.@]
699 * Destroys an image list.
702 * himl [I] handle to image list
710 ImageList_Destroy (HIMAGELIST himl)
715 /* delete image bitmaps */
717 DeleteObject (himl->hbmImage);
719 DeleteObject (himl->hbmMask);
721 /* delete image & mask DCs */
723 DeleteDC(himl->hdcImage);
725 DeleteDC(himl->hdcMask);
727 /* delete blending brushes */
728 if (himl->hbrBlend25)
729 DeleteObject (himl->hbrBlend25);
730 if (himl->hbrBlend50)
731 DeleteObject (himl->hbrBlend50);
733 ZeroMemory(himl, sizeof(*himl));
740 /*************************************************************************
741 * ImageList_DragEnter [COMCTL32.@]
743 * Locks window update and displays the drag image at the given position.
746 * hwndLock [I] handle of the window that owns the drag image.
747 * x [I] X position of the drag image.
748 * y [I] Y position of the drag image.
755 * The position of the drag image is relative to the window, not
760 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
762 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
764 if (!is_valid(InternalDrag.himl))
768 InternalDrag.hwnd = hwndLock;
770 InternalDrag.hwnd = GetDesktopWindow ();
775 /* draw the drag image and save the background */
776 if (!ImageList_DragShowNolock(TRUE)) {
784 /*************************************************************************
785 * ImageList_DragLeave [COMCTL32.@]
787 * Unlocks window update and hides the drag image.
790 * hwndLock [I] handle of the window that owns the drag image.
798 ImageList_DragLeave (HWND hwndLock)
800 /* As we don't save drag info in the window this can lead to problems if
801 an app does not supply the same window as DragEnter */
803 InternalDrag.hwnd = hwndLock;
805 InternalDrag.hwnd = GetDesktopWindow (); */
807 hwndLock = GetDesktopWindow();
808 if(InternalDrag.hwnd != hwndLock)
809 FIXME("DragLeave hWnd != DragEnter hWnd\n");
811 ImageList_DragShowNolock (FALSE);
817 /*************************************************************************
818 * ImageList_InternalDragDraw [Internal]
820 * Draws the drag image.
823 * hdc [I] device context to draw into.
824 * x [I] X position of the drag image.
825 * y [I] Y position of the drag image.
832 * The position of the drag image is relative to the window, not
838 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
840 IMAGELISTDRAWPARAMS imldp;
842 ZeroMemory (&imldp, sizeof(imldp));
843 imldp.cbSize = sizeof(imldp);
844 imldp.himl = InternalDrag.himl;
849 imldp.rgbBk = CLR_DEFAULT;
850 imldp.rgbFg = CLR_DEFAULT;
851 imldp.fStyle = ILD_NORMAL;
852 imldp.fState = ILS_ALPHA;
855 /* FIXME: instead of using the alpha blending, we should
856 * create a 50% mask, and draw it semitransparantly that way */
857 ImageList_DrawIndirect (&imldp);
860 /*************************************************************************
861 * ImageList_DragMove [COMCTL32.@]
863 * Moves the drag image.
866 * x [I] X position of the drag image.
867 * y [I] Y position of the drag image.
874 * The position of the drag image is relative to the window, not
878 * The drag image should be drawn semitransparent.
882 ImageList_DragMove (INT x, INT y)
884 TRACE("(x=%d y=%d)\n", x, y);
886 if (!is_valid(InternalDrag.himl))
889 /* draw/update the drag image */
890 if (InternalDrag.bShow) {
894 HBITMAP hbmOffScreen;
895 INT origNewX, origNewY;
896 INT origOldX, origOldY;
897 INT origRegX, origRegY;
898 INT sizeRegX, sizeRegY;
901 /* calculate the update region */
902 origNewX = x - InternalDrag.dxHotspot;
903 origNewY = y - InternalDrag.dyHotspot;
904 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
905 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
906 origRegX = min(origNewX, origOldX);
907 origRegY = min(origNewY, origOldY);
908 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
909 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
911 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
912 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
913 hdcOffScreen = CreateCompatibleDC(hdcDrag);
914 hdcBg = CreateCompatibleDC(hdcDrag);
916 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
917 SelectObject(hdcOffScreen, hbmOffScreen);
918 SelectObject(hdcBg, InternalDrag.hbmBg);
920 /* get the actual background of the update region */
921 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
922 origRegX, origRegY, SRCCOPY);
923 /* erase the old image */
924 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
925 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
927 /* save the background */
928 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
929 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
931 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
932 origNewY - origRegY);
933 /* draw the update region to the screen */
934 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
935 hdcOffScreen, 0, 0, SRCCOPY);
938 DeleteDC(hdcOffScreen);
939 DeleteObject(hbmOffScreen);
940 ReleaseDC(InternalDrag.hwnd, hdcDrag);
943 /* update the image position */
951 /*************************************************************************
952 * ImageList_DragShowNolock [COMCTL32.@]
954 * Shows or hides the drag image.
957 * bShow [I] TRUE shows the drag image, FALSE hides it.
964 * The drag image should be drawn semitransparent.
968 ImageList_DragShowNolock (BOOL bShow)
974 if (!is_valid(InternalDrag.himl))
977 TRACE("bShow=0x%X!\n", bShow);
979 /* DragImage is already visible/hidden */
980 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
984 /* position of the origin of the DragImage */
985 x = InternalDrag.x - InternalDrag.dxHotspot;
986 y = InternalDrag.y - InternalDrag.dyHotspot;
988 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
989 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
994 hdcBg = CreateCompatibleDC(hdcDrag);
995 if (!InternalDrag.hbmBg) {
996 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
997 InternalDrag.himl->cx, InternalDrag.himl->cy);
999 SelectObject(hdcBg, InternalDrag.hbmBg);
1002 /* save the background */
1003 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1004 hdcDrag, x, y, SRCCOPY);
1005 /* show the image */
1006 ImageList_InternalDragDraw(hdcDrag, x, y);
1008 /* hide the image */
1009 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1010 hdcBg, 0, 0, SRCCOPY);
1013 InternalDrag.bShow = !InternalDrag.bShow;
1016 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1021 /*************************************************************************
1022 * ImageList_Draw [COMCTL32.@]
1027 * himl [I] handle to image list
1029 * hdc [I] handle to device context
1032 * fStyle [I] drawing flags
1043 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1045 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1046 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1050 /*************************************************************************
1051 * ImageList_DrawEx [COMCTL32.@]
1053 * Draws an image and allows to use extended drawing features.
1056 * himl [I] handle to image list
1058 * hdc [I] handle to device context
1063 * rgbBk [I] background color
1064 * rgbFg [I] foreground color
1065 * fStyle [I] drawing flags
1072 * Calls ImageList_DrawIndirect.
1075 * ImageList_DrawIndirect.
1079 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1080 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1083 IMAGELISTDRAWPARAMS imldp;
1085 ZeroMemory (&imldp, sizeof(imldp));
1086 imldp.cbSize = sizeof(imldp);
1094 imldp.rgbBk = rgbBk;
1095 imldp.rgbFg = rgbFg;
1096 imldp.fStyle = fStyle;
1098 return ImageList_DrawIndirect (&imldp);
1102 /*************************************************************************
1103 * ImageList_DrawIndirect [COMCTL32.@]
1105 * Draws an image using various parameters specified in pimldp.
1108 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1116 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1118 INT cx, cy, nOvlIdx;
1119 DWORD fState, dwRop;
1121 COLORREF oldImageBk, oldImageFg;
1122 HDC hImageDC, hImageListDC, hMaskListDC;
1123 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1124 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1128 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1129 if (!is_valid(himl)) return FALSE;
1130 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1132 imagelist_point_from_index( himl, pimldp->i, &pt );
1133 pt.x += pimldp->xBitmap;
1134 pt.y += pimldp->yBitmap;
1136 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1137 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1138 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1139 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1141 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1142 if( pimldp->rgbBk == CLR_NONE )
1143 bIsTransparent = TRUE;
1144 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1145 bIsTransparent = TRUE;
1146 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1147 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1149 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1150 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1152 /* we will use these DCs to access the images and masks in the ImageList */
1153 hImageListDC = himl->hdcImage;
1154 hMaskListDC = himl->hdcMask;
1156 /* these will accumulate the image and mask for the image we're drawing */
1157 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1158 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1159 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1161 /* Create a compatible DC. */
1162 if (!hImageListDC || !hImageDC || !hImageBmp ||
1163 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1166 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1169 * To obtain a transparent look, background color should be set
1170 * to white and foreground color to black when blting the
1173 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1174 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1177 * Draw the initial image
1180 if (himl->hbmMask) {
1182 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1183 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1184 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1185 DeleteObject (SelectObject (hImageDC, hOldBrush));
1186 if( bIsTransparent )
1188 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1193 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1194 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1195 SelectObject(hImageDC, hOldBrush);
1198 /* blend the image with the needed solid background */
1199 COLORREF colour = RGB(0,0,0);
1202 if( !bIsTransparent )
1204 colour = pimldp->rgbBk;
1205 if( colour == CLR_DEFAULT )
1206 colour = himl->clrBk;
1207 if( colour == CLR_NONE )
1208 colour = GetBkColor(pimldp->hdcDst);
1211 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1212 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1213 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1214 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1215 DeleteObject (SelectObject (hImageDC, hOldBrush));
1218 /* Time for blending, if required */
1220 HBRUSH hBlendBrush, hOldBrush;
1221 COLORREF clrBlend = pimldp->rgbFg;
1222 HDC hBlendMaskDC = hImageListDC;
1225 /* Create the blend Mask */
1226 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1227 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1228 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1229 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1230 SelectObject(hBlendMaskDC, hOldBrush);
1232 /* Modify the blend mask if an Image Mask exist */
1234 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1235 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1238 /* now apply blend to the current image given the BlendMask */
1239 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1240 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1241 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1242 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1243 DeleteObject(SelectObject(hImageDC, hOldBrush));
1244 SelectObject(hBlendMaskDC, hOldBitmap);
1247 /* Now do the overlay image, if any */
1248 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1249 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1250 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1251 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1253 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1254 ptOvl.x += pimldp->xBitmap;
1255 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1256 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1257 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1261 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1262 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1263 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1264 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1266 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1267 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1268 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1270 /* now copy the image to the screen */
1272 if (himl->hbmMask && bIsTransparent ) {
1273 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1274 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1275 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1276 SetBkColor(pimldp->hdcDst, oldDstBk);
1277 SetTextColor(pimldp->hdcDst, oldDstFg);
1280 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1281 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1285 /* cleanup the mess */
1286 SetBkColor(hImageDC, oldImageBk);
1287 SetTextColor(hImageDC, oldImageFg);
1288 SelectObject(hImageDC, hOldImageBmp);
1290 DeleteObject(hBlendMaskBmp);
1291 DeleteObject(hImageBmp);
1298 /*************************************************************************
1299 * ImageList_Duplicate [COMCTL32.@]
1301 * Duplicates an image list.
1304 * himlSrc [I] source image list handle
1307 * Success: Handle of duplicated image list.
1312 ImageList_Duplicate (HIMAGELIST himlSrc)
1316 if (!is_valid(himlSrc)) {
1317 ERR("Invalid image list handle!\n");
1321 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1322 himlSrc->cInitial, himlSrc->cGrow);
1328 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cy, &sz);
1329 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1330 himlSrc->hdcImage, 0, 0, SRCCOPY);
1332 if (himlDst->hbmMask)
1333 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1334 himlSrc->hdcMask, 0, 0, SRCCOPY);
1336 himlDst->cCurImage = himlSrc->cCurImage;
1337 himlDst->cMaxImage = himlSrc->cMaxImage;
1343 /*************************************************************************
1344 * ImageList_EndDrag [COMCTL32.@]
1346 * Finishes a drag operation.
1357 ImageList_EndDrag (void)
1359 /* cleanup the InternalDrag struct */
1360 InternalDrag.hwnd = 0;
1361 ImageList_Destroy (InternalDrag.himl);
1362 InternalDrag.himl = 0;
1365 InternalDrag.dxHotspot = 0;
1366 InternalDrag.dyHotspot = 0;
1367 InternalDrag.bShow = FALSE;
1368 DeleteObject(InternalDrag.hbmBg);
1369 InternalDrag.hbmBg = 0;
1373 /*************************************************************************
1374 * ImageList_GetBkColor [COMCTL32.@]
1376 * Returns the background color of an image list.
1379 * himl [I] Image list handle.
1382 * Success: background color
1387 ImageList_GetBkColor (HIMAGELIST himl)
1389 return himl ? himl->clrBk : CLR_NONE;
1393 /*************************************************************************
1394 * ImageList_GetDragImage [COMCTL32.@]
1396 * Returns the handle to the internal drag image list.
1399 * ppt [O] Pointer to the drag position. Can be NULL.
1400 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1403 * Success: Handle of the drag image list.
1408 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1410 if (is_valid(InternalDrag.himl)) {
1412 ppt->x = InternalDrag.x;
1413 ppt->y = InternalDrag.y;
1416 pptHotspot->x = InternalDrag.dxHotspot;
1417 pptHotspot->y = InternalDrag.dyHotspot;
1419 return (InternalDrag.himl);
1426 /*************************************************************************
1427 * ImageList_GetFlags [COMCTL32.@]
1429 * Gets the flags of the specified image list.
1432 * himl [I] Handle to image list
1442 ImageList_GetFlags(HIMAGELIST himl)
1444 FIXME("(%p):empty stub\n", himl);
1449 /*************************************************************************
1450 * ImageList_GetIcon [COMCTL32.@]
1452 * Creates an icon from a masked image of an image list.
1455 * himl [I] handle to image list
1457 * flags [I] drawing style flags
1460 * Success: icon handle
1465 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1469 HBITMAP hOldDstBitmap;
1473 TRACE("%p %d %d\n", himl, i, fStyle);
1474 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1480 /* create colour bitmap */
1482 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1483 ReleaseDC(0, hdcDst);
1485 hdcDst = CreateCompatibleDC(0);
1487 imagelist_point_from_index( himl, i, &pt );
1490 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1491 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1492 if (himl->hbmMask) {
1493 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1494 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1497 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1500 SelectObject (hdcDst, ii.hbmColor);
1501 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1502 himl->hdcImage, pt.x, pt.y, SRCCOPY);
1505 * CreateIconIndirect requires us to deselect the bitmaps from
1506 * the DCs before calling
1508 SelectObject(hdcDst, hOldDstBitmap);
1510 hIcon = CreateIconIndirect (&ii);
1512 DeleteObject (ii.hbmMask);
1513 DeleteObject (ii.hbmColor);
1520 /*************************************************************************
1521 * ImageList_GetIconSize [COMCTL32.@]
1523 * Retrieves the size of an image in an image list.
1526 * himl [I] handle to image list
1527 * cx [O] pointer to the image width.
1528 * cy [O] pointer to the image height.
1535 * All images in an image list have the same size.
1539 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1541 if (!is_valid(himl))
1543 if ((himl->cx <= 0) || (himl->cy <= 0))
1555 /*************************************************************************
1556 * ImageList_GetImageCount [COMCTL32.@]
1558 * Returns the number of images in an image list.
1561 * himl [I] handle to image list
1564 * Success: Number of images.
1569 ImageList_GetImageCount (HIMAGELIST himl)
1571 if (!is_valid(himl))
1574 return himl->cCurImage;
1578 /*************************************************************************
1579 * ImageList_GetImageInfo [COMCTL32.@]
1581 * Returns information about an image in an image list.
1584 * himl [I] handle to image list
1586 * pImageInfo [O] pointer to the image information
1594 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1598 if (!is_valid(himl) || (pImageInfo == NULL))
1600 if ((i < 0) || (i >= himl->cCurImage))
1603 pImageInfo->hbmImage = himl->hbmImage;
1604 pImageInfo->hbmMask = himl->hbmMask;
1606 imagelist_point_from_index( himl, i, &pt );
1607 pImageInfo->rcImage.top = pt.y;
1608 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1609 pImageInfo->rcImage.left = pt.x;
1610 pImageInfo->rcImage.right = pt.x + himl->cx;
1616 /*************************************************************************
1617 * ImageList_GetImageRect [COMCTL32.@]
1619 * Retrieves the rectangle of the specified image in an image list.
1622 * himl [I] handle to image list
1624 * lpRect [O] pointer to the image rectangle
1631 * This is an UNDOCUMENTED function!!!
1635 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1639 if (!is_valid(himl) || (lpRect == NULL))
1641 if ((i < 0) || (i >= himl->cCurImage))
1644 imagelist_point_from_index( himl, i, &pt );
1645 lpRect->left = pt.x;
1647 lpRect->right = pt.x + himl->cx;
1648 lpRect->bottom = pt.y + himl->cy;
1654 /*************************************************************************
1655 * ImageList_LoadImage [COMCTL32.@]
1656 * ImageList_LoadImageA [COMCTL32.@]
1658 * Creates an image list from a bitmap, icon or cursor.
1660 * See ImageList_LoadImageW.
1664 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1665 COLORREF clrMask, UINT uType, UINT uFlags)
1672 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1675 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1676 lpbmpW = Alloc(len * sizeof(WCHAR));
1677 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1679 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1685 /*************************************************************************
1686 * ImageList_LoadImageW [COMCTL32.@]
1688 * Creates an image list from a bitmap, icon or cursor.
1691 * hi [I] instance handle
1692 * lpbmp [I] name or id of the image
1693 * cx [I] width of each image
1694 * cGrow [I] number of images to expand
1695 * clrMask [I] mask color
1696 * uType [I] type of image to load
1697 * uFlags [I] loading flags
1700 * Success: handle to the loaded image list
1708 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1709 COLORREF clrMask, UINT uType, UINT uFlags)
1711 HIMAGELIST himl = NULL;
1715 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1717 ERR("Error loading image!\n");
1721 if (uType == IMAGE_BITMAP) {
1723 GetObjectW (handle, sizeof(BITMAP), &bmp);
1725 /* To match windows behavior, if cx is set to zero and
1726 the flag DI_DEFAULTSIZE is specified, cx becomes the
1727 system metric value for icons. If the flag is not specified
1728 the function sets the size to the height of the bitmap */
1731 if (uFlags & DI_DEFAULTSIZE)
1732 cx = GetSystemMetrics (SM_CXICON);
1737 nImageCount = bmp.bmWidth / cx;
1739 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1740 nImageCount, cGrow);
1742 DeleteObject (handle);
1745 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1747 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1751 GetIconInfo (handle, &ii);
1752 GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1753 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1754 ILC_MASK | ILC_COLOR, 1, cGrow);
1756 DeleteObject (ii.hbmColor);
1757 DeleteObject (ii.hbmMask);
1758 DeleteObject (handle);
1761 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1762 DeleteObject (ii.hbmColor);
1763 DeleteObject (ii.hbmMask);
1766 DeleteObject (handle);
1772 /*************************************************************************
1773 * ImageList_Merge [COMCTL32.@]
1775 * Create an image list containing a merged image from two image lists.
1778 * himl1 [I] handle to first image list
1779 * i1 [I] first image index
1780 * himl2 [I] handle to second image list
1781 * i2 [I] second image index
1782 * dx [I] X offset of the second image relative to the first.
1783 * dy [I] Y offset of the second image relative to the first.
1786 * Success: The newly created image list. It contains a single image
1787 * consisting of the second image merged with the first.
1788 * Failure: NULL, if either himl1 or himl2 are invalid.
1791 * - The returned image list should be deleted by the caller using
1792 * ImageList_Destroy() when it is no longer required.
1793 * - If either i1 or i2 are not valid image indices they will be treated
1797 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1800 HIMAGELIST himlDst = NULL;
1802 INT xOff1, yOff1, xOff2, yOff2;
1805 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1808 if (!is_valid(himl1) || !is_valid(himl2))
1812 cxDst = max (himl1->cx, dx + himl2->cx);
1817 cxDst = max (himl2->cx, himl1->cx - dx);
1822 cxDst = max (himl1->cx, himl2->cx);
1828 cyDst = max (himl1->cy, dy + himl2->cy);
1833 cyDst = max (himl2->cy, himl1->cy - dy);
1838 cyDst = max (himl1->cy, himl2->cy);
1843 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1847 imagelist_point_from_index( himl1, i1, &pt1 );
1848 imagelist_point_from_index( himl1, i2, &pt2 );
1851 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1852 if (i1 >= 0 && i1 < himl1->cCurImage)
1853 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
1854 if (i2 >= 0 && i2 < himl2->cCurImage)
1856 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
1857 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
1861 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1862 if (i1 >= 0 && i1 < himl1->cCurImage)
1863 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
1864 if (i2 >= 0 && i2 < himl2->cCurImage)
1865 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
1867 himlDst->cCurImage = 1;
1874 /* helper for _read_bitmap currently unused */
1876 static int may_use_dibsection(HDC hdc) {
1877 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1882 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1886 /* helper for ImageList_Read, see comments below */
1887 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1888 HDC xdc = 0, hBitmapDC =0;
1889 BITMAPFILEHEADER bmfh;
1890 BITMAPINFOHEADER bmih;
1891 int bitsperpixel,palspace,longsperline,width,height;
1892 LPBITMAPINFOHEADER bmihc = NULL;
1894 HBITMAP hbitmap = 0, hDIB = 0;
1897 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1898 (bmfh.bfType != (('M'<<8)|'B')) ||
1899 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1900 (bmih.biSize != sizeof(bmih))
1904 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1905 if (bitsperpixel<=8)
1906 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1909 width = bmih.biWidth;
1910 height = bmih.biHeight;
1911 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1912 if (!bmihc) goto ret1;
1913 memcpy(bmihc,&bmih,sizeof(bmih));
1914 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1915 bmihc->biSizeImage = (longsperline*height)<<2;
1917 /* read the palette right after the end of the bitmapinfoheader */
1919 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1923 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1924 if ((bitsperpixel>1) &&
1925 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1927 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1930 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1936 int i,nwidth,nheight,nRows;
1938 nwidth = width*(height/cy);
1940 nRows = (height/cy);
1942 if (bitsperpixel==1)
1943 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1945 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1947 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1950 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1953 hBitmapDC = CreateCompatibleDC(0);
1954 SelectObject(hBitmapDC, hbitmap);
1956 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1957 /* Do not forget that windows bitmaps are bottom->top */
1958 TRACE("nRows=%d\n", nRows);
1959 for (i=0; i < nRows; i++){
1960 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1961 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1967 if (xdc) ReleaseDC(0,xdc);
1968 if (bmihc) LocalFree((HLOCAL)bmihc);
1969 if (hDIB) DeleteObject(hDIB);
1970 if (hBitmapDC) DeleteDC(hBitmapDC);
1973 DeleteObject(hbitmap);
1980 /*************************************************************************
1981 * ImageList_Read [COMCTL32.@]
1983 * Reads an image list from a stream.
1986 * pstm [I] pointer to a stream
1989 * Success: handle to image list
1992 * The format is like this:
1993 * ILHEAD ilheadstruct;
1995 * for the color image part:
1996 * BITMAPFILEHEADER bmfh;
1997 * BITMAPINFOHEADER bmih;
1998 * only if it has a palette:
1999 * RGBQUAD rgbs[nr_of_paletted_colors];
2001 * BYTE colorbits[imagesize];
2003 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2004 * BITMAPFILEHEADER bmfh_mask;
2005 * BITMAPINFOHEADER bmih_mask;
2006 * only if it has a palette (it usually does not):
2007 * RGBQUAD rgbs[nr_of_paletted_colors];
2009 * BYTE maskbits[imagesize];
2011 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2012 * _read_bitmap needs to convert them.
2014 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2018 HBITMAP hbmColor=0,hbmMask=0;
2021 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2023 if (ilHead.usMagic != (('L' << 8) | 'I'))
2025 if (ilHead.usVersion != 0x101) /* probably version? */
2029 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2030 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2031 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2032 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2033 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2034 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2035 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2036 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2037 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2038 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2041 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2043 WARN("failed to read bitmap from stream\n");
2046 if (ilHead.flags & ILC_MASK) {
2047 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2049 DeleteObject(hbmColor);
2054 himl = ImageList_Create (
2062 DeleteObject(hbmColor);
2063 DeleteObject(hbmMask);
2066 SelectObject(himl->hdcImage, hbmColor);
2067 DeleteObject(himl->hbmImage);
2068 himl->hbmImage = hbmColor;
2070 SelectObject(himl->hdcMask, hbmMask);
2071 DeleteObject(himl->hbmMask);
2072 himl->hbmMask = hbmMask;
2074 himl->cCurImage = ilHead.cCurImage;
2075 himl->cMaxImage = ilHead.cMaxImage;
2077 ImageList_SetBkColor(himl,ilHead.bkcolor);
2079 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2084 /*************************************************************************
2085 * ImageList_Remove [COMCTL32.@]
2087 * Removes an image from an image list
2090 * himl [I] image list handle
2099 ImageList_Remove (HIMAGELIST himl, INT i)
2101 HBITMAP hbmNewImage, hbmNewMask;
2106 TRACE("(himl=%p i=%d)\n", himl, i);
2108 if (!is_valid(himl)) {
2109 ERR("Invalid image list handle!\n");
2113 if ((i < -1) || (i >= himl->cCurImage)) {
2114 TRACE("index out of range! %d\n", i);
2120 if (himl->cCurImage == 0) {
2121 /* remove all on empty ImageList is allowed */
2122 TRACE("remove all on empty ImageList!\n");
2126 himl->cMaxImage = himl->cInitial + himl->cGrow;
2127 himl->cCurImage = 0;
2128 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2129 himl->nOvlIdx[nCount] = -1;
2131 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2132 SelectObject (himl->hdcImage, hbmNewImage);
2133 DeleteObject (himl->hbmImage);
2134 himl->hbmImage = hbmNewImage;
2136 if (himl->hbmMask) {
2138 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2139 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2140 SelectObject (himl->hdcMask, hbmNewMask);
2141 DeleteObject (himl->hbmMask);
2142 himl->hbmMask = hbmNewMask;
2146 /* delete one image */
2147 TRACE("Remove single image! %d\n", i);
2149 /* create new bitmap(s) */
2150 nCount = (himl->cCurImage + himl->cGrow - 1);
2152 TRACE(" - Number of images: %d / %d (Old/New)\n",
2153 himl->cCurImage, himl->cCurImage - 1);
2154 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2155 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2157 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, nCount, himl->cy);
2159 imagelist_get_bitmap_size(himl, nCount, himl->cy, &sz );
2161 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2163 hbmNewMask = 0; /* Just to keep compiler happy! */
2165 hdcBmp = CreateCompatibleDC (0);
2167 /* copy all images and masks prior to the "removed" image */
2169 TRACE("Pre image copy: Copy %d images\n", i);
2171 SelectObject (hdcBmp, hbmNewImage);
2172 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2174 if (himl->hbmMask) {
2175 SelectObject (hdcBmp, hbmNewMask);
2176 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2180 /* copy all images and masks behind the removed image */
2181 if (i < himl->cCurImage - 1) {
2182 TRACE("Post image copy!\n");
2184 SelectObject (hdcBmp, hbmNewImage);
2185 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i,
2186 (himl->cCurImage - i - 1), i + 1 );
2188 if (himl->hbmMask) {
2189 SelectObject (hdcBmp, hbmNewMask);
2190 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i,
2191 (himl->cCurImage - i - 1), i + 1 );
2197 /* delete old images and insert new ones */
2198 SelectObject (himl->hdcImage, hbmNewImage);
2199 DeleteObject (himl->hbmImage);
2200 himl->hbmImage = hbmNewImage;
2201 if (himl->hbmMask) {
2202 SelectObject (himl->hdcMask, hbmNewMask);
2203 DeleteObject (himl->hbmMask);
2204 himl->hbmMask = hbmNewMask;
2208 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2215 /*************************************************************************
2216 * ImageList_Replace [COMCTL32.@]
2218 * Replaces an image in an image list with a new image.
2221 * himl [I] handle to image list
2223 * hbmImage [I] handle to image bitmap
2224 * hbmMask [I] handle to mask bitmap. Can be NULL.
2232 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2240 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2242 if (!is_valid(himl)) {
2243 ERR("Invalid image list handle!\n");
2247 if ((i >= himl->cMaxImage) || (i < 0)) {
2248 ERR("Invalid image index!\n");
2252 if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
2255 hdcImage = CreateCompatibleDC (0);
2258 hOldBitmap = SelectObject (hdcImage, hbmImage);
2260 imagelist_point_from_index(himl, i, &pt);
2261 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2262 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2267 HBITMAP hOldBitmapTemp;
2269 hdcTemp = CreateCompatibleDC(0);
2270 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2272 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2273 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2274 SelectObject(hdcTemp, hOldBitmapTemp);
2277 /* Remove the background from the image
2279 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2280 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2283 SelectObject (hdcImage, hOldBitmap);
2284 DeleteDC (hdcImage);
2290 /*************************************************************************
2291 * ImageList_ReplaceIcon [COMCTL32.@]
2293 * Replaces an image in an image list using an icon.
2296 * himl [I] handle to image list
2298 * hIcon [I] handle to icon
2301 * Success: index of the replaced image
2306 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2317 TRACE("(%p %d %p)\n", himl, i, hIcon);
2319 if (!is_valid(himl)) {
2320 ERR("invalid image list\n");
2323 if ((i >= himl->cMaxImage) || (i < -1)) {
2324 ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2328 hBestFitIcon = CopyImage(
2331 LR_COPYFROMRESOURCE);
2332 /* the above will fail if the icon wasn't loaded from a resource, so try
2333 * again without LR_COPYFROMRESOURCE flag */
2335 hBestFitIcon = CopyImage(
2342 ret = GetIconInfo (hBestFitIcon, &ii);
2344 DestroyIcon(hBestFitIcon);
2348 if (ii.hbmColor == 0)
2350 ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2352 ERR("couldn't get mask bitmap info\n");
2354 DeleteObject (ii.hbmColor);
2356 DeleteObject (ii.hbmMask);
2357 DestroyIcon(hBestFitIcon);
2362 if (himl->cCurImage + 1 > himl->cMaxImage)
2363 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2365 nIndex = himl->cCurImage;
2371 hdcImage = CreateCompatibleDC (0);
2372 TRACE("hdcImage=%p\n", hdcImage);
2374 ERR("invalid hdcImage!\n");
2376 SetTextColor(himl->hdcImage, RGB(0,0,0));
2377 SetBkColor (himl->hdcImage, RGB(255,255,255));
2378 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2380 imagelist_point_from_index(himl, nIndex, &pt);
2381 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2382 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2384 if (himl->hbmMask) {
2385 SelectObject (hdcImage, ii.hbmMask);
2386 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2387 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2390 SelectObject (hdcImage, hbmOldSrc);
2392 DestroyIcon(hBestFitIcon);
2394 DeleteDC (hdcImage);
2396 DeleteObject (ii.hbmColor);
2398 DeleteObject (ii.hbmMask);
2400 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2405 /*************************************************************************
2406 * ImageList_SetBkColor [COMCTL32.@]
2408 * Sets the background color of an image list.
2411 * himl [I] handle to image list
2412 * clrBk [I] background color
2415 * Success: previous background color
2420 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2424 if (!is_valid(himl))
2427 clrOldBk = himl->clrBk;
2428 himl->clrBk = clrBk;
2433 /*************************************************************************
2434 * ImageList_SetDragCursorImage [COMCTL32.@]
2436 * Combines the specified image with the current drag image
2439 * himlDrag [I] handle to drag image list
2440 * iDrag [I] drag image index
2441 * dxHotspot [I] X position of the hot spot
2442 * dyHotspot [I] Y position of the hot spot
2449 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2450 * to do with a hotspot but are only the offset of the origin of the new
2451 * image relative to the origin of the old image.
2453 * - When this function is called and the drag image is visible, a
2454 * short flickering occurs but this matches the Win9x behavior. It is
2455 * possible to fix the flickering using code like in ImageList_DragMove.
2459 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2460 INT dxHotspot, INT dyHotspot)
2462 HIMAGELIST himlTemp;
2465 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2468 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2469 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2471 visible = InternalDrag.bShow;
2473 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2474 dxHotspot, dyHotspot);
2477 /* hide the drag image */
2478 ImageList_DragShowNolock(FALSE);
2480 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2481 (InternalDrag.himl->cy != himlTemp->cy)) {
2482 /* the size of the drag image changed, invalidate the buffer */
2483 DeleteObject(InternalDrag.hbmBg);
2484 InternalDrag.hbmBg = 0;
2487 ImageList_Destroy (InternalDrag.himl);
2488 InternalDrag.himl = himlTemp;
2491 /* show the drag image */
2492 ImageList_DragShowNolock(TRUE);
2499 /*************************************************************************
2500 * ImageList_SetFilter [COMCTL32.@]
2502 * Sets a filter (or does something completely different)!!???
2503 * It removes 12 Bytes from the stack (3 Parameters).
2506 * himl [I] SHOULD be a handle to image list
2507 * i [I] COULD be an index?
2512 * Failure: FALSE ???
2515 * This is an UNDOCUMENTED function!!!!
2520 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2522 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2528 /*************************************************************************
2529 * ImageList_SetFlags [COMCTL32.@]
2531 * Sets the image list flags.
2534 * himl [I] Handle to image list
2535 * flags [I] Flags to set
2545 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2547 FIXME("(%p %08x):empty stub\n", himl, flags);
2552 /*************************************************************************
2553 * ImageList_SetIconSize [COMCTL32.@]
2555 * Sets the image size of the bitmap and deletes all images.
2558 * himl [I] handle to image list
2559 * cx [I] image width
2560 * cy [I] image height
2568 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2573 if (!is_valid(himl))
2576 /* remove all images */
2577 himl->cMaxImage = himl->cInitial + himl->cGrow;
2578 himl->cCurImage = 0;
2582 /* initialize overlay mask indices */
2583 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2584 himl->nOvlIdx[nCount] = -1;
2586 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2587 SelectObject (himl->hdcImage, hbmNew);
2588 DeleteObject (himl->hbmImage);
2589 himl->hbmImage = hbmNew;
2591 if (himl->hbmMask) {
2593 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2594 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2595 SelectObject (himl->hdcMask, hbmNew);
2596 DeleteObject (himl->hbmMask);
2597 himl->hbmMask = hbmNew;
2604 /*************************************************************************
2605 * ImageList_SetImageCount [COMCTL32.@]
2607 * Resizes an image list to the specified number of images.
2610 * himl [I] handle to image list
2611 * iImageCount [I] number of images in the image list
2619 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2622 HBITMAP hbmNewBitmap;
2623 INT nNewCount, nCopyCount;
2625 TRACE("%p %d\n",himl,iImageCount);
2627 if (!is_valid(himl))
2629 if (iImageCount < 0)
2631 if (himl->cMaxImage > iImageCount)
2633 himl->cCurImage = iImageCount;
2634 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2638 nNewCount = iImageCount + himl->cGrow;
2639 nCopyCount = min(himl->cCurImage, iImageCount);
2641 hdcBitmap = CreateCompatibleDC (0);
2643 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cy);
2645 if (hbmNewBitmap != 0)
2647 SelectObject (hdcBitmap, hbmNewBitmap);
2648 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2650 /* FIXME: delete 'empty' image space? */
2652 SelectObject (himl->hdcImage, hbmNewBitmap);
2653 DeleteObject (himl->hbmImage);
2654 himl->hbmImage = hbmNewBitmap;
2657 ERR("Could not create new image bitmap !\n");
2662 imagelist_get_bitmap_size( himl, nNewCount, himl->cy, &sz );
2663 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2664 if (hbmNewBitmap != 0)
2666 SelectObject (hdcBitmap, hbmNewBitmap);
2667 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2669 /* FIXME: delete 'empty' image space? */
2671 SelectObject (himl->hdcMask, hbmNewBitmap);
2672 DeleteObject (himl->hbmMask);
2673 himl->hbmMask = hbmNewBitmap;
2676 ERR("Could not create new mask bitmap!\n");
2679 DeleteDC (hdcBitmap);
2681 /* Update max image count and current image count */
2682 himl->cMaxImage = nNewCount;
2683 himl->cCurImage = iImageCount;
2689 /*************************************************************************
2690 * ImageList_SetOverlayImage [COMCTL32.@]
2692 * Assigns an overlay mask index to an existing image in an image list.
2695 * himl [I] handle to image list
2696 * iImage [I] image index
2697 * iOverlay [I] overlay mask index
2705 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2707 if (!is_valid(himl))
2709 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2711 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2713 himl->nOvlIdx[iOverlay - 1] = iImage;
2719 /* helper for ImageList_Write - write bitmap to pstm
2720 * currently everything is written as 24 bit RGB, except masks
2723 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2725 LPBITMAPFILEHEADER bmfh;
2726 LPBITMAPINFOHEADER bmih;
2727 LPBYTE data = NULL, lpBits = NULL, lpBitsOrg = NULL;
2729 INT bitCount, sizeImage, offBits, totalSize;
2730 INT nwidth, nheight, nsizeImage, icount;
2732 BOOL result = FALSE;
2736 if (!GetObjectW(hBitmap, sizeof(BITMAP), (LPVOID)&bm))
2739 /* XXX is this always correct? */
2740 icount = bm.bmWidth / cx;
2742 nheight = cy * icount;
2744 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2745 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2746 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2748 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2750 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2751 offBits = totalSize;
2752 totalSize += nsizeImage;
2754 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2755 bmfh = (LPBITMAPFILEHEADER)data;
2756 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2757 lpBits = data + offBits;
2759 /* setup BITMAPFILEHEADER */
2760 bmfh->bfType = (('M' << 8) | 'B');
2762 bmfh->bfReserved1 = 0;
2763 bmfh->bfReserved2 = 0;
2764 bmfh->bfOffBits = offBits;
2766 /* setup BITMAPINFOHEADER */
2767 bmih->biSize = sizeof(BITMAPINFOHEADER);
2768 bmih->biWidth = bm.bmWidth;
2769 bmih->biHeight = bm.bmHeight;
2771 bmih->biBitCount = bitCount;
2772 bmih->biCompression = BI_RGB;
2773 bmih->biSizeImage = sizeImage;
2774 bmih->biXPelsPerMeter = 0;
2775 bmih->biYPelsPerMeter = 0;
2776 bmih->biClrUsed = 0;
2777 bmih->biClrImportant = 0;
2779 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2780 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2781 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2785 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2786 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2788 for(i = 0; i < nheight; i++) {
2789 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2790 int noff = (nbpl * (nheight-1-i));
2791 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2795 bmih->biWidth = nwidth;
2796 bmih->biHeight = nheight;
2797 bmih->biSizeImage = nsizeImage;
2801 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2802 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2803 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2806 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2813 LocalFree((HLOCAL)lpBitsOrg);
2814 LocalFree((HLOCAL)data);
2820 /*************************************************************************
2821 * ImageList_Write [COMCTL32.@]
2823 * Writes an image list to a stream.
2826 * himl [I] handle to image list
2827 * pstm [O] Pointer to a stream.
2838 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2843 if (!is_valid(himl))
2846 ilHead.usMagic = (('L' << 8) | 'I');
2847 ilHead.usVersion = 0x101;
2848 ilHead.cCurImage = himl->cCurImage;
2849 ilHead.cMaxImage = himl->cMaxImage;
2850 ilHead.cGrow = himl->cGrow;
2851 ilHead.cx = himl->cx;
2852 ilHead.cy = himl->cy;
2853 ilHead.bkcolor = himl->clrBk;
2854 ilHead.flags = himl->flags;
2855 for(i = 0; i < 4; i++) {
2856 ilHead.ovls[i] = himl->nOvlIdx[i];
2859 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2862 /* write the bitmap */
2863 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2866 /* write the mask if we have one */
2867 if(himl->flags & ILC_MASK) {
2868 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2876 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height)
2878 HBITMAP hbmNewBitmap;
2879 UINT ilc = (himl->flags & 0xFE);
2882 imagelist_get_bitmap_size( himl, count, height, &sz );
2884 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2889 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2891 if (himl->uBitsPixel <= ILC_COLOR8)
2897 colors = 1 << himl->uBitsPixel;
2898 bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2899 sizeof(PALETTEENTRY) * colors);
2901 pal = (LPPALETTEENTRY)bmi->bmiColors;
2902 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2904 /* Swap colors returned by GetPaletteEntries so we can use them for
2905 * CreateDIBSection call. */
2906 for (i = 0; i < colors; i++)
2908 temp = pal[i].peBlue;
2909 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2910 bmi->bmiColors[i].rgbBlue = temp;
2915 bmi = Alloc(sizeof(BITMAPINFOHEADER));
2918 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2919 bmi->bmiHeader.biWidth = sz.cx;
2920 bmi->bmiHeader.biHeight = sz.cy;
2921 bmi->bmiHeader.biPlanes = 1;
2922 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2923 bmi->bmiHeader.biCompression = BI_RGB;
2924 bmi->bmiHeader.biSizeImage = 0;
2925 bmi->bmiHeader.biXPelsPerMeter = 0;
2926 bmi->bmiHeader.biYPelsPerMeter = 0;
2927 bmi->bmiHeader.biClrUsed = 0;
2928 bmi->bmiHeader.biClrImportant = 0;
2930 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2934 else /*if (ilc == ILC_COLORDDB)*/
2936 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2938 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
2940 TRACE("returning %p\n", hbmNewBitmap);
2941 return hbmNewBitmap;
2944 /*************************************************************************
2945 * ImageList_SetColorTable [COMCTL32.@]
2947 * Sets the color table of an image list.
2950 * himl [I] Handle to the image list.
2951 * uStartIndex [I] The first index to set.
2952 * cEntries [I] Number of entries to set.
2953 * prgb [I] New color information for color table for the image list.
2956 * Success: Number of entries in the table that were set.
2960 * ImageList_Create(), SetDIBColorTable()
2964 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2966 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);