Correct errors with move to kernel time functions.
[wine/multimedia.git] / dlls / comctl32 / imagelist.c
blobbf81080837acac8b42c74a5defd531302658316a
1 /*
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
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
38 * FIXME:
39 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
40 * is the offset of the image position relative to the actual mouse pointer
41 * position. However the Hotspot passed to SetDragCursorImage is the
42 * offset of the mouse messages sent to the application...
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "winerror.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "objbase.h"
52 #include "wingdi.h"
53 #include "winuser.h"
54 #include "commctrl.h"
55 #include "comctl32.h"
56 #include "imagelist.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
62 #define MAX_OVERLAYIMAGE 15
64 /* internal image list data used for Drag & Drop operations */
65 typedef struct
67 HWND hwnd;
68 HIMAGELIST himl;
69 /* position of the drag image relative to the window */
70 INT x;
71 INT y;
72 /* offset of the hotspot relative to the origin of the image */
73 INT dxHotspot;
74 INT dyHotspot;
75 /* is the drag image visible */
76 BOOL bShow;
77 /* saved background */
78 HBITMAP hbmBg;
79 BOOL bHSPending;
80 } INTERNALDRAG;
82 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
84 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height);
86 static inline BOOL is_valid(HIMAGELIST himl)
88 return himl && himl->magic == IMAGELIST_MAGIC;
92 /*************************************************************************
93 * IMAGELIST_InternalExpandBitmaps [Internal]
95 * Expands the bitmaps of an image list by the given number of images.
97 * PARAMS
98 * himl [I] handle to image list
99 * nImageCount [I] number of images to add
101 * RETURNS
102 * nothing
104 * NOTES
105 * This function can NOT be used to reduce the number of images.
107 static void
108 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
110 HDC hdcBitmap;
111 HBITMAP hbmNewBitmap, hbmNull;
112 INT nNewWidth, nNewCount;
114 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
115 && (himl->cy >= cy))
116 return;
118 if (cy == 0) cy = himl->cy;
119 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
120 nNewWidth = nNewCount * himl->cx;
122 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
123 hdcBitmap = CreateCompatibleDC (0);
125 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy);
127 if (hbmNewBitmap == 0)
128 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
130 if(himl->cCurImage)
132 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
133 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
134 himl->hdcImage, 0, 0, SRCCOPY);
135 SelectObject (hdcBitmap, hbmNull);
137 SelectObject (himl->hdcImage, hbmNewBitmap);
138 DeleteObject (himl->hbmImage);
139 himl->hbmImage = hbmNewBitmap;
141 if (himl->flags & ILC_MASK)
143 hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL);
145 if (hbmNewBitmap == 0)
146 ERR("creating new mask bitmap!\n");
148 if(himl->cCurImage)
150 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
151 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
152 himl->hdcMask, 0, 0, SRCCOPY);
153 SelectObject (hdcBitmap, hbmNull);
155 SelectObject (himl->hdcMask, hbmNewBitmap);
156 DeleteObject (himl->hbmMask);
157 himl->hbmMask = hbmNewBitmap;
160 himl->cMaxImage = nNewCount;
162 DeleteDC (hdcBitmap);
166 /*************************************************************************
167 * ImageList_Add [COMCTL32.@]
169 * Add an image or images to an image list.
171 * PARAMS
172 * himl [I] handle to image list
173 * hbmImage [I] handle to image bitmap
174 * hbmMask [I] handle to mask bitmap
176 * RETURNS
177 * Success: Index of the first new image.
178 * Failure: -1
181 INT WINAPI
182 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
184 HDC hdcBitmap;
185 INT nFirstIndex, nImageCount;
186 INT nStartX;
187 BITMAP bmp;
188 HBITMAP hOldBitmap;
190 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
191 if (!is_valid(himl))
192 return -1;
194 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
195 nImageCount = bmp.bmWidth / himl->cx;
197 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
199 nStartX = himl->cCurImage * himl->cx;
201 hdcBitmap = CreateCompatibleDC(0);
203 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
205 /* Copy result to the imagelist
207 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
208 hdcBitmap, 0, 0, SRCCOPY);
210 if(himl->hbmMask)
212 HDC hdcTemp;
213 HBITMAP hOldBitmapTemp;
215 hdcTemp = CreateCompatibleDC(0);
216 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
218 BitBlt (himl->hdcMask,
219 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
220 hdcTemp,
221 0, 0,
222 SRCCOPY);
224 SelectObject(hdcTemp, hOldBitmapTemp);
225 DeleteDC(hdcTemp);
227 /* Remove the background from the image
229 BitBlt (himl->hdcImage,
230 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
231 himl->hdcMask,
232 nStartX, 0,
233 0x220326); /* NOTSRCAND */
236 SelectObject(hdcBitmap, hOldBitmap);
237 DeleteDC(hdcBitmap);
239 nFirstIndex = himl->cCurImage;
240 himl->cCurImage += nImageCount;
242 return nFirstIndex;
246 /*************************************************************************
247 * ImageList_AddIcon [COMCTL32.@]
249 * Adds an icon to an image list.
251 * PARAMS
252 * himl [I] handle to image list
253 * hIcon [I] handle to icon
255 * RETURNS
256 * Success: index of the new image
257 * Failure: -1
259 #undef ImageList_AddIcon
260 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
262 return ImageList_ReplaceIcon (himl, -1, hIcon);
266 /*************************************************************************
267 * ImageList_AddMasked [COMCTL32.@]
269 * Adds an image or images to an image list and creates a mask from the
270 * specified bitmap using the mask color.
272 * PARAMS
273 * himl [I] handle to image list.
274 * hBitmap [I] handle to bitmap
275 * clrMask [I] mask color.
277 * RETURNS
278 * Success: Index of the first new image.
279 * Failure: -1
282 INT WINAPI
283 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
285 HDC hdcMask, hdcBitmap;
286 INT nIndex, nImageCount, nMaskXOffset=0;
287 BITMAP bmp;
288 HBITMAP hOldBitmap;
289 HBITMAP hMaskBitmap=0;
290 COLORREF bkColor;
292 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
293 if (!is_valid(himl))
294 return -1;
296 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
297 return -1;
299 if (himl->cx > 0)
300 nImageCount = bmp.bmWidth / himl->cx;
301 else
302 nImageCount = 0;
304 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
306 nIndex = himl->cCurImage;
307 himl->cCurImage += nImageCount;
309 hdcBitmap = CreateCompatibleDC(0);
312 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
313 if(himl->hbmMask)
315 hdcMask = himl->hdcMask;
316 nMaskXOffset = nIndex * himl->cx;
318 else
321 Create a temp Mask so we can remove the background of
322 the Image (Windows does this even if there is no mask)
324 hdcMask = CreateCompatibleDC(0);
325 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
326 SelectObject(hdcMask, hMaskBitmap);
327 nMaskXOffset = 0;
329 /* create monochrome image to the mask bitmap */
330 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
331 GetPixel (hdcBitmap, 0, 0);
332 SetBkColor (hdcBitmap, bkColor);
333 BitBlt (hdcMask,
334 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
335 hdcBitmap, 0, 0,
336 SRCCOPY);
338 SetBkColor(hdcBitmap, RGB(255,255,255));
339 /*Remove the background from the image
342 WINDOWS BUG ALERT!!!!!!
343 The statement below should not be done in common practice
344 but this is how ImageList_AddMasked works in Windows.
345 It overwrites the original bitmap passed, this was discovered
346 by using the same bitmap to iterate the different styles
347 on windows where it failed (BUT ImageList_Add is OK)
348 This is here in case some apps rely on this bug
350 BitBlt(hdcBitmap,
351 0, 0, bmp.bmWidth, bmp.bmHeight,
352 hdcMask,
353 nMaskXOffset, 0,
354 0x220326); /* NOTSRCAND */
355 /* Copy result to the imagelist
357 BitBlt (himl->hdcImage,
358 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
359 hdcBitmap,
360 0, 0,
361 SRCCOPY);
362 /* Clean up
364 SelectObject(hdcBitmap, hOldBitmap);
365 DeleteDC(hdcBitmap);
366 if(!himl->hbmMask)
368 DeleteObject(hMaskBitmap);
369 DeleteDC(hdcMask);
372 return nIndex;
376 /*************************************************************************
377 * ImageList_BeginDrag [COMCTL32.@]
379 * Creates a temporary image list that contains one image. It will be used
380 * as a drag image.
382 * PARAMS
383 * himlTrack [I] handle to the source image list
384 * iTrack [I] index of the drag image in the source image list
385 * dxHotspot [I] X position of the hot spot of the drag image
386 * dyHotspot [I] Y position of the hot spot of the drag image
388 * RETURNS
389 * Success: TRUE
390 * Failure: FALSE
393 BOOL WINAPI
394 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
395 INT dxHotspot, INT dyHotspot)
397 INT cx, cy;
399 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
400 dxHotspot, dyHotspot);
402 if (!is_valid(himlTrack))
403 return FALSE;
405 if (InternalDrag.himl)
406 ImageList_EndDrag ();
408 cx = himlTrack->cx;
409 cy = himlTrack->cy;
411 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
412 if (InternalDrag.himl == NULL) {
413 WARN("Error creating drag image list!\n");
414 return FALSE;
417 InternalDrag.dxHotspot = dxHotspot;
418 InternalDrag.dyHotspot = dyHotspot;
420 /* copy image */
421 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
423 /* copy mask */
424 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
426 InternalDrag.himl->cCurImage = 1;
427 InternalDrag.bHSPending = TRUE;
429 return TRUE;
433 /*************************************************************************
434 * ImageList_Copy [COMCTL32.@]
436 * Copies an image of the source image list to an image of the
437 * destination image list. Images can be copied or swapped.
439 * PARAMS
440 * himlDst [I] handle to the destination image list
441 * iDst [I] destination image index.
442 * himlSrc [I] handle to the source image list
443 * iSrc [I] source image index
444 * uFlags [I] flags for the copy operation
446 * RETURNS
447 * Success: TRUE
448 * Failure: FALSE
450 * NOTES
451 * Copying from one image list to another is possible. The original
452 * implementation just copies or swaps within one image list.
453 * Could this feature become a bug??? ;-)
456 BOOL WINAPI
457 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
458 INT iSrc, UINT uFlags)
460 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
462 if (!is_valid(himlSrc) || !is_valid(himlDst))
463 return FALSE;
464 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
465 return FALSE;
466 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
467 return FALSE;
469 if (uFlags & ILCF_SWAP) {
470 /* swap */
471 HDC hdcBmp;
472 HBITMAP hbmTempImage, hbmTempMask;
474 hdcBmp = CreateCompatibleDC (0);
476 /* create temporary bitmaps */
477 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
478 himlSrc->uBitsPixel, NULL);
479 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
480 1, NULL);
482 /* copy (and stretch) destination to temporary bitmaps.(save) */
483 /* image */
484 SelectObject (hdcBmp, hbmTempImage);
485 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
486 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
487 SRCCOPY);
488 /* mask */
489 SelectObject (hdcBmp, hbmTempMask);
490 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
491 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
492 SRCCOPY);
494 /* copy (and stretch) source to destination */
495 /* image */
496 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
497 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
498 SRCCOPY);
499 /* mask */
500 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
501 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
502 SRCCOPY);
504 /* copy (without stretching) temporary bitmaps to source (restore) */
505 /* mask */
506 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
507 hdcBmp, 0, 0, SRCCOPY);
509 /* image */
510 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
511 hdcBmp, 0, 0, SRCCOPY);
512 /* delete temporary bitmaps */
513 DeleteObject (hbmTempMask);
514 DeleteObject (hbmTempImage);
515 DeleteDC(hdcBmp);
517 else {
518 /* copy image */
519 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
520 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
521 SRCCOPY);
523 /* copy mask */
524 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
525 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
526 SRCCOPY);
529 return TRUE;
533 /*************************************************************************
534 * ImageList_Create [COMCTL32.@]
536 * Creates a new image list.
538 * PARAMS
539 * cx [I] image height
540 * cy [I] image width
541 * flags [I] creation flags
542 * cInitial [I] initial number of images in the image list
543 * cGrow [I] number of images by which image list grows
545 * RETURNS
546 * Success: Handle to the created image list
547 * Failure: NULL
549 HIMAGELIST WINAPI
550 ImageList_Create (INT cx, INT cy, UINT flags,
551 INT cInitial, INT cGrow)
553 HIMAGELIST himl;
554 INT nCount;
555 HBITMAP hbmTemp;
556 UINT ilc = (flags & 0xFE);
557 static WORD aBitBlend25[] =
558 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
560 static WORD aBitBlend50[] =
561 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
563 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
565 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
566 if (!himl)
567 return NULL;
569 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
571 himl->magic = IMAGELIST_MAGIC;
572 himl->cx = cx;
573 himl->cy = cy;
574 himl->flags = flags;
575 himl->cMaxImage = cInitial + cGrow;
576 himl->cInitial = cInitial;
577 himl->cGrow = cGrow;
578 himl->clrFg = CLR_DEFAULT;
579 himl->clrBk = CLR_NONE;
581 /* initialize overlay mask indices */
582 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
583 himl->nOvlIdx[nCount] = -1;
585 /* Create Image & Mask DCs */
586 himl->hdcImage = CreateCompatibleDC (0);
587 if (!himl->hdcImage)
588 goto cleanup;
589 if (himl->flags & ILC_MASK){
590 himl->hdcMask = CreateCompatibleDC(0);
591 if (!himl->hdcMask)
592 goto cleanup;
595 /* Default to ILC_COLOR4 if non of the ILC_COLOR* flags are specified */
596 if (ilc == ILC_COLOR)
597 ilc = ILC_COLOR4;
599 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
600 himl->uBitsPixel = ilc;
601 else
602 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
604 if (himl->cMaxImage > 0) {
605 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy);
606 SelectObject(himl->hdcImage, himl->hbmImage);
607 } else
608 himl->hbmImage = 0;
610 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
611 himl->hbmMask =
612 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
613 1, 1, NULL);
614 if (himl->hbmMask == 0) {
615 ERR("Error creating mask bitmap!\n");
616 goto cleanup;
618 SelectObject(himl->hdcMask, himl->hbmMask);
621 /* create blending brushes */
622 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
623 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
624 DeleteObject (hbmTemp);
626 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
627 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
628 DeleteObject (hbmTemp);
630 TRACE("created imagelist %p\n", himl);
631 return himl;
633 cleanup:
634 if (himl) ImageList_Destroy(himl);
635 return NULL;
639 /*************************************************************************
640 * ImageList_Destroy [COMCTL32.@]
642 * Destroys an image list.
644 * PARAMS
645 * himl [I] handle to image list
647 * RETURNS
648 * Success: TRUE
649 * Failure: FALSE
652 BOOL WINAPI
653 ImageList_Destroy (HIMAGELIST himl)
655 if (!is_valid(himl))
656 return FALSE;
658 /* delete image bitmaps */
659 if (himl->hbmImage)
660 DeleteObject (himl->hbmImage);
661 if (himl->hbmMask)
662 DeleteObject (himl->hbmMask);
664 /* delete image & mask DCs */
665 if (himl->hdcImage)
666 DeleteDC(himl->hdcImage);
667 if (himl->hdcMask)
668 DeleteDC(himl->hdcMask);
670 /* delete blending brushes */
671 if (himl->hbrBlend25)
672 DeleteObject (himl->hbrBlend25);
673 if (himl->hbrBlend50)
674 DeleteObject (himl->hbrBlend50);
676 ZeroMemory(himl, sizeof(*himl));
677 Free (himl);
679 return TRUE;
683 /*************************************************************************
684 * ImageList_DragEnter [COMCTL32.@]
686 * Locks window update and displays the drag image at the given position.
688 * PARAMS
689 * hwndLock [I] handle of the window that owns the drag image.
690 * x [I] X position of the drag image.
691 * y [I] Y position of the drag image.
693 * RETURNS
694 * Success: TRUE
695 * Failure: FALSE
697 * NOTES
698 * The position of the drag image is relative to the window, not
699 * the client area.
702 BOOL WINAPI
703 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
705 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
707 if (!is_valid(InternalDrag.himl))
708 return FALSE;
710 if (hwndLock)
711 InternalDrag.hwnd = hwndLock;
712 else
713 InternalDrag.hwnd = GetDesktopWindow ();
715 InternalDrag.x = x;
716 InternalDrag.y = y;
718 /* draw the drag image and save the background */
719 if (!ImageList_DragShowNolock(TRUE)) {
720 return FALSE;
723 return TRUE;
727 /*************************************************************************
728 * ImageList_DragLeave [COMCTL32.@]
730 * Unlocks window update and hides the drag image.
732 * PARAMS
733 * hwndLock [I] handle of the window that owns the drag image.
735 * RETURNS
736 * Success: TRUE
737 * Failure: FALSE
740 BOOL WINAPI
741 ImageList_DragLeave (HWND hwndLock)
743 /* As we don't save drag info in the window this can lead to problems if
744 an app does not supply the same window as DragEnter */
745 /* if (hwndLock)
746 InternalDrag.hwnd = hwndLock;
747 else
748 InternalDrag.hwnd = GetDesktopWindow (); */
749 if(!hwndLock)
750 hwndLock = GetDesktopWindow();
751 if(InternalDrag.hwnd != hwndLock)
752 FIXME("DragLeave hWnd != DragEnter hWnd\n");
754 ImageList_DragShowNolock (FALSE);
756 return TRUE;
760 /*************************************************************************
761 * ImageList_InternalDragDraw [Internal]
763 * Draws the drag image.
765 * PARAMS
766 * hdc [I] device context to draw into.
767 * x [I] X position of the drag image.
768 * y [I] Y position of the drag image.
770 * RETURNS
771 * Success: TRUE
772 * Failure: FALSE
774 * NOTES
775 * The position of the drag image is relative to the window, not
776 * the client area.
780 static inline void
781 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
783 IMAGELISTDRAWPARAMS imldp;
785 ZeroMemory (&imldp, sizeof(imldp));
786 imldp.cbSize = sizeof(imldp);
787 imldp.himl = InternalDrag.himl;
788 imldp.i = 0;
789 imldp.hdcDst = hdc,
790 imldp.x = x;
791 imldp.y = y;
792 imldp.rgbBk = CLR_DEFAULT;
793 imldp.rgbFg = CLR_DEFAULT;
794 imldp.fStyle = ILD_NORMAL;
795 imldp.fState = ILS_ALPHA;
796 imldp.Frame = 128;
798 /* FIXME: instead of using the alpha blending, we should
799 * create a 50% mask, and draw it semitransparantly that way */
800 ImageList_DrawIndirect (&imldp);
803 /*************************************************************************
804 * ImageList_DragMove [COMCTL32.@]
806 * Moves the drag image.
808 * PARAMS
809 * x [I] X position of the drag image.
810 * y [I] Y position of the drag image.
812 * RETURNS
813 * Success: TRUE
814 * Failure: FALSE
816 * NOTES
817 * The position of the drag image is relative to the window, not
818 * the client area.
820 * BUGS
821 * The drag image should be drawn semitransparent.
824 BOOL WINAPI
825 ImageList_DragMove (INT x, INT y)
827 TRACE("(x=%d y=%d)\n", x, y);
829 if (!is_valid(InternalDrag.himl))
830 return FALSE;
832 /* draw/update the drag image */
833 if (InternalDrag.bShow) {
834 HDC hdcDrag;
835 HDC hdcOffScreen;
836 HDC hdcBg;
837 HBITMAP hbmOffScreen;
838 INT origNewX, origNewY;
839 INT origOldX, origOldY;
840 INT origRegX, origRegY;
841 INT sizeRegX, sizeRegY;
844 /* calculate the update region */
845 origNewX = x - InternalDrag.dxHotspot;
846 origNewY = y - InternalDrag.dyHotspot;
847 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
848 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
849 origRegX = min(origNewX, origOldX);
850 origRegY = min(origNewY, origOldY);
851 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
852 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
854 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
855 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
856 hdcOffScreen = CreateCompatibleDC(hdcDrag);
857 hdcBg = CreateCompatibleDC(hdcDrag);
859 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
860 SelectObject(hdcOffScreen, hbmOffScreen);
861 SelectObject(hdcBg, InternalDrag.hbmBg);
863 /* get the actual background of the update region */
864 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
865 origRegX, origRegY, SRCCOPY);
866 /* erase the old image */
867 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
868 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
869 SRCCOPY);
870 /* save the background */
871 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
872 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
873 /* draw the image */
874 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
875 origNewY - origRegY);
876 /* draw the update region to the screen */
877 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
878 hdcOffScreen, 0, 0, SRCCOPY);
880 DeleteDC(hdcBg);
881 DeleteDC(hdcOffScreen);
882 DeleteObject(hbmOffScreen);
883 ReleaseDC(InternalDrag.hwnd, hdcDrag);
886 /* update the image position */
887 InternalDrag.x = x;
888 InternalDrag.y = y;
890 return TRUE;
894 /*************************************************************************
895 * ImageList_DragShowNolock [COMCTL32.@]
897 * Shows or hides the drag image.
899 * PARAMS
900 * bShow [I] TRUE shows the drag image, FALSE hides it.
902 * RETURNS
903 * Success: TRUE
904 * Failure: FALSE
906 * BUGS
907 * The drag image should be drawn semitransparent.
910 BOOL WINAPI
911 ImageList_DragShowNolock (BOOL bShow)
913 HDC hdcDrag;
914 HDC hdcBg;
915 INT x, y;
917 if (!is_valid(InternalDrag.himl))
918 return FALSE;
920 TRACE("bShow=0x%X!\n", bShow);
922 /* DragImage is already visible/hidden */
923 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
924 return FALSE;
927 /* position of the origin of the DragImage */
928 x = InternalDrag.x - InternalDrag.dxHotspot;
929 y = InternalDrag.y - InternalDrag.dyHotspot;
931 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
932 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
933 if (!hdcDrag) {
934 return FALSE;
937 hdcBg = CreateCompatibleDC(hdcDrag);
938 if (!InternalDrag.hbmBg) {
939 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
940 InternalDrag.himl->cx, InternalDrag.himl->cy);
942 SelectObject(hdcBg, InternalDrag.hbmBg);
944 if (bShow) {
945 /* save the background */
946 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
947 hdcDrag, x, y, SRCCOPY);
948 /* show the image */
949 ImageList_InternalDragDraw(hdcDrag, x, y);
950 } else {
951 /* hide the image */
952 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
953 hdcBg, 0, 0, SRCCOPY);
956 InternalDrag.bShow = !InternalDrag.bShow;
958 DeleteDC(hdcBg);
959 ReleaseDC (InternalDrag.hwnd, hdcDrag);
960 return TRUE;
964 /*************************************************************************
965 * ImageList_Draw [COMCTL32.@]
967 * Draws an image.
969 * PARAMS
970 * himl [I] handle to image list
971 * i [I] image index
972 * hdc [I] handle to device context
973 * x [I] x position
974 * y [I] y position
975 * fStyle [I] drawing flags
977 * RETURNS
978 * Success: TRUE
979 * Failure: FALSE
981 * SEE
982 * ImageList_DrawEx.
985 BOOL WINAPI
986 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
988 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
989 CLR_DEFAULT, CLR_DEFAULT, fStyle);
993 /*************************************************************************
994 * ImageList_DrawEx [COMCTL32.@]
996 * Draws an image and allows to use extended drawing features.
998 * PARAMS
999 * himl [I] handle to image list
1000 * i [I] image index
1001 * hdc [I] handle to device context
1002 * x [I] X position
1003 * y [I] Y position
1004 * dx [I] X offset
1005 * dy [I] Y offset
1006 * rgbBk [I] background color
1007 * rgbFg [I] foreground color
1008 * fStyle [I] drawing flags
1010 * RETURNS
1011 * Success: TRUE
1012 * Failure: FALSE
1014 * NOTES
1015 * Calls ImageList_DrawIndirect.
1017 * SEE
1018 * ImageList_DrawIndirect.
1021 BOOL WINAPI
1022 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1023 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1024 UINT fStyle)
1026 IMAGELISTDRAWPARAMS imldp;
1028 ZeroMemory (&imldp, sizeof(imldp));
1029 imldp.cbSize = sizeof(imldp);
1030 imldp.himl = himl;
1031 imldp.i = i;
1032 imldp.hdcDst = hdc,
1033 imldp.x = x;
1034 imldp.y = y;
1035 imldp.cx = dx;
1036 imldp.cy = dy;
1037 imldp.rgbBk = rgbBk;
1038 imldp.rgbFg = rgbFg;
1039 imldp.fStyle = fStyle;
1041 return ImageList_DrawIndirect (&imldp);
1045 /*************************************************************************
1046 * ImageList_DrawIndirect [COMCTL32.@]
1048 * Draws an image using various parameters specified in pimldp.
1050 * PARAMS
1051 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1053 * RETURNS
1054 * Success: TRUE
1055 * Failure: FALSE
1058 BOOL WINAPI
1059 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1061 INT cx, cy, lx, ly, nOvlIdx;
1062 DWORD fState, dwRop;
1063 UINT fStyle;
1064 COLORREF clrBk, oldImageBk, oldImageFg;
1065 HDC hImageDC, hImageListDC, hMaskListDC;
1066 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1067 BOOL bIsTransparent, bBlend, bResult = FALSE;
1068 HIMAGELIST himl;
1070 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1071 if (!is_valid(himl)) return FALSE;
1072 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1074 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1075 ly = pimldp->yBitmap;
1077 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1078 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1079 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1080 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1081 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1082 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1083 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1085 TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1086 (DWORD)himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1088 /* we will use these DCs to access the images and masks in the ImageList */
1089 hImageListDC = himl->hdcImage;
1090 hMaskListDC = himl->hdcMask;
1092 /* these will accumulate the image and mask for the image we're drawing */
1093 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1094 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1095 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1097 /* Create a compatible DC. */
1098 if (!hImageListDC || !hImageDC || !hImageBmp ||
1099 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1100 goto cleanup;
1102 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1105 * To obtain a transparent look, background color should be set
1106 * to white and foreground color to black when blting the
1107 * monochrome mask.
1109 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1110 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1113 * Draw the initial image
1115 if(fStyle & ILD_MASK) {
1116 if (himl->hbmMask) {
1117 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1118 } else {
1119 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1120 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1121 SelectObject(hImageDC, hOldBrush);
1123 } else if (himl->hbmMask && !bIsTransparent) {
1124 /* blend the image with the needed solid background */
1125 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1126 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1127 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1128 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1129 DeleteObject (SelectObject (hImageDC, hOldBrush));
1130 } else {
1131 /* start off with the image, if we have a mask, we'll use it later */
1132 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1135 /* Time for blending, if required */
1136 if (bBlend) {
1137 HBRUSH hBlendBrush, hOldBrush;
1138 COLORREF clrBlend = pimldp->rgbFg;
1139 HDC hBlendMaskDC = hImageListDC;
1140 HBITMAP hOldBitmap;
1142 /* Create the blend Mask */
1143 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1144 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1145 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1146 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1147 SelectObject(hBlendMaskDC, hOldBrush);
1149 /* Modify the blend mask if an Image Mask exist */
1150 if(himl->hbmMask) {
1151 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1152 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1155 /* now apply blend to the current image given the BlendMask */
1156 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1157 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1158 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1159 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1160 DeleteObject(SelectObject(hImageDC, hOldBrush));
1161 SelectObject(hBlendMaskDC, hOldBitmap);
1164 /* Now do the overlay image, if any */
1165 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1166 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1167 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1168 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1169 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1170 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1171 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1172 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1176 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1177 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1178 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1179 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1181 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1182 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1183 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1185 /* now copy the image to the screen */
1186 dwRop = SRCCOPY;
1187 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1188 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1189 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1190 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1191 SetBkColor(pimldp->hdcDst, oldDstBk);
1192 SetTextColor(pimldp->hdcDst, oldDstFg);
1193 dwRop = SRCPAINT;
1195 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1196 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1198 bResult = TRUE;
1200 /* cleanup the mess */
1201 SetBkColor(hImageDC, oldImageBk);
1202 SetTextColor(hImageDC, oldImageFg);
1203 SelectObject(hImageDC, hOldImageBmp);
1204 cleanup:
1205 DeleteObject(hBlendMaskBmp);
1206 DeleteObject(hImageBmp);
1207 DeleteDC(hImageDC);
1209 return bResult;
1213 /*************************************************************************
1214 * ImageList_Duplicate [COMCTL32.@]
1216 * Duplicates an image list.
1218 * PARAMS
1219 * himlSrc [I] source image list handle
1221 * RETURNS
1222 * Success: Handle of duplicated image list.
1223 * Failure: NULL
1226 HIMAGELIST WINAPI
1227 ImageList_Duplicate (HIMAGELIST himlSrc)
1229 HIMAGELIST himlDst;
1231 if (!is_valid(himlSrc)) {
1232 ERR("Invalid image list handle!\n");
1233 return NULL;
1236 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1237 himlSrc->cInitial, himlSrc->cGrow);
1239 if (himlDst)
1241 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1242 himlSrc->hdcImage, 0, 0, SRCCOPY);
1244 if (himlDst->hbmMask)
1245 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1246 himlSrc->hdcMask, 0, 0, SRCCOPY);
1248 himlDst->cCurImage = himlSrc->cCurImage;
1249 himlDst->cMaxImage = himlSrc->cMaxImage;
1251 return himlDst;
1255 /*************************************************************************
1256 * ImageList_EndDrag [COMCTL32.@]
1258 * Finishes a drag operation.
1260 * PARAMS
1261 * no Parameters
1263 * RETURNS
1264 * Success: TRUE
1265 * Failure: FALSE
1268 VOID WINAPI
1269 ImageList_EndDrag (void)
1271 /* cleanup the InternalDrag struct */
1272 InternalDrag.hwnd = 0;
1273 ImageList_Destroy (InternalDrag.himl);
1274 InternalDrag.himl = 0;
1275 InternalDrag.x= 0;
1276 InternalDrag.y= 0;
1277 InternalDrag.dxHotspot = 0;
1278 InternalDrag.dyHotspot = 0;
1279 InternalDrag.bShow = FALSE;
1280 DeleteObject(InternalDrag.hbmBg);
1281 InternalDrag.hbmBg = 0;
1282 InternalDrag.bHSPending = FALSE;
1286 /*************************************************************************
1287 * ImageList_GetBkColor [COMCTL32.@]
1289 * Returns the background color of an image list.
1291 * PARAMS
1292 * himl [I] Image list handle.
1294 * RETURNS
1295 * Success: background color
1296 * Failure: CLR_NONE
1299 COLORREF WINAPI
1300 ImageList_GetBkColor (HIMAGELIST himl)
1302 return himl ? himl->clrBk : CLR_NONE;
1306 /*************************************************************************
1307 * ImageList_GetDragImage [COMCTL32.@]
1309 * Returns the handle to the internal drag image list.
1311 * PARAMS
1312 * ppt [O] Pointer to the drag position. Can be NULL.
1313 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1315 * RETURNS
1316 * Success: Handle of the drag image list.
1317 * Failure: NULL.
1320 HIMAGELIST WINAPI
1321 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1323 if (is_valid(InternalDrag.himl)) {
1324 if (ppt) {
1325 ppt->x = InternalDrag.x;
1326 ppt->y = InternalDrag.y;
1328 if (pptHotspot) {
1329 pptHotspot->x = InternalDrag.dxHotspot;
1330 pptHotspot->y = InternalDrag.dyHotspot;
1332 return (InternalDrag.himl);
1335 return NULL;
1339 /*************************************************************************
1340 * ImageList_GetFlags [COMCTL32.@]
1342 * Gets the flags of the specified image list.
1344 * PARAMS
1345 * himl [I] Handle to image list
1347 * RETURNS
1348 * Image list flags.
1350 * BUGS
1351 * Stub.
1354 DWORD WINAPI
1355 ImageList_GetFlags(HIMAGELIST himl)
1357 FIXME("(%p):empty stub\n", himl);
1358 return 0;
1362 /*************************************************************************
1363 * ImageList_GetIcon [COMCTL32.@]
1365 * Creates an icon from a masked image of an image list.
1367 * PARAMS
1368 * himl [I] handle to image list
1369 * i [I] image index
1370 * flags [I] drawing style flags
1372 * RETURNS
1373 * Success: icon handle
1374 * Failure: NULL
1377 HICON WINAPI
1378 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1380 ICONINFO ii;
1381 HICON hIcon;
1382 HBITMAP hOldDstBitmap;
1383 HDC hdcDst;
1385 TRACE("%p %d %d\n", himl, i, fStyle);
1386 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1388 hdcDst = CreateCompatibleDC(0);
1390 ii.fIcon = TRUE;
1391 ii.xHotspot = 0;
1392 ii.yHotspot = 0;
1394 /* draw mask*/
1395 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1396 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1397 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1398 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1400 /* draw image*/
1401 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1402 SelectObject (hdcDst, ii.hbmColor);
1403 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1404 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1407 * CreateIconIndirect requires us to deselect the bitmaps from
1408 * the DCs before calling
1410 SelectObject(hdcDst, hOldDstBitmap);
1412 hIcon = CreateIconIndirect (&ii);
1414 DeleteObject (ii.hbmMask);
1415 DeleteObject (ii.hbmColor);
1416 DeleteDC (hdcDst);
1418 return hIcon;
1422 /*************************************************************************
1423 * ImageList_GetIconSize [COMCTL32.@]
1425 * Retrieves the size of an image in an image list.
1427 * PARAMS
1428 * himl [I] handle to image list
1429 * cx [O] pointer to the image width.
1430 * cy [O] pointer to the image height.
1432 * RETURNS
1433 * Success: TRUE
1434 * Failure: FALSE
1436 * NOTES
1437 * All images in an image list have the same size.
1440 BOOL WINAPI
1441 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1443 if (!is_valid(himl))
1444 return FALSE;
1445 if ((himl->cx <= 0) || (himl->cy <= 0))
1446 return FALSE;
1448 if (cx)
1449 *cx = himl->cx;
1450 if (cy)
1451 *cy = himl->cy;
1453 return TRUE;
1457 /*************************************************************************
1458 * ImageList_GetImageCount [COMCTL32.@]
1460 * Returns the number of images in an image list.
1462 * PARAMS
1463 * himl [I] handle to image list
1465 * RETURNS
1466 * Success: Number of images.
1467 * Failure: 0
1470 INT WINAPI
1471 ImageList_GetImageCount (HIMAGELIST himl)
1473 if (!is_valid(himl))
1474 return 0;
1476 return himl->cCurImage;
1480 /*************************************************************************
1481 * ImageList_GetImageInfo [COMCTL32.@]
1483 * Returns information about an image in an image list.
1485 * PARAMS
1486 * himl [I] handle to image list
1487 * i [I] image index
1488 * pImageInfo [O] pointer to the image information
1490 * RETURNS
1491 * Success: TRUE
1492 * Failure: FALSE
1495 BOOL WINAPI
1496 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1498 if (!is_valid(himl) || (pImageInfo == NULL))
1499 return FALSE;
1500 if ((i < 0) || (i >= himl->cCurImage))
1501 return FALSE;
1503 pImageInfo->hbmImage = himl->hbmImage;
1504 pImageInfo->hbmMask = himl->hbmMask;
1506 pImageInfo->rcImage.top = 0;
1507 pImageInfo->rcImage.bottom = himl->cy;
1508 pImageInfo->rcImage.left = i * himl->cx;
1509 pImageInfo->rcImage.right = (i+1) * himl->cx;
1511 return TRUE;
1515 /*************************************************************************
1516 * ImageList_GetImageRect [COMCTL32.@]
1518 * Retrieves the rectangle of the specified image in an image list.
1520 * PARAMS
1521 * himl [I] handle to image list
1522 * i [I] image index
1523 * lpRect [O] pointer to the image rectangle
1525 * RETURNS
1526 * Success: TRUE
1527 * Failure: FALSE
1529 * NOTES
1530 * This is an UNDOCUMENTED function!!!
1533 BOOL WINAPI
1534 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1536 if (!is_valid(himl) || (lpRect == NULL))
1537 return FALSE;
1538 if ((i < 0) || (i >= himl->cCurImage))
1539 return FALSE;
1541 lpRect->left = i * himl->cx;
1542 lpRect->top = 0;
1543 lpRect->right = lpRect->left + himl->cx;
1544 lpRect->bottom = himl->cy;
1546 return TRUE;
1550 /*************************************************************************
1551 * ImageList_LoadImage [COMCTL32.@]
1552 * ImageList_LoadImageA [COMCTL32.@]
1554 * Creates an image list from a bitmap, icon or cursor.
1556 * PARAMS
1557 * hi [I] instance handle
1558 * lpbmp [I] name or id of the image
1559 * cx [I] width of each image
1560 * cGrow [I] number of images to expand
1561 * clrMask [I] mask color
1562 * uType [I] type of image to load
1563 * uFlags [I] loading flags
1565 * RETURNS
1566 * Success: handle to the loaded image list
1567 * Failure: NULL
1569 * SEE
1570 * LoadImage ()
1573 HIMAGELIST WINAPI
1574 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1575 COLORREF clrMask, UINT uType, UINT uFlags)
1577 HIMAGELIST himl = NULL;
1578 HANDLE handle;
1579 INT nImageCount;
1581 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1582 if (!handle) {
1583 ERR("Error loading image!\n");
1584 return NULL;
1587 if (uType == IMAGE_BITMAP) {
1588 BITMAP bmp;
1589 GetObjectA (handle, sizeof(BITMAP), &bmp);
1591 /* To match windows behavior, if cx is set to zero and
1592 the flag DI_DEFAULTSIZE is specified, cx becomes the
1593 system metric value for icons. If the flag is not specified
1594 the function sets the size to the height of the bitmap */
1595 if (cx == 0)
1597 if (uFlags & DI_DEFAULTSIZE)
1598 cx = GetSystemMetrics (SM_CXICON);
1599 else
1600 cx = bmp.bmHeight;
1603 nImageCount = bmp.bmWidth / cx;
1605 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1606 nImageCount, cGrow);
1607 if (!himl) {
1608 DeleteObject (handle);
1609 return NULL;
1611 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1613 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1614 ICONINFO ii;
1615 BITMAP bmp;
1617 GetIconInfo (handle, &ii);
1618 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1619 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1620 ILC_MASK | ILC_COLOR, 1, cGrow);
1621 if (!himl) {
1622 DeleteObject (ii.hbmColor);
1623 DeleteObject (ii.hbmMask);
1624 DeleteObject (handle);
1625 return NULL;
1627 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1628 DeleteObject (ii.hbmColor);
1629 DeleteObject (ii.hbmMask);
1632 DeleteObject (handle);
1634 return himl;
1638 /*************************************************************************
1639 * ImageList_LoadImageW [COMCTL32.@]
1641 * Creates an image list from a bitmap, icon or cursor.
1643 * PARAMS
1644 * hi [I] instance handle
1645 * lpbmp [I] name or id of the image
1646 * cx [I] width of each image
1647 * cGrow [I] number of images to expand
1648 * clrMask [I] mask color
1649 * uType [I] type of image to load
1650 * uFlags [I] loading flags
1652 * RETURNS
1653 * Success: handle to the loaded image list
1654 * Failure: NULL
1656 * SEE
1657 * LoadImage ()
1660 HIMAGELIST WINAPI
1661 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1662 COLORREF clrMask, UINT uType, UINT uFlags)
1664 HIMAGELIST himl = NULL;
1665 HANDLE handle;
1666 INT nImageCount;
1668 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1669 if (!handle) {
1670 ERR("Error loading image!\n");
1671 return NULL;
1674 if (uType == IMAGE_BITMAP) {
1675 BITMAP bmp;
1676 GetObjectW (handle, sizeof(BITMAP), &bmp);
1678 /* To match windows behavior, if cx is set to zero and
1679 the flag DI_DEFAULTSIZE is specified, cx becomes the
1680 system metric value for icons. If the flag is not specified
1681 the function sets the size to the height of the bitmap */
1682 if (cx == 0)
1684 if (uFlags & DI_DEFAULTSIZE)
1685 cx = GetSystemMetrics (SM_CXICON);
1686 else
1687 cx = bmp.bmHeight;
1690 nImageCount = bmp.bmWidth / cx;
1692 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1693 nImageCount, cGrow);
1694 if (!himl) {
1695 DeleteObject (handle);
1696 return NULL;
1698 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1700 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1701 ICONINFO ii;
1702 BITMAP bmp;
1704 GetIconInfo (handle, &ii);
1705 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1706 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1707 ILC_MASK | ILC_COLOR, 1, cGrow);
1708 if (!himl) {
1709 DeleteObject (ii.hbmColor);
1710 DeleteObject (ii.hbmMask);
1711 DeleteObject (handle);
1712 return NULL;
1714 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1715 DeleteObject (ii.hbmColor);
1716 DeleteObject (ii.hbmMask);
1719 DeleteObject (handle);
1721 return himl;
1725 /*************************************************************************
1726 * ImageList_Merge [COMCTL32.@]
1728 * Creates a new image list that contains a merged image from the specified
1729 * images of both source image lists.
1731 * PARAMS
1732 * himl1 [I] handle to first image list
1733 * i1 [I] first image index
1734 * himl2 [I] handle to second image list
1735 * i2 [I] second image index
1736 * dx [I] X offset of the second image relative to the first.
1737 * dy [I] Y offset of the second image relative to the first.
1739 * RETURNS
1740 * Success: handle of the merged image list.
1741 * Failure: NULL
1744 HIMAGELIST WINAPI
1745 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1746 INT dx, INT dy)
1748 HIMAGELIST himlDst = NULL;
1749 INT cxDst, cyDst;
1750 INT xOff1, yOff1, xOff2, yOff2;
1751 INT nX1, nX2;
1753 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1754 i2, dx, dy);
1756 if (!is_valid(himl1) || !is_valid(himl2))
1757 return NULL;
1759 /* check indices */
1760 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1761 ERR("Index 1 out of range! %d\n", i1);
1762 return NULL;
1765 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1766 ERR("Index 2 out of range! %d\n", i2);
1767 return NULL;
1770 if (dx > 0) {
1771 cxDst = max (himl1->cx, dx + himl2->cx);
1772 xOff1 = 0;
1773 xOff2 = dx;
1775 else if (dx < 0) {
1776 cxDst = max (himl2->cx, himl1->cx - dx);
1777 xOff1 = -dx;
1778 xOff2 = 0;
1780 else {
1781 cxDst = max (himl1->cx, himl2->cx);
1782 xOff1 = 0;
1783 xOff2 = 0;
1786 if (dy > 0) {
1787 cyDst = max (himl1->cy, dy + himl2->cy);
1788 yOff1 = 0;
1789 yOff2 = dy;
1791 else if (dy < 0) {
1792 cyDst = max (himl2->cy, himl1->cy - dy);
1793 yOff1 = -dy;
1794 yOff2 = 0;
1796 else {
1797 cyDst = max (himl1->cy, himl2->cy);
1798 yOff1 = 0;
1799 yOff2 = 0;
1802 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1803 if (!himlDst)
1804 return NULL;
1806 if (himlDst) {
1807 nX1 = i1 * himl1->cx;
1808 nX2 = i2 * himl2->cx;
1810 /* copy image */
1811 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1812 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1813 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1814 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1816 /* copy mask */
1817 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1818 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1819 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1821 himlDst->cCurImage = 1;
1824 return himlDst;
1828 /* helper for _read_bitmap currently unused */
1829 #if 0
1830 static int may_use_dibsection(HDC hdc) {
1831 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1832 if (bitspixel>8)
1833 return TRUE;
1834 if (bitspixel<=4)
1835 return FALSE;
1836 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1838 #endif
1840 /* helper for ImageList_Read, see comments below */
1841 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1842 HDC xdc = 0, hBitmapDC =0;
1843 BITMAPFILEHEADER bmfh;
1844 BITMAPINFOHEADER bmih;
1845 int bitsperpixel,palspace,longsperline,width,height;
1846 LPBITMAPINFOHEADER bmihc = NULL;
1847 int result = 0;
1848 HBITMAP hbitmap = 0, hDIB = 0;
1849 LPBYTE bits = NULL;
1851 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1852 (bmfh.bfType != (('M'<<8)|'B')) ||
1853 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1854 (bmih.biSize != sizeof(bmih))
1856 return 0;
1858 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1859 if (bitsperpixel<=8)
1860 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1861 else
1862 palspace = 0;
1863 width = bmih.biWidth;
1864 height = bmih.biHeight;
1865 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1866 memcpy(bmihc,&bmih,sizeof(bmih));
1867 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1868 bmihc->biSizeImage = (longsperline*height)<<2;
1870 /* read the palette right after the end of the bitmapinfoheader */
1871 if (palspace)
1872 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1873 goto ret1;
1875 xdc = GetDC(0);
1876 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1877 if ((bitsperpixel>1) &&
1878 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1880 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1881 if (!hbitmap)
1882 goto ret1;
1883 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1884 goto ret1;
1885 result = 1;
1886 } else
1887 #endif
1889 int i,nwidth,nheight,nRows;
1891 nwidth = width*(height/cy);
1892 nheight = cy;
1893 nRows = (height/cy);
1895 if (bitsperpixel==1)
1896 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1897 else
1898 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1900 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1901 if (!hDIB)
1902 goto ret1;
1903 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1904 goto ret1;
1906 hBitmapDC = CreateCompatibleDC(0);
1907 SelectObject(hBitmapDC, hbitmap);
1909 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1910 /* Do not forget that windows bitmaps are bottom->top */
1911 TRACE("nRows=%d\n", nRows);
1912 for (i=0; i < nRows; i++){
1913 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1914 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1917 result = 1;
1919 ret1:
1920 if (xdc) ReleaseDC(0,xdc);
1921 if (bmihc) LocalFree((HLOCAL)bmihc);
1922 if (hDIB) DeleteObject(hDIB);
1923 if (hBitmapDC) DeleteDC(hBitmapDC);
1924 if (!result) {
1925 if (hbitmap) {
1926 DeleteObject(hbitmap);
1927 hbitmap = 0;
1930 return hbitmap;
1933 /*************************************************************************
1934 * ImageList_Read [COMCTL32.@]
1936 * Reads an image list from a stream.
1938 * PARAMS
1939 * pstm [I] pointer to a stream
1941 * RETURNS
1942 * Success: handle to image list
1943 * Failure: NULL
1945 * The format is like this:
1946 * ILHEAD ilheadstruct;
1948 * for the color image part:
1949 * BITMAPFILEHEADER bmfh;
1950 * BITMAPINFOHEADER bmih;
1951 * only if it has a palette:
1952 * RGBQUAD rgbs[nr_of_paletted_colors];
1954 * BYTE colorbits[imagesize];
1956 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1957 * BITMAPFILEHEADER bmfh_mask;
1958 * BITMAPINFOHEADER bmih_mask;
1959 * only if it has a palette (it usually does not):
1960 * RGBQUAD rgbs[nr_of_paletted_colors];
1962 * BYTE maskbits[imagesize];
1964 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1965 * _read_bitmap needs to convert them.
1967 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1969 ILHEAD ilHead;
1970 HIMAGELIST himl;
1971 HBITMAP hbmColor=0,hbmMask=0;
1972 int i;
1974 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1975 return NULL;
1976 if (ilHead.usMagic != (('L' << 8) | 'I'))
1977 return NULL;
1978 if (ilHead.usVersion != 0x101) /* probably version? */
1979 return NULL;
1981 #if 0
1982 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1983 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1984 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1985 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1986 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1987 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1988 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1989 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1990 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1991 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1992 #endif
1994 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1995 if (!hbmColor)
1996 return NULL;
1997 if (ilHead.flags & ILC_MASK) {
1998 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1999 if (!hbmMask) {
2000 DeleteObject(hbmColor);
2001 return NULL;
2005 himl = ImageList_Create (
2006 ilHead.cx,
2007 ilHead.cy,
2008 ilHead.flags,
2009 1, /* initial */
2010 ilHead.cGrow
2012 if (!himl) {
2013 DeleteObject(hbmColor);
2014 DeleteObject(hbmMask);
2015 return NULL;
2017 SelectObject(himl->hdcImage, hbmColor);
2018 DeleteObject(himl->hbmImage);
2019 himl->hbmImage = hbmColor;
2020 if (hbmMask){
2021 SelectObject(himl->hdcMask, hbmMask);
2022 DeleteObject(himl->hbmMask);
2023 himl->hbmMask = hbmMask;
2025 himl->cCurImage = ilHead.cCurImage;
2026 himl->cMaxImage = ilHead.cMaxImage;
2028 ImageList_SetBkColor(himl,ilHead.bkcolor);
2029 for (i=0;i<4;i++)
2030 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2031 return himl;
2035 /*************************************************************************
2036 * ImageList_Remove [COMCTL32.@]
2038 * Removes an image from an image list
2040 * PARAMS
2041 * himl [I] image list handle
2042 * i [I] image index
2044 * RETURNS
2045 * Success: TRUE
2046 * Failure: FALSE
2049 BOOL WINAPI
2050 ImageList_Remove (HIMAGELIST himl, INT i)
2052 HBITMAP hbmNewImage, hbmNewMask;
2053 HDC hdcBmp;
2054 INT cxNew, nCount;
2056 TRACE("(himl=%p i=%d)\n", himl, i);
2058 if (!is_valid(himl)) {
2059 ERR("Invalid image list handle!\n");
2060 return FALSE;
2063 if ((i < -1) || (i >= himl->cCurImage)) {
2064 ERR("index out of range! %d\n", i);
2065 return FALSE;
2068 if (i == -1) {
2069 /* remove all */
2070 if (himl->cCurImage == 0) {
2071 /* remove all on empty ImageList is allowed */
2072 TRACE("remove all on empty ImageList!\n");
2073 return TRUE;
2076 himl->cMaxImage = himl->cInitial + himl->cGrow;
2077 himl->cCurImage = 0;
2078 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2079 himl->nOvlIdx[nCount] = -1;
2081 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2082 SelectObject (himl->hdcImage, hbmNewImage);
2083 DeleteObject (himl->hbmImage);
2084 himl->hbmImage = hbmNewImage;
2086 if (himl->hbmMask) {
2087 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2088 1, 1, NULL);
2089 SelectObject (himl->hdcMask, hbmNewMask);
2090 DeleteObject (himl->hbmMask);
2091 himl->hbmMask = hbmNewMask;
2094 else {
2095 /* delete one image */
2096 TRACE("Remove single image! %d\n", i);
2098 /* create new bitmap(s) */
2099 nCount = (himl->cCurImage + himl->cGrow - 1);
2100 cxNew = nCount * himl->cx;
2102 TRACE(" - Number of images: %d / %d (Old/New)\n",
2103 himl->cCurImage, himl->cCurImage - 1);
2104 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2105 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2107 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy);
2109 if (himl->hbmMask)
2110 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2111 else
2112 hbmNewMask = 0; /* Just to keep compiler happy! */
2114 hdcBmp = CreateCompatibleDC (0);
2116 /* copy all images and masks prior to the "removed" image */
2117 if (i > 0) {
2118 TRACE("Pre image copy: Copy %d images\n", i);
2120 SelectObject (hdcBmp, hbmNewImage);
2121 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2122 himl->hdcImage, 0, 0, SRCCOPY);
2124 if (himl->hbmMask) {
2125 SelectObject (hdcBmp, hbmNewMask);
2126 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2127 himl->hdcMask, 0, 0, SRCCOPY);
2131 /* copy all images and masks behind the removed image */
2132 if (i < himl->cCurImage - 1) {
2133 TRACE("Post image copy!\n");
2134 SelectObject (hdcBmp, hbmNewImage);
2135 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2136 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2138 if (himl->hbmMask) {
2139 SelectObject (hdcBmp, hbmNewMask);
2140 BitBlt (hdcBmp, i * himl->cx, 0,
2141 (himl->cCurImage - i - 1) * himl->cx,
2142 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2146 DeleteDC (hdcBmp);
2148 /* delete old images and insert new ones */
2149 SelectObject (himl->hdcImage, hbmNewImage);
2150 DeleteObject (himl->hbmImage);
2151 himl->hbmImage = hbmNewImage;
2152 if (himl->hbmMask) {
2153 SelectObject (himl->hdcMask, hbmNewMask);
2154 DeleteObject (himl->hbmMask);
2155 himl->hbmMask = hbmNewMask;
2158 himl->cCurImage--;
2159 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2162 return TRUE;
2166 /*************************************************************************
2167 * ImageList_Replace [COMCTL32.@]
2169 * Replaces an image in an image list with a new image.
2171 * PARAMS
2172 * himl [I] handle to image list
2173 * i [I] image index
2174 * hbmImage [I] handle to image bitmap
2175 * hbmMask [I] handle to mask bitmap. Can be NULL.
2177 * RETURNS
2178 * Success: TRUE
2179 * Failure: FALSE
2182 BOOL WINAPI
2183 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2184 HBITMAP hbmMask)
2186 HDC hdcImage;
2187 BITMAP bmp;
2189 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2191 if (!is_valid(himl)) {
2192 ERR("Invalid image list handle!\n");
2193 return FALSE;
2196 if ((i >= himl->cMaxImage) || (i < 0)) {
2197 ERR("Invalid image index!\n");
2198 return FALSE;
2201 hdcImage = CreateCompatibleDC (0);
2202 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2204 /* Replace Image */
2205 SelectObject (hdcImage, hbmImage);
2207 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2208 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2210 if (himl->hbmMask)
2212 /* Replace Mask */
2213 SelectObject (hdcImage, hbmMask);
2215 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2216 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2219 /* Remove the background from the image
2221 StretchBlt (himl->hdcImage,
2222 i*himl->cx, 0, himl->cx, himl->cy,
2223 hdcImage,
2224 0, 0, bmp.bmWidth, bmp.bmHeight,
2225 0x220326); /* NOTSRCAND */
2228 DeleteDC (hdcImage);
2230 return TRUE;
2234 /*************************************************************************
2235 * ImageList_ReplaceIcon [COMCTL32.@]
2237 * Replaces an image in an image list using an icon.
2239 * PARAMS
2240 * himl [I] handle to image list
2241 * i [I] image index
2242 * hIcon [I] handle to icon
2244 * RETURNS
2245 * Success: index of the replaced image
2246 * Failure: -1
2249 INT WINAPI
2250 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2252 HDC hdcImage;
2253 INT nIndex;
2254 HICON hBestFitIcon;
2255 HBITMAP hbmOldSrc;
2256 ICONINFO ii;
2257 BITMAP bmp;
2259 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2261 if (!is_valid(himl))
2262 return -1;
2263 if ((i >= himl->cMaxImage) || (i < -1))
2264 return -1;
2266 hBestFitIcon = CopyImage(
2267 hIcon, IMAGE_ICON,
2268 himl->cx, himl->cy,
2269 LR_COPYFROMRESOURCE);
2271 GetIconInfo (hBestFitIcon, &ii);
2272 if (ii.hbmMask == 0)
2273 ERR("no mask!\n");
2274 if (ii.hbmColor == 0)
2275 ERR("no color!\n");
2276 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2278 if (i == -1) {
2279 if (himl->cCurImage + 1 > himl->cMaxImage)
2280 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2282 nIndex = himl->cCurImage;
2283 himl->cCurImage++;
2285 else
2286 nIndex = i;
2288 hdcImage = CreateCompatibleDC (0);
2289 TRACE("hdcImage=%p\n", hdcImage);
2290 if (hdcImage == 0)
2291 ERR("invalid hdcImage!\n");
2293 SetTextColor(himl->hdcImage, RGB(0,0,0));
2294 SetBkColor (himl->hdcImage, RGB(255,255,255));
2295 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2297 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2298 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2300 if (himl->hbmMask) {
2301 SelectObject (hdcImage, ii.hbmMask);
2302 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2303 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2306 SelectObject (hdcImage, hbmOldSrc);
2308 if(hBestFitIcon)
2309 DestroyIcon(hBestFitIcon);
2310 if (hdcImage)
2311 DeleteDC (hdcImage);
2312 if (ii.hbmColor)
2313 DeleteObject (ii.hbmColor);
2314 if (ii.hbmMask)
2315 DeleteObject (ii.hbmMask);
2317 return nIndex;
2321 /*************************************************************************
2322 * ImageList_SetBkColor [COMCTL32.@]
2324 * Sets the background color of an image list.
2326 * PARAMS
2327 * himl [I] handle to image list
2328 * clrBk [I] background color
2330 * RETURNS
2331 * Success: previous background color
2332 * Failure: CLR_NONE
2335 COLORREF WINAPI
2336 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2338 COLORREF clrOldBk;
2340 if (!is_valid(himl))
2341 return CLR_NONE;
2343 clrOldBk = himl->clrBk;
2344 himl->clrBk = clrBk;
2345 return clrOldBk;
2349 /*************************************************************************
2350 * ImageList_SetDragCursorImage [COMCTL32.@]
2352 * Combines the specified image with the current drag image
2354 * PARAMS
2355 * himlDrag [I] handle to drag image list
2356 * iDrag [I] drag image index
2357 * dxHotspot [I] X position of the hot spot
2358 * dyHotspot [I] Y position of the hot spot
2360 * RETURNS
2361 * Success: TRUE
2362 * Failure: FALSE
2364 * NOTES
2365 * When this function is called and the drag image is visible, a
2366 * short flickering occurs but this matches the Win9x behavior. It is
2367 * possible to fix the flickering using code like in ImageList_DragMove.
2370 BOOL WINAPI
2371 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2372 INT dxHotspot, INT dyHotspot)
2374 HIMAGELIST himlTemp;
2375 INT dx, dy;
2376 BOOL visible;
2378 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2379 return FALSE;
2381 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2382 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2384 visible = InternalDrag.bShow;
2386 /* Calculate the offset between the origin of the old image and the
2387 * origin of the second image.
2388 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2389 * hotspot) to the origin of the second image.
2390 * See M$DN for details */
2391 if(InternalDrag.bHSPending) {
2392 dx = 0;
2393 dy = 0;
2394 InternalDrag.bHSPending = FALSE;
2395 } else {
2396 dx = InternalDrag.dxHotspot - dxHotspot;
2397 dy = InternalDrag.dyHotspot - dyHotspot;
2399 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2401 if (visible) {
2402 /* hide the drag image */
2403 ImageList_DragShowNolock(FALSE);
2405 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2406 (InternalDrag.himl->cy != himlTemp->cy)) {
2407 /* the size of the drag image changed, invalidate the buffer */
2408 DeleteObject(InternalDrag.hbmBg);
2409 InternalDrag.hbmBg = 0;
2412 ImageList_Destroy (InternalDrag.himl);
2413 InternalDrag.himl = himlTemp;
2415 /* update the InternalDragOffset, if the origin of the
2416 * DragImage was changed by ImageList_Merge. */
2417 if (dx <= 0)
2418 InternalDrag.dxHotspot = dxHotspot;
2419 if (dy <= 0)
2420 InternalDrag.dyHotspot = dyHotspot;
2422 if (visible) {
2423 /* show the drag image */
2424 ImageList_DragShowNolock(TRUE);
2427 return TRUE;
2431 /*************************************************************************
2432 * ImageList_SetFilter [COMCTL32.@]
2434 * Sets a filter (or does something completely different)!!???
2435 * It removes 12 Bytes from the stack (3 Parameters).
2437 * PARAMS
2438 * himl [I] SHOULD be a handle to image list
2439 * i [I] COULD be an index?
2440 * dwFilter [I] ???
2442 * RETURNS
2443 * Success: TRUE ???
2444 * Failure: FALSE ???
2446 * BUGS
2447 * This is an UNDOCUMENTED function!!!!
2448 * empty stub.
2451 BOOL WINAPI
2452 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2454 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2456 return FALSE;
2460 /*************************************************************************
2461 * ImageList_SetFlags [COMCTL32.@]
2463 * Sets the image list flags.
2465 * PARAMS
2466 * himl [I] Handle to image list
2467 * flags [I] Flags to set
2469 * RETURNS
2470 * Old flags?
2472 * BUGS
2473 * Stub.
2476 DWORD WINAPI
2477 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2479 FIXME("(%p %08lx):empty stub\n", himl, flags);
2480 return 0;
2484 /*************************************************************************
2485 * ImageList_SetIconSize [COMCTL32.@]
2487 * Sets the image size of the bitmap and deletes all images.
2489 * PARAMS
2490 * himl [I] handle to image list
2491 * cx [I] image width
2492 * cy [I] image height
2494 * RETURNS
2495 * Success: TRUE
2496 * Failure: FALSE
2499 BOOL WINAPI
2500 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2502 INT nCount;
2503 HBITMAP hbmNew;
2505 if (!is_valid(himl))
2506 return FALSE;
2508 /* remove all images */
2509 himl->cMaxImage = himl->cInitial + himl->cGrow;
2510 himl->cCurImage = 0;
2511 himl->cx = cx;
2512 himl->cy = cy;
2514 /* initialize overlay mask indices */
2515 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2516 himl->nOvlIdx[nCount] = -1;
2518 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy);
2519 SelectObject (himl->hdcImage, hbmNew);
2520 DeleteObject (himl->hbmImage);
2521 himl->hbmImage = hbmNew;
2523 if (himl->hbmMask) {
2524 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2525 1, 1, NULL);
2526 SelectObject (himl->hdcMask, hbmNew);
2527 DeleteObject (himl->hbmMask);
2528 himl->hbmMask = hbmNew;
2531 return TRUE;
2535 /*************************************************************************
2536 * ImageList_SetImageCount [COMCTL32.@]
2538 * Resizes an image list to the specified number of images.
2540 * PARAMS
2541 * himl [I] handle to image list
2542 * iImageCount [I] number of images in the image list
2544 * RETURNS
2545 * Success: TRUE
2546 * Failure: FALSE
2549 BOOL WINAPI
2550 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2552 HDC hdcBitmap;
2553 HBITMAP hbmNewBitmap;
2554 INT nNewCount, nCopyCount;
2556 TRACE("%p %d\n",himl,iImageCount);
2558 if (!is_valid(himl))
2559 return FALSE;
2560 if (himl->cCurImage >= iImageCount)
2561 return FALSE;
2562 if (himl->cMaxImage > iImageCount)
2564 himl->cCurImage = iImageCount;
2565 return TRUE;
2568 nNewCount = iImageCount + himl->cGrow;
2569 nCopyCount = min(himl->cCurImage, iImageCount);
2571 hdcBitmap = CreateCompatibleDC (0);
2573 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy);
2575 if (hbmNewBitmap != 0)
2577 SelectObject (hdcBitmap, hbmNewBitmap);
2579 /* copy images */
2580 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2581 himl->hdcImage, 0, 0, SRCCOPY);
2582 #if 0
2583 /* delete 'empty' image space */
2584 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2585 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2586 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2587 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2588 #endif
2589 SelectObject (himl->hdcImage, hbmNewBitmap);
2590 DeleteObject (himl->hbmImage);
2591 himl->hbmImage = hbmNewBitmap;
2593 else
2594 ERR("Could not create new image bitmap !\n");
2596 if (himl->hbmMask)
2598 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2599 1, 1, NULL);
2600 if (hbmNewBitmap != 0)
2602 SelectObject (hdcBitmap, hbmNewBitmap);
2604 /* copy images */
2605 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2606 himl->hdcMask, 0, 0, SRCCOPY);
2607 #if 0
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);
2613 #endif
2614 SelectObject (himl->hdcMask, hbmNewBitmap);
2615 DeleteObject (himl->hbmMask);
2616 himl->hbmMask = hbmNewBitmap;
2618 else
2619 ERR("Could not create new mask bitmap!\n");
2622 DeleteDC (hdcBitmap);
2624 /* Update max image count and current image count */
2625 himl->cMaxImage = nNewCount;
2626 himl->cCurImage = iImageCount;
2628 return TRUE;
2632 /*************************************************************************
2633 * ImageList_SetOverlayImage [COMCTL32.@]
2635 * Assigns an overlay mask index to an existing image in an image list.
2637 * PARAMS
2638 * himl [I] handle to image list
2639 * iImage [I] image index
2640 * iOverlay [I] overlay mask index
2642 * RETURNS
2643 * Success: TRUE
2644 * Failure: FALSE
2647 BOOL WINAPI
2648 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2650 if (!is_valid(himl))
2651 return FALSE;
2652 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2653 return FALSE;
2654 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2655 return FALSE;
2656 himl->nOvlIdx[iOverlay - 1] = iImage;
2657 return TRUE;
2662 /* helper for ImageList_Write - write bitmap to pstm
2663 * currently everything is written as 24 bit RGB, except masks
2665 static BOOL
2666 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2668 LPBITMAPFILEHEADER bmfh;
2669 LPBITMAPINFOHEADER bmih;
2670 LPBYTE data, lpBits, lpBitsOrg;
2671 BITMAP bm;
2672 INT bitCount, sizeImage, offBits, totalSize;
2673 INT nwidth, nheight, nsizeImage, icount;
2674 HDC xdc;
2675 BOOL result = FALSE;
2678 xdc = GetDC(0);
2679 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2681 /* XXX is this always correct? */
2682 icount = bm.bmWidth / cx;
2683 nwidth = cx;
2684 nheight = cy * icount;
2686 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2687 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2688 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2690 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2691 if(bitCount != 24)
2692 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2693 offBits = totalSize;
2694 totalSize += nsizeImage;
2696 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2697 bmfh = (LPBITMAPFILEHEADER)data;
2698 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2699 lpBits = data + offBits;
2701 /* setup BITMAPFILEHEADER */
2702 bmfh->bfType = (('M' << 8) | 'B');
2703 bmfh->bfSize = 0;
2704 bmfh->bfReserved1 = 0;
2705 bmfh->bfReserved2 = 0;
2706 bmfh->bfOffBits = offBits;
2708 /* setup BITMAPINFOHEADER */
2709 bmih->biSize = sizeof(BITMAPINFOHEADER);
2710 bmih->biWidth = bm.bmWidth;
2711 bmih->biHeight = bm.bmHeight;
2712 bmih->biPlanes = 1;
2713 bmih->biBitCount = bitCount;
2714 bmih->biCompression = BI_RGB;
2715 bmih->biSizeImage = sizeImage;
2716 bmih->biXPelsPerMeter = 0;
2717 bmih->biYPelsPerMeter = 0;
2718 bmih->biClrUsed = 0;
2719 bmih->biClrImportant = 0;
2721 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2722 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2723 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2724 goto failed;
2725 else {
2726 int i;
2727 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2728 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2730 for(i = 0; i < nheight; i++) {
2731 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2732 int noff = (nbpl * (nheight-1-i));
2733 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2737 bmih->biWidth = nwidth;
2738 bmih->biHeight = nheight;
2739 bmih->biSizeImage = nsizeImage;
2741 if(bitCount == 1) {
2742 /* Hack. */
2743 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2744 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2745 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2748 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2749 goto failed;
2751 result = TRUE;
2753 failed:
2754 ReleaseDC(0, xdc);
2755 LocalFree((HLOCAL)lpBitsOrg);
2757 return result;
2761 /*************************************************************************
2762 * ImageList_Write [COMCTL32.@]
2764 * Writes an image list to a stream.
2766 * PARAMS
2767 * himl [I] handle to image list
2768 * pstm [O] Pointer to a stream.
2770 * RETURNS
2771 * Success: TRUE
2772 * Failure: FALSE
2774 * BUGS
2775 * probably.
2778 BOOL WINAPI
2779 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2781 ILHEAD ilHead;
2782 int i;
2784 if (!is_valid(himl))
2785 return FALSE;
2787 ilHead.usMagic = (('L' << 8) | 'I');
2788 ilHead.usVersion = 0x101;
2789 ilHead.cCurImage = himl->cCurImage;
2790 ilHead.cMaxImage = himl->cMaxImage;
2791 ilHead.cGrow = himl->cGrow;
2792 ilHead.cx = himl->cx;
2793 ilHead.cy = himl->cy;
2794 ilHead.bkcolor = himl->clrBk;
2795 ilHead.flags = himl->flags;
2796 for(i = 0; i < 4; i++) {
2797 ilHead.ovls[i] = himl->nOvlIdx[i];
2800 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2801 return FALSE;
2803 /* write the bitmap */
2804 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2805 return FALSE;
2807 /* write the mask if we have one */
2808 if(himl->flags & ILC_MASK) {
2809 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2810 return FALSE;
2813 return TRUE;
2817 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height)
2819 HBITMAP hbmNewBitmap;
2820 UINT ilc = (himl->flags & 0xFE);
2822 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2824 VOID* bits;
2825 BITMAPINFO bmi;
2827 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2829 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2830 bmi.bmiHeader.biWidth = width;
2831 bmi.bmiHeader.biHeight = height;
2832 bmi.bmiHeader.biPlanes = 1;
2833 bmi.bmiHeader.biBitCount = himl->uBitsPixel;
2834 bmi.bmiHeader.biCompression = BI_RGB;
2835 bmi.bmiHeader.biSizeImage = 0;
2836 bmi.bmiHeader.biXPelsPerMeter = 0;
2837 bmi.bmiHeader.biYPelsPerMeter = 0;
2838 bmi.bmiHeader.biClrUsed = 0;
2839 bmi.bmiHeader.biClrImportant = 0;
2841 hbmNewBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, 0, 0);
2843 else /*if (ilc == ILC_COLORDDB)*/
2845 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2847 hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL);
2850 return hbmNewBitmap;