msi: Create macro functions to set feature and component states.
[wine.git] / dlls / comctl32 / imagelist.c
blob0da2a90574413b2f34bdfaa4e2e2a1d12fcb621b
1 /*
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
24 * NOTE
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.
33 * TODO:
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
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #define COBJMACROS
45 #include "winerror.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "objbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "commctrl.h"
52 #include "comctl32.h"
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 */
62 typedef struct
64 HWND hwnd;
65 HIMAGELIST himl;
66 /* position of the drag image relative to the window */
67 INT x;
68 INT y;
69 /* offset of the hotspot relative to the origin of the image */
70 INT dxHotspot;
71 INT dyHotspot;
72 /* is the drag image visible */
73 BOOL bShow;
74 /* saved background */
75 HBITMAP hbmBg;
76 } INTERNALDRAG;
78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
82 static inline BOOL is_valid(HIMAGELIST himl)
84 return himl && himl->magic == IMAGELIST_MAGIC;
87 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
89 pt->x = index * himl->cx;
90 pt->y = 0;
93 /*************************************************************************
94 * IMAGELIST_InternalExpandBitmaps [Internal]
96 * Expands the bitmaps of an image list by the given number of images.
98 * PARAMS
99 * himl [I] handle to image list
100 * nImageCount [I] number of images to add
102 * RETURNS
103 * nothing
105 * NOTES
106 * This function CANNOT be used to reduce the number of images.
108 static void
109 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
111 HDC hdcBitmap;
112 HBITMAP hbmNewBitmap, hbmNull;
113 INT nNewWidth, nNewCount;
115 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
116 && (himl->cy >= cy))
117 return;
119 if (cy == 0) cy = himl->cy;
120 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
121 nNewWidth = nNewCount * himl->cx;
123 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
124 hdcBitmap = CreateCompatibleDC (0);
126 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
128 if (hbmNewBitmap == 0)
129 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
131 if(himl->cCurImage)
133 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
134 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
135 himl->hdcImage, 0, 0, SRCCOPY);
136 SelectObject (hdcBitmap, hbmNull);
138 SelectObject (himl->hdcImage, hbmNewBitmap);
139 DeleteObject (himl->hbmImage);
140 himl->hbmImage = hbmNewBitmap;
142 if (himl->flags & ILC_MASK)
144 hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
146 if (hbmNewBitmap == 0)
147 ERR("creating new mask bitmap!\n");
149 if(himl->cCurImage)
151 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
152 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
153 himl->hdcMask, 0, 0, SRCCOPY);
154 SelectObject (hdcBitmap, hbmNull);
156 SelectObject (himl->hdcMask, hbmNewBitmap);
157 DeleteObject (himl->hbmMask);
158 himl->hbmMask = hbmNewBitmap;
161 himl->cMaxImage = nNewCount;
163 DeleteDC (hdcBitmap);
167 /*************************************************************************
168 * ImageList_Add [COMCTL32.@]
170 * Add an image or images to an image list.
172 * PARAMS
173 * himl [I] handle to image list
174 * hbmImage [I] handle to image bitmap
175 * hbmMask [I] handle to mask bitmap
177 * RETURNS
178 * Success: Index of the first new image.
179 * Failure: -1
182 INT WINAPI
183 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
185 HDC hdcBitmap;
186 INT nFirstIndex, nImageCount;
187 BITMAP bmp;
188 HBITMAP hOldBitmap;
189 POINT pt;
191 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
192 if (!is_valid(himl))
193 return -1;
195 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
196 nImageCount = bmp.bmWidth / himl->cx;
198 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
200 imagelist_point_from_index( himl, himl->cCurImage, &pt );
202 hdcBitmap = CreateCompatibleDC(0);
204 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
206 /* Copy result to the imagelist
208 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
209 hdcBitmap, 0, 0, SRCCOPY);
211 if(himl->hbmMask)
213 HDC hdcTemp;
214 HBITMAP hOldBitmapTemp;
216 hdcTemp = CreateCompatibleDC(0);
217 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
219 BitBlt (himl->hdcMask,
220 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
221 hdcTemp,
222 0, 0,
223 SRCCOPY);
225 SelectObject(hdcTemp, hOldBitmapTemp);
226 DeleteDC(hdcTemp);
228 /* Remove the background from the image
230 BitBlt (himl->hdcImage,
231 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
232 himl->hdcMask,
233 pt.x, pt.y,
234 0x220326); /* NOTSRCAND */
237 SelectObject(hdcBitmap, hOldBitmap);
238 DeleteDC(hdcBitmap);
240 nFirstIndex = himl->cCurImage;
241 himl->cCurImage += nImageCount;
243 return nFirstIndex;
247 /*************************************************************************
248 * ImageList_AddIcon [COMCTL32.@]
250 * Adds an icon to an image list.
252 * PARAMS
253 * himl [I] handle to image list
254 * hIcon [I] handle to icon
256 * RETURNS
257 * Success: index of the new image
258 * Failure: -1
260 #undef ImageList_AddIcon
261 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
263 return ImageList_ReplaceIcon (himl, -1, hIcon);
267 /*************************************************************************
268 * ImageList_AddMasked [COMCTL32.@]
270 * Adds an image or images to an image list and creates a mask from the
271 * specified bitmap using the mask color.
273 * PARAMS
274 * himl [I] handle to image list.
275 * hBitmap [I] handle to bitmap
276 * clrMask [I] mask color.
278 * RETURNS
279 * Success: Index of the first new image.
280 * Failure: -1
283 INT WINAPI
284 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
286 HDC hdcMask, hdcBitmap;
287 INT nIndex, nImageCount, nMaskXOffset=0;
288 BITMAP bmp;
289 HBITMAP hOldBitmap;
290 HBITMAP hMaskBitmap=0;
291 COLORREF bkColor;
292 POINT pt;
294 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
295 if (!is_valid(himl))
296 return -1;
298 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
299 return -1;
301 if (himl->cx > 0)
302 nImageCount = bmp.bmWidth / himl->cx;
303 else
304 nImageCount = 0;
306 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
308 nIndex = himl->cCurImage;
309 himl->cCurImage += nImageCount;
311 hdcBitmap = CreateCompatibleDC(0);
314 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
315 if(himl->hbmMask)
317 hdcMask = himl->hdcMask;
318 nMaskXOffset = nIndex * himl->cx;
320 else
323 Create a temp Mask so we can remove the background of
324 the Image (Windows does this even if there is no mask)
326 hdcMask = CreateCompatibleDC(0);
327 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
328 SelectObject(hdcMask, hMaskBitmap);
329 nMaskXOffset = 0;
331 /* create monochrome image to the mask bitmap */
332 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
333 GetPixel (hdcBitmap, 0, 0);
334 SetBkColor (hdcBitmap, bkColor);
335 BitBlt (hdcMask,
336 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
337 hdcBitmap, 0, 0,
338 SRCCOPY);
340 SetBkColor(hdcBitmap, RGB(255,255,255));
341 /*Remove the background from the image
344 WINDOWS BUG ALERT!!!!!!
345 The statement below should not be done in common practice
346 but this is how ImageList_AddMasked works in Windows.
347 It overwrites the original bitmap passed, this was discovered
348 by using the same bitmap to iterate the different styles
349 on windows where it failed (BUT ImageList_Add is OK)
350 This is here in case some apps rely on this bug
352 BitBlt(hdcBitmap,
353 0, 0, bmp.bmWidth, bmp.bmHeight,
354 hdcMask,
355 nMaskXOffset, 0,
356 0x220326); /* NOTSRCAND */
357 /* Copy result to the imagelist
359 imagelist_point_from_index( himl, nIndex, &pt );
360 BitBlt (himl->hdcImage,
361 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
362 hdcBitmap,
363 0, 0,
364 SRCCOPY);
365 /* Clean up
367 SelectObject(hdcBitmap, hOldBitmap);
368 DeleteDC(hdcBitmap);
369 if(!himl->hbmMask)
371 DeleteObject(hMaskBitmap);
372 DeleteDC(hdcMask);
375 return nIndex;
379 /*************************************************************************
380 * ImageList_BeginDrag [COMCTL32.@]
382 * Creates a temporary image list that contains one image. It will be used
383 * as a drag image.
385 * PARAMS
386 * himlTrack [I] handle to the source image list
387 * iTrack [I] index of the drag image in the source image list
388 * dxHotspot [I] X position of the hot spot of the drag image
389 * dyHotspot [I] Y position of the hot spot of the drag image
391 * RETURNS
392 * Success: TRUE
393 * Failure: FALSE
396 BOOL WINAPI
397 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
398 INT dxHotspot, INT dyHotspot)
400 INT cx, cy;
402 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
403 dxHotspot, dyHotspot);
405 if (!is_valid(himlTrack))
406 return FALSE;
408 if (InternalDrag.himl)
409 ImageList_EndDrag ();
411 cx = himlTrack->cx;
412 cy = himlTrack->cy;
414 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
415 if (InternalDrag.himl == NULL) {
416 WARN("Error creating drag image list!\n");
417 return FALSE;
420 InternalDrag.dxHotspot = dxHotspot;
421 InternalDrag.dyHotspot = dyHotspot;
423 /* copy image */
424 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
426 /* copy mask */
427 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
429 InternalDrag.himl->cCurImage = 1;
431 return TRUE;
435 /*************************************************************************
436 * ImageList_Copy [COMCTL32.@]
438 * Copies an image of the source image list to an image of the
439 * destination image list. Images can be copied or swapped.
441 * PARAMS
442 * himlDst [I] handle to the destination image list
443 * iDst [I] destination image index.
444 * himlSrc [I] handle to the source image list
445 * iSrc [I] source image index
446 * uFlags [I] flags for the copy operation
448 * RETURNS
449 * Success: TRUE
450 * Failure: FALSE
452 * NOTES
453 * Copying from one image list to another is possible. The original
454 * implementation just copies or swaps within one image list.
455 * Could this feature become a bug??? ;-)
458 BOOL WINAPI
459 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
460 INT iSrc, UINT uFlags)
462 POINT ptSrc, ptDst;
464 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
466 if (!is_valid(himlSrc) || !is_valid(himlDst))
467 return FALSE;
468 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
469 return FALSE;
470 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
471 return FALSE;
473 imagelist_point_from_index( himlDst, iDst, &ptDst );
474 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
476 if (uFlags & ILCF_SWAP) {
477 /* swap */
478 HDC hdcBmp;
479 HBITMAP hbmTempImage, hbmTempMask;
481 hdcBmp = CreateCompatibleDC (0);
483 /* create temporary bitmaps */
484 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
485 himlSrc->uBitsPixel, NULL);
486 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
487 1, NULL);
489 /* copy (and stretch) destination to temporary bitmaps.(save) */
490 /* image */
491 SelectObject (hdcBmp, hbmTempImage);
492 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
493 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
494 SRCCOPY);
495 /* mask */
496 SelectObject (hdcBmp, hbmTempMask);
497 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
498 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
499 SRCCOPY);
501 /* copy (and stretch) source to destination */
502 /* image */
503 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
504 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
505 SRCCOPY);
506 /* mask */
507 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
508 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
509 SRCCOPY);
511 /* copy (without stretching) temporary bitmaps to source (restore) */
512 /* mask */
513 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
514 hdcBmp, 0, 0, SRCCOPY);
516 /* image */
517 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
518 hdcBmp, 0, 0, SRCCOPY);
519 /* delete temporary bitmaps */
520 DeleteObject (hbmTempMask);
521 DeleteObject (hbmTempImage);
522 DeleteDC(hdcBmp);
524 else {
525 /* copy image */
526 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
527 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
528 SRCCOPY);
530 /* copy mask */
531 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
532 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
533 SRCCOPY);
536 return TRUE;
540 /*************************************************************************
541 * ImageList_Create [COMCTL32.@]
543 * Creates a new image list.
545 * PARAMS
546 * cx [I] image height
547 * cy [I] image width
548 * flags [I] creation flags
549 * cInitial [I] initial number of images in the image list
550 * cGrow [I] number of images by which image list grows
552 * RETURNS
553 * Success: Handle to the created image list
554 * Failure: NULL
556 HIMAGELIST WINAPI
557 ImageList_Create (INT cx, INT cy, UINT flags,
558 INT cInitial, INT cGrow)
560 HIMAGELIST himl;
561 INT nCount;
562 HBITMAP hbmTemp;
563 UINT ilc = (flags & 0xFE);
564 static const WORD aBitBlend25[] =
565 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
567 static const WORD aBitBlend50[] =
568 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
570 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
572 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
573 if (!himl)
574 return NULL;
576 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
578 himl->magic = IMAGELIST_MAGIC;
579 himl->cx = cx;
580 himl->cy = cy;
581 himl->flags = flags;
582 himl->cMaxImage = cInitial + cGrow;
583 himl->cInitial = cInitial;
584 himl->cGrow = cGrow;
585 himl->clrFg = CLR_DEFAULT;
586 himl->clrBk = CLR_NONE;
588 /* initialize overlay mask indices */
589 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
590 himl->nOvlIdx[nCount] = -1;
592 /* Create Image & Mask DCs */
593 himl->hdcImage = CreateCompatibleDC (0);
594 if (!himl->hdcImage)
595 goto cleanup;
596 if (himl->flags & ILC_MASK){
597 himl->hdcMask = CreateCompatibleDC(0);
598 if (!himl->hdcMask)
599 goto cleanup;
602 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
603 if (ilc == ILC_COLOR)
604 ilc = ILC_COLOR4;
606 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
607 himl->uBitsPixel = ilc;
608 else
609 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
611 if (himl->cMaxImage > 0) {
612 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy);
613 SelectObject(himl->hdcImage, himl->hbmImage);
614 } else
615 himl->hbmImage = 0;
617 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
618 himl->hbmMask =
619 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
620 1, 1, NULL);
621 if (himl->hbmMask == 0) {
622 ERR("Error creating mask bitmap!\n");
623 goto cleanup;
625 SelectObject(himl->hdcMask, himl->hbmMask);
627 else
628 himl->hbmMask = 0;
630 /* create blending brushes */
631 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
632 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
633 DeleteObject (hbmTemp);
635 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
636 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
637 DeleteObject (hbmTemp);
639 TRACE("created imagelist %p\n", himl);
640 return himl;
642 cleanup:
643 if (himl) ImageList_Destroy(himl);
644 return NULL;
648 /*************************************************************************
649 * ImageList_Destroy [COMCTL32.@]
651 * Destroys an image list.
653 * PARAMS
654 * himl [I] handle to image list
656 * RETURNS
657 * Success: TRUE
658 * Failure: FALSE
661 BOOL WINAPI
662 ImageList_Destroy (HIMAGELIST himl)
664 if (!is_valid(himl))
665 return FALSE;
667 /* delete image bitmaps */
668 if (himl->hbmImage)
669 DeleteObject (himl->hbmImage);
670 if (himl->hbmMask)
671 DeleteObject (himl->hbmMask);
673 /* delete image & mask DCs */
674 if (himl->hdcImage)
675 DeleteDC(himl->hdcImage);
676 if (himl->hdcMask)
677 DeleteDC(himl->hdcMask);
679 /* delete blending brushes */
680 if (himl->hbrBlend25)
681 DeleteObject (himl->hbrBlend25);
682 if (himl->hbrBlend50)
683 DeleteObject (himl->hbrBlend50);
685 ZeroMemory(himl, sizeof(*himl));
686 Free (himl);
688 return TRUE;
692 /*************************************************************************
693 * ImageList_DragEnter [COMCTL32.@]
695 * Locks window update and displays the drag image at the given position.
697 * PARAMS
698 * hwndLock [I] handle of the window that owns the drag image.
699 * x [I] X position of the drag image.
700 * y [I] Y position of the drag image.
702 * RETURNS
703 * Success: TRUE
704 * Failure: FALSE
706 * NOTES
707 * The position of the drag image is relative to the window, not
708 * the client area.
711 BOOL WINAPI
712 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
714 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
716 if (!is_valid(InternalDrag.himl))
717 return FALSE;
719 if (hwndLock)
720 InternalDrag.hwnd = hwndLock;
721 else
722 InternalDrag.hwnd = GetDesktopWindow ();
724 InternalDrag.x = x;
725 InternalDrag.y = y;
727 /* draw the drag image and save the background */
728 if (!ImageList_DragShowNolock(TRUE)) {
729 return FALSE;
732 return TRUE;
736 /*************************************************************************
737 * ImageList_DragLeave [COMCTL32.@]
739 * Unlocks window update and hides the drag image.
741 * PARAMS
742 * hwndLock [I] handle of the window that owns the drag image.
744 * RETURNS
745 * Success: TRUE
746 * Failure: FALSE
749 BOOL WINAPI
750 ImageList_DragLeave (HWND hwndLock)
752 /* As we don't save drag info in the window this can lead to problems if
753 an app does not supply the same window as DragEnter */
754 /* if (hwndLock)
755 InternalDrag.hwnd = hwndLock;
756 else
757 InternalDrag.hwnd = GetDesktopWindow (); */
758 if(!hwndLock)
759 hwndLock = GetDesktopWindow();
760 if(InternalDrag.hwnd != hwndLock)
761 FIXME("DragLeave hWnd != DragEnter hWnd\n");
763 ImageList_DragShowNolock (FALSE);
765 return TRUE;
769 /*************************************************************************
770 * ImageList_InternalDragDraw [Internal]
772 * Draws the drag image.
774 * PARAMS
775 * hdc [I] device context to draw into.
776 * x [I] X position of the drag image.
777 * y [I] Y position of the drag image.
779 * RETURNS
780 * Success: TRUE
781 * Failure: FALSE
783 * NOTES
784 * The position of the drag image is relative to the window, not
785 * the client area.
789 static inline void
790 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
792 IMAGELISTDRAWPARAMS imldp;
794 ZeroMemory (&imldp, sizeof(imldp));
795 imldp.cbSize = sizeof(imldp);
796 imldp.himl = InternalDrag.himl;
797 imldp.i = 0;
798 imldp.hdcDst = hdc,
799 imldp.x = x;
800 imldp.y = y;
801 imldp.rgbBk = CLR_DEFAULT;
802 imldp.rgbFg = CLR_DEFAULT;
803 imldp.fStyle = ILD_NORMAL;
804 imldp.fState = ILS_ALPHA;
805 imldp.Frame = 128;
807 /* FIXME: instead of using the alpha blending, we should
808 * create a 50% mask, and draw it semitransparantly that way */
809 ImageList_DrawIndirect (&imldp);
812 /*************************************************************************
813 * ImageList_DragMove [COMCTL32.@]
815 * Moves the drag image.
817 * PARAMS
818 * x [I] X position of the drag image.
819 * y [I] Y position of the drag image.
821 * RETURNS
822 * Success: TRUE
823 * Failure: FALSE
825 * NOTES
826 * The position of the drag image is relative to the window, not
827 * the client area.
829 * BUGS
830 * The drag image should be drawn semitransparent.
833 BOOL WINAPI
834 ImageList_DragMove (INT x, INT y)
836 TRACE("(x=%d y=%d)\n", x, y);
838 if (!is_valid(InternalDrag.himl))
839 return FALSE;
841 /* draw/update the drag image */
842 if (InternalDrag.bShow) {
843 HDC hdcDrag;
844 HDC hdcOffScreen;
845 HDC hdcBg;
846 HBITMAP hbmOffScreen;
847 INT origNewX, origNewY;
848 INT origOldX, origOldY;
849 INT origRegX, origRegY;
850 INT sizeRegX, sizeRegY;
853 /* calculate the update region */
854 origNewX = x - InternalDrag.dxHotspot;
855 origNewY = y - InternalDrag.dyHotspot;
856 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
857 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
858 origRegX = min(origNewX, origOldX);
859 origRegY = min(origNewY, origOldY);
860 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
861 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
863 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
864 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
865 hdcOffScreen = CreateCompatibleDC(hdcDrag);
866 hdcBg = CreateCompatibleDC(hdcDrag);
868 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
869 SelectObject(hdcOffScreen, hbmOffScreen);
870 SelectObject(hdcBg, InternalDrag.hbmBg);
872 /* get the actual background of the update region */
873 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
874 origRegX, origRegY, SRCCOPY);
875 /* erase the old image */
876 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
877 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
878 SRCCOPY);
879 /* save the background */
880 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
881 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
882 /* draw the image */
883 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
884 origNewY - origRegY);
885 /* draw the update region to the screen */
886 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
887 hdcOffScreen, 0, 0, SRCCOPY);
889 DeleteDC(hdcBg);
890 DeleteDC(hdcOffScreen);
891 DeleteObject(hbmOffScreen);
892 ReleaseDC(InternalDrag.hwnd, hdcDrag);
895 /* update the image position */
896 InternalDrag.x = x;
897 InternalDrag.y = y;
899 return TRUE;
903 /*************************************************************************
904 * ImageList_DragShowNolock [COMCTL32.@]
906 * Shows or hides the drag image.
908 * PARAMS
909 * bShow [I] TRUE shows the drag image, FALSE hides it.
911 * RETURNS
912 * Success: TRUE
913 * Failure: FALSE
915 * BUGS
916 * The drag image should be drawn semitransparent.
919 BOOL WINAPI
920 ImageList_DragShowNolock (BOOL bShow)
922 HDC hdcDrag;
923 HDC hdcBg;
924 INT x, y;
926 if (!is_valid(InternalDrag.himl))
927 return FALSE;
929 TRACE("bShow=0x%X!\n", bShow);
931 /* DragImage is already visible/hidden */
932 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
933 return FALSE;
936 /* position of the origin of the DragImage */
937 x = InternalDrag.x - InternalDrag.dxHotspot;
938 y = InternalDrag.y - InternalDrag.dyHotspot;
940 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
941 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
942 if (!hdcDrag) {
943 return FALSE;
946 hdcBg = CreateCompatibleDC(hdcDrag);
947 if (!InternalDrag.hbmBg) {
948 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
949 InternalDrag.himl->cx, InternalDrag.himl->cy);
951 SelectObject(hdcBg, InternalDrag.hbmBg);
953 if (bShow) {
954 /* save the background */
955 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
956 hdcDrag, x, y, SRCCOPY);
957 /* show the image */
958 ImageList_InternalDragDraw(hdcDrag, x, y);
959 } else {
960 /* hide the image */
961 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
962 hdcBg, 0, 0, SRCCOPY);
965 InternalDrag.bShow = !InternalDrag.bShow;
967 DeleteDC(hdcBg);
968 ReleaseDC (InternalDrag.hwnd, hdcDrag);
969 return TRUE;
973 /*************************************************************************
974 * ImageList_Draw [COMCTL32.@]
976 * Draws an image.
978 * PARAMS
979 * himl [I] handle to image list
980 * i [I] image index
981 * hdc [I] handle to device context
982 * x [I] x position
983 * y [I] y position
984 * fStyle [I] drawing flags
986 * RETURNS
987 * Success: TRUE
988 * Failure: FALSE
990 * SEE
991 * ImageList_DrawEx.
994 BOOL WINAPI
995 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
997 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
998 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1002 /*************************************************************************
1003 * ImageList_DrawEx [COMCTL32.@]
1005 * Draws an image and allows to use extended drawing features.
1007 * PARAMS
1008 * himl [I] handle to image list
1009 * i [I] image index
1010 * hdc [I] handle to device context
1011 * x [I] X position
1012 * y [I] Y position
1013 * dx [I] X offset
1014 * dy [I] Y offset
1015 * rgbBk [I] background color
1016 * rgbFg [I] foreground color
1017 * fStyle [I] drawing flags
1019 * RETURNS
1020 * Success: TRUE
1021 * Failure: FALSE
1023 * NOTES
1024 * Calls ImageList_DrawIndirect.
1026 * SEE
1027 * ImageList_DrawIndirect.
1030 BOOL WINAPI
1031 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1032 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1033 UINT fStyle)
1035 IMAGELISTDRAWPARAMS imldp;
1037 ZeroMemory (&imldp, sizeof(imldp));
1038 imldp.cbSize = sizeof(imldp);
1039 imldp.himl = himl;
1040 imldp.i = i;
1041 imldp.hdcDst = hdc,
1042 imldp.x = x;
1043 imldp.y = y;
1044 imldp.cx = dx;
1045 imldp.cy = dy;
1046 imldp.rgbBk = rgbBk;
1047 imldp.rgbFg = rgbFg;
1048 imldp.fStyle = fStyle;
1050 return ImageList_DrawIndirect (&imldp);
1054 /*************************************************************************
1055 * ImageList_DrawIndirect [COMCTL32.@]
1057 * Draws an image using various parameters specified in pimldp.
1059 * PARAMS
1060 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1062 * RETURNS
1063 * Success: TRUE
1064 * Failure: FALSE
1067 BOOL WINAPI
1068 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1070 INT cx, cy, nOvlIdx;
1071 DWORD fState, dwRop;
1072 UINT fStyle;
1073 COLORREF oldImageBk, oldImageFg;
1074 HDC hImageDC, hImageListDC, hMaskListDC;
1075 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1076 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1077 HIMAGELIST himl;
1078 POINT pt;
1080 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1081 if (!is_valid(himl)) return FALSE;
1082 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1084 imagelist_point_from_index( himl, pimldp->i, &pt );
1085 pt.x += pimldp->xBitmap;
1086 pt.y += pimldp->yBitmap;
1088 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1089 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1090 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1091 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1093 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1094 if( pimldp->rgbBk == CLR_NONE )
1095 bIsTransparent = TRUE;
1096 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1097 bIsTransparent = TRUE;
1098 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1099 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1101 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1102 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1104 /* we will use these DCs to access the images and masks in the ImageList */
1105 hImageListDC = himl->hdcImage;
1106 hMaskListDC = himl->hdcMask;
1108 /* these will accumulate the image and mask for the image we're drawing */
1109 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1110 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1111 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1113 /* Create a compatible DC. */
1114 if (!hImageListDC || !hImageDC || !hImageBmp ||
1115 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1116 goto cleanup;
1118 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1121 * To obtain a transparent look, background color should be set
1122 * to white and foreground color to black when blting the
1123 * monochrome mask.
1125 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1126 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1129 * Draw the initial image
1131 if( bMask ) {
1132 if (himl->hbmMask) {
1133 HBRUSH hOldBrush;
1134 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1135 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1136 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1137 DeleteObject (SelectObject (hImageDC, hOldBrush));
1138 if( bIsTransparent )
1140 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1141 bResult = TRUE;
1142 goto end;
1144 } else {
1145 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1146 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1147 SelectObject(hImageDC, hOldBrush);
1149 } else {
1150 /* blend the image with the needed solid background */
1151 COLORREF colour = RGB(0,0,0);
1152 HBRUSH hOldBrush;
1154 if( !bIsTransparent )
1156 colour = pimldp->rgbBk;
1157 if( colour == CLR_DEFAULT )
1158 colour = himl->clrBk;
1159 if( colour == CLR_NONE )
1160 colour = GetBkColor(pimldp->hdcDst);
1163 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1164 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1165 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1166 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1167 DeleteObject (SelectObject (hImageDC, hOldBrush));
1170 /* Time for blending, if required */
1171 if (bBlend) {
1172 HBRUSH hBlendBrush, hOldBrush;
1173 COLORREF clrBlend = pimldp->rgbFg;
1174 HDC hBlendMaskDC = hImageListDC;
1175 HBITMAP hOldBitmap;
1177 /* Create the blend Mask */
1178 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1179 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1180 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1181 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1182 SelectObject(hBlendMaskDC, hOldBrush);
1184 /* Modify the blend mask if an Image Mask exist */
1185 if(himl->hbmMask) {
1186 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1187 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1190 /* now apply blend to the current image given the BlendMask */
1191 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1192 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1193 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1194 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1195 DeleteObject(SelectObject(hImageDC, hOldBrush));
1196 SelectObject(hBlendMaskDC, hOldBitmap);
1199 /* Now do the overlay image, if any */
1200 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1201 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1202 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1203 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1204 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1205 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1206 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, pt.x, SRCAND);
1207 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, pt.y, SRCPAINT);
1211 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1212 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1213 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1214 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1216 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1217 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1218 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1220 /* now copy the image to the screen */
1221 dwRop = SRCCOPY;
1222 if (himl->hbmMask && bIsTransparent ) {
1223 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1224 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1225 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1226 SetBkColor(pimldp->hdcDst, oldDstBk);
1227 SetTextColor(pimldp->hdcDst, oldDstFg);
1228 dwRop = SRCPAINT;
1230 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1231 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1233 bResult = TRUE;
1234 end:
1235 /* cleanup the mess */
1236 SetBkColor(hImageDC, oldImageBk);
1237 SetTextColor(hImageDC, oldImageFg);
1238 SelectObject(hImageDC, hOldImageBmp);
1239 cleanup:
1240 DeleteObject(hBlendMaskBmp);
1241 DeleteObject(hImageBmp);
1242 DeleteDC(hImageDC);
1244 return bResult;
1248 /*************************************************************************
1249 * ImageList_Duplicate [COMCTL32.@]
1251 * Duplicates an image list.
1253 * PARAMS
1254 * himlSrc [I] source image list handle
1256 * RETURNS
1257 * Success: Handle of duplicated image list.
1258 * Failure: NULL
1261 HIMAGELIST WINAPI
1262 ImageList_Duplicate (HIMAGELIST himlSrc)
1264 HIMAGELIST himlDst;
1266 if (!is_valid(himlSrc)) {
1267 ERR("Invalid image list handle!\n");
1268 return NULL;
1271 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1272 himlSrc->cInitial, himlSrc->cGrow);
1274 if (himlDst)
1276 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1277 himlSrc->hdcImage, 0, 0, SRCCOPY);
1279 if (himlDst->hbmMask)
1280 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1281 himlSrc->hdcMask, 0, 0, SRCCOPY);
1283 himlDst->cCurImage = himlSrc->cCurImage;
1284 himlDst->cMaxImage = himlSrc->cMaxImage;
1286 return himlDst;
1290 /*************************************************************************
1291 * ImageList_EndDrag [COMCTL32.@]
1293 * Finishes a drag operation.
1295 * PARAMS
1296 * no Parameters
1298 * RETURNS
1299 * Success: TRUE
1300 * Failure: FALSE
1303 VOID WINAPI
1304 ImageList_EndDrag (void)
1306 /* cleanup the InternalDrag struct */
1307 InternalDrag.hwnd = 0;
1308 ImageList_Destroy (InternalDrag.himl);
1309 InternalDrag.himl = 0;
1310 InternalDrag.x= 0;
1311 InternalDrag.y= 0;
1312 InternalDrag.dxHotspot = 0;
1313 InternalDrag.dyHotspot = 0;
1314 InternalDrag.bShow = FALSE;
1315 DeleteObject(InternalDrag.hbmBg);
1316 InternalDrag.hbmBg = 0;
1320 /*************************************************************************
1321 * ImageList_GetBkColor [COMCTL32.@]
1323 * Returns the background color of an image list.
1325 * PARAMS
1326 * himl [I] Image list handle.
1328 * RETURNS
1329 * Success: background color
1330 * Failure: CLR_NONE
1333 COLORREF WINAPI
1334 ImageList_GetBkColor (HIMAGELIST himl)
1336 return himl ? himl->clrBk : CLR_NONE;
1340 /*************************************************************************
1341 * ImageList_GetDragImage [COMCTL32.@]
1343 * Returns the handle to the internal drag image list.
1345 * PARAMS
1346 * ppt [O] Pointer to the drag position. Can be NULL.
1347 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1349 * RETURNS
1350 * Success: Handle of the drag image list.
1351 * Failure: NULL.
1354 HIMAGELIST WINAPI
1355 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1357 if (is_valid(InternalDrag.himl)) {
1358 if (ppt) {
1359 ppt->x = InternalDrag.x;
1360 ppt->y = InternalDrag.y;
1362 if (pptHotspot) {
1363 pptHotspot->x = InternalDrag.dxHotspot;
1364 pptHotspot->y = InternalDrag.dyHotspot;
1366 return (InternalDrag.himl);
1369 return NULL;
1373 /*************************************************************************
1374 * ImageList_GetFlags [COMCTL32.@]
1376 * Gets the flags of the specified image list.
1378 * PARAMS
1379 * himl [I] Handle to image list
1381 * RETURNS
1382 * Image list flags.
1384 * BUGS
1385 * Stub.
1388 DWORD WINAPI
1389 ImageList_GetFlags(HIMAGELIST himl)
1391 FIXME("(%p):empty stub\n", himl);
1392 return 0;
1396 /*************************************************************************
1397 * ImageList_GetIcon [COMCTL32.@]
1399 * Creates an icon from a masked image of an image list.
1401 * PARAMS
1402 * himl [I] handle to image list
1403 * i [I] image index
1404 * flags [I] drawing style flags
1406 * RETURNS
1407 * Success: icon handle
1408 * Failure: NULL
1411 HICON WINAPI
1412 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1414 ICONINFO ii;
1415 HICON hIcon;
1416 HBITMAP hOldDstBitmap;
1417 HDC hdcDst;
1419 TRACE("%p %d %d\n", himl, i, fStyle);
1420 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1422 ii.fIcon = TRUE;
1423 ii.xHotspot = 0;
1424 ii.yHotspot = 0;
1426 /* create colour bitmap */
1427 hdcDst = GetDC(0);
1428 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1429 ReleaseDC(0, hdcDst);
1431 hdcDst = CreateCompatibleDC(0);
1433 /* draw mask*/
1434 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1435 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1436 if (himl->hbmMask) {
1437 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1438 himl->hdcMask, i * himl->cx, 0, SRCCOPY);
1440 else
1441 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1443 /* draw image*/
1444 SelectObject (hdcDst, ii.hbmColor);
1445 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1446 himl->hdcImage, i * himl->cx, 0, SRCCOPY);
1449 * CreateIconIndirect requires us to deselect the bitmaps from
1450 * the DCs before calling
1452 SelectObject(hdcDst, hOldDstBitmap);
1454 hIcon = CreateIconIndirect (&ii);
1456 DeleteObject (ii.hbmMask);
1457 DeleteObject (ii.hbmColor);
1458 DeleteDC (hdcDst);
1460 return hIcon;
1464 /*************************************************************************
1465 * ImageList_GetIconSize [COMCTL32.@]
1467 * Retrieves the size of an image in an image list.
1469 * PARAMS
1470 * himl [I] handle to image list
1471 * cx [O] pointer to the image width.
1472 * cy [O] pointer to the image height.
1474 * RETURNS
1475 * Success: TRUE
1476 * Failure: FALSE
1478 * NOTES
1479 * All images in an image list have the same size.
1482 BOOL WINAPI
1483 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1485 if (!is_valid(himl))
1486 return FALSE;
1487 if ((himl->cx <= 0) || (himl->cy <= 0))
1488 return FALSE;
1490 if (cx)
1491 *cx = himl->cx;
1492 if (cy)
1493 *cy = himl->cy;
1495 return TRUE;
1499 /*************************************************************************
1500 * ImageList_GetImageCount [COMCTL32.@]
1502 * Returns the number of images in an image list.
1504 * PARAMS
1505 * himl [I] handle to image list
1507 * RETURNS
1508 * Success: Number of images.
1509 * Failure: 0
1512 INT WINAPI
1513 ImageList_GetImageCount (HIMAGELIST himl)
1515 if (!is_valid(himl))
1516 return 0;
1518 return himl->cCurImage;
1522 /*************************************************************************
1523 * ImageList_GetImageInfo [COMCTL32.@]
1525 * Returns information about an image in an image list.
1527 * PARAMS
1528 * himl [I] handle to image list
1529 * i [I] image index
1530 * pImageInfo [O] pointer to the image information
1532 * RETURNS
1533 * Success: TRUE
1534 * Failure: FALSE
1537 BOOL WINAPI
1538 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1540 POINT pt;
1542 if (!is_valid(himl) || (pImageInfo == NULL))
1543 return FALSE;
1544 if ((i < 0) || (i >= himl->cCurImage))
1545 return FALSE;
1547 pImageInfo->hbmImage = himl->hbmImage;
1548 pImageInfo->hbmMask = himl->hbmMask;
1550 imagelist_point_from_index( himl, i, &pt );
1551 pImageInfo->rcImage.top = pt.y;
1552 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1553 pImageInfo->rcImage.left = pt.x;
1554 pImageInfo->rcImage.right = pt.x + himl->cx;
1556 return TRUE;
1560 /*************************************************************************
1561 * ImageList_GetImageRect [COMCTL32.@]
1563 * Retrieves the rectangle of the specified image in an image list.
1565 * PARAMS
1566 * himl [I] handle to image list
1567 * i [I] image index
1568 * lpRect [O] pointer to the image rectangle
1570 * RETURNS
1571 * Success: TRUE
1572 * Failure: FALSE
1574 * NOTES
1575 * This is an UNDOCUMENTED function!!!
1578 BOOL WINAPI
1579 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1581 POINT pt;
1583 if (!is_valid(himl) || (lpRect == NULL))
1584 return FALSE;
1585 if ((i < 0) || (i >= himl->cCurImage))
1586 return FALSE;
1588 imagelist_point_from_index( himl, i, &pt );
1589 lpRect->left = pt.x;
1590 lpRect->top = pt.y;
1591 lpRect->right = pt.x + himl->cx;
1592 lpRect->bottom = pt.y + himl->cy;
1594 return TRUE;
1598 /*************************************************************************
1599 * ImageList_LoadImage [COMCTL32.@]
1600 * ImageList_LoadImageA [COMCTL32.@]
1602 * Creates an image list from a bitmap, icon or cursor.
1604 * See ImageList_LoadImageW.
1607 HIMAGELIST WINAPI
1608 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1609 COLORREF clrMask, UINT uType, UINT uFlags)
1611 HIMAGELIST himl;
1612 LPWSTR lpbmpW;
1613 DWORD len;
1615 if (!HIWORD(lpbmp))
1616 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1617 uType, uFlags);
1619 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1620 lpbmpW = Alloc(len * sizeof(WCHAR));
1621 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1623 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1624 Free (lpbmpW);
1625 return himl;
1629 /*************************************************************************
1630 * ImageList_LoadImageW [COMCTL32.@]
1632 * Creates an image list from a bitmap, icon or cursor.
1634 * PARAMS
1635 * hi [I] instance handle
1636 * lpbmp [I] name or id of the image
1637 * cx [I] width of each image
1638 * cGrow [I] number of images to expand
1639 * clrMask [I] mask color
1640 * uType [I] type of image to load
1641 * uFlags [I] loading flags
1643 * RETURNS
1644 * Success: handle to the loaded image list
1645 * Failure: NULL
1647 * SEE
1648 * LoadImage ()
1651 HIMAGELIST WINAPI
1652 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1653 COLORREF clrMask, UINT uType, UINT uFlags)
1655 HIMAGELIST himl = NULL;
1656 HANDLE handle;
1657 INT nImageCount;
1659 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1660 if (!handle) {
1661 ERR("Error loading image!\n");
1662 return NULL;
1665 if (uType == IMAGE_BITMAP) {
1666 BITMAP bmp;
1667 GetObjectW (handle, sizeof(BITMAP), &bmp);
1669 /* To match windows behavior, if cx is set to zero and
1670 the flag DI_DEFAULTSIZE is specified, cx becomes the
1671 system metric value for icons. If the flag is not specified
1672 the function sets the size to the height of the bitmap */
1673 if (cx == 0)
1675 if (uFlags & DI_DEFAULTSIZE)
1676 cx = GetSystemMetrics (SM_CXICON);
1677 else
1678 cx = bmp.bmHeight;
1681 nImageCount = bmp.bmWidth / cx;
1683 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1684 nImageCount, cGrow);
1685 if (!himl) {
1686 DeleteObject (handle);
1687 return NULL;
1689 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1691 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1692 ICONINFO ii;
1693 BITMAP bmp;
1695 GetIconInfo (handle, &ii);
1696 GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1697 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1698 ILC_MASK | ILC_COLOR, 1, cGrow);
1699 if (!himl) {
1700 DeleteObject (ii.hbmColor);
1701 DeleteObject (ii.hbmMask);
1702 DeleteObject (handle);
1703 return NULL;
1705 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1706 DeleteObject (ii.hbmColor);
1707 DeleteObject (ii.hbmMask);
1710 DeleteObject (handle);
1712 return himl;
1716 /*************************************************************************
1717 * ImageList_Merge [COMCTL32.@]
1719 * Create an image list containing a merged image from two image lists.
1721 * PARAMS
1722 * himl1 [I] handle to first image list
1723 * i1 [I] first image index
1724 * himl2 [I] handle to second image list
1725 * i2 [I] second image index
1726 * dx [I] X offset of the second image relative to the first.
1727 * dy [I] Y offset of the second image relative to the first.
1729 * RETURNS
1730 * Success: The newly created image list. It contains a single image
1731 * consisting of the second image merged with the first.
1732 * Failure: NULL, if either himl1 or himl2 are invalid.
1734 * NOTES
1735 * - The returned image list should be deleted by the caller using
1736 * ImageList_Destroy() when it is no longer required.
1737 * - If either i1 or i2 are not valid image indices they will be treated
1738 * as a blank image.
1740 HIMAGELIST WINAPI
1741 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1742 INT dx, INT dy)
1744 HIMAGELIST himlDst = NULL;
1745 INT cxDst, cyDst;
1746 INT xOff1, yOff1, xOff2, yOff2;
1747 INT nX1, nX2;
1749 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1750 i2, dx, dy);
1752 if (!is_valid(himl1) || !is_valid(himl2))
1753 return NULL;
1755 if (dx > 0) {
1756 cxDst = max (himl1->cx, dx + himl2->cx);
1757 xOff1 = 0;
1758 xOff2 = dx;
1760 else if (dx < 0) {
1761 cxDst = max (himl2->cx, himl1->cx - dx);
1762 xOff1 = -dx;
1763 xOff2 = 0;
1765 else {
1766 cxDst = max (himl1->cx, himl2->cx);
1767 xOff1 = 0;
1768 xOff2 = 0;
1771 if (dy > 0) {
1772 cyDst = max (himl1->cy, dy + himl2->cy);
1773 yOff1 = 0;
1774 yOff2 = dy;
1776 else if (dy < 0) {
1777 cyDst = max (himl2->cy, himl1->cy - dy);
1778 yOff1 = -dy;
1779 yOff2 = 0;
1781 else {
1782 cyDst = max (himl1->cy, himl2->cy);
1783 yOff1 = 0;
1784 yOff2 = 0;
1787 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1789 if (himlDst)
1791 nX1 = i1 * himl1->cx;
1792 nX2 = i2 * himl2->cx;
1794 /* copy image */
1795 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1796 if (i1 >= 0 && i1 < himl1->cCurImage)
1797 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1798 if (i2 >= 0 && i2 < himl2->cCurImage)
1800 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1801 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1804 /* copy mask */
1805 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1806 if (i1 >= 0 && i1 < himl1->cCurImage)
1807 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1808 if (i2 >= 0 && i2 < himl2->cCurImage)
1809 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1811 himlDst->cCurImage = 1;
1814 return himlDst;
1818 /* helper for _read_bitmap currently unused */
1819 #if 0
1820 static int may_use_dibsection(HDC hdc) {
1821 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1822 if (bitspixel>8)
1823 return TRUE;
1824 if (bitspixel<=4)
1825 return FALSE;
1826 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1828 #endif
1830 /* helper for ImageList_Read, see comments below */
1831 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1832 HDC xdc = 0, hBitmapDC =0;
1833 BITMAPFILEHEADER bmfh;
1834 BITMAPINFOHEADER bmih;
1835 int bitsperpixel,palspace,longsperline,width,height;
1836 LPBITMAPINFOHEADER bmihc = NULL;
1837 int result = 0;
1838 HBITMAP hbitmap = 0, hDIB = 0;
1839 LPBYTE bits = NULL;
1841 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1842 (bmfh.bfType != (('M'<<8)|'B')) ||
1843 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1844 (bmih.biSize != sizeof(bmih))
1846 return 0;
1848 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1849 if (bitsperpixel<=8)
1850 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1851 else
1852 palspace = 0;
1853 width = bmih.biWidth;
1854 height = bmih.biHeight;
1855 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1856 if (!bmihc) goto ret1;
1857 memcpy(bmihc,&bmih,sizeof(bmih));
1858 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1859 bmihc->biSizeImage = (longsperline*height)<<2;
1861 /* read the palette right after the end of the bitmapinfoheader */
1862 if (palspace)
1863 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1864 goto ret1;
1866 xdc = GetDC(0);
1867 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1868 if ((bitsperpixel>1) &&
1869 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1871 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1872 if (!hbitmap)
1873 goto ret1;
1874 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1875 goto ret1;
1876 result = 1;
1877 } else
1878 #endif
1880 int i,nwidth,nheight,nRows;
1882 nwidth = width*(height/cy);
1883 nheight = cy;
1884 nRows = (height/cy);
1886 if (bitsperpixel==1)
1887 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1888 else
1889 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1891 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1892 if (!hDIB)
1893 goto ret1;
1894 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1895 goto ret1;
1897 hBitmapDC = CreateCompatibleDC(0);
1898 SelectObject(hBitmapDC, hbitmap);
1900 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1901 /* Do not forget that windows bitmaps are bottom->top */
1902 TRACE("nRows=%d\n", nRows);
1903 for (i=0; i < nRows; i++){
1904 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1905 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1908 result = 1;
1910 ret1:
1911 if (xdc) ReleaseDC(0,xdc);
1912 if (bmihc) LocalFree((HLOCAL)bmihc);
1913 if (hDIB) DeleteObject(hDIB);
1914 if (hBitmapDC) DeleteDC(hBitmapDC);
1915 if (!result) {
1916 if (hbitmap) {
1917 DeleteObject(hbitmap);
1918 hbitmap = 0;
1921 return hbitmap;
1924 /*************************************************************************
1925 * ImageList_Read [COMCTL32.@]
1927 * Reads an image list from a stream.
1929 * PARAMS
1930 * pstm [I] pointer to a stream
1932 * RETURNS
1933 * Success: handle to image list
1934 * Failure: NULL
1936 * The format is like this:
1937 * ILHEAD ilheadstruct;
1939 * for the color image part:
1940 * BITMAPFILEHEADER bmfh;
1941 * BITMAPINFOHEADER bmih;
1942 * only if it has a palette:
1943 * RGBQUAD rgbs[nr_of_paletted_colors];
1945 * BYTE colorbits[imagesize];
1947 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1948 * BITMAPFILEHEADER bmfh_mask;
1949 * BITMAPINFOHEADER bmih_mask;
1950 * only if it has a palette (it usually does not):
1951 * RGBQUAD rgbs[nr_of_paletted_colors];
1953 * BYTE maskbits[imagesize];
1955 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1956 * _read_bitmap needs to convert them.
1958 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1960 ILHEAD ilHead;
1961 HIMAGELIST himl;
1962 HBITMAP hbmColor=0,hbmMask=0;
1963 int i;
1965 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1966 return NULL;
1967 if (ilHead.usMagic != (('L' << 8) | 'I'))
1968 return NULL;
1969 if (ilHead.usVersion != 0x101) /* probably version? */
1970 return NULL;
1972 #if 0
1973 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1974 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1975 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1976 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1977 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1978 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1979 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1980 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1981 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1982 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1983 #endif
1985 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1986 if (!hbmColor) {
1987 WARN("failed to read bitmap from stream\n");
1988 return NULL;
1990 if (ilHead.flags & ILC_MASK) {
1991 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1992 if (!hbmMask) {
1993 DeleteObject(hbmColor);
1994 return NULL;
1998 himl = ImageList_Create (
1999 ilHead.cx,
2000 ilHead.cy,
2001 ilHead.flags,
2002 1, /* initial */
2003 ilHead.cGrow
2005 if (!himl) {
2006 DeleteObject(hbmColor);
2007 DeleteObject(hbmMask);
2008 return NULL;
2010 SelectObject(himl->hdcImage, hbmColor);
2011 DeleteObject(himl->hbmImage);
2012 himl->hbmImage = hbmColor;
2013 if (hbmMask){
2014 SelectObject(himl->hdcMask, hbmMask);
2015 DeleteObject(himl->hbmMask);
2016 himl->hbmMask = hbmMask;
2018 himl->cCurImage = ilHead.cCurImage;
2019 himl->cMaxImage = ilHead.cMaxImage;
2021 ImageList_SetBkColor(himl,ilHead.bkcolor);
2022 for (i=0;i<4;i++)
2023 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2024 return himl;
2028 /*************************************************************************
2029 * ImageList_Remove [COMCTL32.@]
2031 * Removes an image from an image list
2033 * PARAMS
2034 * himl [I] image list handle
2035 * i [I] image index
2037 * RETURNS
2038 * Success: TRUE
2039 * Failure: FALSE
2042 BOOL WINAPI
2043 ImageList_Remove (HIMAGELIST himl, INT i)
2045 HBITMAP hbmNewImage, hbmNewMask;
2046 HDC hdcBmp;
2047 INT cxNew, nCount;
2049 TRACE("(himl=%p i=%d)\n", himl, i);
2051 if (!is_valid(himl)) {
2052 ERR("Invalid image list handle!\n");
2053 return FALSE;
2056 if ((i < -1) || (i >= himl->cCurImage)) {
2057 TRACE("index out of range! %d\n", i);
2058 return FALSE;
2061 if (i == -1) {
2062 /* remove all */
2063 if (himl->cCurImage == 0) {
2064 /* remove all on empty ImageList is allowed */
2065 TRACE("remove all on empty ImageList!\n");
2066 return TRUE;
2069 himl->cMaxImage = himl->cInitial + himl->cGrow;
2070 himl->cCurImage = 0;
2071 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2072 himl->nOvlIdx[nCount] = -1;
2074 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2075 SelectObject (himl->hdcImage, hbmNewImage);
2076 DeleteObject (himl->hbmImage);
2077 himl->hbmImage = hbmNewImage;
2079 if (himl->hbmMask) {
2080 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2081 1, 1, NULL);
2082 SelectObject (himl->hdcMask, hbmNewMask);
2083 DeleteObject (himl->hbmMask);
2084 himl->hbmMask = hbmNewMask;
2087 else {
2088 /* delete one image */
2089 TRACE("Remove single image! %d\n", i);
2091 /* create new bitmap(s) */
2092 nCount = (himl->cCurImage + himl->cGrow - 1);
2093 cxNew = nCount * himl->cx;
2095 TRACE(" - Number of images: %d / %d (Old/New)\n",
2096 himl->cCurImage, himl->cCurImage - 1);
2097 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2098 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2100 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy);
2102 if (himl->hbmMask)
2103 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2104 else
2105 hbmNewMask = 0; /* Just to keep compiler happy! */
2107 hdcBmp = CreateCompatibleDC (0);
2109 /* copy all images and masks prior to the "removed" image */
2110 if (i > 0) {
2111 TRACE("Pre image copy: Copy %d images\n", i);
2113 SelectObject (hdcBmp, hbmNewImage);
2114 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2115 himl->hdcImage, 0, 0, SRCCOPY);
2117 if (himl->hbmMask) {
2118 SelectObject (hdcBmp, hbmNewMask);
2119 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2120 himl->hdcMask, 0, 0, SRCCOPY);
2124 /* copy all images and masks behind the removed image */
2125 if (i < himl->cCurImage - 1) {
2126 TRACE("Post image copy!\n");
2127 SelectObject (hdcBmp, hbmNewImage);
2128 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2129 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2131 if (himl->hbmMask) {
2132 SelectObject (hdcBmp, hbmNewMask);
2133 BitBlt (hdcBmp, i * himl->cx, 0,
2134 (himl->cCurImage - i - 1) * himl->cx,
2135 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2139 DeleteDC (hdcBmp);
2141 /* delete old images and insert new ones */
2142 SelectObject (himl->hdcImage, hbmNewImage);
2143 DeleteObject (himl->hbmImage);
2144 himl->hbmImage = hbmNewImage;
2145 if (himl->hbmMask) {
2146 SelectObject (himl->hdcMask, hbmNewMask);
2147 DeleteObject (himl->hbmMask);
2148 himl->hbmMask = hbmNewMask;
2151 himl->cCurImage--;
2152 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2155 return TRUE;
2159 /*************************************************************************
2160 * ImageList_Replace [COMCTL32.@]
2162 * Replaces an image in an image list with a new image.
2164 * PARAMS
2165 * himl [I] handle to image list
2166 * i [I] image index
2167 * hbmImage [I] handle to image bitmap
2168 * hbmMask [I] handle to mask bitmap. Can be NULL.
2170 * RETURNS
2171 * Success: TRUE
2172 * Failure: FALSE
2175 BOOL WINAPI
2176 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2177 HBITMAP hbmMask)
2179 HDC hdcImage;
2180 BITMAP bmp;
2181 HBITMAP hOldBitmap;
2183 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2185 if (!is_valid(himl)) {
2186 ERR("Invalid image list handle!\n");
2187 return FALSE;
2190 if ((i >= himl->cMaxImage) || (i < 0)) {
2191 ERR("Invalid image index!\n");
2192 return FALSE;
2195 hdcImage = CreateCompatibleDC (0);
2196 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2198 /* Replace Image */
2199 hOldBitmap = SelectObject (hdcImage, hbmImage);
2201 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2202 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2204 if (himl->hbmMask)
2206 HDC hdcTemp;
2207 HBITMAP hOldBitmapTemp;
2209 hdcTemp = CreateCompatibleDC(0);
2210 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2212 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2213 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2214 SelectObject(hdcTemp, hOldBitmapTemp);
2215 DeleteDC(hdcTemp);
2217 /* Remove the background from the image
2219 BitBlt (himl->hdcImage,
2220 i*himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
2221 himl->hdcMask,
2222 i*himl->cx, 0,
2223 0x220326); /* NOTSRCAND */
2226 SelectObject (hdcImage, hOldBitmap);
2227 DeleteDC (hdcImage);
2229 return TRUE;
2233 /*************************************************************************
2234 * ImageList_ReplaceIcon [COMCTL32.@]
2236 * Replaces an image in an image list using an icon.
2238 * PARAMS
2239 * himl [I] handle to image list
2240 * i [I] image index
2241 * hIcon [I] handle to icon
2243 * RETURNS
2244 * Success: index of the replaced image
2245 * Failure: -1
2248 INT WINAPI
2249 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2251 HDC hdcImage;
2252 INT nIndex;
2253 HICON hBestFitIcon;
2254 HBITMAP hbmOldSrc;
2255 ICONINFO ii;
2256 BITMAP bmp;
2257 BOOL ret;
2259 TRACE("(%p %d %p)\n", himl, i, hIcon);
2261 if (!is_valid(himl)) {
2262 ERR("invalid image list\n");
2263 return -1;
2265 if ((i >= himl->cMaxImage) || (i < -1)) {
2266 ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2267 return -1;
2270 hBestFitIcon = CopyImage(
2271 hIcon, IMAGE_ICON,
2272 himl->cx, himl->cy,
2273 LR_COPYFROMRESOURCE);
2274 /* the above will fail if the icon wasn't loaded from a resource, so try
2275 * again without LR_COPYFROMRESOURCE flag */
2276 if (!hBestFitIcon)
2277 hBestFitIcon = CopyImage(
2278 hIcon, IMAGE_ICON,
2279 himl->cx, himl->cy,
2281 if (!hBestFitIcon)
2282 return -1;
2284 ret = GetIconInfo (hBestFitIcon, &ii);
2285 if (!ret) {
2286 DestroyIcon(hBestFitIcon);
2287 return -1;
2290 if (ii.hbmColor == 0)
2291 ERR("no color!\n");
2292 ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2293 if (!ret) {
2294 ERR("couldn't get mask bitmap info\n");
2295 if (ii.hbmColor)
2296 DeleteObject (ii.hbmColor);
2297 if (ii.hbmMask)
2298 DeleteObject (ii.hbmMask);
2299 DestroyIcon(hBestFitIcon);
2300 return -1;
2303 if (i == -1) {
2304 if (himl->cCurImage + 1 > himl->cMaxImage)
2305 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2307 nIndex = himl->cCurImage;
2308 himl->cCurImage++;
2310 else
2311 nIndex = i;
2313 hdcImage = CreateCompatibleDC (0);
2314 TRACE("hdcImage=%p\n", hdcImage);
2315 if (hdcImage == 0)
2316 ERR("invalid hdcImage!\n");
2318 SetTextColor(himl->hdcImage, RGB(0,0,0));
2319 SetBkColor (himl->hdcImage, RGB(255,255,255));
2320 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2322 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2323 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2325 if (himl->hbmMask) {
2326 SelectObject (hdcImage, ii.hbmMask);
2327 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2328 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2331 SelectObject (hdcImage, hbmOldSrc);
2333 DestroyIcon(hBestFitIcon);
2334 if (hdcImage)
2335 DeleteDC (hdcImage);
2336 if (ii.hbmColor)
2337 DeleteObject (ii.hbmColor);
2338 if (ii.hbmMask)
2339 DeleteObject (ii.hbmMask);
2341 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2342 return nIndex;
2346 /*************************************************************************
2347 * ImageList_SetBkColor [COMCTL32.@]
2349 * Sets the background color of an image list.
2351 * PARAMS
2352 * himl [I] handle to image list
2353 * clrBk [I] background color
2355 * RETURNS
2356 * Success: previous background color
2357 * Failure: CLR_NONE
2360 COLORREF WINAPI
2361 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2363 COLORREF clrOldBk;
2365 if (!is_valid(himl))
2366 return CLR_NONE;
2368 clrOldBk = himl->clrBk;
2369 himl->clrBk = clrBk;
2370 return clrOldBk;
2374 /*************************************************************************
2375 * ImageList_SetDragCursorImage [COMCTL32.@]
2377 * Combines the specified image with the current drag image
2379 * PARAMS
2380 * himlDrag [I] handle to drag image list
2381 * iDrag [I] drag image index
2382 * dxHotspot [I] X position of the hot spot
2383 * dyHotspot [I] Y position of the hot spot
2385 * RETURNS
2386 * Success: TRUE
2387 * Failure: FALSE
2389 * NOTES
2390 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2391 * to do with a hotspot but are only the offset of the origin of the new
2392 * image relative to the origin of the old image.
2394 * - When this function is called and the drag image is visible, a
2395 * short flickering occurs but this matches the Win9x behavior. It is
2396 * possible to fix the flickering using code like in ImageList_DragMove.
2399 BOOL WINAPI
2400 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2401 INT dxHotspot, INT dyHotspot)
2403 HIMAGELIST himlTemp;
2404 BOOL visible;
2406 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2407 return FALSE;
2409 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2410 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2412 visible = InternalDrag.bShow;
2414 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2415 dxHotspot, dyHotspot);
2417 if (visible) {
2418 /* hide the drag image */
2419 ImageList_DragShowNolock(FALSE);
2421 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2422 (InternalDrag.himl->cy != himlTemp->cy)) {
2423 /* the size of the drag image changed, invalidate the buffer */
2424 DeleteObject(InternalDrag.hbmBg);
2425 InternalDrag.hbmBg = 0;
2428 ImageList_Destroy (InternalDrag.himl);
2429 InternalDrag.himl = himlTemp;
2431 if (visible) {
2432 /* show the drag image */
2433 ImageList_DragShowNolock(TRUE);
2436 return TRUE;
2440 /*************************************************************************
2441 * ImageList_SetFilter [COMCTL32.@]
2443 * Sets a filter (or does something completely different)!!???
2444 * It removes 12 Bytes from the stack (3 Parameters).
2446 * PARAMS
2447 * himl [I] SHOULD be a handle to image list
2448 * i [I] COULD be an index?
2449 * dwFilter [I] ???
2451 * RETURNS
2452 * Success: TRUE ???
2453 * Failure: FALSE ???
2455 * BUGS
2456 * This is an UNDOCUMENTED function!!!!
2457 * empty stub.
2460 BOOL WINAPI
2461 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2463 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2465 return FALSE;
2469 /*************************************************************************
2470 * ImageList_SetFlags [COMCTL32.@]
2472 * Sets the image list flags.
2474 * PARAMS
2475 * himl [I] Handle to image list
2476 * flags [I] Flags to set
2478 * RETURNS
2479 * Old flags?
2481 * BUGS
2482 * Stub.
2485 DWORD WINAPI
2486 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2488 FIXME("(%p %08x):empty stub\n", himl, flags);
2489 return 0;
2493 /*************************************************************************
2494 * ImageList_SetIconSize [COMCTL32.@]
2496 * Sets the image size of the bitmap and deletes all images.
2498 * PARAMS
2499 * himl [I] handle to image list
2500 * cx [I] image width
2501 * cy [I] image height
2503 * RETURNS
2504 * Success: TRUE
2505 * Failure: FALSE
2508 BOOL WINAPI
2509 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2511 INT nCount;
2512 HBITMAP hbmNew;
2514 if (!is_valid(himl))
2515 return FALSE;
2517 /* remove all images */
2518 himl->cMaxImage = himl->cInitial + himl->cGrow;
2519 himl->cCurImage = 0;
2520 himl->cx = cx;
2521 himl->cy = cy;
2523 /* initialize overlay mask indices */
2524 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2525 himl->nOvlIdx[nCount] = -1;
2527 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2528 SelectObject (himl->hdcImage, hbmNew);
2529 DeleteObject (himl->hbmImage);
2530 himl->hbmImage = hbmNew;
2532 if (himl->hbmMask) {
2533 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2534 1, 1, NULL);
2535 SelectObject (himl->hdcMask, hbmNew);
2536 DeleteObject (himl->hbmMask);
2537 himl->hbmMask = hbmNew;
2540 return TRUE;
2544 /*************************************************************************
2545 * ImageList_SetImageCount [COMCTL32.@]
2547 * Resizes an image list to the specified number of images.
2549 * PARAMS
2550 * himl [I] handle to image list
2551 * iImageCount [I] number of images in the image list
2553 * RETURNS
2554 * Success: TRUE
2555 * Failure: FALSE
2558 BOOL WINAPI
2559 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2561 HDC hdcBitmap;
2562 HBITMAP hbmNewBitmap;
2563 INT nNewCount, nCopyCount;
2565 TRACE("%p %d\n",himl,iImageCount);
2567 if (!is_valid(himl))
2568 return FALSE;
2569 if (iImageCount < 0)
2570 return FALSE;
2571 if (himl->cMaxImage > iImageCount)
2573 himl->cCurImage = iImageCount;
2574 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2575 return TRUE;
2578 nNewCount = iImageCount + himl->cGrow;
2579 nCopyCount = min(himl->cCurImage, iImageCount);
2581 hdcBitmap = CreateCompatibleDC (0);
2583 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy);
2585 if (hbmNewBitmap != 0)
2587 SelectObject (hdcBitmap, hbmNewBitmap);
2589 /* copy images */
2590 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2591 himl->hdcImage, 0, 0, SRCCOPY);
2592 #if 0
2593 /* delete 'empty' image space */
2594 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2595 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2596 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2597 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2598 #endif
2599 SelectObject (himl->hdcImage, hbmNewBitmap);
2600 DeleteObject (himl->hbmImage);
2601 himl->hbmImage = hbmNewBitmap;
2603 else
2604 ERR("Could not create new image bitmap !\n");
2606 if (himl->hbmMask)
2608 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2609 1, 1, NULL);
2610 if (hbmNewBitmap != 0)
2612 SelectObject (hdcBitmap, hbmNewBitmap);
2614 /* copy images */
2615 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2616 himl->hdcMask, 0, 0, SRCCOPY);
2617 #if 0
2618 /* delete 'empty' image space */
2619 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2620 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2621 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2622 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2623 #endif
2624 SelectObject (himl->hdcMask, hbmNewBitmap);
2625 DeleteObject (himl->hbmMask);
2626 himl->hbmMask = hbmNewBitmap;
2628 else
2629 ERR("Could not create new mask bitmap!\n");
2632 DeleteDC (hdcBitmap);
2634 /* Update max image count and current image count */
2635 himl->cMaxImage = nNewCount;
2636 himl->cCurImage = iImageCount;
2638 return TRUE;
2642 /*************************************************************************
2643 * ImageList_SetOverlayImage [COMCTL32.@]
2645 * Assigns an overlay mask index to an existing image in an image list.
2647 * PARAMS
2648 * himl [I] handle to image list
2649 * iImage [I] image index
2650 * iOverlay [I] overlay mask index
2652 * RETURNS
2653 * Success: TRUE
2654 * Failure: FALSE
2657 BOOL WINAPI
2658 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2660 if (!is_valid(himl))
2661 return FALSE;
2662 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2663 return FALSE;
2664 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2665 return FALSE;
2666 himl->nOvlIdx[iOverlay - 1] = iImage;
2667 return TRUE;
2672 /* helper for ImageList_Write - write bitmap to pstm
2673 * currently everything is written as 24 bit RGB, except masks
2675 static BOOL
2676 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2678 LPBITMAPFILEHEADER bmfh;
2679 LPBITMAPINFOHEADER bmih;
2680 LPBYTE data, lpBits, lpBitsOrg;
2681 BITMAP bm;
2682 INT bitCount, sizeImage, offBits, totalSize;
2683 INT nwidth, nheight, nsizeImage, icount;
2684 HDC xdc;
2685 BOOL result = FALSE;
2688 xdc = GetDC(0);
2689 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2691 /* XXX is this always correct? */
2692 icount = bm.bmWidth / cx;
2693 nwidth = cx;
2694 nheight = cy * icount;
2696 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2697 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2698 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2700 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2701 if(bitCount != 24)
2702 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2703 offBits = totalSize;
2704 totalSize += nsizeImage;
2706 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2707 bmfh = (LPBITMAPFILEHEADER)data;
2708 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2709 lpBits = data + offBits;
2711 /* setup BITMAPFILEHEADER */
2712 bmfh->bfType = (('M' << 8) | 'B');
2713 bmfh->bfSize = 0;
2714 bmfh->bfReserved1 = 0;
2715 bmfh->bfReserved2 = 0;
2716 bmfh->bfOffBits = offBits;
2718 /* setup BITMAPINFOHEADER */
2719 bmih->biSize = sizeof(BITMAPINFOHEADER);
2720 bmih->biWidth = bm.bmWidth;
2721 bmih->biHeight = bm.bmHeight;
2722 bmih->biPlanes = 1;
2723 bmih->biBitCount = bitCount;
2724 bmih->biCompression = BI_RGB;
2725 bmih->biSizeImage = sizeImage;
2726 bmih->biXPelsPerMeter = 0;
2727 bmih->biYPelsPerMeter = 0;
2728 bmih->biClrUsed = 0;
2729 bmih->biClrImportant = 0;
2731 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2732 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2733 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2734 goto failed;
2735 else {
2736 int i;
2737 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2738 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2740 for(i = 0; i < nheight; i++) {
2741 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2742 int noff = (nbpl * (nheight-1-i));
2743 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2747 bmih->biWidth = nwidth;
2748 bmih->biHeight = nheight;
2749 bmih->biSizeImage = nsizeImage;
2751 if(bitCount == 1) {
2752 /* Hack. */
2753 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2754 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2755 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2758 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2759 goto failed;
2761 result = TRUE;
2763 failed:
2764 ReleaseDC(0, xdc);
2765 LocalFree((HLOCAL)lpBitsOrg);
2766 LocalFree((HLOCAL)data);
2768 return result;
2772 /*************************************************************************
2773 * ImageList_Write [COMCTL32.@]
2775 * Writes an image list to a stream.
2777 * PARAMS
2778 * himl [I] handle to image list
2779 * pstm [O] Pointer to a stream.
2781 * RETURNS
2782 * Success: TRUE
2783 * Failure: FALSE
2785 * BUGS
2786 * probably.
2789 BOOL WINAPI
2790 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2792 ILHEAD ilHead;
2793 int i;
2795 if (!is_valid(himl))
2796 return FALSE;
2798 ilHead.usMagic = (('L' << 8) | 'I');
2799 ilHead.usVersion = 0x101;
2800 ilHead.cCurImage = himl->cCurImage;
2801 ilHead.cMaxImage = himl->cMaxImage;
2802 ilHead.cGrow = himl->cGrow;
2803 ilHead.cx = himl->cx;
2804 ilHead.cy = himl->cy;
2805 ilHead.bkcolor = himl->clrBk;
2806 ilHead.flags = himl->flags;
2807 for(i = 0; i < 4; i++) {
2808 ilHead.ovls[i] = himl->nOvlIdx[i];
2811 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2812 return FALSE;
2814 /* write the bitmap */
2815 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2816 return FALSE;
2818 /* write the mask if we have one */
2819 if(himl->flags & ILC_MASK) {
2820 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2821 return FALSE;
2824 return TRUE;
2828 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height)
2830 HBITMAP hbmNewBitmap;
2831 UINT ilc = (himl->flags & 0xFE);
2833 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2835 VOID* bits;
2836 BITMAPINFO *bmi;
2838 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2840 if (himl->uBitsPixel <= ILC_COLOR8)
2842 LPPALETTEENTRY pal;
2843 ULONG i, colors;
2844 BYTE temp;
2846 colors = 1 << himl->uBitsPixel;
2847 bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2848 sizeof(PALETTEENTRY) * colors);
2850 pal = (LPPALETTEENTRY)bmi->bmiColors;
2851 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2853 /* Swap colors returned by GetPaletteEntries so we can use them for
2854 * CreateDIBSection call. */
2855 for (i = 0; i < colors; i++)
2857 temp = pal[i].peBlue;
2858 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2859 bmi->bmiColors[i].rgbBlue = temp;
2862 else
2864 bmi = Alloc(sizeof(BITMAPINFOHEADER));
2867 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2868 bmi->bmiHeader.biWidth = width;
2869 bmi->bmiHeader.biHeight = height;
2870 bmi->bmiHeader.biPlanes = 1;
2871 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2872 bmi->bmiHeader.biCompression = BI_RGB;
2873 bmi->bmiHeader.biSizeImage = 0;
2874 bmi->bmiHeader.biXPelsPerMeter = 0;
2875 bmi->bmiHeader.biYPelsPerMeter = 0;
2876 bmi->bmiHeader.biClrUsed = 0;
2877 bmi->bmiHeader.biClrImportant = 0;
2879 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2881 Free (bmi);
2883 else /*if (ilc == ILC_COLORDDB)*/
2885 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2887 hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL);
2889 TRACE("returning %p\n", hbmNewBitmap);
2890 return hbmNewBitmap;
2893 /*************************************************************************
2894 * ImageList_SetColorTable [COMCTL32.@]
2896 * Sets the color table of an image list.
2898 * PARAMS
2899 * himl [I] Handle to the image list.
2900 * uStartIndex [I] The first index to set.
2901 * cEntries [I] Number of entries to set.
2902 * prgb [I] New color information for color table for the image list.
2904 * RETURNS
2905 * Success: Number of entries in the table that were set.
2906 * Failure: Zero.
2908 * SEE
2909 * ImageList_Create(), SetDIBColorTable()
2912 UINT WINAPI
2913 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2915 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);