2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we belive this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
38 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
39 * is the offset of the image position relative to the actual mouse pointer
40 * position. However the Hotspot passed to SetDragCursorImage is the
41 * offset of the mouse messages sent to the application...
50 #include "imagelist.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
56 #define MAX_OVERLAYIMAGE 15
58 /* internal image list data used for Drag & Drop operations */
63 /* position of the drag image relative to the window */
66 /* offset of the hotspot relative to the origin of the image */
69 /* is the drag image visible */
71 /* saved background */
76 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
80 /*************************************************************************
81 * IMAGELIST_InternalExpandBitmaps [Internal]
83 * Expands the bitmaps of an image list by the given number of images.
86 * himl [I] handle to image list
87 * nImageCount [I] number of images to add
93 * This function can NOT be used to reduce the number of images.
96 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
98 HDC hdcImageList, hdcBitmap;
100 INT nNewWidth, nNewCount;
102 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
106 if (cy == 0) cy = himl->cy;
107 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
108 nNewWidth = nNewCount * himl->cx;
110 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
111 hdcImageList = CreateCompatibleDC (0);
112 hdcBitmap = CreateCompatibleDC (0);
115 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
116 if (hbmNewBitmap == 0)
117 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
119 SelectObject (hdcImageList, himl->hbmImage);
120 SelectObject (hdcBitmap, hbmNewBitmap);
121 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
122 hdcImageList, 0, 0, SRCCOPY);
124 DeleteObject (himl->hbmImage);
125 himl->hbmImage = hbmNewBitmap;
129 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
131 if (hbmNewBitmap == 0)
132 ERR("creating new mask bitmap!\n");
134 SelectObject (hdcImageList, himl->hbmMask);
135 SelectObject (hdcBitmap, hbmNewBitmap);
136 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
137 hdcImageList, 0, 0, SRCCOPY);
138 DeleteObject (himl->hbmMask);
139 himl->hbmMask = hbmNewBitmap;
142 himl->cMaxImage = nNewCount;
144 DeleteDC (hdcImageList);
145 DeleteDC (hdcBitmap);
149 /*************************************************************************
150 * ImageList_Add [COMCTL32.@]
152 * Add an image or images to an image list.
155 * himl [I] handle to image list
156 * hbmImage [I] handle to image bitmap
157 * hbmMask [I] handle to mask bitmap
160 * Success: Index of the first new image.
165 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
167 HDC hdcImage, hdcBitmap;
168 INT nFirstIndex, nImageCount;
171 HBITMAP hOldBitmapImage, hOldBitmap;
173 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
174 if (!himl || !hbmImage)
177 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
178 nImageCount = bmp.bmWidth / himl->cx;
180 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
182 nStartX = himl->cCurImage * himl->cx;
184 hdcImage = CreateCompatibleDC(0);
185 hdcBitmap = CreateCompatibleDC(0);
187 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
188 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
190 /* Copy result to the imagelist
192 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
193 hdcBitmap, 0, 0, SRCCOPY);
197 HDC hdcMask, hdcTemp;
198 HBITMAP hOldBitmapMask, hOldBitmapTemp;
200 hdcMask = CreateCompatibleDC (0);
201 hdcTemp = CreateCompatibleDC(0);
202 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
203 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
206 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
211 SelectObject(hdcTemp, hOldBitmapTemp);
214 /* Remove the background from the image
217 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
220 0x220326); /* NOTSRCAND */
222 SelectObject(hdcMask, hOldBitmapMask);
226 SelectObject(hdcImage, hOldBitmapImage);
227 SelectObject(hdcBitmap, hOldBitmap);
231 nFirstIndex = himl->cCurImage;
232 himl->cCurImage += nImageCount;
238 /*************************************************************************
239 * ImageList_AddIcon [COMCTL32.@]
241 * Adds an icon to an image list.
244 * himl [I] handle to image list
245 * hIcon [I] handle to icon
248 * Success: index of the new image
253 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
255 return ImageList_ReplaceIcon (himl, -1, hIcon);
259 /*************************************************************************
260 * ImageList_AddMasked [COMCTL32.@]
262 * Adds an image or images to an image list and creates a mask from the
263 * specified bitmap using the mask color.
266 * himl [I] handle to image list.
267 * hBitmap [I] handle to bitmap
268 * clrMask [I] mask color.
271 * Success: Index of the first new image.
276 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
278 HDC hdcImage, hdcMask, hdcBitmap;
279 INT nIndex, nImageCount, nMaskXOffset=0;
281 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
282 HBITMAP hMaskBitmap=0;
285 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
289 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
292 nImageCount = bmp.bmWidth / himl->cx;
294 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
296 nIndex = himl->cCurImage;
297 himl->cCurImage += nImageCount;
299 hdcMask = CreateCompatibleDC (0);
300 hdcImage = CreateCompatibleDC(0);
301 hdcBitmap = CreateCompatibleDC(0);
304 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
305 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
308 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
309 nMaskXOffset = nIndex * himl->cx;
314 Create a temp Mask so we can remove the background of
315 the Image (Windows does this even if there is no mask)
317 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
318 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
321 /* create monochrome image to the mask bitmap */
322 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
323 GetPixel (hdcBitmap, 0, 0);
324 SetBkColor (hdcBitmap, bkColor);
326 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
330 SetBkColor(hdcBitmap, RGB(255,255,255));
331 /*Remove the background from the image
334 WINDOWS BUG ALERT!!!!!!
335 The statement below should not be done in common practice
336 but this is how ImageList_AddMasked works in Windows.
337 It overwrites the original bitmap passed, this was discovered
338 by using the same bitmap to iterate the different styles
339 on windows where it failed (BUT ImageList_Add is OK)
340 This is here in case some apps rely on this bug
343 0, 0, bmp.bmWidth, bmp.bmHeight,
346 0x220326); /* NOTSRCAND */
347 /* Copy result to the imagelist
350 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
356 SelectObject(hdcMask,hOldBitmapMask);
357 SelectObject(hdcImage, hOldBitmapImage);
358 SelectObject(hdcBitmap, hOldBitmap);
364 DeleteObject(hMaskBitmap);
371 /*************************************************************************
372 * ImageList_BeginDrag [COMCTL32.@]
374 * Creates a temporary image list that contains one image. It will be used
378 * himlTrack [I] handle to the source image list
379 * iTrack [I] index of the drag image in the source image list
380 * dxHotspot [I] X position of the hot spot of the drag image
381 * dyHotspot [I] Y position of the hot spot of the drag image
389 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
390 INT dxHotspot, INT dyHotspot)
395 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
396 dxHotspot, dyHotspot);
398 if (himlTrack == NULL)
401 if (InternalDrag.himl)
402 ImageList_EndDrag ();
407 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
408 if (InternalDrag.himl == NULL) {
409 WARN("Error creating drag image list!\n");
413 InternalDrag.dxHotspot = dxHotspot;
414 InternalDrag.dyHotspot = dyHotspot;
416 hdcSrc = CreateCompatibleDC (0);
417 hdcDst = CreateCompatibleDC (0);
420 SelectObject (hdcSrc, himlTrack->hbmImage);
421 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
422 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
425 SelectObject (hdcSrc, himlTrack->hbmMask);
426 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
427 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
432 InternalDrag.himl->cCurImage = 1;
433 InternalDrag.bHSPending = TRUE;
439 /*************************************************************************
440 * ImageList_Copy [COMCTL32.@]
442 * Copies an image of the source image list to an image of the
443 * destination image list. Images can be copied or swapped.
446 * himlDst [I] handle to the destination image list
447 * iDst [I] destination image index.
448 * himlSrc [I] handle to the source image list
449 * iSrc [I] source image index
450 * uFlags [I] flags for the copy operation
457 * Copying from one image list to another is possible. The original
458 * implementation just copies or swaps within one image list.
459 * Could this feature become a bug??? ;-)
463 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
464 INT iSrc, INT uFlags)
468 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
470 if ((himlSrc == NULL) || (himlDst == NULL))
472 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
474 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
477 hdcSrc = CreateCompatibleDC (0);
478 if (himlDst == himlSrc)
481 hdcDst = CreateCompatibleDC (0);
483 if (uFlags & ILCF_SWAP) {
485 HBITMAP hbmTempImage, hbmTempMask;
487 /* create temporary bitmaps */
488 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
489 himlSrc->uBitsPixel, NULL);
490 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
493 /* copy (and stretch) destination to temporary bitmaps.(save) */
495 SelectObject (hdcSrc, himlDst->hbmImage);
496 SelectObject (hdcDst, hbmTempImage);
497 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
498 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
501 SelectObject (hdcSrc, himlDst->hbmMask);
502 SelectObject (hdcDst, hbmTempMask);
503 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
504 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
507 /* copy (and stretch) source to destination */
509 SelectObject (hdcSrc, himlSrc->hbmImage);
510 SelectObject (hdcDst, himlDst->hbmImage);
511 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
512 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
515 SelectObject (hdcSrc, himlSrc->hbmMask);
516 SelectObject (hdcDst, himlDst->hbmMask);
517 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
518 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
521 /* copy (without stretching) temporary bitmaps to source (restore) */
523 SelectObject (hdcSrc, hbmTempImage);
524 SelectObject (hdcDst, himlSrc->hbmImage);
525 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
526 hdcSrc, 0, 0, SRCCOPY);
528 SelectObject (hdcSrc, hbmTempMask);
529 SelectObject (hdcDst, himlSrc->hbmMask);
530 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
531 hdcSrc, 0, 0, SRCCOPY);
533 /* delete temporary bitmaps */
534 DeleteObject (hbmTempMask);
535 DeleteObject (hbmTempImage);
539 SelectObject (hdcSrc, himlSrc->hbmImage);
540 if (himlSrc == himlDst)
543 SelectObject (hdcDst, himlDst->hbmImage);
544 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
545 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
549 SelectObject (hdcSrc, himlSrc->hbmMask);
550 if (himlSrc == himlDst)
553 SelectObject (hdcDst, himlDst->hbmMask);
554 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
555 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
560 if (himlSrc != himlDst)
567 /*************************************************************************
568 * ImageList_Create [COMCTL32.@] Creates a new image list.
571 * cx [I] image height
573 * flags [I] creation flags
574 * cInitial [I] initial number of images in the image list
575 * cGrow [I] number of images by which image list grows
578 * Success: Handle to the created image list
583 ImageList_Create (INT cx, INT cy, UINT flags,
584 INT cInitial, INT cGrow)
590 static WORD aBitBlend25[] =
591 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
593 static WORD aBitBlend50[] =
594 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
596 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
598 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
605 himl->cMaxImage = cInitial + cGrow;
606 himl->cInitial = cInitial;
609 himl->clrFg = CLR_DEFAULT;
610 himl->clrBk = CLR_NONE;
612 /* initialize overlay mask indices */
613 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
614 himl->nOvlIdx[nCount] = -1;
616 hdc = CreateCompatibleDC (0);
617 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
620 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
622 if (himl->cMaxImage > 0) {
624 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
625 1, himl->uBitsPixel, NULL);
626 if (himl->hbmImage == 0) {
627 ERR("Error creating image bitmap!\n");
634 if ( (himl->flags & ILC_MASK)) {
635 int images = himl->cMaxImage;
639 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
641 if (himl->hbmMask == 0) {
642 ERR("Error creating mask bitmap!\n");
644 DeleteObject (himl->hbmImage);
651 /* create blending brushes */
652 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
653 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
654 DeleteObject (hbmTemp);
656 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
657 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
658 DeleteObject (hbmTemp);
660 TRACE("created imagelist %p\n", himl);
665 /*************************************************************************
666 * ImageList_Destroy [COMCTL32.@]
668 * Destroys an image list.
671 * himl [I] handle to image list
679 ImageList_Destroy (HIMAGELIST himl)
684 /* delete image bitmaps */
686 DeleteObject (himl->hbmImage);
688 DeleteObject (himl->hbmMask);
690 /* delete blending brushes */
691 if (himl->hbrBlend25)
692 DeleteObject (himl->hbrBlend25);
693 if (himl->hbrBlend50)
694 DeleteObject (himl->hbrBlend50);
696 ZeroMemory(himl, sizeof(*himl));
697 COMCTL32_Free (himl);
703 /*************************************************************************
704 * ImageList_DragEnter [COMCTL32.@]
706 * Locks window update and displays the drag image at the given position.
709 * hwndLock [I] handle of the window that owns the drag image.
710 * x [I] X position of the drag image.
711 * y [I] Y position of the drag image.
718 * The position of the drag image is relative to the window, not
723 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
725 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
727 if (InternalDrag.himl == NULL)
731 InternalDrag.hwnd = hwndLock;
733 InternalDrag.hwnd = GetDesktopWindow ();
738 /* draw the drag image and save the background */
739 if (!ImageList_DragShowNolock(TRUE)) {
747 /*************************************************************************
748 * ImageList_DragLeave [COMCTL32.@]
750 * Unlocks window update and hides the drag image.
753 * hwndLock [I] handle of the window that owns the drag image.
761 ImageList_DragLeave (HWND hwndLock)
763 /* As we don't save drag info in the window this can lead to problems if
764 an app does not supply the same window as DragEnter */
766 InternalDrag.hwnd = hwndLock;
768 InternalDrag.hwnd = GetDesktopWindow (); */
770 hwndLock = GetDesktopWindow();
771 if(InternalDrag.hwnd != hwndLock)
772 FIXME("DragLeave hWnd != DragEnter hWnd\n");
774 ImageList_DragShowNolock (FALSE);
780 /*************************************************************************
781 * ImageList_InternalDragDraw [Internal]
783 * Draws the drag image.
786 * hdc [I] device context to draw into.
787 * x [I] X position of the drag image.
788 * y [I] Y position of the drag image.
795 * The position of the drag image is relative to the window, not
801 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
803 IMAGELISTDRAWPARAMS imldp;
805 ZeroMemory (&imldp, sizeof(imldp));
806 imldp.cbSize = sizeof(imldp);
807 imldp.himl = InternalDrag.himl;
812 imldp.rgbBk = CLR_DEFAULT;
813 imldp.rgbFg = CLR_DEFAULT;
814 imldp.fStyle = ILD_NORMAL;
815 imldp.fState = ILS_ALPHA;
818 /* FIXME: instead of using the alpha blending, we should
819 * create a 50% mask, and draw it semitransparantly that way */
820 ImageList_DrawIndirect (&imldp);
823 /*************************************************************************
824 * ImageList_DragMove [COMCTL32.@]
826 * Moves the drag image.
829 * x [I] X position of the drag image.
830 * y [I] Y position of the drag image.
837 * The position of the drag image is relative to the window, not
841 * The drag image should be drawn semitransparent.
845 ImageList_DragMove (INT x, INT y)
847 TRACE("(x=%d y=%d)\n", x, y);
849 if (!InternalDrag.himl) {
853 /* draw/update the drag image */
854 if (InternalDrag.bShow) {
858 HBITMAP hbmOffScreen;
859 INT origNewX, origNewY;
860 INT origOldX, origOldY;
861 INT origRegX, origRegY;
862 INT sizeRegX, sizeRegY;
865 /* calculate the update region */
866 origNewX = x - InternalDrag.dxHotspot;
867 origNewY = y - InternalDrag.dyHotspot;
868 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
869 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
870 origRegX = min(origNewX, origOldX);
871 origRegY = min(origNewY, origOldY);
872 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
873 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
875 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
876 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
877 hdcOffScreen = CreateCompatibleDC(hdcDrag);
878 hdcBg = CreateCompatibleDC(hdcDrag);
880 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
881 SelectObject(hdcOffScreen, hbmOffScreen);
882 SelectObject(hdcBg, InternalDrag.hbmBg);
884 /* get the actual background of the update region */
885 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
886 origRegX, origRegY, SRCCOPY);
887 /* erase the old image */
888 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
889 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
891 /* save the background */
892 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
893 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
895 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
896 origNewY - origRegY);
897 /* draw the update region to the screen */
898 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
899 hdcOffScreen, 0, 0, SRCCOPY);
902 DeleteDC(hdcOffScreen);
903 DeleteObject(hbmOffScreen);
904 ReleaseDC(InternalDrag.hwnd, hdcDrag);
907 /* update the image position */
915 /*************************************************************************
916 * ImageList_DragShowNolock [COMCTL32.@]
918 * Shows or hides the drag image.
921 * bShow [I] TRUE shows the drag image, FALSE hides it.
928 * The drag image should be drawn semitransparent.
932 ImageList_DragShowNolock (BOOL bShow)
938 TRACE("bShow=0x%X!\n", bShow);
940 /* DragImage is already visible/hidden */
941 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
945 /* position of the origin of the DragImage */
946 x = InternalDrag.x - InternalDrag.dxHotspot;
947 y = InternalDrag.y - InternalDrag.dyHotspot;
949 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
950 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
955 hdcBg = CreateCompatibleDC(hdcDrag);
956 if (!InternalDrag.hbmBg) {
957 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
958 InternalDrag.himl->cx, InternalDrag.himl->cy);
960 SelectObject(hdcBg, InternalDrag.hbmBg);
963 /* save the background */
964 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
965 hdcDrag, x, y, SRCCOPY);
967 ImageList_InternalDragDraw(hdcDrag, x, y);
970 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
971 hdcBg, 0, 0, SRCCOPY);
974 InternalDrag.bShow = !InternalDrag.bShow;
977 ReleaseDC (InternalDrag.hwnd, hdcDrag);
982 /*************************************************************************
983 * ImageList_Draw [COMCTL32.@] Draws an image.
986 * himl [I] handle to image list
988 * hdc [I] handle to device context
991 * fStyle [I] drawing flags
1002 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1004 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1005 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1009 /*************************************************************************
1010 * ImageList_DrawEx [COMCTL32.@]
1012 * Draws an image and allows to use extended drawing features.
1015 * himl [I] handle to image list
1017 * hdc [I] handle to device context
1022 * rgbBk [I] background color
1023 * rgbFg [I] foreground color
1024 * fStyle [I] drawing flags
1031 * Calls ImageList_DrawIndirect.
1034 * ImageList_DrawIndirect.
1038 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1039 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1042 IMAGELISTDRAWPARAMS imldp;
1044 ZeroMemory (&imldp, sizeof(imldp));
1045 imldp.cbSize = sizeof(imldp);
1053 imldp.rgbBk = rgbBk;
1054 imldp.rgbFg = rgbFg;
1055 imldp.fStyle = fStyle;
1057 return ImageList_DrawIndirect (&imldp);
1061 /*************************************************************************
1062 * ImageList_DrawIndirect [COMCTL32.@]
1064 * Draws an image using ...
1067 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1075 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1077 INT cx, cy, lx, ly, nOvlIdx;
1078 DWORD fState, dwRop;
1080 COLORREF clrBk, oldImageBk, oldImageFg;
1081 HDC hImageDC, hImageListDC, hMaskListDC;
1082 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1083 BOOL bIsTransparent, bBlend, bResult = FALSE;
1086 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1087 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1089 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1090 ly = pimldp->yBitmap;
1092 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1093 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1094 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1095 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1096 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1097 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1098 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1100 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1101 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1103 /* we will use these DCs to access the images and masks in the ImageList */
1104 hImageListDC = CreateCompatibleDC(0);
1105 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1107 /* these will accumulate the image and mask for the image we're drawing */
1108 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1109 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1110 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1112 /* Create a compatible DC. */
1113 if (!hImageListDC || !hImageDC || !hImageBmp ||
1114 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1117 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1118 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1119 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1122 * To obtain a transparent look, background color should be set
1123 * to white and foreground color to black when blting the
1126 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1127 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1130 * Draw the initial image
1132 if(fStyle & ILD_MASK) {
1133 if (himl->hbmMask) {
1134 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1136 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1137 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1138 SelectObject(hImageDC, hOldBrush);
1140 } else if (himl->hbmMask && !bIsTransparent) {
1141 /* blend the image with the needed solid background */
1142 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1143 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1144 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1145 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1146 DeleteObject (SelectObject (hImageDC, hOldBrush));
1148 /* start off with the image, if we have a mask, we'll use it later */
1149 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1152 /* Time for blending, if required */
1154 HBRUSH hBlendBrush, hOldBrush;
1155 COLORREF clrBlend = pimldp->rgbFg;
1156 HDC hBlendMaskDC = hImageListDC;
1159 /* Create the blend Mask */
1160 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1161 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1162 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1163 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1164 SelectObject(hBlendMaskDC, hOldBrush);
1166 /* Modify the blend mask if an Image Mask exist */
1168 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1169 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1172 /* now apply blend to the current image given the BlendMask */
1173 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1174 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1175 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1176 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1177 DeleteObject(SelectObject(hImageDC, hOldBrush));
1178 SelectObject(hBlendMaskDC, hOldBitmap);
1181 /* Now do the overlay image, if any */
1182 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1183 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1184 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1185 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1186 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1187 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1188 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1189 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1193 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1194 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1195 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1196 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1198 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1199 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1200 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1202 /* now copy the image to the screen */
1204 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1205 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1206 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1207 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1208 SetBkColor(pimldp->hdcDst, oldDstBk);
1209 SetTextColor(pimldp->hdcDst, oldDstFg);
1212 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1213 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1217 /* cleanup the mess */
1218 SetBkColor(hImageDC, oldImageBk);
1219 SetTextColor(hImageDC, oldImageFg);
1220 SelectObject(hImageDC, hOldImageBmp);
1221 SelectObject(hImageListDC, hOldImageListBmp);
1222 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1224 DeleteObject(hBlendMaskBmp);
1225 DeleteObject(hImageBmp);
1227 DeleteDC(hImageListDC);
1228 DeleteDC(hMaskListDC);
1234 /*************************************************************************
1235 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1238 * himlSrc [I] source image list handle
1241 * Success: Handle of duplicated image list.
1246 ImageList_Duplicate (HIMAGELIST himlSrc)
1251 if (himlSrc == NULL) {
1252 ERR("Invalid image list handle!\n");
1256 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1257 himlSrc->cInitial, himlSrc->cGrow);
1261 hdcSrc = CreateCompatibleDC (0);
1262 hdcDst = CreateCompatibleDC (0);
1263 SelectObject (hdcSrc, himlSrc->hbmImage);
1264 SelectObject (hdcDst, himlDst->hbmImage);
1265 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1266 hdcSrc, 0, 0, SRCCOPY);
1268 if (himlDst->hbmMask)
1270 SelectObject (hdcSrc, himlSrc->hbmMask);
1271 SelectObject (hdcDst, himlDst->hbmMask);
1272 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1273 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1279 himlDst->cCurImage = himlSrc->cCurImage;
1280 himlDst->cMaxImage = himlSrc->cMaxImage;
1286 /*************************************************************************
1287 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1289 * Finishes a drag operation.
1300 ImageList_EndDrag (void)
1302 /* cleanup the InternalDrag struct */
1303 InternalDrag.hwnd = 0;
1304 ImageList_Destroy (InternalDrag.himl);
1305 InternalDrag.himl = 0;
1308 InternalDrag.dxHotspot = 0;
1309 InternalDrag.dyHotspot = 0;
1310 InternalDrag.bShow = FALSE;
1311 DeleteObject(InternalDrag.hbmBg);
1312 InternalDrag.hbmBg = 0;
1313 InternalDrag.bHSPending = FALSE;
1319 /*************************************************************************
1320 * ImageList_GetBkColor [COMCTL32.@]
1322 * Returns the background color of an image list.
1325 * himl [I] Image list handle.
1328 * Success: background color
1333 ImageList_GetBkColor (HIMAGELIST himl)
1335 return himl ? himl->clrBk : CLR_NONE;
1339 /*************************************************************************
1340 * ImageList_GetDragImage [COMCTL32.@]
1342 * Returns the handle to the internal drag image list.
1345 * ppt [O] Pointer to the drag position. Can be NULL.
1346 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1349 * Success: Handle of the drag image list.
1354 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1356 if (InternalDrag.himl) {
1358 ppt->x = InternalDrag.x;
1359 ppt->y = InternalDrag.y;
1362 pptHotspot->x = InternalDrag.dxHotspot;
1363 pptHotspot->y = InternalDrag.dyHotspot;
1365 return (InternalDrag.himl);
1372 /*************************************************************************
1373 * ImageList_GetFlags [COMCTL32.@]
1380 ImageList_GetFlags(HIMAGELIST himl)
1382 FIXME("(%p):empty stub\n", himl);
1387 /*************************************************************************
1388 * ImageList_GetIcon [COMCTL32.@]
1390 * Creates an icon from a masked image of an image list.
1393 * himl [I] handle to image list
1395 * flags [I] drawing style flags
1398 * Success: icon handle
1403 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1407 HBITMAP hOldDstBitmap;
1410 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1412 hdcDst = CreateCompatibleDC(0);
1417 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1418 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1419 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1422 SelectObject (hdcDst, himl->hbmImage);
1423 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1424 SelectObject (hdcDst, ii.hbmColor);
1425 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1428 * CreateIconIndirect requires us to deselect the bitmaps from
1429 * the DCs before calling
1431 SelectObject(hdcDst, hOldDstBitmap);
1433 hIcon = CreateIconIndirect (&ii);
1435 DeleteObject (ii.hbmMask);
1436 DeleteObject (ii.hbmColor);
1443 /*************************************************************************
1444 * ImageList_GetIconSize [COMCTL32.@]
1446 * Retrieves the size of an image in an image list.
1449 * himl [I] handle to image list
1450 * cx [O] pointer to the image width.
1451 * cy [O] pointer to the image height.
1458 * All images in an image list have the same size.
1462 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1466 if ((himl->cx <= 0) || (himl->cy <= 0))
1478 /*************************************************************************
1479 * ImageList_GetImageCount [COMCTL32.@]
1481 * Returns the number of images in an image list.
1484 * himl [I] handle to image list
1487 * Success: Number of images.
1492 ImageList_GetImageCount (HIMAGELIST himl)
1497 return himl->cCurImage;
1501 /*************************************************************************
1502 * ImageList_GetImageInfo [COMCTL32.@]
1504 * Returns information about an image in an image list.
1507 * himl [I] handle to image list
1509 * pImageInfo [O] pointer to the image information
1517 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1519 if ((himl == NULL) || (pImageInfo == NULL))
1521 if ((i < 0) || (i >= himl->cCurImage))
1524 pImageInfo->hbmImage = himl->hbmImage;
1525 pImageInfo->hbmMask = himl->hbmMask;
1527 pImageInfo->rcImage.top = 0;
1528 pImageInfo->rcImage.bottom = himl->cy;
1529 pImageInfo->rcImage.left = i * himl->cx;
1530 pImageInfo->rcImage.right = (i+1) * himl->cx;
1536 /*************************************************************************
1537 * ImageList_GetImageRect [COMCTL32.@]
1539 * Retrieves the rectangle of the specified image in an image list.
1542 * himl [I] handle to image list
1544 * lpRect [O] pointer to the image rectangle
1551 * This is an UNDOCUMENTED function!!!
1555 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1557 if ((himl == NULL) || (lpRect == NULL))
1559 if ((i < 0) || (i >= himl->cCurImage))
1562 lpRect->left = i * himl->cx;
1564 lpRect->right = lpRect->left + himl->cx;
1565 lpRect->bottom = himl->cy;
1571 /*************************************************************************
1572 * ImageList_LoadImage [COMCTL32.@]
1573 * ImageList_LoadImageA [COMCTL32.@]
1575 * Creates an image list from a bitmap, icon or cursor.
1578 * hi [I] instance handle
1579 * lpbmp [I] name or id of the image
1580 * cx [I] width of each image
1581 * cGrow [I] number of images to expand
1582 * clrMask [I] mask color
1583 * uType [I] type of image to load
1584 * uFlags [I] loading flags
1587 * Success: handle to the loaded image list
1595 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1596 COLORREF clrMask, UINT uType, UINT uFlags)
1598 HIMAGELIST himl = NULL;
1602 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1604 ERR("Error loading image!\n");
1608 if (uType == IMAGE_BITMAP) {
1610 GetObjectA (handle, sizeof(BITMAP), &bmp);
1612 /* To match windows behavior, if cx is set to zero and
1613 the flag DI_DEFAULTSIZE is specified, cx becomes the
1614 system metric value for icons. If the flag is not specified
1615 the function sets the size to the height of the bitmap */
1618 if (uFlags & DI_DEFAULTSIZE)
1619 cx = GetSystemMetrics (SM_CXICON);
1624 nImageCount = bmp.bmWidth / cx;
1626 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1627 nImageCount, cGrow);
1628 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1630 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1634 GetIconInfo (handle, &ii);
1635 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1636 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1637 ILC_MASK | ILC_COLOR, 1, cGrow);
1638 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1639 DeleteObject (ii.hbmColor);
1640 DeleteObject (ii.hbmMask);
1643 DeleteObject (handle);
1649 /*************************************************************************
1650 * ImageList_LoadImageW [COMCTL32.@]
1652 * Creates an image list from a bitmap, icon or cursor.
1655 * hi [I] instance handle
1656 * lpbmp [I] name or id of the image
1657 * cx [I] width of each image
1658 * cGrow [I] number of images to expand
1659 * clrMask [I] mask color
1660 * uType [I] type of image to load
1661 * uFlags [I] loading flags
1664 * Success: handle to the loaded image list
1672 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1673 COLORREF clrMask, UINT uType, UINT uFlags)
1675 HIMAGELIST himl = NULL;
1679 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1681 ERR("Error loading image!\n");
1685 if (uType == IMAGE_BITMAP) {
1687 GetObjectA (handle, sizeof(BITMAP), &bmp);
1689 /* To match windows behavior, if cx is set to zero and
1690 the flag DI_DEFAULTSIZE is specified, cx becomes the
1691 system metric value for icons. If the flag is not specified
1692 the function sets the size to the height of the bitmap */
1695 if (uFlags & DI_DEFAULTSIZE)
1696 cx = GetSystemMetrics (SM_CXICON);
1701 nImageCount = bmp.bmWidth / cx;
1703 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1704 nImageCount, cGrow);
1705 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1707 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1711 GetIconInfo (handle, &ii);
1712 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1713 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1714 ILC_MASK | ILC_COLOR, 1, cGrow);
1715 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1716 DeleteObject (ii.hbmColor);
1717 DeleteObject (ii.hbmMask);
1720 DeleteObject (handle);
1726 /*************************************************************************
1727 * ImageList_Merge [COMCTL32.@]
1729 * Creates a new image list that contains a merged image from the specified
1730 * images of both source image lists.
1733 * himl1 [I] handle to first image list
1734 * i1 [I] first image index
1735 * himl2 [I] handle to second image list
1736 * i2 [I] second image index
1737 * dx [I] X offset of the second image relative to the first.
1738 * dy [I] Y offset of the second image relative to the first.
1741 * Success: handle of the merged image list.
1746 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1749 HIMAGELIST himlDst = NULL;
1750 HDC hdcSrcImage, hdcDstImage;
1752 INT xOff1, yOff1, xOff2, yOff2;
1755 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1758 if ((himl1 == NULL) || (himl2 == NULL))
1762 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1763 ERR("Index 1 out of range! %d\n", i1);
1767 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1768 ERR("Index 2 out of range! %d\n", i2);
1773 cxDst = max (himl1->cx, dx + himl2->cx);
1778 cxDst = max (himl2->cx, himl1->cx - dx);
1783 cxDst = max (himl1->cx, himl2->cx);
1789 cyDst = max (himl1->cy, dy + himl2->cy);
1794 cyDst = max (himl2->cy, himl1->cy - dy);
1799 cyDst = max (himl1->cy, himl2->cy);
1804 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1807 hdcSrcImage = CreateCompatibleDC (0);
1808 hdcDstImage = CreateCompatibleDC (0);
1809 nX1 = i1 * himl1->cx;
1810 nX2 = i2 * himl2->cx;
1813 SelectObject (hdcSrcImage, himl1->hbmImage);
1814 SelectObject (hdcDstImage, himlDst->hbmImage);
1815 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1816 hdcSrcImage, 0, 0, BLACKNESS);
1817 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1818 hdcSrcImage, nX1, 0, SRCCOPY);
1820 SelectObject (hdcSrcImage, himl2->hbmMask);
1821 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1822 hdcSrcImage, nX2, 0, SRCAND);
1824 SelectObject (hdcSrcImage, himl2->hbmImage);
1825 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1826 hdcSrcImage, nX2, 0, SRCPAINT);
1829 SelectObject (hdcSrcImage, himl1->hbmMask);
1830 SelectObject (hdcDstImage, himlDst->hbmMask);
1831 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1832 hdcSrcImage, 0, 0, WHITENESS);
1833 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1834 hdcSrcImage, nX1, 0, SRCCOPY);
1836 SelectObject (hdcSrcImage, himl2->hbmMask);
1837 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1838 hdcSrcImage, nX2, 0, SRCAND);
1840 DeleteDC (hdcSrcImage);
1841 DeleteDC (hdcDstImage);
1842 himlDst->cCurImage = 1;
1849 /* helper for _read_bitmap currently unused */
1851 static int may_use_dibsection(HDC hdc) {
1852 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1857 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1861 /* helper for ImageList_Read, see comments below */
1862 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1864 BITMAPFILEHEADER bmfh;
1865 BITMAPINFOHEADER bmih;
1866 int bitsperpixel,palspace,longsperline,width,height;
1867 LPBITMAPINFOHEADER bmihc = NULL;
1869 HBITMAP hbitmap = 0;
1870 LPBYTE bits = NULL,nbits = NULL;
1871 int nbytesperline,bytesperline;
1873 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1874 (bmfh.bfType != (('M'<<8)|'B')) ||
1875 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1876 (bmih.biSize != sizeof(bmih))
1880 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1881 if (bitsperpixel<=8)
1882 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1885 width = bmih.biWidth;
1886 height = bmih.biHeight;
1887 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1888 memcpy(bmihc,&bmih,sizeof(bmih));
1889 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1890 bmihc->biSizeImage = (longsperline*height)<<2;
1892 /* read the palette right after the end of the bitmapinfoheader */
1894 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1898 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1899 if ((bitsperpixel>1) &&
1900 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1902 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1905 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1911 int i,nwidth,nheight;
1913 nwidth = width*(height/cy);
1916 if (bitsperpixel==1)
1917 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1919 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1921 /* Might be a bit excessive memory use here */
1922 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1923 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1924 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1927 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1928 /* Do not forget that windows bitmaps are bottom->top */
1929 bytesperline = longsperline*4;
1930 nbytesperline = (height/cy)*bytesperline;
1931 for (i=0;i<height;i++) {
1933 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1934 bits+bytesperline*(height-1-i),
1938 bmihc->biWidth = nwidth;
1939 bmihc->biHeight = nheight;
1940 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1942 LocalFree((HLOCAL)nbits);
1943 LocalFree((HLOCAL)bits);
1947 if (xdc) ReleaseDC(0,xdc);
1948 if (bmihc) LocalFree((HLOCAL)bmihc);
1951 DeleteObject(hbitmap);
1958 /*************************************************************************
1959 * ImageList_Read [COMCTL32.@]
1961 * Reads an image list from a stream.
1964 * pstm [I] pointer to a stream
1967 * Success: handle to image list
1970 * The format is like this:
1971 * ILHEAD ilheadstruct;
1973 * for the color image part:
1974 * BITMAPFILEHEADER bmfh;
1975 * BITMAPINFOHEADER bmih;
1976 * only if it has a palette:
1977 * RGBQUAD rgbs[nr_of_paletted_colors];
1979 * BYTE colorbits[imagesize];
1981 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1982 * BITMAPFILEHEADER bmfh_mask;
1983 * BITMAPINFOHEADER bmih_mask;
1984 * only if it has a palette (it usually does not):
1985 * RGBQUAD rgbs[nr_of_paletted_colors];
1987 * BYTE maskbits[imagesize];
1989 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1990 * _read_bitmap needs to convert them.
1992 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1996 HBITMAP hbmColor=0,hbmMask=0;
1999 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2001 if (ilHead.usMagic != (('L' << 8) | 'I'))
2003 if (ilHead.usVersion != 0x101) /* probably version? */
2007 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2008 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2009 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2010 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2011 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2012 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2013 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2014 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2015 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2016 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2019 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2022 if (ilHead.flags & ILC_MASK) {
2023 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2025 DeleteObject(hbmColor);
2030 himl = ImageList_Create (
2038 DeleteObject(hbmColor);
2039 DeleteObject(hbmMask);
2042 himl->hbmImage = hbmColor;
2043 himl->hbmMask = hbmMask;
2044 himl->cCurImage = ilHead.cCurImage;
2045 himl->cMaxImage = ilHead.cMaxImage;
2047 ImageList_SetBkColor(himl,ilHead.bkcolor);
2049 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2054 /*************************************************************************
2055 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2058 * himl [I] image list handle
2067 ImageList_Remove (HIMAGELIST himl, INT i)
2069 HBITMAP hbmNewImage, hbmNewMask;
2073 TRACE("(himl=%p i=%d)\n", himl, i);
2076 ERR("Invalid image list handle!\n");
2080 if ((i < -1) || (i >= himl->cCurImage)) {
2081 ERR("index out of range! %d\n", i);
2087 if (himl->cCurImage == 0) {
2088 /* remove all on empty ImageList is allowed */
2089 TRACE("remove all on empty ImageList!\n");
2093 himl->cMaxImage = himl->cInitial + himl->cGrow;
2094 himl->cCurImage = 0;
2095 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2096 himl->nOvlIdx[nCount] = -1;
2098 DeleteObject (himl->hbmImage);
2100 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2101 1, himl->uBitsPixel, NULL);
2103 if (himl->hbmMask) {
2104 DeleteObject (himl->hbmMask);
2106 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2111 /* delete one image */
2112 TRACE("Remove single image! %d\n", i);
2114 /* create new bitmap(s) */
2115 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2117 TRACE(" - Number of images: %d / %d (Old/New)\n",
2118 himl->cCurImage, himl->cCurImage - 1);
2119 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2120 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2123 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2126 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2128 hbmNewMask = 0; /* Just to keep compiler happy! */
2130 hdcSrc = CreateCompatibleDC (0);
2131 hdcDst = CreateCompatibleDC (0);
2133 /* copy all images and masks prior to the "removed" image */
2135 TRACE("Pre image copy: Copy %d images\n", i);
2137 SelectObject (hdcSrc, himl->hbmImage);
2138 SelectObject (hdcDst, hbmNewImage);
2139 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2140 hdcSrc, 0, 0, SRCCOPY);
2142 if (himl->hbmMask) {
2143 SelectObject (hdcSrc, himl->hbmMask);
2144 SelectObject (hdcDst, hbmNewMask);
2145 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2146 hdcSrc, 0, 0, SRCCOPY);
2150 /* copy all images and masks behind the removed image */
2151 if (i < himl->cCurImage - 1) {
2152 TRACE("Post image copy!\n");
2153 SelectObject (hdcSrc, himl->hbmImage);
2154 SelectObject (hdcDst, hbmNewImage);
2155 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2156 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2158 if (himl->hbmMask) {
2159 SelectObject (hdcSrc, himl->hbmMask);
2160 SelectObject (hdcDst, hbmNewMask);
2161 BitBlt (hdcDst, i * himl->cx, 0,
2162 (himl->cCurImage - i - 1) * himl->cx,
2163 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2170 /* delete old images and insert new ones */
2171 DeleteObject (himl->hbmImage);
2172 himl->hbmImage = hbmNewImage;
2173 if (himl->hbmMask) {
2174 DeleteObject (himl->hbmMask);
2175 himl->hbmMask = hbmNewMask;
2179 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2186 /*************************************************************************
2187 * ImageList_Replace [COMCTL32.@]
2189 * Replaces an image in an image list with a new image.
2192 * himl [I] handle to image list
2194 * hbmImage [I] handle to image bitmap
2195 * hbmMask [I] handle to mask bitmap. Can be NULL.
2203 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2206 HDC hdcImageList, hdcImage;
2209 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2212 ERR("Invalid image list handle!\n");
2216 if ((i >= himl->cMaxImage) || (i < 0)) {
2217 ERR("Invalid image index!\n");
2221 hdcImageList = CreateCompatibleDC (0);
2222 hdcImage = CreateCompatibleDC (0);
2223 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2226 SelectObject (hdcImageList, himl->hbmImage);
2227 SelectObject (hdcImage, hbmImage);
2229 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2230 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2235 SelectObject (hdcImageList, himl->hbmMask);
2236 SelectObject (hdcImage, hbmMask);
2238 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2239 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2242 /* Remove the background from the image
2244 SelectObject (hdcImageList, himl->hbmImage);
2245 StretchBlt (hdcImageList,
2246 i*himl->cx, 0, himl->cx, himl->cy,
2248 0, 0, bmp.bmWidth, bmp.bmHeight,
2249 0x220326); /* NOTSRCAND */
2252 DeleteDC (hdcImage);
2253 DeleteDC (hdcImageList);
2259 /*************************************************************************
2260 * ImageList_ReplaceIcon [COMCTL32.@]
2262 * Replaces an image in an image list using an icon.
2265 * himl [I] handle to image list
2267 * hIcon [I] handle to icon
2270 * Success: index of the replaced image
2275 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2277 HDC hdcImageList, hdcImage;
2280 HBITMAP hbmOldSrc, hbmOldDst;
2284 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2288 if ((i >= himl->cMaxImage) || (i < -1))
2291 hBestFitIcon = CopyImage(
2294 LR_COPYFROMRESOURCE);
2296 GetIconInfo (hBestFitIcon, &ii);
2297 if (ii.hbmMask == 0)
2299 if (ii.hbmColor == 0)
2301 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2304 if (himl->cCurImage + 1 > himl->cMaxImage)
2305 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2307 nIndex = himl->cCurImage;
2313 hdcImageList = CreateCompatibleDC (0);
2314 TRACE("hdcImageList=%p!\n", hdcImageList);
2315 if (hdcImageList == 0)
2316 ERR("invalid hdcImageList!\n");
2318 hdcImage = CreateCompatibleDC (0);
2319 TRACE("hdcImage=%p!\n", hdcImage);
2321 ERR("invalid hdcImage!\n");
2323 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2324 SetTextColor( hdcImageList, RGB(0,0,0));
2325 SetBkColor( hdcImageList, RGB(255,255,255));
2326 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2327 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2328 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2330 if (himl->hbmMask) {
2331 SelectObject (hdcImageList, himl->hbmMask);
2332 SelectObject (hdcImage, ii.hbmMask);
2333 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2334 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2337 SelectObject (hdcImage, hbmOldSrc);
2338 SelectObject (hdcImageList, hbmOldDst);
2341 DestroyIcon(hBestFitIcon);
2343 DeleteDC (hdcImageList);
2345 DeleteDC (hdcImage);
2347 DeleteObject (ii.hbmColor);
2349 DeleteObject (ii.hbmMask);
2355 /*************************************************************************
2356 * ImageList_SetBkColor [COMCTL32.@]
2358 * Sets the background color of an image list.
2361 * himl [I] handle to image list
2362 * clrBk [I] background color
2365 * Success: previous background color
2370 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2377 clrOldBk = himl->clrBk;
2378 himl->clrBk = clrBk;
2383 /*************************************************************************
2384 * ImageList_SetDragCursorImage [COMCTL32.@]
2386 * Combines the specified image with the current drag image
2389 * himlDrag [I] handle to drag image list
2390 * iDrag [I] drag image index
2391 * dxHotspot [I] X position of the hot spot
2392 * dyHotspot [I] Y position of the hot spot
2399 * When this function is called and the drag image is visible, a
2400 * short flickering occurs but this matches the Win9x behavior. It is
2401 * possible to fix the flickering using code like in ImageList_DragMove.
2405 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2406 INT dxHotspot, INT dyHotspot)
2408 HIMAGELIST himlTemp;
2412 if (InternalDrag.himl == NULL)
2415 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2416 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2418 visible = InternalDrag.bShow;
2420 /* Calculate the offset between the origin of the old image and the
2421 * origin of the second image.
2422 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2423 * hotspot) to the origin of the second image.
2424 * See M$DN for details */
2425 if(InternalDrag.bHSPending) {
2428 InternalDrag.bHSPending = FALSE;
2430 dx = InternalDrag.dxHotspot - dxHotspot;
2431 dy = InternalDrag.dyHotspot - dyHotspot;
2433 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2436 /* hide the drag image */
2437 ImageList_DragShowNolock(FALSE);
2439 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2440 (InternalDrag.himl->cy != himlTemp->cy)) {
2441 /* the size of the drag image changed, invalidate the buffer */
2442 DeleteObject(InternalDrag.hbmBg);
2443 InternalDrag.hbmBg = 0;
2446 ImageList_Destroy (InternalDrag.himl);
2447 InternalDrag.himl = himlTemp;
2449 /* update the InternalDragOffset, if the origin of the
2450 * DragImage was changed by ImageList_Merge. */
2452 InternalDrag.dxHotspot = dxHotspot;
2454 InternalDrag.dyHotspot = dyHotspot;
2457 /* show the drag image */
2458 ImageList_DragShowNolock(TRUE);
2465 /*************************************************************************
2466 * ImageList_SetFilter [COMCTL32.@]
2468 * Sets a filter (or does something completely different)!!???
2469 * It removes 12 Bytes from the stack (3 Parameters).
2472 * himl [I] SHOULD be a handle to image list
2473 * i [I] COULD be an index?
2478 * Failure: FALSE ???
2481 * This is an UNDOCUMENTED function!!!!
2486 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2488 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2494 /*************************************************************************
2495 * ImageList_SetFlags [COMCTL32.@]
2502 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2504 FIXME("(%p %08lx):empty stub\n", himl, flags);
2509 /*************************************************************************
2510 * ImageList_SetIconSize [COMCTL32.@]
2512 * Sets the image size of the bitmap and deletes all images.
2515 * himl [I] handle to image list
2516 * cx [I] image width
2517 * cy [I] image height
2525 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2532 /* remove all images */
2533 himl->cMaxImage = himl->cInitial + himl->cGrow;
2534 himl->cCurImage = 0;
2538 /* initialize overlay mask indices */
2539 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2540 himl->nOvlIdx[nCount] = -1;
2542 DeleteObject (himl->hbmImage);
2544 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2545 1, himl->uBitsPixel, NULL);
2547 if (himl->hbmMask) {
2548 DeleteObject (himl->hbmMask);
2550 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2558 /*************************************************************************
2559 * ImageList_SetImageCount [COMCTL32.@]
2561 * Resizes an image list to the specified number of images.
2564 * himl [I] handle to image list
2565 * iImageCount [I] number of images in the image list
2573 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2575 HDC hdcImageList, hdcBitmap;
2576 HBITMAP hbmNewBitmap;
2577 INT nNewCount, nCopyCount;
2579 TRACE("%p %d\n",himl,iImageCount);
2583 if (himl->cCurImage >= iImageCount)
2585 if (himl->cMaxImage > iImageCount)
2587 himl->cCurImage = iImageCount;
2591 nNewCount = iImageCount + himl->cGrow;
2592 nCopyCount = min(himl->cCurImage, iImageCount);
2594 hdcImageList = CreateCompatibleDC (0);
2595 hdcBitmap = CreateCompatibleDC (0);
2597 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2598 1, himl->uBitsPixel, NULL);
2599 if (hbmNewBitmap != 0)
2601 SelectObject (hdcImageList, himl->hbmImage);
2602 SelectObject (hdcBitmap, hbmNewBitmap);
2605 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2606 hdcImageList, 0, 0, SRCCOPY);
2608 /* delete 'empty' image space */
2609 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2610 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2611 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2612 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2614 DeleteObject (himl->hbmImage);
2615 himl->hbmImage = hbmNewBitmap;
2618 ERR("Could not create new image bitmap !\n");
2622 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2624 if (hbmNewBitmap != 0)
2626 SelectObject (hdcImageList, himl->hbmMask);
2627 SelectObject (hdcBitmap, hbmNewBitmap);
2630 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2631 hdcImageList, 0, 0, SRCCOPY);
2633 /* delete 'empty' image space */
2634 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2635 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2636 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2637 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2639 DeleteObject (himl->hbmMask);
2640 himl->hbmMask = hbmNewBitmap;
2643 ERR("Could not create new mask bitmap!\n");
2646 DeleteDC (hdcImageList);
2647 DeleteDC (hdcBitmap);
2649 /* Update max image count and current image count */
2650 himl->cMaxImage = nNewCount;
2651 himl->cCurImage = iImageCount;
2657 /*************************************************************************
2658 * ImageList_SetOverlayImage [COMCTL32.@]
2660 * Assigns an overlay mask index to an existing image in an image list.
2663 * himl [I] handle to image list
2664 * iImage [I] image index
2665 * iOverlay [I] overlay mask index
2673 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2677 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2679 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2681 himl->nOvlIdx[iOverlay - 1] = iImage;
2687 /* helper for ImageList_Write - write bitmap to pstm
2688 * currently everything is written as 24 bit RGB, except masks
2691 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2693 LPBITMAPFILEHEADER bmfh;
2694 LPBITMAPINFOHEADER bmih;
2695 LPBYTE data, lpBits, lpBitsOrg;
2697 INT bitCount, sizeImage, offBits, totalSize;
2698 INT nwidth, nheight, nsizeImage, icount;
2700 BOOL result = FALSE;
2704 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2706 /* XXX is this always correct? */
2707 icount = bm.bmWidth / cx;
2709 nheight = cy * ((icount+3)>>2);
2711 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2712 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2713 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2715 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2717 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2718 offBits = totalSize;
2719 totalSize += nsizeImage;
2721 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2722 bmfh = (LPBITMAPFILEHEADER)data;
2723 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2724 lpBits = data + offBits;
2726 /* setup BITMAPFILEHEADER */
2727 bmfh->bfType = (('M' << 8) | 'B');
2729 bmfh->bfReserved1 = 0;
2730 bmfh->bfReserved2 = 0;
2731 bmfh->bfOffBits = offBits;
2733 /* setup BITMAPINFOHEADER */
2734 bmih->biSize = sizeof(BITMAPINFOHEADER);
2735 bmih->biWidth = bm.bmWidth;
2736 bmih->biHeight = bm.bmHeight;
2738 bmih->biBitCount = bitCount;
2739 bmih->biCompression = BI_RGB;
2740 bmih->biSizeImage = nsizeImage;
2741 bmih->biXPelsPerMeter = 0;
2742 bmih->biYPelsPerMeter = 0;
2743 bmih->biClrUsed = 0;
2744 bmih->biClrImportant = 0;
2746 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2747 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2748 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2752 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2753 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2755 for(i = 0; i < nheight; i++) {
2756 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2757 int noff = (nbpl * (nheight-1-i));
2758 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2762 bmih->biWidth = nwidth;
2763 bmih->biHeight = nheight;
2767 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2768 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2769 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2772 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2779 LocalFree((HLOCAL)lpBitsOrg);
2785 /*************************************************************************
2786 * ImageList_Write [COMCTL32.@]
2788 * Writes an image list to a stream.
2791 * himl [I] handle to image list
2792 * pstm [O] Pointer to a stream.
2803 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2811 ilHead.usMagic = (('L' << 8) | 'I');
2812 ilHead.usVersion = 0x101;
2813 ilHead.cCurImage = himl->cCurImage;
2814 ilHead.cMaxImage = himl->cMaxImage;
2815 ilHead.cGrow = himl->cGrow;
2816 ilHead.cx = himl->cx;
2817 ilHead.cy = himl->cy;
2818 ilHead.bkcolor = himl->clrBk;
2819 ilHead.flags = himl->flags;
2820 for(i = 0; i < 4; i++) {
2821 ilHead.ovls[i] = himl->nOvlIdx[i];
2824 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2827 /* write the bitmap */
2828 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2831 /* write the mask if we have one */
2832 if(himl->flags & ILC_MASK) {
2833 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))