comctl32: Remove a Nx1 assuption in ImageList_AddMasked().
[wine/wine-gecko.git] / dlls / comctl32 / imagelist.c
blob20da02f17f77c85d3a5844712bbce0a58bc35858
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 count, 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 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cy, SIZE *sz )
95 sz->cx = count * himl->cx;
96 sz->cy = cy;
99 static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
100 UINT src, UINT count, UINT dest )
102 POINT ptSrc, ptDest;
103 SIZE sz;
105 imagelist_point_from_index( himl, src, &ptSrc );
106 imagelist_point_from_index( himl, dest, &ptDest );
107 imagelist_get_bitmap_size( himl, count, himl->cy, &sz );
108 BitBlt (hdcDest, ptSrc.x, ptSrc.y, sz.cx, sz.cy, hdcSrc, ptDest.x, ptDest.y, SRCCOPY);
111 /*************************************************************************
112 * IMAGELIST_InternalExpandBitmaps [Internal]
114 * Expands the bitmaps of an image list by the given number of images.
116 * PARAMS
117 * himl [I] handle to image list
118 * nImageCount [I] number of images to add
120 * RETURNS
121 * nothing
123 * NOTES
124 * This function CANNOT be used to reduce the number of images.
126 static void
127 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
129 HDC hdcBitmap;
130 HBITMAP hbmNewBitmap, hbmNull;
131 INT nNewCount;
132 SIZE sz;
134 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
135 && (himl->cy >= cy))
136 return;
138 if (cy == 0) cy = himl->cy;
139 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
141 imagelist_get_bitmap_size(himl, nNewCount, cy, &sz);
143 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
144 hdcBitmap = CreateCompatibleDC (0);
146 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cy);
148 if (hbmNewBitmap == 0)
149 ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
151 if (himl->cCurImage)
153 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
154 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
155 himl->hdcImage, 0, 0, SRCCOPY);
156 SelectObject (hdcBitmap, hbmNull);
158 SelectObject (himl->hdcImage, hbmNewBitmap);
159 DeleteObject (himl->hbmImage);
160 himl->hbmImage = hbmNewBitmap;
162 if (himl->flags & ILC_MASK)
164 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
166 if (hbmNewBitmap == 0)
167 ERR("creating new mask bitmap!\n");
169 if(himl->cCurImage)
171 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
172 BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
173 himl->hdcMask, 0, 0, SRCCOPY);
174 SelectObject (hdcBitmap, hbmNull);
176 SelectObject (himl->hdcMask, hbmNewBitmap);
177 DeleteObject (himl->hbmMask);
178 himl->hbmMask = hbmNewBitmap;
181 himl->cMaxImage = nNewCount;
183 DeleteDC (hdcBitmap);
187 /*************************************************************************
188 * ImageList_Add [COMCTL32.@]
190 * Add an image or images to an image list.
192 * PARAMS
193 * himl [I] handle to image list
194 * hbmImage [I] handle to image bitmap
195 * hbmMask [I] handle to mask bitmap
197 * RETURNS
198 * Success: Index of the first new image.
199 * Failure: -1
202 INT WINAPI
203 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
205 HDC hdcBitmap, hdcTemp;
206 INT nFirstIndex, nImageCount, i;
207 BITMAP bmp;
208 HBITMAP hOldBitmap, hOldBitmapTemp;
209 POINT pt;
211 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
212 if (!is_valid(himl))
213 return -1;
215 if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
216 return -1;
218 nImageCount = bmp.bmWidth / himl->cx;
220 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
222 hdcBitmap = CreateCompatibleDC(0);
224 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
226 for (i=0; i<nImageCount; i++)
228 imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
230 /* Copy result to the imagelist
232 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
233 hdcBitmap, i*himl->cx, 0, SRCCOPY );
235 if (!himl->hbmMask)
236 continue;
238 hdcTemp = CreateCompatibleDC(0);
239 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
241 BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
242 hdcTemp, i*himl->cx, 0, SRCCOPY );
244 SelectObject(hdcTemp, hOldBitmapTemp);
245 DeleteDC(hdcTemp);
247 /* Remove the background from the image
249 BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
250 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
253 SelectObject(hdcBitmap, hOldBitmap);
254 DeleteDC(hdcBitmap);
256 nFirstIndex = himl->cCurImage;
257 himl->cCurImage += nImageCount;
259 return nFirstIndex;
263 /*************************************************************************
264 * ImageList_AddIcon [COMCTL32.@]
266 * Adds an icon to an image list.
268 * PARAMS
269 * himl [I] handle to image list
270 * hIcon [I] handle to icon
272 * RETURNS
273 * Success: index of the new image
274 * Failure: -1
276 #undef ImageList_AddIcon
277 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
279 return ImageList_ReplaceIcon (himl, -1, hIcon);
283 /*************************************************************************
284 * ImageList_AddMasked [COMCTL32.@]
286 * Adds an image or images to an image list and creates a mask from the
287 * specified bitmap using the mask color.
289 * PARAMS
290 * himl [I] handle to image list.
291 * hBitmap [I] handle to bitmap
292 * clrMask [I] mask color.
294 * RETURNS
295 * Success: Index of the first new image.
296 * Failure: -1
299 INT WINAPI
300 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
302 HDC hdcMask, hdcBitmap;
303 INT nIndex, nImageCount;
304 BITMAP bmp;
305 HBITMAP hOldBitmap;
306 HBITMAP hMaskBitmap=0;
307 COLORREF bkColor;
308 POINT pt;
310 TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
311 if (!is_valid(himl))
312 return -1;
314 if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
315 return -1;
317 if (himl->cx > 0)
318 nImageCount = bmp.bmWidth / himl->cx;
319 else
320 nImageCount = 0;
322 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
324 nIndex = himl->cCurImage;
325 himl->cCurImage += nImageCount;
327 hdcBitmap = CreateCompatibleDC(0);
330 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
331 if(himl->hbmMask)
333 hdcMask = himl->hdcMask;
334 imagelist_point_from_index( himl, nIndex, &pt );
336 else
339 Create a temp Mask so we can remove the background of
340 the Image (Windows does this even if there is no mask)
342 hdcMask = CreateCompatibleDC(0);
343 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
344 SelectObject(hdcMask, hMaskBitmap);
345 imagelist_point_from_index( himl, 0, &pt );
347 /* create monochrome image to the mask bitmap */
348 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
349 GetPixel (hdcBitmap, 0, 0);
350 SetBkColor (hdcBitmap, bkColor);
351 BitBlt (hdcMask,
352 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
353 hdcBitmap, 0, 0,
354 SRCCOPY);
356 SetBkColor(hdcBitmap, RGB(255,255,255));
357 /*Remove the background from the image
360 WINDOWS BUG ALERT!!!!!!
361 The statement below should not be done in common practice
362 but this is how ImageList_AddMasked works in Windows.
363 It overwrites the original bitmap passed, this was discovered
364 by using the same bitmap to iterate the different styles
365 on windows where it failed (BUT ImageList_Add is OK)
366 This is here in case some apps rely on this bug
368 BitBlt(hdcBitmap,
369 0, 0, bmp.bmWidth, bmp.bmHeight,
370 hdcMask,
371 pt.x, pt.y,
372 0x220326); /* NOTSRCAND */
373 /* Copy result to the imagelist
375 imagelist_point_from_index( himl, nIndex, &pt );
376 BitBlt (himl->hdcImage,
377 pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
378 hdcBitmap,
379 0, 0,
380 SRCCOPY);
381 /* Clean up
383 SelectObject(hdcBitmap, hOldBitmap);
384 DeleteDC(hdcBitmap);
385 if(!himl->hbmMask)
387 DeleteObject(hMaskBitmap);
388 DeleteDC(hdcMask);
391 return nIndex;
395 /*************************************************************************
396 * ImageList_BeginDrag [COMCTL32.@]
398 * Creates a temporary image list that contains one image. It will be used
399 * as a drag image.
401 * PARAMS
402 * himlTrack [I] handle to the source image list
403 * iTrack [I] index of the drag image in the source image list
404 * dxHotspot [I] X position of the hot spot of the drag image
405 * dyHotspot [I] Y position of the hot spot of the drag image
407 * RETURNS
408 * Success: TRUE
409 * Failure: FALSE
412 BOOL WINAPI
413 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
414 INT dxHotspot, INT dyHotspot)
416 INT cx, cy;
418 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
419 dxHotspot, dyHotspot);
421 if (!is_valid(himlTrack))
422 return FALSE;
424 if (InternalDrag.himl)
425 ImageList_EndDrag ();
427 cx = himlTrack->cx;
428 cy = himlTrack->cy;
430 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
431 if (InternalDrag.himl == NULL) {
432 WARN("Error creating drag image list!\n");
433 return FALSE;
436 InternalDrag.dxHotspot = dxHotspot;
437 InternalDrag.dyHotspot = dyHotspot;
439 /* copy image */
440 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
442 /* copy mask */
443 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
445 InternalDrag.himl->cCurImage = 1;
447 return TRUE;
451 /*************************************************************************
452 * ImageList_Copy [COMCTL32.@]
454 * Copies an image of the source image list to an image of the
455 * destination image list. Images can be copied or swapped.
457 * PARAMS
458 * himlDst [I] handle to the destination image list
459 * iDst [I] destination image index.
460 * himlSrc [I] handle to the source image list
461 * iSrc [I] source image index
462 * uFlags [I] flags for the copy operation
464 * RETURNS
465 * Success: TRUE
466 * Failure: FALSE
468 * NOTES
469 * Copying from one image list to another is possible. The original
470 * implementation just copies or swaps within one image list.
471 * Could this feature become a bug??? ;-)
474 BOOL WINAPI
475 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
476 INT iSrc, UINT uFlags)
478 POINT ptSrc, ptDst;
480 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
482 if (!is_valid(himlSrc) || !is_valid(himlDst))
483 return FALSE;
484 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
485 return FALSE;
486 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
487 return FALSE;
489 imagelist_point_from_index( himlDst, iDst, &ptDst );
490 imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
492 if (uFlags & ILCF_SWAP) {
493 /* swap */
494 HDC hdcBmp;
495 HBITMAP hbmTempImage, hbmTempMask;
497 hdcBmp = CreateCompatibleDC (0);
499 /* create temporary bitmaps */
500 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
501 himlSrc->uBitsPixel, NULL);
502 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
503 1, NULL);
505 /* copy (and stretch) destination to temporary bitmaps.(save) */
506 /* image */
507 SelectObject (hdcBmp, hbmTempImage);
508 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
509 himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
510 SRCCOPY);
511 /* mask */
512 SelectObject (hdcBmp, hbmTempMask);
513 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
514 himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
515 SRCCOPY);
517 /* copy (and stretch) source to destination */
518 /* image */
519 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
520 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
521 SRCCOPY);
522 /* mask */
523 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
524 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
525 SRCCOPY);
527 /* copy (without stretching) temporary bitmaps to source (restore) */
528 /* mask */
529 BitBlt (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
530 hdcBmp, 0, 0, SRCCOPY);
532 /* image */
533 BitBlt (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
534 hdcBmp, 0, 0, SRCCOPY);
535 /* delete temporary bitmaps */
536 DeleteObject (hbmTempMask);
537 DeleteObject (hbmTempImage);
538 DeleteDC(hdcBmp);
540 else {
541 /* copy image */
542 StretchBlt (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
543 himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
544 SRCCOPY);
546 /* copy mask */
547 StretchBlt (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
548 himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
549 SRCCOPY);
552 return TRUE;
556 /*************************************************************************
557 * ImageList_Create [COMCTL32.@]
559 * Creates a new image list.
561 * PARAMS
562 * cx [I] image height
563 * cy [I] image width
564 * flags [I] creation flags
565 * cInitial [I] initial number of images in the image list
566 * cGrow [I] number of images by which image list grows
568 * RETURNS
569 * Success: Handle to the created image list
570 * Failure: NULL
572 HIMAGELIST WINAPI
573 ImageList_Create (INT cx, INT cy, UINT flags,
574 INT cInitial, INT cGrow)
576 HIMAGELIST himl;
577 INT nCount;
578 HBITMAP hbmTemp;
579 UINT ilc = (flags & 0xFE);
580 static const WORD aBitBlend25[] =
581 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
583 static const WORD aBitBlend50[] =
584 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
586 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
588 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
589 if (!himl)
590 return NULL;
592 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
594 himl->magic = IMAGELIST_MAGIC;
595 himl->cx = cx;
596 himl->cy = cy;
597 himl->flags = flags;
598 himl->cMaxImage = cInitial + cGrow;
599 himl->cInitial = cInitial;
600 himl->cGrow = cGrow;
601 himl->clrFg = CLR_DEFAULT;
602 himl->clrBk = CLR_NONE;
604 /* initialize overlay mask indices */
605 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
606 himl->nOvlIdx[nCount] = -1;
608 /* Create Image & Mask DCs */
609 himl->hdcImage = CreateCompatibleDC (0);
610 if (!himl->hdcImage)
611 goto cleanup;
612 if (himl->flags & ILC_MASK){
613 himl->hdcMask = CreateCompatibleDC(0);
614 if (!himl->hdcMask)
615 goto cleanup;
618 /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
619 if (ilc == ILC_COLOR)
620 ilc = ILC_COLOR4;
622 if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
623 himl->uBitsPixel = ilc;
624 else
625 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
627 if (himl->cMaxImage > 0) {
628 himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cy);
629 SelectObject(himl->hdcImage, himl->hbmImage);
630 } else
631 himl->hbmImage = 0;
633 if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
634 SIZE sz;
636 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
637 himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
638 if (himl->hbmMask == 0) {
639 ERR("Error creating mask bitmap!\n");
640 goto cleanup;
642 SelectObject(himl->hdcMask, himl->hbmMask);
644 else
645 himl->hbmMask = 0;
647 /* create blending brushes */
648 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
649 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
650 DeleteObject (hbmTemp);
652 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
653 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
654 DeleteObject (hbmTemp);
656 TRACE("created imagelist %p\n", himl);
657 return himl;
659 cleanup:
660 if (himl) ImageList_Destroy(himl);
661 return NULL;
665 /*************************************************************************
666 * ImageList_Destroy [COMCTL32.@]
668 * Destroys an image list.
670 * PARAMS
671 * himl [I] handle to image list
673 * RETURNS
674 * Success: TRUE
675 * Failure: FALSE
678 BOOL WINAPI
679 ImageList_Destroy (HIMAGELIST himl)
681 if (!is_valid(himl))
682 return FALSE;
684 /* delete image bitmaps */
685 if (himl->hbmImage)
686 DeleteObject (himl->hbmImage);
687 if (himl->hbmMask)
688 DeleteObject (himl->hbmMask);
690 /* delete image & mask DCs */
691 if (himl->hdcImage)
692 DeleteDC(himl->hdcImage);
693 if (himl->hdcMask)
694 DeleteDC(himl->hdcMask);
696 /* delete blending brushes */
697 if (himl->hbrBlend25)
698 DeleteObject (himl->hbrBlend25);
699 if (himl->hbrBlend50)
700 DeleteObject (himl->hbrBlend50);
702 ZeroMemory(himl, sizeof(*himl));
703 Free (himl);
705 return TRUE;
709 /*************************************************************************
710 * ImageList_DragEnter [COMCTL32.@]
712 * Locks window update and displays the drag image at the given position.
714 * PARAMS
715 * hwndLock [I] handle of the window that owns the drag image.
716 * x [I] X position of the drag image.
717 * y [I] Y position of the drag image.
719 * RETURNS
720 * Success: TRUE
721 * Failure: FALSE
723 * NOTES
724 * The position of the drag image is relative to the window, not
725 * the client area.
728 BOOL WINAPI
729 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
731 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
733 if (!is_valid(InternalDrag.himl))
734 return FALSE;
736 if (hwndLock)
737 InternalDrag.hwnd = hwndLock;
738 else
739 InternalDrag.hwnd = GetDesktopWindow ();
741 InternalDrag.x = x;
742 InternalDrag.y = y;
744 /* draw the drag image and save the background */
745 if (!ImageList_DragShowNolock(TRUE)) {
746 return FALSE;
749 return TRUE;
753 /*************************************************************************
754 * ImageList_DragLeave [COMCTL32.@]
756 * Unlocks window update and hides the drag image.
758 * PARAMS
759 * hwndLock [I] handle of the window that owns the drag image.
761 * RETURNS
762 * Success: TRUE
763 * Failure: FALSE
766 BOOL WINAPI
767 ImageList_DragLeave (HWND hwndLock)
769 /* As we don't save drag info in the window this can lead to problems if
770 an app does not supply the same window as DragEnter */
771 /* if (hwndLock)
772 InternalDrag.hwnd = hwndLock;
773 else
774 InternalDrag.hwnd = GetDesktopWindow (); */
775 if(!hwndLock)
776 hwndLock = GetDesktopWindow();
777 if(InternalDrag.hwnd != hwndLock)
778 FIXME("DragLeave hWnd != DragEnter hWnd\n");
780 ImageList_DragShowNolock (FALSE);
782 return TRUE;
786 /*************************************************************************
787 * ImageList_InternalDragDraw [Internal]
789 * Draws the drag image.
791 * PARAMS
792 * hdc [I] device context to draw into.
793 * x [I] X position of the drag image.
794 * y [I] Y position of the drag image.
796 * RETURNS
797 * Success: TRUE
798 * Failure: FALSE
800 * NOTES
801 * The position of the drag image is relative to the window, not
802 * the client area.
806 static inline void
807 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
809 IMAGELISTDRAWPARAMS imldp;
811 ZeroMemory (&imldp, sizeof(imldp));
812 imldp.cbSize = sizeof(imldp);
813 imldp.himl = InternalDrag.himl;
814 imldp.i = 0;
815 imldp.hdcDst = hdc,
816 imldp.x = x;
817 imldp.y = y;
818 imldp.rgbBk = CLR_DEFAULT;
819 imldp.rgbFg = CLR_DEFAULT;
820 imldp.fStyle = ILD_NORMAL;
821 imldp.fState = ILS_ALPHA;
822 imldp.Frame = 128;
824 /* FIXME: instead of using the alpha blending, we should
825 * create a 50% mask, and draw it semitransparantly that way */
826 ImageList_DrawIndirect (&imldp);
829 /*************************************************************************
830 * ImageList_DragMove [COMCTL32.@]
832 * Moves the drag image.
834 * PARAMS
835 * x [I] X position of the drag image.
836 * y [I] Y position of the drag image.
838 * RETURNS
839 * Success: TRUE
840 * Failure: FALSE
842 * NOTES
843 * The position of the drag image is relative to the window, not
844 * the client area.
846 * BUGS
847 * The drag image should be drawn semitransparent.
850 BOOL WINAPI
851 ImageList_DragMove (INT x, INT y)
853 TRACE("(x=%d y=%d)\n", x, y);
855 if (!is_valid(InternalDrag.himl))
856 return FALSE;
858 /* draw/update the drag image */
859 if (InternalDrag.bShow) {
860 HDC hdcDrag;
861 HDC hdcOffScreen;
862 HDC hdcBg;
863 HBITMAP hbmOffScreen;
864 INT origNewX, origNewY;
865 INT origOldX, origOldY;
866 INT origRegX, origRegY;
867 INT sizeRegX, sizeRegY;
870 /* calculate the update region */
871 origNewX = x - InternalDrag.dxHotspot;
872 origNewY = y - InternalDrag.dyHotspot;
873 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
874 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
875 origRegX = min(origNewX, origOldX);
876 origRegY = min(origNewY, origOldY);
877 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
878 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
880 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
881 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
882 hdcOffScreen = CreateCompatibleDC(hdcDrag);
883 hdcBg = CreateCompatibleDC(hdcDrag);
885 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
886 SelectObject(hdcOffScreen, hbmOffScreen);
887 SelectObject(hdcBg, InternalDrag.hbmBg);
889 /* get the actual background of the update region */
890 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
891 origRegX, origRegY, SRCCOPY);
892 /* erase the old image */
893 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
894 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
895 SRCCOPY);
896 /* save the background */
897 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
898 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
899 /* draw the image */
900 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
901 origNewY - origRegY);
902 /* draw the update region to the screen */
903 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
904 hdcOffScreen, 0, 0, SRCCOPY);
906 DeleteDC(hdcBg);
907 DeleteDC(hdcOffScreen);
908 DeleteObject(hbmOffScreen);
909 ReleaseDC(InternalDrag.hwnd, hdcDrag);
912 /* update the image position */
913 InternalDrag.x = x;
914 InternalDrag.y = y;
916 return TRUE;
920 /*************************************************************************
921 * ImageList_DragShowNolock [COMCTL32.@]
923 * Shows or hides the drag image.
925 * PARAMS
926 * bShow [I] TRUE shows the drag image, FALSE hides it.
928 * RETURNS
929 * Success: TRUE
930 * Failure: FALSE
932 * BUGS
933 * The drag image should be drawn semitransparent.
936 BOOL WINAPI
937 ImageList_DragShowNolock (BOOL bShow)
939 HDC hdcDrag;
940 HDC hdcBg;
941 INT x, y;
943 if (!is_valid(InternalDrag.himl))
944 return FALSE;
946 TRACE("bShow=0x%X!\n", bShow);
948 /* DragImage is already visible/hidden */
949 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
950 return FALSE;
953 /* position of the origin of the DragImage */
954 x = InternalDrag.x - InternalDrag.dxHotspot;
955 y = InternalDrag.y - InternalDrag.dyHotspot;
957 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
958 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
959 if (!hdcDrag) {
960 return FALSE;
963 hdcBg = CreateCompatibleDC(hdcDrag);
964 if (!InternalDrag.hbmBg) {
965 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
966 InternalDrag.himl->cx, InternalDrag.himl->cy);
968 SelectObject(hdcBg, InternalDrag.hbmBg);
970 if (bShow) {
971 /* save the background */
972 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
973 hdcDrag, x, y, SRCCOPY);
974 /* show the image */
975 ImageList_InternalDragDraw(hdcDrag, x, y);
976 } else {
977 /* hide the image */
978 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
979 hdcBg, 0, 0, SRCCOPY);
982 InternalDrag.bShow = !InternalDrag.bShow;
984 DeleteDC(hdcBg);
985 ReleaseDC (InternalDrag.hwnd, hdcDrag);
986 return TRUE;
990 /*************************************************************************
991 * ImageList_Draw [COMCTL32.@]
993 * Draws an image.
995 * PARAMS
996 * himl [I] handle to image list
997 * i [I] image index
998 * hdc [I] handle to device context
999 * x [I] x position
1000 * y [I] y position
1001 * fStyle [I] drawing flags
1003 * RETURNS
1004 * Success: TRUE
1005 * Failure: FALSE
1007 * SEE
1008 * ImageList_DrawEx.
1011 BOOL WINAPI
1012 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1014 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1015 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1019 /*************************************************************************
1020 * ImageList_DrawEx [COMCTL32.@]
1022 * Draws an image and allows to use extended drawing features.
1024 * PARAMS
1025 * himl [I] handle to image list
1026 * i [I] image index
1027 * hdc [I] handle to device context
1028 * x [I] X position
1029 * y [I] Y position
1030 * dx [I] X offset
1031 * dy [I] Y offset
1032 * rgbBk [I] background color
1033 * rgbFg [I] foreground color
1034 * fStyle [I] drawing flags
1036 * RETURNS
1037 * Success: TRUE
1038 * Failure: FALSE
1040 * NOTES
1041 * Calls ImageList_DrawIndirect.
1043 * SEE
1044 * ImageList_DrawIndirect.
1047 BOOL WINAPI
1048 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1049 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1050 UINT fStyle)
1052 IMAGELISTDRAWPARAMS imldp;
1054 ZeroMemory (&imldp, sizeof(imldp));
1055 imldp.cbSize = sizeof(imldp);
1056 imldp.himl = himl;
1057 imldp.i = i;
1058 imldp.hdcDst = hdc,
1059 imldp.x = x;
1060 imldp.y = y;
1061 imldp.cx = dx;
1062 imldp.cy = dy;
1063 imldp.rgbBk = rgbBk;
1064 imldp.rgbFg = rgbFg;
1065 imldp.fStyle = fStyle;
1067 return ImageList_DrawIndirect (&imldp);
1071 /*************************************************************************
1072 * ImageList_DrawIndirect [COMCTL32.@]
1074 * Draws an image using various parameters specified in pimldp.
1076 * PARAMS
1077 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1079 * RETURNS
1080 * Success: TRUE
1081 * Failure: FALSE
1084 BOOL WINAPI
1085 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1087 INT cx, cy, nOvlIdx;
1088 DWORD fState, dwRop;
1089 UINT fStyle;
1090 COLORREF oldImageBk, oldImageFg;
1091 HDC hImageDC, hImageListDC, hMaskListDC;
1092 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1093 BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
1094 HIMAGELIST himl;
1095 POINT pt;
1097 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1098 if (!is_valid(himl)) return FALSE;
1099 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1101 imagelist_point_from_index( himl, pimldp->i, &pt );
1102 pt.x += pimldp->xBitmap;
1103 pt.y += pimldp->yBitmap;
1105 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1106 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1107 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1108 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1110 bIsTransparent = (fStyle & ILD_TRANSPARENT);
1111 if( pimldp->rgbBk == CLR_NONE )
1112 bIsTransparent = TRUE;
1113 if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) )
1114 bIsTransparent = TRUE;
1115 bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ;
1116 bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask;
1118 TRACE("himl(%p) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1119 himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1121 /* we will use these DCs to access the images and masks in the ImageList */
1122 hImageListDC = himl->hdcImage;
1123 hMaskListDC = himl->hdcMask;
1125 /* these will accumulate the image and mask for the image we're drawing */
1126 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1127 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1128 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1130 /* Create a compatible DC. */
1131 if (!hImageListDC || !hImageDC || !hImageBmp ||
1132 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1133 goto cleanup;
1135 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1138 * To obtain a transparent look, background color should be set
1139 * to white and foreground color to black when blting the
1140 * monochrome mask.
1142 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1143 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1146 * Draw the initial image
1148 if( bMask ) {
1149 if (himl->hbmMask) {
1150 HBRUSH hOldBrush;
1151 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
1152 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1153 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
1154 DeleteObject (SelectObject (hImageDC, hOldBrush));
1155 if( bIsTransparent )
1157 BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND);
1158 bResult = TRUE;
1159 goto end;
1161 } else {
1162 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1163 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1164 SelectObject(hImageDC, hOldBrush);
1166 } else {
1167 /* blend the image with the needed solid background */
1168 COLORREF colour = RGB(0,0,0);
1169 HBRUSH hOldBrush;
1171 if( !bIsTransparent )
1173 colour = pimldp->rgbBk;
1174 if( colour == CLR_DEFAULT )
1175 colour = himl->clrBk;
1176 if( colour == CLR_NONE )
1177 colour = GetBkColor(pimldp->hdcDst);
1180 hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
1181 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1182 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND );
1183 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, pt.x, pt.y, SRCPAINT );
1184 DeleteObject (SelectObject (hImageDC, hOldBrush));
1187 /* Time for blending, if required */
1188 if (bBlend) {
1189 HBRUSH hBlendBrush, hOldBrush;
1190 COLORREF clrBlend = pimldp->rgbFg;
1191 HDC hBlendMaskDC = hImageListDC;
1192 HBITMAP hOldBitmap;
1194 /* Create the blend Mask */
1195 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1196 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1197 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1198 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1199 SelectObject(hBlendMaskDC, hOldBrush);
1201 /* Modify the blend mask if an Image Mask exist */
1202 if(himl->hbmMask) {
1203 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, 0x220326); /* NOTSRCAND */
1204 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1207 /* now apply blend to the current image given the BlendMask */
1208 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1209 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1210 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1211 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1212 DeleteObject(SelectObject(hImageDC, hOldBrush));
1213 SelectObject(hBlendMaskDC, hOldBitmap);
1216 /* Now do the overlay image, if any */
1217 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1218 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1219 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1220 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1221 POINT ptOvl;
1222 imagelist_point_from_index( himl, nOvlIdx, &ptOvl );
1223 ptOvl.x += pimldp->xBitmap;
1224 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1225 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ptOvl.x, ptOvl.y, SRCAND);
1226 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ptOvl.x, ptOvl.y, SRCPAINT);
1230 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1231 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1232 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1233 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1235 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1236 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1237 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1239 /* now copy the image to the screen */
1240 dwRop = SRCCOPY;
1241 if (himl->hbmMask && bIsTransparent ) {
1242 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1243 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1244 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, pt.x, pt.y, SRCAND);
1245 SetBkColor(pimldp->hdcDst, oldDstBk);
1246 SetTextColor(pimldp->hdcDst, oldDstFg);
1247 dwRop = SRCPAINT;
1249 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1250 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1252 bResult = TRUE;
1253 end:
1254 /* cleanup the mess */
1255 SetBkColor(hImageDC, oldImageBk);
1256 SetTextColor(hImageDC, oldImageFg);
1257 SelectObject(hImageDC, hOldImageBmp);
1258 cleanup:
1259 DeleteObject(hBlendMaskBmp);
1260 DeleteObject(hImageBmp);
1261 DeleteDC(hImageDC);
1263 return bResult;
1267 /*************************************************************************
1268 * ImageList_Duplicate [COMCTL32.@]
1270 * Duplicates an image list.
1272 * PARAMS
1273 * himlSrc [I] source image list handle
1275 * RETURNS
1276 * Success: Handle of duplicated image list.
1277 * Failure: NULL
1280 HIMAGELIST WINAPI
1281 ImageList_Duplicate (HIMAGELIST himlSrc)
1283 HIMAGELIST himlDst;
1285 if (!is_valid(himlSrc)) {
1286 ERR("Invalid image list handle!\n");
1287 return NULL;
1290 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1291 himlSrc->cInitial, himlSrc->cGrow);
1293 if (himlDst)
1295 SIZE sz;
1297 imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cy, &sz);
1298 BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
1299 himlSrc->hdcImage, 0, 0, SRCCOPY);
1301 if (himlDst->hbmMask)
1302 BitBlt (himlDst->hdcMask, 0, 0, sz.cx, sz.cy,
1303 himlSrc->hdcMask, 0, 0, SRCCOPY);
1305 himlDst->cCurImage = himlSrc->cCurImage;
1306 himlDst->cMaxImage = himlSrc->cMaxImage;
1308 return himlDst;
1312 /*************************************************************************
1313 * ImageList_EndDrag [COMCTL32.@]
1315 * Finishes a drag operation.
1317 * PARAMS
1318 * no Parameters
1320 * RETURNS
1321 * Success: TRUE
1322 * Failure: FALSE
1325 VOID WINAPI
1326 ImageList_EndDrag (void)
1328 /* cleanup the InternalDrag struct */
1329 InternalDrag.hwnd = 0;
1330 ImageList_Destroy (InternalDrag.himl);
1331 InternalDrag.himl = 0;
1332 InternalDrag.x= 0;
1333 InternalDrag.y= 0;
1334 InternalDrag.dxHotspot = 0;
1335 InternalDrag.dyHotspot = 0;
1336 InternalDrag.bShow = FALSE;
1337 DeleteObject(InternalDrag.hbmBg);
1338 InternalDrag.hbmBg = 0;
1342 /*************************************************************************
1343 * ImageList_GetBkColor [COMCTL32.@]
1345 * Returns the background color of an image list.
1347 * PARAMS
1348 * himl [I] Image list handle.
1350 * RETURNS
1351 * Success: background color
1352 * Failure: CLR_NONE
1355 COLORREF WINAPI
1356 ImageList_GetBkColor (HIMAGELIST himl)
1358 return himl ? himl->clrBk : CLR_NONE;
1362 /*************************************************************************
1363 * ImageList_GetDragImage [COMCTL32.@]
1365 * Returns the handle to the internal drag image list.
1367 * PARAMS
1368 * ppt [O] Pointer to the drag position. Can be NULL.
1369 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1371 * RETURNS
1372 * Success: Handle of the drag image list.
1373 * Failure: NULL.
1376 HIMAGELIST WINAPI
1377 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1379 if (is_valid(InternalDrag.himl)) {
1380 if (ppt) {
1381 ppt->x = InternalDrag.x;
1382 ppt->y = InternalDrag.y;
1384 if (pptHotspot) {
1385 pptHotspot->x = InternalDrag.dxHotspot;
1386 pptHotspot->y = InternalDrag.dyHotspot;
1388 return (InternalDrag.himl);
1391 return NULL;
1395 /*************************************************************************
1396 * ImageList_GetFlags [COMCTL32.@]
1398 * Gets the flags of the specified image list.
1400 * PARAMS
1401 * himl [I] Handle to image list
1403 * RETURNS
1404 * Image list flags.
1406 * BUGS
1407 * Stub.
1410 DWORD WINAPI
1411 ImageList_GetFlags(HIMAGELIST himl)
1413 FIXME("(%p):empty stub\n", himl);
1414 return 0;
1418 /*************************************************************************
1419 * ImageList_GetIcon [COMCTL32.@]
1421 * Creates an icon from a masked image of an image list.
1423 * PARAMS
1424 * himl [I] handle to image list
1425 * i [I] image index
1426 * flags [I] drawing style flags
1428 * RETURNS
1429 * Success: icon handle
1430 * Failure: NULL
1433 HICON WINAPI
1434 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1436 ICONINFO ii;
1437 HICON hIcon;
1438 HBITMAP hOldDstBitmap;
1439 HDC hdcDst;
1440 POINT pt;
1442 TRACE("%p %d %d\n", himl, i, fStyle);
1443 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1445 ii.fIcon = TRUE;
1446 ii.xHotspot = 0;
1447 ii.yHotspot = 0;
1449 /* create colour bitmap */
1450 hdcDst = GetDC(0);
1451 ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy);
1452 ReleaseDC(0, hdcDst);
1454 hdcDst = CreateCompatibleDC(0);
1456 imagelist_point_from_index( himl, i, &pt );
1458 /* draw mask*/
1459 ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
1460 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1461 if (himl->hbmMask) {
1462 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1463 himl->hdcMask, pt.x, pt.y, SRCCOPY);
1465 else
1466 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1468 /* draw image*/
1469 SelectObject (hdcDst, ii.hbmColor);
1470 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1471 himl->hdcImage, pt.x, pt.y, SRCCOPY);
1474 * CreateIconIndirect requires us to deselect the bitmaps from
1475 * the DCs before calling
1477 SelectObject(hdcDst, hOldDstBitmap);
1479 hIcon = CreateIconIndirect (&ii);
1481 DeleteObject (ii.hbmMask);
1482 DeleteObject (ii.hbmColor);
1483 DeleteDC (hdcDst);
1485 return hIcon;
1489 /*************************************************************************
1490 * ImageList_GetIconSize [COMCTL32.@]
1492 * Retrieves the size of an image in an image list.
1494 * PARAMS
1495 * himl [I] handle to image list
1496 * cx [O] pointer to the image width.
1497 * cy [O] pointer to the image height.
1499 * RETURNS
1500 * Success: TRUE
1501 * Failure: FALSE
1503 * NOTES
1504 * All images in an image list have the same size.
1507 BOOL WINAPI
1508 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1510 if (!is_valid(himl))
1511 return FALSE;
1512 if ((himl->cx <= 0) || (himl->cy <= 0))
1513 return FALSE;
1515 if (cx)
1516 *cx = himl->cx;
1517 if (cy)
1518 *cy = himl->cy;
1520 return TRUE;
1524 /*************************************************************************
1525 * ImageList_GetImageCount [COMCTL32.@]
1527 * Returns the number of images in an image list.
1529 * PARAMS
1530 * himl [I] handle to image list
1532 * RETURNS
1533 * Success: Number of images.
1534 * Failure: 0
1537 INT WINAPI
1538 ImageList_GetImageCount (HIMAGELIST himl)
1540 if (!is_valid(himl))
1541 return 0;
1543 return himl->cCurImage;
1547 /*************************************************************************
1548 * ImageList_GetImageInfo [COMCTL32.@]
1550 * Returns information about an image in an image list.
1552 * PARAMS
1553 * himl [I] handle to image list
1554 * i [I] image index
1555 * pImageInfo [O] pointer to the image information
1557 * RETURNS
1558 * Success: TRUE
1559 * Failure: FALSE
1562 BOOL WINAPI
1563 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1565 POINT pt;
1567 if (!is_valid(himl) || (pImageInfo == NULL))
1568 return FALSE;
1569 if ((i < 0) || (i >= himl->cCurImage))
1570 return FALSE;
1572 pImageInfo->hbmImage = himl->hbmImage;
1573 pImageInfo->hbmMask = himl->hbmMask;
1575 imagelist_point_from_index( himl, i, &pt );
1576 pImageInfo->rcImage.top = pt.y;
1577 pImageInfo->rcImage.bottom = pt.y + himl->cy;
1578 pImageInfo->rcImage.left = pt.x;
1579 pImageInfo->rcImage.right = pt.x + himl->cx;
1581 return TRUE;
1585 /*************************************************************************
1586 * ImageList_GetImageRect [COMCTL32.@]
1588 * Retrieves the rectangle of the specified image in an image list.
1590 * PARAMS
1591 * himl [I] handle to image list
1592 * i [I] image index
1593 * lpRect [O] pointer to the image rectangle
1595 * RETURNS
1596 * Success: TRUE
1597 * Failure: FALSE
1599 * NOTES
1600 * This is an UNDOCUMENTED function!!!
1603 BOOL WINAPI
1604 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1606 POINT pt;
1608 if (!is_valid(himl) || (lpRect == NULL))
1609 return FALSE;
1610 if ((i < 0) || (i >= himl->cCurImage))
1611 return FALSE;
1613 imagelist_point_from_index( himl, i, &pt );
1614 lpRect->left = pt.x;
1615 lpRect->top = pt.y;
1616 lpRect->right = pt.x + himl->cx;
1617 lpRect->bottom = pt.y + himl->cy;
1619 return TRUE;
1623 /*************************************************************************
1624 * ImageList_LoadImage [COMCTL32.@]
1625 * ImageList_LoadImageA [COMCTL32.@]
1627 * Creates an image list from a bitmap, icon or cursor.
1629 * See ImageList_LoadImageW.
1632 HIMAGELIST WINAPI
1633 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1634 COLORREF clrMask, UINT uType, UINT uFlags)
1636 HIMAGELIST himl;
1637 LPWSTR lpbmpW;
1638 DWORD len;
1640 if (!HIWORD(lpbmp))
1641 return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
1642 uType, uFlags);
1644 len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0);
1645 lpbmpW = Alloc(len * sizeof(WCHAR));
1646 MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len);
1648 himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags);
1649 Free (lpbmpW);
1650 return himl;
1654 /*************************************************************************
1655 * ImageList_LoadImageW [COMCTL32.@]
1657 * Creates an image list from a bitmap, icon or cursor.
1659 * PARAMS
1660 * hi [I] instance handle
1661 * lpbmp [I] name or id of the image
1662 * cx [I] width of each image
1663 * cGrow [I] number of images to expand
1664 * clrMask [I] mask color
1665 * uType [I] type of image to load
1666 * uFlags [I] loading flags
1668 * RETURNS
1669 * Success: handle to the loaded image list
1670 * Failure: NULL
1672 * SEE
1673 * LoadImage ()
1676 HIMAGELIST WINAPI
1677 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1678 COLORREF clrMask, UINT uType, UINT uFlags)
1680 HIMAGELIST himl = NULL;
1681 HANDLE handle;
1682 INT nImageCount;
1684 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1685 if (!handle) {
1686 ERR("Error loading image!\n");
1687 return NULL;
1690 if (uType == IMAGE_BITMAP) {
1691 BITMAP bmp;
1692 GetObjectW (handle, sizeof(BITMAP), &bmp);
1694 /* To match windows behavior, if cx is set to zero and
1695 the flag DI_DEFAULTSIZE is specified, cx becomes the
1696 system metric value for icons. If the flag is not specified
1697 the function sets the size to the height of the bitmap */
1698 if (cx == 0)
1700 if (uFlags & DI_DEFAULTSIZE)
1701 cx = GetSystemMetrics (SM_CXICON);
1702 else
1703 cx = bmp.bmHeight;
1706 nImageCount = bmp.bmWidth / cx;
1708 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1709 nImageCount, cGrow);
1710 if (!himl) {
1711 DeleteObject (handle);
1712 return NULL;
1714 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1716 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1717 ICONINFO ii;
1718 BITMAP bmp;
1720 GetIconInfo (handle, &ii);
1721 GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1722 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1723 ILC_MASK | ILC_COLOR, 1, cGrow);
1724 if (!himl) {
1725 DeleteObject (ii.hbmColor);
1726 DeleteObject (ii.hbmMask);
1727 DeleteObject (handle);
1728 return NULL;
1730 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1731 DeleteObject (ii.hbmColor);
1732 DeleteObject (ii.hbmMask);
1735 DeleteObject (handle);
1737 return himl;
1741 /*************************************************************************
1742 * ImageList_Merge [COMCTL32.@]
1744 * Create an image list containing a merged image from two image lists.
1746 * PARAMS
1747 * himl1 [I] handle to first image list
1748 * i1 [I] first image index
1749 * himl2 [I] handle to second image list
1750 * i2 [I] second image index
1751 * dx [I] X offset of the second image relative to the first.
1752 * dy [I] Y offset of the second image relative to the first.
1754 * RETURNS
1755 * Success: The newly created image list. It contains a single image
1756 * consisting of the second image merged with the first.
1757 * Failure: NULL, if either himl1 or himl2 are invalid.
1759 * NOTES
1760 * - The returned image list should be deleted by the caller using
1761 * ImageList_Destroy() when it is no longer required.
1762 * - If either i1 or i2 are not valid image indices they will be treated
1763 * as a blank image.
1765 HIMAGELIST WINAPI
1766 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1767 INT dx, INT dy)
1769 HIMAGELIST himlDst = NULL;
1770 INT cxDst, cyDst;
1771 INT xOff1, yOff1, xOff2, yOff2;
1772 POINT pt1, pt2;
1774 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1775 i2, dx, dy);
1777 if (!is_valid(himl1) || !is_valid(himl2))
1778 return NULL;
1780 if (dx > 0) {
1781 cxDst = max (himl1->cx, dx + himl2->cx);
1782 xOff1 = 0;
1783 xOff2 = dx;
1785 else if (dx < 0) {
1786 cxDst = max (himl2->cx, himl1->cx - dx);
1787 xOff1 = -dx;
1788 xOff2 = 0;
1790 else {
1791 cxDst = max (himl1->cx, himl2->cx);
1792 xOff1 = 0;
1793 xOff2 = 0;
1796 if (dy > 0) {
1797 cyDst = max (himl1->cy, dy + himl2->cy);
1798 yOff1 = 0;
1799 yOff2 = dy;
1801 else if (dy < 0) {
1802 cyDst = max (himl2->cy, himl1->cy - dy);
1803 yOff1 = -dy;
1804 yOff2 = 0;
1806 else {
1807 cyDst = max (himl1->cy, himl2->cy);
1808 yOff1 = 0;
1809 yOff2 = 0;
1812 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1814 if (himlDst)
1816 imagelist_point_from_index( himl1, i1, &pt1 );
1817 imagelist_point_from_index( himl1, i2, &pt2 );
1819 /* copy image */
1820 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1821 if (i1 >= 0 && i1 < himl1->cCurImage)
1822 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY);
1823 if (i2 >= 0 && i2 < himl2->cCurImage)
1825 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND);
1826 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT);
1829 /* copy mask */
1830 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1831 if (i1 >= 0 && i1 < himl1->cCurImage)
1832 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, pt1.x, pt1.y, SRCCOPY);
1833 if (i2 >= 0 && i2 < himl2->cCurImage)
1834 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, pt2.x, pt2.y, SRCAND);
1836 himlDst->cCurImage = 1;
1839 return himlDst;
1843 /* helper for _read_bitmap currently unused */
1844 #if 0
1845 static int may_use_dibsection(HDC hdc) {
1846 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1847 if (bitspixel>8)
1848 return TRUE;
1849 if (bitspixel<=4)
1850 return FALSE;
1851 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1853 #endif
1855 /* helper for ImageList_Read, see comments below */
1856 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1857 HDC xdc = 0, hBitmapDC =0;
1858 BITMAPFILEHEADER bmfh;
1859 BITMAPINFOHEADER bmih;
1860 int bitsperpixel,palspace,longsperline,width,height;
1861 LPBITMAPINFOHEADER bmihc = NULL;
1862 int result = 0;
1863 HBITMAP hbitmap = 0, hDIB = 0;
1864 LPBYTE bits = NULL;
1866 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1867 (bmfh.bfType != (('M'<<8)|'B')) ||
1868 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1869 (bmih.biSize != sizeof(bmih))
1871 return 0;
1873 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1874 if (bitsperpixel<=8)
1875 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1876 else
1877 palspace = 0;
1878 width = bmih.biWidth;
1879 height = bmih.biHeight;
1880 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1881 if (!bmihc) goto ret1;
1882 memcpy(bmihc,&bmih,sizeof(bmih));
1883 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1884 bmihc->biSizeImage = (longsperline*height)<<2;
1886 /* read the palette right after the end of the bitmapinfoheader */
1887 if (palspace)
1888 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1889 goto ret1;
1891 xdc = GetDC(0);
1892 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1893 if ((bitsperpixel>1) &&
1894 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1896 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1897 if (!hbitmap)
1898 goto ret1;
1899 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1900 goto ret1;
1901 result = 1;
1902 } else
1903 #endif
1905 int i,nwidth,nheight,nRows;
1907 nwidth = width*(height/cy);
1908 nheight = cy;
1909 nRows = (height/cy);
1911 if (bitsperpixel==1)
1912 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1913 else
1914 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1916 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1917 if (!hDIB)
1918 goto ret1;
1919 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1920 goto ret1;
1922 hBitmapDC = CreateCompatibleDC(0);
1923 SelectObject(hBitmapDC, hbitmap);
1925 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1926 /* Do not forget that windows bitmaps are bottom->top */
1927 TRACE("nRows=%d\n", nRows);
1928 for (i=0; i < nRows; i++){
1929 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1930 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1933 result = 1;
1935 ret1:
1936 if (xdc) ReleaseDC(0,xdc);
1937 if (bmihc) LocalFree((HLOCAL)bmihc);
1938 if (hDIB) DeleteObject(hDIB);
1939 if (hBitmapDC) DeleteDC(hBitmapDC);
1940 if (!result) {
1941 if (hbitmap) {
1942 DeleteObject(hbitmap);
1943 hbitmap = 0;
1946 return hbitmap;
1949 /*************************************************************************
1950 * ImageList_Read [COMCTL32.@]
1952 * Reads an image list from a stream.
1954 * PARAMS
1955 * pstm [I] pointer to a stream
1957 * RETURNS
1958 * Success: handle to image list
1959 * Failure: NULL
1961 * The format is like this:
1962 * ILHEAD ilheadstruct;
1964 * for the color image part:
1965 * BITMAPFILEHEADER bmfh;
1966 * BITMAPINFOHEADER bmih;
1967 * only if it has a palette:
1968 * RGBQUAD rgbs[nr_of_paletted_colors];
1970 * BYTE colorbits[imagesize];
1972 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1973 * BITMAPFILEHEADER bmfh_mask;
1974 * BITMAPINFOHEADER bmih_mask;
1975 * only if it has a palette (it usually does not):
1976 * RGBQUAD rgbs[nr_of_paletted_colors];
1978 * BYTE maskbits[imagesize];
1980 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1981 * _read_bitmap needs to convert them.
1983 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1985 ILHEAD ilHead;
1986 HIMAGELIST himl;
1987 HBITMAP hbmColor=0,hbmMask=0;
1988 int i;
1990 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1991 return NULL;
1992 if (ilHead.usMagic != (('L' << 8) | 'I'))
1993 return NULL;
1994 if (ilHead.usVersion != 0x101) /* probably version? */
1995 return NULL;
1997 #if 0
1998 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1999 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2000 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2001 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2002 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2003 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2004 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2005 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2006 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2007 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2008 #endif
2010 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2011 if (!hbmColor) {
2012 WARN("failed to read bitmap from stream\n");
2013 return NULL;
2015 if (ilHead.flags & ILC_MASK) {
2016 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2017 if (!hbmMask) {
2018 DeleteObject(hbmColor);
2019 return NULL;
2023 himl = ImageList_Create (
2024 ilHead.cx,
2025 ilHead.cy,
2026 ilHead.flags,
2027 1, /* initial */
2028 ilHead.cGrow
2030 if (!himl) {
2031 DeleteObject(hbmColor);
2032 DeleteObject(hbmMask);
2033 return NULL;
2035 SelectObject(himl->hdcImage, hbmColor);
2036 DeleteObject(himl->hbmImage);
2037 himl->hbmImage = hbmColor;
2038 if (hbmMask){
2039 SelectObject(himl->hdcMask, hbmMask);
2040 DeleteObject(himl->hbmMask);
2041 himl->hbmMask = hbmMask;
2043 himl->cCurImage = ilHead.cCurImage;
2044 himl->cMaxImage = ilHead.cMaxImage;
2046 ImageList_SetBkColor(himl,ilHead.bkcolor);
2047 for (i=0;i<4;i++)
2048 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2049 return himl;
2053 /*************************************************************************
2054 * ImageList_Remove [COMCTL32.@]
2056 * Removes an image from an image list
2058 * PARAMS
2059 * himl [I] image list handle
2060 * i [I] image index
2062 * RETURNS
2063 * Success: TRUE
2064 * Failure: FALSE
2067 BOOL WINAPI
2068 ImageList_Remove (HIMAGELIST himl, INT i)
2070 HBITMAP hbmNewImage, hbmNewMask;
2071 HDC hdcBmp;
2072 INT nCount;
2073 SIZE sz;
2075 TRACE("(himl=%p i=%d)\n", himl, i);
2077 if (!is_valid(himl)) {
2078 ERR("Invalid image list handle!\n");
2079 return FALSE;
2082 if ((i < -1) || (i >= himl->cCurImage)) {
2083 TRACE("index out of range! %d\n", i);
2084 return FALSE;
2087 if (i == -1) {
2088 /* remove all */
2089 if (himl->cCurImage == 0) {
2090 /* remove all on empty ImageList is allowed */
2091 TRACE("remove all on empty ImageList!\n");
2092 return TRUE;
2095 himl->cMaxImage = himl->cInitial + himl->cGrow;
2096 himl->cCurImage = 0;
2097 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2098 himl->nOvlIdx[nCount] = -1;
2100 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2101 SelectObject (himl->hdcImage, hbmNewImage);
2102 DeleteObject (himl->hbmImage);
2103 himl->hbmImage = hbmNewImage;
2105 if (himl->hbmMask) {
2107 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2108 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2109 SelectObject (himl->hdcMask, hbmNewMask);
2110 DeleteObject (himl->hbmMask);
2111 himl->hbmMask = hbmNewMask;
2114 else {
2115 /* delete one image */
2116 TRACE("Remove single image! %d\n", i);
2118 /* create new bitmap(s) */
2119 nCount = (himl->cCurImage + himl->cGrow - 1);
2121 TRACE(" - Number of images: %d / %d (Old/New)\n",
2122 himl->cCurImage, himl->cCurImage - 1);
2123 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2124 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2126 hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, nCount, himl->cy);
2128 imagelist_get_bitmap_size(himl, nCount, himl->cy, &sz );
2129 if (himl->hbmMask)
2130 hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2131 else
2132 hbmNewMask = 0; /* Just to keep compiler happy! */
2134 hdcBmp = CreateCompatibleDC (0);
2136 /* copy all images and masks prior to the "removed" image */
2137 if (i > 0) {
2138 TRACE("Pre image copy: Copy %d images\n", i);
2140 SelectObject (hdcBmp, hbmNewImage);
2141 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, 0, i, 0 );
2143 if (himl->hbmMask) {
2144 SelectObject (hdcBmp, hbmNewMask);
2145 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, 0, i, 0 );
2149 /* copy all images and masks behind the removed image */
2150 if (i < himl->cCurImage - 1) {
2151 TRACE("Post image copy!\n");
2153 SelectObject (hdcBmp, hbmNewImage);
2154 imagelist_copy_images( himl, himl->hdcImage, hdcBmp, i,
2155 (himl->cCurImage - i - 1), i + 1 );
2157 if (himl->hbmMask) {
2158 SelectObject (hdcBmp, hbmNewMask);
2159 imagelist_copy_images( himl, himl->hdcMask, hdcBmp, i,
2160 (himl->cCurImage - i - 1), i + 1 );
2164 DeleteDC (hdcBmp);
2166 /* delete old images and insert new ones */
2167 SelectObject (himl->hdcImage, hbmNewImage);
2168 DeleteObject (himl->hbmImage);
2169 himl->hbmImage = hbmNewImage;
2170 if (himl->hbmMask) {
2171 SelectObject (himl->hdcMask, hbmNewMask);
2172 DeleteObject (himl->hbmMask);
2173 himl->hbmMask = hbmNewMask;
2176 himl->cCurImage--;
2177 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2180 return TRUE;
2184 /*************************************************************************
2185 * ImageList_Replace [COMCTL32.@]
2187 * Replaces an image in an image list with a new image.
2189 * PARAMS
2190 * himl [I] handle to image list
2191 * i [I] image index
2192 * hbmImage [I] handle to image bitmap
2193 * hbmMask [I] handle to mask bitmap. Can be NULL.
2195 * RETURNS
2196 * Success: TRUE
2197 * Failure: FALSE
2200 BOOL WINAPI
2201 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2202 HBITMAP hbmMask)
2204 HDC hdcImage;
2205 BITMAP bmp;
2206 HBITMAP hOldBitmap;
2207 POINT pt;
2209 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2211 if (!is_valid(himl)) {
2212 ERR("Invalid image list handle!\n");
2213 return FALSE;
2216 if ((i >= himl->cMaxImage) || (i < 0)) {
2217 ERR("Invalid image index!\n");
2218 return FALSE;
2221 if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
2222 return FALSE;
2224 hdcImage = CreateCompatibleDC (0);
2226 /* Replace Image */
2227 hOldBitmap = SelectObject (hdcImage, hbmImage);
2229 imagelist_point_from_index(himl, i, &pt);
2230 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2231 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2233 if (himl->hbmMask)
2235 HDC hdcTemp;
2236 HBITMAP hOldBitmapTemp;
2238 hdcTemp = CreateCompatibleDC(0);
2239 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
2241 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2242 hdcTemp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2243 SelectObject(hdcTemp, hOldBitmapTemp);
2244 DeleteDC(hdcTemp);
2246 /* Remove the background from the image
2248 BitBlt (himl->hdcImage, pt.x, pt.y, bmp.bmWidth, bmp.bmHeight,
2249 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
2252 SelectObject (hdcImage, hOldBitmap);
2253 DeleteDC (hdcImage);
2255 return TRUE;
2259 /*************************************************************************
2260 * ImageList_ReplaceIcon [COMCTL32.@]
2262 * Replaces an image in an image list using an icon.
2264 * PARAMS
2265 * himl [I] handle to image list
2266 * i [I] image index
2267 * hIcon [I] handle to icon
2269 * RETURNS
2270 * Success: index of the replaced image
2271 * Failure: -1
2274 INT WINAPI
2275 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2277 HDC hdcImage;
2278 INT nIndex;
2279 HICON hBestFitIcon;
2280 HBITMAP hbmOldSrc;
2281 ICONINFO ii;
2282 BITMAP bmp;
2283 BOOL ret;
2284 POINT pt;
2286 TRACE("(%p %d %p)\n", himl, i, hIcon);
2288 if (!is_valid(himl)) {
2289 ERR("invalid image list\n");
2290 return -1;
2292 if ((i >= himl->cMaxImage) || (i < -1)) {
2293 ERR("invalid image index %d / %d\n", i, himl->cMaxImage);
2294 return -1;
2297 hBestFitIcon = CopyImage(
2298 hIcon, IMAGE_ICON,
2299 himl->cx, himl->cy,
2300 LR_COPYFROMRESOURCE);
2301 /* the above will fail if the icon wasn't loaded from a resource, so try
2302 * again without LR_COPYFROMRESOURCE flag */
2303 if (!hBestFitIcon)
2304 hBestFitIcon = CopyImage(
2305 hIcon, IMAGE_ICON,
2306 himl->cx, himl->cy,
2308 if (!hBestFitIcon)
2309 return -1;
2311 ret = GetIconInfo (hBestFitIcon, &ii);
2312 if (!ret) {
2313 DestroyIcon(hBestFitIcon);
2314 return -1;
2317 if (ii.hbmColor == 0)
2318 ERR("no color!\n");
2319 ret = GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2320 if (!ret) {
2321 ERR("couldn't get mask bitmap info\n");
2322 if (ii.hbmColor)
2323 DeleteObject (ii.hbmColor);
2324 if (ii.hbmMask)
2325 DeleteObject (ii.hbmMask);
2326 DestroyIcon(hBestFitIcon);
2327 return -1;
2330 if (i == -1) {
2331 if (himl->cCurImage + 1 > himl->cMaxImage)
2332 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2334 nIndex = himl->cCurImage;
2335 himl->cCurImage++;
2337 else
2338 nIndex = i;
2340 hdcImage = CreateCompatibleDC (0);
2341 TRACE("hdcImage=%p\n", hdcImage);
2342 if (hdcImage == 0)
2343 ERR("invalid hdcImage!\n");
2345 SetTextColor(himl->hdcImage, RGB(0,0,0));
2346 SetBkColor (himl->hdcImage, RGB(255,255,255));
2347 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2349 imagelist_point_from_index(himl, nIndex, &pt);
2350 StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
2351 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2353 if (himl->hbmMask) {
2354 SelectObject (hdcImage, ii.hbmMask);
2355 StretchBlt (himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
2356 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2359 SelectObject (hdcImage, hbmOldSrc);
2361 DestroyIcon(hBestFitIcon);
2362 if (hdcImage)
2363 DeleteDC (hdcImage);
2364 if (ii.hbmColor)
2365 DeleteObject (ii.hbmColor);
2366 if (ii.hbmMask)
2367 DeleteObject (ii.hbmMask);
2369 TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage);
2370 return nIndex;
2374 /*************************************************************************
2375 * ImageList_SetBkColor [COMCTL32.@]
2377 * Sets the background color of an image list.
2379 * PARAMS
2380 * himl [I] handle to image list
2381 * clrBk [I] background color
2383 * RETURNS
2384 * Success: previous background color
2385 * Failure: CLR_NONE
2388 COLORREF WINAPI
2389 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2391 COLORREF clrOldBk;
2393 if (!is_valid(himl))
2394 return CLR_NONE;
2396 clrOldBk = himl->clrBk;
2397 himl->clrBk = clrBk;
2398 return clrOldBk;
2402 /*************************************************************************
2403 * ImageList_SetDragCursorImage [COMCTL32.@]
2405 * Combines the specified image with the current drag image
2407 * PARAMS
2408 * himlDrag [I] handle to drag image list
2409 * iDrag [I] drag image index
2410 * dxHotspot [I] X position of the hot spot
2411 * dyHotspot [I] Y position of the hot spot
2413 * RETURNS
2414 * Success: TRUE
2415 * Failure: FALSE
2417 * NOTES
2418 * - The names dxHotspot, dyHotspot are misleading because they have nothing
2419 * to do with a hotspot but are only the offset of the origin of the new
2420 * image relative to the origin of the old image.
2422 * - When this function is called and the drag image is visible, a
2423 * short flickering occurs but this matches the Win9x behavior. It is
2424 * possible to fix the flickering using code like in ImageList_DragMove.
2427 BOOL WINAPI
2428 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2429 INT dxHotspot, INT dyHotspot)
2431 HIMAGELIST himlTemp;
2432 BOOL visible;
2434 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2435 return FALSE;
2437 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2438 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2440 visible = InternalDrag.bShow;
2442 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag,
2443 dxHotspot, dyHotspot);
2445 if (visible) {
2446 /* hide the drag image */
2447 ImageList_DragShowNolock(FALSE);
2449 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2450 (InternalDrag.himl->cy != himlTemp->cy)) {
2451 /* the size of the drag image changed, invalidate the buffer */
2452 DeleteObject(InternalDrag.hbmBg);
2453 InternalDrag.hbmBg = 0;
2456 ImageList_Destroy (InternalDrag.himl);
2457 InternalDrag.himl = himlTemp;
2459 if (visible) {
2460 /* show the drag image */
2461 ImageList_DragShowNolock(TRUE);
2464 return TRUE;
2468 /*************************************************************************
2469 * ImageList_SetFilter [COMCTL32.@]
2471 * Sets a filter (or does something completely different)!!???
2472 * It removes 12 Bytes from the stack (3 Parameters).
2474 * PARAMS
2475 * himl [I] SHOULD be a handle to image list
2476 * i [I] COULD be an index?
2477 * dwFilter [I] ???
2479 * RETURNS
2480 * Success: TRUE ???
2481 * Failure: FALSE ???
2483 * BUGS
2484 * This is an UNDOCUMENTED function!!!!
2485 * empty stub.
2488 BOOL WINAPI
2489 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2491 FIXME("(%p 0x%x 0x%x):empty stub!\n", himl, i, dwFilter);
2493 return FALSE;
2497 /*************************************************************************
2498 * ImageList_SetFlags [COMCTL32.@]
2500 * Sets the image list flags.
2502 * PARAMS
2503 * himl [I] Handle to image list
2504 * flags [I] Flags to set
2506 * RETURNS
2507 * Old flags?
2509 * BUGS
2510 * Stub.
2513 DWORD WINAPI
2514 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2516 FIXME("(%p %08x):empty stub\n", himl, flags);
2517 return 0;
2521 /*************************************************************************
2522 * ImageList_SetIconSize [COMCTL32.@]
2524 * Sets the image size of the bitmap and deletes all images.
2526 * PARAMS
2527 * himl [I] handle to image list
2528 * cx [I] image width
2529 * cy [I] image height
2531 * RETURNS
2532 * Success: TRUE
2533 * Failure: FALSE
2536 BOOL WINAPI
2537 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2539 INT nCount;
2540 HBITMAP hbmNew;
2542 if (!is_valid(himl))
2543 return FALSE;
2545 /* remove all images */
2546 himl->cMaxImage = himl->cInitial + himl->cGrow;
2547 himl->cCurImage = 0;
2548 himl->cx = cx;
2549 himl->cy = cy;
2551 /* initialize overlay mask indices */
2552 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2553 himl->nOvlIdx[nCount] = -1;
2555 hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cy);
2556 SelectObject (himl->hdcImage, hbmNew);
2557 DeleteObject (himl->hbmImage);
2558 himl->hbmImage = hbmNew;
2560 if (himl->hbmMask) {
2561 SIZE sz;
2562 imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cy, &sz);
2563 hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2564 SelectObject (himl->hdcMask, hbmNew);
2565 DeleteObject (himl->hbmMask);
2566 himl->hbmMask = hbmNew;
2569 return TRUE;
2573 /*************************************************************************
2574 * ImageList_SetImageCount [COMCTL32.@]
2576 * Resizes an image list to the specified number of images.
2578 * PARAMS
2579 * himl [I] handle to image list
2580 * iImageCount [I] number of images in the image list
2582 * RETURNS
2583 * Success: TRUE
2584 * Failure: FALSE
2587 BOOL WINAPI
2588 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2590 HDC hdcBitmap;
2591 HBITMAP hbmNewBitmap;
2592 INT nNewCount, nCopyCount;
2594 TRACE("%p %d\n",himl,iImageCount);
2596 if (!is_valid(himl))
2597 return FALSE;
2598 if (iImageCount < 0)
2599 return FALSE;
2600 if (himl->cMaxImage > iImageCount)
2602 himl->cCurImage = iImageCount;
2603 /* TODO: shrink the bitmap when cMaxImage-cCurImage>cGrow ? */
2604 return TRUE;
2607 nNewCount = iImageCount + himl->cGrow;
2608 nCopyCount = min(himl->cCurImage, iImageCount);
2610 hdcBitmap = CreateCompatibleDC (0);
2612 hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cy);
2614 if (hbmNewBitmap != 0)
2616 SelectObject (hdcBitmap, hbmNewBitmap);
2617 imagelist_copy_images( himl, himl->hdcImage, hdcBitmap, 0, nCopyCount, 0 );
2619 /* FIXME: delete 'empty' image space? */
2621 SelectObject (himl->hdcImage, hbmNewBitmap);
2622 DeleteObject (himl->hbmImage);
2623 himl->hbmImage = hbmNewBitmap;
2625 else
2626 ERR("Could not create new image bitmap !\n");
2628 if (himl->hbmMask)
2630 SIZE sz;
2631 imagelist_get_bitmap_size( himl, nNewCount, himl->cy, &sz );
2632 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
2633 if (hbmNewBitmap != 0)
2635 SelectObject (hdcBitmap, hbmNewBitmap);
2636 imagelist_copy_images( himl, himl->hdcMask, hdcBitmap, 0, nCopyCount, 0 );
2638 /* FIXME: delete 'empty' image space? */
2640 SelectObject (himl->hdcMask, hbmNewBitmap);
2641 DeleteObject (himl->hbmMask);
2642 himl->hbmMask = hbmNewBitmap;
2644 else
2645 ERR("Could not create new mask bitmap!\n");
2648 DeleteDC (hdcBitmap);
2650 /* Update max image count and current image count */
2651 himl->cMaxImage = nNewCount;
2652 himl->cCurImage = iImageCount;
2654 return TRUE;
2658 /*************************************************************************
2659 * ImageList_SetOverlayImage [COMCTL32.@]
2661 * Assigns an overlay mask index to an existing image in an image list.
2663 * PARAMS
2664 * himl [I] handle to image list
2665 * iImage [I] image index
2666 * iOverlay [I] overlay mask index
2668 * RETURNS
2669 * Success: TRUE
2670 * Failure: FALSE
2673 BOOL WINAPI
2674 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2676 if (!is_valid(himl))
2677 return FALSE;
2678 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2679 return FALSE;
2680 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2681 return FALSE;
2682 himl->nOvlIdx[iOverlay - 1] = iImage;
2683 return TRUE;
2688 /* helper for ImageList_Write - write bitmap to pstm
2689 * currently everything is written as 24 bit RGB, except masks
2691 static BOOL
2692 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2694 LPBITMAPFILEHEADER bmfh;
2695 LPBITMAPINFOHEADER bmih;
2696 LPBYTE data = NULL, lpBits = NULL, lpBitsOrg = NULL;
2697 BITMAP bm;
2698 INT bitCount, sizeImage, offBits, totalSize;
2699 INT nwidth, nheight, nsizeImage, icount;
2700 HDC xdc;
2701 BOOL result = FALSE;
2704 xdc = GetDC(0);
2705 if (!GetObjectW(hBitmap, sizeof(BITMAP), (LPVOID)&bm))
2706 goto failed;
2708 /* XXX is this always correct? */
2709 icount = bm.bmWidth / cx;
2710 nwidth = cx;
2711 nheight = cy * icount;
2713 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2714 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2715 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2717 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2718 if(bitCount != 24)
2719 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2720 offBits = totalSize;
2721 totalSize += nsizeImage;
2723 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2724 bmfh = (LPBITMAPFILEHEADER)data;
2725 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2726 lpBits = data + offBits;
2728 /* setup BITMAPFILEHEADER */
2729 bmfh->bfType = (('M' << 8) | 'B');
2730 bmfh->bfSize = 0;
2731 bmfh->bfReserved1 = 0;
2732 bmfh->bfReserved2 = 0;
2733 bmfh->bfOffBits = offBits;
2735 /* setup BITMAPINFOHEADER */
2736 bmih->biSize = sizeof(BITMAPINFOHEADER);
2737 bmih->biWidth = bm.bmWidth;
2738 bmih->biHeight = bm.bmHeight;
2739 bmih->biPlanes = 1;
2740 bmih->biBitCount = bitCount;
2741 bmih->biCompression = BI_RGB;
2742 bmih->biSizeImage = sizeImage;
2743 bmih->biXPelsPerMeter = 0;
2744 bmih->biYPelsPerMeter = 0;
2745 bmih->biClrUsed = 0;
2746 bmih->biClrImportant = 0;
2748 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2749 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2750 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2751 goto failed;
2752 else {
2753 int i;
2754 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2755 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2757 for(i = 0; i < nheight; i++) {
2758 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2759 int noff = (nbpl * (nheight-1-i));
2760 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2764 bmih->biWidth = nwidth;
2765 bmih->biHeight = nheight;
2766 bmih->biSizeImage = nsizeImage;
2768 if(bitCount == 1) {
2769 /* Hack. */
2770 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2771 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2772 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2775 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2776 goto failed;
2778 result = TRUE;
2780 failed:
2781 ReleaseDC(0, xdc);
2782 LocalFree((HLOCAL)lpBitsOrg);
2783 LocalFree((HLOCAL)data);
2785 return result;
2789 /*************************************************************************
2790 * ImageList_Write [COMCTL32.@]
2792 * Writes an image list to a stream.
2794 * PARAMS
2795 * himl [I] handle to image list
2796 * pstm [O] Pointer to a stream.
2798 * RETURNS
2799 * Success: TRUE
2800 * Failure: FALSE
2802 * BUGS
2803 * probably.
2806 BOOL WINAPI
2807 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2809 ILHEAD ilHead;
2810 int i;
2812 if (!is_valid(himl))
2813 return FALSE;
2815 ilHead.usMagic = (('L' << 8) | 'I');
2816 ilHead.usVersion = 0x101;
2817 ilHead.cCurImage = himl->cCurImage;
2818 ilHead.cMaxImage = himl->cMaxImage;
2819 ilHead.cGrow = himl->cGrow;
2820 ilHead.cx = himl->cx;
2821 ilHead.cy = himl->cy;
2822 ilHead.bkcolor = himl->clrBk;
2823 ilHead.flags = himl->flags;
2824 for(i = 0; i < 4; i++) {
2825 ilHead.ovls[i] = himl->nOvlIdx[i];
2828 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2829 return FALSE;
2831 /* write the bitmap */
2832 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2833 return FALSE;
2835 /* write the mask if we have one */
2836 if(himl->flags & ILC_MASK) {
2837 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2838 return FALSE;
2841 return TRUE;
2845 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT height)
2847 HBITMAP hbmNewBitmap;
2848 UINT ilc = (himl->flags & 0xFE);
2849 SIZE sz;
2851 imagelist_get_bitmap_size( himl, count, height, &sz );
2853 if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
2855 VOID* bits;
2856 BITMAPINFO *bmi;
2858 TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel);
2860 if (himl->uBitsPixel <= ILC_COLOR8)
2862 LPPALETTEENTRY pal;
2863 ULONG i, colors;
2864 BYTE temp;
2866 colors = 1 << himl->uBitsPixel;
2867 bmi = Alloc(sizeof(BITMAPINFOHEADER) +
2868 sizeof(PALETTEENTRY) * colors);
2870 pal = (LPPALETTEENTRY)bmi->bmiColors;
2871 GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal);
2873 /* Swap colors returned by GetPaletteEntries so we can use them for
2874 * CreateDIBSection call. */
2875 for (i = 0; i < colors; i++)
2877 temp = pal[i].peBlue;
2878 bmi->bmiColors[i].rgbRed = pal[i].peRed;
2879 bmi->bmiColors[i].rgbBlue = temp;
2882 else
2884 bmi = Alloc(sizeof(BITMAPINFOHEADER));
2887 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2888 bmi->bmiHeader.biWidth = sz.cx;
2889 bmi->bmiHeader.biHeight = sz.cy;
2890 bmi->bmiHeader.biPlanes = 1;
2891 bmi->bmiHeader.biBitCount = himl->uBitsPixel;
2892 bmi->bmiHeader.biCompression = BI_RGB;
2893 bmi->bmiHeader.biSizeImage = 0;
2894 bmi->bmiHeader.biXPelsPerMeter = 0;
2895 bmi->bmiHeader.biYPelsPerMeter = 0;
2896 bmi->bmiHeader.biClrUsed = 0;
2897 bmi->bmiHeader.biClrImportant = 0;
2899 hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0);
2901 Free (bmi);
2903 else /*if (ilc == ILC_COLORDDB)*/
2905 TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel);
2907 hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, himl->uBitsPixel, NULL);
2909 TRACE("returning %p\n", hbmNewBitmap);
2910 return hbmNewBitmap;
2913 /*************************************************************************
2914 * ImageList_SetColorTable [COMCTL32.@]
2916 * Sets the color table of an image list.
2918 * PARAMS
2919 * himl [I] Handle to the image list.
2920 * uStartIndex [I] The first index to set.
2921 * cEntries [I] Number of entries to set.
2922 * prgb [I] New color information for color table for the image list.
2924 * RETURNS
2925 * Success: Number of entries in the table that were set.
2926 * Failure: Zero.
2928 * SEE
2929 * ImageList_Create(), SetDIBColorTable()
2932 UINT WINAPI
2933 ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb)
2935 return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);