- fix the "int format, HANDLE arg" type of warnings for comctl32
[wine/multimedia.git] / dlls / comctl32 / imagelist.c
blob4afb9eae0ec58feeffc31cc467c7d4a591c28de8
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 belive this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
33 * TODO:
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
37 * FIXME:
38 * - Hotspot handling still not correct. The Hotspot passed to BeginDrag
39 * is the offset of the image position relative to the actual mouse pointer
40 * position. However the Hotspot passed to SetDragCursorImage is the
41 * offset of the mouse messages sent to the application...
44 #include <stdlib.h>
45 #include <string.h>
46 #include "winerror.h"
47 #include "winbase.h"
48 #include "wine/obj_base.h"
49 #include "wine/obj_storage.h"
50 #include "commctrl.h"
51 #include "imagelist.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
57 #define MAX_OVERLAYIMAGE 15
59 /* internal image list data used for Drag & Drop operations */
60 typedef struct
62 HWND hwnd;
63 HIMAGELIST himl;
64 /* position of the drag image relative to the window */
65 INT x;
66 INT y;
67 /* offset of the hotspot relative to the origin of the image */
68 INT dxHotspot;
69 INT dyHotspot;
70 /* is the drag image visible */
71 BOOL bShow;
72 /* saved background */
73 HBITMAP hbmBg;
74 BOOL bHSPending;
75 } INTERNALDRAG;
77 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
81 /*************************************************************************
82 * IMAGELIST_InternalExpandBitmaps [Internal]
84 * Expands the bitmaps of an image list by the given number of images.
86 * PARAMS
87 * himl [I] handle to image list
88 * nImageCount [I] number of images to add
90 * RETURNS
91 * nothing
93 * NOTES
94 * This function can NOT be used to reduce the number of images.
96 static void
97 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
99 HDC hdcImageList, hdcBitmap;
100 HBITMAP hbmNewBitmap;
101 INT nNewWidth, nNewCount;
103 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
104 && (himl->cy >= cy))
105 return;
107 if (cy == 0) cy = himl->cy;
108 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
109 nNewWidth = nNewCount * himl->cx;
111 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
112 hdcImageList = CreateCompatibleDC (0);
113 hdcBitmap = CreateCompatibleDC (0);
115 hbmNewBitmap =
116 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
117 if (hbmNewBitmap == 0)
118 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
120 SelectObject (hdcImageList, himl->hbmImage);
121 SelectObject (hdcBitmap, hbmNewBitmap);
122 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
123 hdcImageList, 0, 0, SRCCOPY);
125 DeleteObject (himl->hbmImage);
126 himl->hbmImage = hbmNewBitmap;
128 if (himl->hbmMask) {
129 hbmNewBitmap =
130 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
132 if (hbmNewBitmap == 0)
133 ERR("creating new mask bitmap!\n");
135 SelectObject (hdcImageList, himl->hbmMask);
136 SelectObject (hdcBitmap, hbmNewBitmap);
137 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
138 hdcImageList, 0, 0, SRCCOPY);
139 DeleteObject (himl->hbmMask);
140 himl->hbmMask = hbmNewBitmap;
143 himl->cMaxImage = nNewCount;
145 DeleteDC (hdcImageList);
146 DeleteDC (hdcBitmap);
150 /*************************************************************************
151 * ImageList_Add [COMCTL32.@]
153 * Add an image or images to an image list.
155 * PARAMS
156 * himl [I] handle to image list
157 * hbmImage [I] handle to image bitmap
158 * hbmMask [I] handle to mask bitmap
160 * RETURNS
161 * Success: Index of the first new image.
162 * Failure: -1
165 INT WINAPI
166 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
168 HDC hdcImage, hdcBitmap;
169 INT nFirstIndex, nImageCount;
170 INT nStartX;
171 BITMAP bmp;
172 HBITMAP hOldBitmapImage, hOldBitmap;
174 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
175 if (!himl || !hbmImage)
176 return -1;
178 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
179 nImageCount = bmp.bmWidth / himl->cx;
181 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
183 nStartX = himl->cCurImage * himl->cx;
185 hdcImage = CreateCompatibleDC(0);
186 hdcBitmap = CreateCompatibleDC(0);
188 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
189 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
191 /* Copy result to the imagelist
193 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
194 hdcBitmap, 0, 0, SRCCOPY);
196 if(himl->hbmMask)
198 HDC hdcMask, hdcTemp;
199 HBITMAP hOldBitmapMask, hOldBitmapTemp;
201 hdcMask = CreateCompatibleDC (0);
202 hdcTemp = CreateCompatibleDC(0);
203 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
204 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
206 BitBlt (hdcMask,
207 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
208 hdcTemp,
209 0, 0,
210 SRCCOPY);
212 SelectObject(hdcTemp, hOldBitmapTemp);
213 DeleteDC(hdcTemp);
215 /* Remove the background from the image
217 BitBlt (hdcImage,
218 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
219 hdcMask,
220 nStartX, 0,
221 0x220326); /* NOTSRCAND */
223 SelectObject(hdcMask, hOldBitmapMask);
224 DeleteDC(hdcMask);
227 SelectObject(hdcImage, hOldBitmapImage);
228 SelectObject(hdcBitmap, hOldBitmap);
229 DeleteDC(hdcImage);
230 DeleteDC(hdcBitmap);
232 nFirstIndex = himl->cCurImage;
233 himl->cCurImage += nImageCount;
235 return nFirstIndex;
239 /*************************************************************************
240 * ImageList_AddIcon [COMCTL32.@]
242 * Adds an icon to an image list.
244 * PARAMS
245 * himl [I] handle to image list
246 * hIcon [I] handle to icon
248 * RETURNS
249 * Success: index of the new image
250 * Failure: -1
253 INT WINAPI
254 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
256 return ImageList_ReplaceIcon (himl, -1, hIcon);
260 /*************************************************************************
261 * ImageList_AddMasked [COMCTL32.@]
263 * Adds an image or images to an image list and creates a mask from the
264 * specified bitmap using the mask color.
266 * PARAMS
267 * himl [I] handle to image list.
268 * hBitmap [I] handle to bitmap
269 * clrMask [I] mask color.
271 * RETURNS
272 * Success: Index of the first new image.
273 * Failure: -1
276 INT WINAPI
277 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
279 HDC hdcImage, hdcMask, hdcBitmap;
280 INT nIndex, nImageCount, nMaskXOffset=0;
281 BITMAP bmp;
282 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
283 HBITMAP hMaskBitmap=0;
284 COLORREF bkColor;
286 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
287 if (himl == NULL)
288 return -1;
290 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
291 return -1;
293 nImageCount = bmp.bmWidth / himl->cx;
295 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
297 nIndex = himl->cCurImage;
298 himl->cCurImage += nImageCount;
300 hdcMask = CreateCompatibleDC (0);
301 hdcImage = CreateCompatibleDC(0);
302 hdcBitmap = CreateCompatibleDC(0);
305 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
306 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
307 if(himl->hbmMask)
309 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
310 nMaskXOffset = nIndex * himl->cx;
312 else
315 Create a temp Mask so we can remove the background of
316 the Image (Windows does this even if there is no mask)
318 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
319 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
320 nMaskXOffset = 0;
322 /* create monochrome image to the mask bitmap */
323 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
324 GetPixel (hdcBitmap, 0, 0);
325 SetBkColor (hdcBitmap, bkColor);
326 BitBlt (hdcMask,
327 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
328 hdcBitmap, 0, 0,
329 SRCCOPY);
331 SetBkColor(hdcBitmap, RGB(255,255,255));
332 /*Remove the background from the image
335 WINDOWS BUG ALERT!!!!!!
336 The statement below should not be done in common practice
337 but this is how ImageList_AddMasked works in Windows.
338 It overwrites the original bitmap passed, this was discovered
339 by using the same bitmap to iterate the different styles
340 on windows where it failed (BUT ImageList_Add is OK)
341 This is here in case some apps rely on this bug
343 BitBlt(hdcBitmap,
344 0, 0, bmp.bmWidth, bmp.bmHeight,
345 hdcMask,
346 nMaskXOffset, 0,
347 0x220326); /* NOTSRCAND */
348 /* Copy result to the imagelist
350 BitBlt (hdcImage,
351 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
352 hdcBitmap,
353 0, 0,
354 SRCCOPY);
355 /* Clean up
357 SelectObject(hdcMask,hOldBitmapMask);
358 SelectObject(hdcImage, hOldBitmapImage);
359 SelectObject(hdcBitmap, hOldBitmap);
360 DeleteDC(hdcMask);
361 DeleteDC(hdcImage);
362 DeleteDC(hdcBitmap);
363 if(!himl->hbmMask)
365 DeleteObject(hMaskBitmap);
368 return nIndex;
372 /*************************************************************************
373 * ImageList_BeginDrag [COMCTL32.@]
375 * Creates a temporary image list that contains one image. It will be used
376 * as a drag image.
378 * PARAMS
379 * himlTrack [I] handle to the source image list
380 * iTrack [I] index of the drag image in the source image list
381 * dxHotspot [I] X position of the hot spot of the drag image
382 * dyHotspot [I] Y position of the hot spot of the drag image
384 * RETURNS
385 * Success: TRUE
386 * Failure: FALSE
389 BOOL WINAPI
390 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
391 INT dxHotspot, INT dyHotspot)
393 HDC hdcSrc, hdcDst;
394 INT cx, cy;
396 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
397 dxHotspot, dyHotspot);
399 if (himlTrack == NULL)
400 return FALSE;
402 if (InternalDrag.himl)
403 ImageList_EndDrag ();
405 cx = himlTrack->cx;
406 cy = himlTrack->cy;
408 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
409 if (InternalDrag.himl == NULL) {
410 WARN("Error creating drag image list!\n");
411 return FALSE;
414 InternalDrag.dxHotspot = dxHotspot;
415 InternalDrag.dyHotspot = dyHotspot;
417 hdcSrc = CreateCompatibleDC (0);
418 hdcDst = CreateCompatibleDC (0);
420 /* copy image */
421 SelectObject (hdcSrc, himlTrack->hbmImage);
422 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
423 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
425 /* copy mask */
426 SelectObject (hdcSrc, himlTrack->hbmMask);
427 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
428 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
430 DeleteDC (hdcSrc);
431 DeleteDC (hdcDst);
433 InternalDrag.himl->cCurImage = 1;
434 InternalDrag.bHSPending = TRUE;
436 return TRUE;
440 /*************************************************************************
441 * ImageList_Copy [COMCTL32.@]
443 * Copies an image of the source image list to an image of the
444 * destination image list. Images can be copied or swapped.
446 * PARAMS
447 * himlDst [I] handle to the destination image list
448 * iDst [I] destination image index.
449 * himlSrc [I] handle to the source image list
450 * iSrc [I] source image index
451 * uFlags [I] flags for the copy operation
453 * RETURNS
454 * Success: TRUE
455 * Failure: FALSE
457 * NOTES
458 * Copying from one image list to another is possible. The original
459 * implementation just copies or swaps within one image list.
460 * Could this feature become a bug??? ;-)
463 BOOL WINAPI
464 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
465 INT iSrc, INT uFlags)
467 HDC hdcSrc, hdcDst;
469 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
471 if ((himlSrc == NULL) || (himlDst == NULL))
472 return FALSE;
473 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
474 return FALSE;
475 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
476 return FALSE;
478 hdcSrc = CreateCompatibleDC (0);
479 if (himlDst == himlSrc)
480 hdcDst = hdcSrc;
481 else
482 hdcDst = CreateCompatibleDC (0);
484 if (uFlags & ILCF_SWAP) {
485 /* swap */
486 HBITMAP hbmTempImage, hbmTempMask;
488 /* create temporary bitmaps */
489 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
490 himlSrc->uBitsPixel, NULL);
491 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
492 1, NULL);
494 /* copy (and stretch) destination to temporary bitmaps.(save) */
495 /* image */
496 SelectObject (hdcSrc, himlDst->hbmImage);
497 SelectObject (hdcDst, hbmTempImage);
498 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
499 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
500 SRCCOPY);
501 /* mask */
502 SelectObject (hdcSrc, himlDst->hbmMask);
503 SelectObject (hdcDst, hbmTempMask);
504 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
505 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
506 SRCCOPY);
508 /* copy (and stretch) source to destination */
509 /* image */
510 SelectObject (hdcSrc, himlSrc->hbmImage);
511 SelectObject (hdcDst, himlDst->hbmImage);
512 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
513 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
514 SRCCOPY);
515 /* mask */
516 SelectObject (hdcSrc, himlSrc->hbmMask);
517 SelectObject (hdcDst, himlDst->hbmMask);
518 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
519 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
520 SRCCOPY);
522 /* copy (without stretching) temporary bitmaps to source (restore) */
523 /* image */
524 SelectObject (hdcSrc, hbmTempImage);
525 SelectObject (hdcDst, himlSrc->hbmImage);
526 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
527 hdcSrc, 0, 0, SRCCOPY);
528 /* mask */
529 SelectObject (hdcSrc, hbmTempMask);
530 SelectObject (hdcDst, himlSrc->hbmMask);
531 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
532 hdcSrc, 0, 0, SRCCOPY);
534 /* delete temporary bitmaps */
535 DeleteObject (hbmTempMask);
536 DeleteObject (hbmTempImage);
538 else {
539 /* copy image */
540 SelectObject (hdcSrc, himlSrc->hbmImage);
541 if (himlSrc == himlDst)
542 hdcDst = hdcSrc;
543 else
544 SelectObject (hdcDst, himlDst->hbmImage);
545 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
546 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
547 SRCCOPY);
549 /* copy mask */
550 SelectObject (hdcSrc, himlSrc->hbmMask);
551 if (himlSrc == himlDst)
552 hdcDst = hdcSrc;
553 else
554 SelectObject (hdcDst, himlDst->hbmMask);
555 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
556 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
557 SRCCOPY);
560 DeleteDC (hdcSrc);
561 if (himlSrc != himlDst)
562 DeleteDC (hdcDst);
564 return TRUE;
568 /*************************************************************************
569 * ImageList_Create [COMCTL32.@] Creates a new image list.
571 * PARAMS
572 * cx [I] image height
573 * cy [I] image width
574 * flags [I] creation flags
575 * cInitial [I] initial number of images in the image list
576 * cGrow [I] number of images by which image list grows
578 * RETURNS
579 * Success: Handle to the created image list
580 * Failure: NULL
583 HIMAGELIST WINAPI
584 ImageList_Create (INT cx, INT cy, UINT flags,
585 INT cInitial, INT cGrow)
587 HIMAGELIST himl;
588 HDC hdc;
589 INT nCount;
590 HBITMAP hbmTemp;
591 static WORD aBitBlend25[] =
592 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
594 static WORD aBitBlend50[] =
595 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
597 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
599 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
600 if (!himl)
601 return NULL;
603 himl->cx = cx;
604 himl->cy = cy;
605 himl->flags = flags;
606 himl->cMaxImage = cInitial + cGrow;
607 himl->cInitial = cInitial;
608 himl->cGrow = cGrow;
609 himl->cCurImage = 0;
610 himl->clrFg = CLR_DEFAULT;
611 himl->clrBk = CLR_NONE;
613 /* initialize overlay mask indices */
614 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
615 himl->nOvlIdx[nCount] = -1;
617 hdc = CreateCompatibleDC (0);
618 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
619 DeleteDC (hdc);
621 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
623 if (himl->cMaxImage > 0) {
624 himl->hbmImage =
625 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
626 1, himl->uBitsPixel, NULL);
627 if (himl->hbmImage == 0) {
628 ERR("Error creating image bitmap!\n");
629 return NULL;
632 else
633 himl->hbmImage = 0;
635 if ( (himl->flags & ILC_MASK)) {
636 int images = himl->cMaxImage;
637 if (images <= 0)
638 images = 1;
640 himl->hbmMask = CreateBitmap (himl->cx * images, himl->cy,
641 1, 1, NULL);
642 if (himl->hbmMask == 0) {
643 ERR("Error creating mask bitmap!\n");
644 if (himl->hbmImage)
645 DeleteObject (himl->hbmImage);
646 return NULL;
649 else
650 himl->hbmMask = 0;
652 /* create blending brushes */
653 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
654 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
655 DeleteObject (hbmTemp);
657 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
658 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
659 DeleteObject (hbmTemp);
661 TRACE("created imagelist %p\n", himl);
662 return himl;
666 /*************************************************************************
667 * ImageList_Destroy [COMCTL32.@]
669 * Destroys an image list.
671 * PARAMS
672 * himl [I] handle to image list
674 * RETURNS
675 * Success: TRUE
676 * Failure: FALSE
679 BOOL WINAPI
680 ImageList_Destroy (HIMAGELIST himl)
682 if (!himl)
683 return FALSE;
685 /* delete image bitmaps */
686 if (himl->hbmImage)
687 DeleteObject (himl->hbmImage);
688 if (himl->hbmMask)
689 DeleteObject (himl->hbmMask);
691 /* delete blending brushes */
692 if (himl->hbrBlend25)
693 DeleteObject (himl->hbrBlend25);
694 if (himl->hbrBlend50)
695 DeleteObject (himl->hbrBlend50);
697 COMCTL32_Free (himl);
699 return TRUE;
703 /*************************************************************************
704 * ImageList_DragEnter [COMCTL32.@]
706 * Locks window update and displays the drag image at the given position.
708 * PARAMS
709 * hwndLock [I] handle of the window that owns the drag image.
710 * x [I] X position of the drag image.
711 * y [I] Y position of the drag image.
713 * RETURNS
714 * Success: TRUE
715 * Failure: FALSE
717 * NOTES
718 * The position of the drag image is relative to the window, not
719 * the client area.
722 BOOL WINAPI
723 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
725 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
727 if (InternalDrag.himl == NULL)
728 return FALSE;
730 if (hwndLock)
731 InternalDrag.hwnd = hwndLock;
732 else
733 InternalDrag.hwnd = GetDesktopWindow ();
735 InternalDrag.x = x;
736 InternalDrag.y = y;
738 /* draw the drag image and save the background */
739 if (!ImageList_DragShowNolock(TRUE)) {
740 return FALSE;
743 return TRUE;
747 /*************************************************************************
748 * ImageList_DragLeave [COMCTL32.@]
750 * Unlocks window update and hides the drag image.
752 * PARAMS
753 * hwndLock [I] handle of the window that owns the drag image.
755 * RETURNS
756 * Success: TRUE
757 * Failure: FALSE
760 BOOL WINAPI
761 ImageList_DragLeave (HWND hwndLock)
763 /* As we don't save drag info in the window this can lead to problems if
764 an app does not supply the same window as DragEnter */
765 /* if (hwndLock)
766 InternalDrag.hwnd = hwndLock;
767 else
768 InternalDrag.hwnd = GetDesktopWindow (); */
769 if(!hwndLock)
770 hwndLock = GetDesktopWindow();
771 if(InternalDrag.hwnd != hwndLock)
772 FIXME("DragLeave hWnd != DragEnter hWnd\n");
774 ImageList_DragShowNolock (FALSE);
776 return TRUE;
780 /*************************************************************************
781 * ImageList_InternalDragDraw [Internal]
783 * Draws the drag image.
785 * PARAMS
786 * hdc [I] device context to draw into.
787 * x [I] X position of the drag image.
788 * y [I] Y position of the drag image.
790 * RETURNS
791 * Success: TRUE
792 * Failure: FALSE
794 * NOTES
795 * The position of the drag image is relative to the window, not
796 * the client area.
800 static inline void
801 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
803 IMAGELISTDRAWPARAMS imldp;
805 ZeroMemory (&imldp, sizeof(imldp));
806 imldp.cbSize = sizeof(imldp);
807 imldp.himl = InternalDrag.himl;
808 imldp.i = 0;
809 imldp.hdcDst = hdc,
810 imldp.x = x;
811 imldp.y = y;
812 imldp.rgbBk = CLR_DEFAULT;
813 imldp.rgbFg = CLR_DEFAULT;
814 imldp.fStyle = ILD_NORMAL;
815 imldp.fState = ILS_ALPHA;
816 imldp.Frame = 128;
818 /* FIXME: instead of using the alpha blending, we should
819 * create a 50% mask, and draw it semitransparantly that way */
820 ImageList_DrawIndirect (&imldp);
823 /*************************************************************************
824 * ImageList_DragMove [COMCTL32.@]
826 * Moves the drag image.
828 * PARAMS
829 * x [I] X position of the drag image.
830 * y [I] Y position of the drag image.
832 * RETURNS
833 * Success: TRUE
834 * Failure: FALSE
836 * NOTES
837 * The position of the drag image is relative to the window, not
838 * the client area.
840 * BUGS
841 * The drag image should be drawn semitransparent.
844 BOOL WINAPI
845 ImageList_DragMove (INT x, INT y)
847 TRACE("(x=%d y=%d)\n", x, y);
849 if (!InternalDrag.himl) {
850 return FALSE;
853 /* draw/update the drag image */
854 if (InternalDrag.bShow) {
855 HDC hdcDrag;
856 HDC hdcOffScreen;
857 HDC hdcBg;
858 HBITMAP hbmOffScreen;
859 INT origNewX, origNewY;
860 INT origOldX, origOldY;
861 INT origRegX, origRegY;
862 INT sizeRegX, sizeRegY;
865 /* calculate the update region */
866 origNewX = x - InternalDrag.dxHotspot;
867 origNewY = y - InternalDrag.dyHotspot;
868 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
869 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
870 origRegX = min(origNewX, origOldX);
871 origRegY = min(origNewY, origOldY);
872 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
873 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
875 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
876 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
877 hdcOffScreen = CreateCompatibleDC(hdcDrag);
878 hdcBg = CreateCompatibleDC(hdcDrag);
880 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
881 SelectObject(hdcOffScreen, hbmOffScreen);
882 SelectObject(hdcBg, InternalDrag.hbmBg);
884 /* get the actual background of the update region */
885 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
886 origRegX, origRegY, SRCCOPY);
887 /* erase the old image */
888 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
889 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
890 SRCCOPY);
891 /* save the background */
892 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
893 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
894 /* draw the image */
895 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
896 origNewY - origRegY);
897 /* draw the update region to the screen */
898 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
899 hdcOffScreen, 0, 0, SRCCOPY);
901 DeleteDC(hdcBg);
902 DeleteDC(hdcOffScreen);
903 DeleteObject(hbmOffScreen);
904 ReleaseDC(InternalDrag.hwnd, hdcDrag);
907 /* update the image position */
908 InternalDrag.x = x;
909 InternalDrag.y = y;
911 return TRUE;
915 /*************************************************************************
916 * ImageList_DragShowNolock [COMCTL32.@]
918 * Shows or hides the drag image.
920 * PARAMS
921 * bShow [I] TRUE shows the drag image, FALSE hides it.
923 * RETURNS
924 * Success: TRUE
925 * Failure: FALSE
927 * BUGS
928 * The drag image should be drawn semitransparent.
931 BOOL WINAPI
932 ImageList_DragShowNolock (BOOL bShow)
934 HDC hdcDrag;
935 HDC hdcBg;
936 INT x, y;
938 TRACE("bShow=0x%X!\n", bShow);
940 /* DragImage is already visible/hidden */
941 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
942 return FALSE;
945 /* position of the origin of the DragImage */
946 x = InternalDrag.x - InternalDrag.dxHotspot;
947 y = InternalDrag.y - InternalDrag.dyHotspot;
949 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
950 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
951 if (!hdcDrag) {
952 return FALSE;
955 hdcBg = CreateCompatibleDC(hdcDrag);
956 if (!InternalDrag.hbmBg) {
957 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
958 InternalDrag.himl->cx, InternalDrag.himl->cy);
960 SelectObject(hdcBg, InternalDrag.hbmBg);
962 if (bShow) {
963 /* save the background */
964 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
965 hdcDrag, x, y, SRCCOPY);
966 /* show the image */
967 ImageList_InternalDragDraw(hdcDrag, x, y);
968 } else {
969 /* hide the image */
970 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
971 hdcBg, 0, 0, SRCCOPY);
974 InternalDrag.bShow = !InternalDrag.bShow;
976 DeleteDC(hdcBg);
977 ReleaseDC (InternalDrag.hwnd, hdcDrag);
978 return TRUE;
982 /*************************************************************************
983 * ImageList_Draw [COMCTL32.@] Draws an image.
985 * PARAMS
986 * himl [I] handle to image list
987 * i [I] image index
988 * hdc [I] handle to device context
989 * x [I] x position
990 * y [I] y position
991 * fStyle [I] drawing flags
993 * RETURNS
994 * Success: TRUE
995 * Failure: FALSE
997 * SEE
998 * ImageList_DrawEx.
1001 BOOL WINAPI
1002 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
1004 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
1005 CLR_DEFAULT, CLR_DEFAULT, fStyle);
1009 /*************************************************************************
1010 * ImageList_DrawEx [COMCTL32.@]
1012 * Draws an image and allows to use extended drawing features.
1014 * PARAMS
1015 * himl [I] handle to image list
1016 * i [I] image index
1017 * hdc [I] handle to device context
1018 * x [I] X position
1019 * y [I] Y position
1020 * dx [I] X offset
1021 * dy [I] Y offset
1022 * rgbBk [I] background color
1023 * rgbFg [I] foreground color
1024 * fStyle [I] drawing flags
1026 * RETURNS
1027 * Success: TRUE
1028 * Failure: FALSE
1030 * NOTES
1031 * Calls ImageList_DrawIndirect.
1033 * SEE
1034 * ImageList_DrawIndirect.
1037 BOOL WINAPI
1038 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1039 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1040 UINT fStyle)
1042 IMAGELISTDRAWPARAMS imldp;
1044 ZeroMemory (&imldp, sizeof(imldp));
1045 imldp.cbSize = sizeof(imldp);
1046 imldp.himl = himl;
1047 imldp.i = i;
1048 imldp.hdcDst = hdc,
1049 imldp.x = x;
1050 imldp.y = y;
1051 imldp.cx = dx;
1052 imldp.cy = dy;
1053 imldp.rgbBk = rgbBk;
1054 imldp.rgbFg = rgbFg;
1055 imldp.fStyle = fStyle;
1057 return ImageList_DrawIndirect (&imldp);
1061 /*************************************************************************
1062 * ImageList_DrawIndirect [COMCTL32.@]
1064 * Draws an image using ...
1066 * PARAMS
1067 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1069 * RETURNS
1070 * Success: TRUE
1071 * Failure: FALSE
1074 BOOL WINAPI
1075 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1077 INT cx, cy, nOvlIdx;
1078 DWORD fState, dwRop;
1079 UINT fStyle;
1080 COLORREF clrBk, oldImageBk, oldImageFg;
1081 HDC hImageDC, hImageListDC, hMaskListDC;
1082 HBITMAP hImageBmp, hOldImageBmp, hOldImageListBmp, hOldMaskListBmp, hBlendMaskBmp;
1083 BOOL bIsTransparent, bBlend, bResult = FALSE;
1084 const HIMAGELIST himl = pimldp->himl;
1085 const INT lx = himl->cx * pimldp->i + pimldp->xBitmap;
1086 const INT ly = pimldp->yBitmap;
1088 if (!pimldp || !himl) return FALSE;
1089 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1091 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1092 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1093 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1094 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1095 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1096 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1097 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1099 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1100 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1102 /* we will use these DCs to access the images and masks in the ImageList */
1103 hImageListDC = CreateCompatibleDC(0);
1104 hMaskListDC = himl->hbmMask ? CreateCompatibleDC(0) : 0;
1106 /* these will accumulate the image and mask for the image we're drawing */
1107 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1108 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1109 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1111 /* Create a compatible DC. */
1112 if (!hImageListDC || !hImageDC || !hImageBmp ||
1113 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1114 goto cleanup;
1116 hOldImageListBmp = SelectObject(hImageListDC, himl->hbmImage);
1117 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1118 hOldMaskListBmp = hMaskListDC ? SelectObject(hMaskListDC, himl->hbmMask) : 0;
1121 * To obtain a transparent look, background color should be set
1122 * to white and foreground color to black when blting the
1123 * monochrome mask.
1125 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1126 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1129 * Draw the initial image
1131 if(fStyle & ILD_MASK) {
1132 if (himl->hbmMask) {
1133 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1134 } else {
1135 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1136 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1137 SelectObject(hImageDC, hOldBrush);
1139 } else if (himl->hbmMask && !bIsTransparent) {
1140 /* blend the image with the needed solid background */
1141 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1142 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1143 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1144 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1145 DeleteObject (SelectObject (hImageDC, hOldBrush));
1146 } else {
1147 /* start off with the image, if we have a mask, we'll use it later */
1148 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1151 /* Time for blending, if required */
1152 if (bBlend) {
1153 HBRUSH hBlendBrush, hOldBrush;
1154 COLORREF clrBlend = pimldp->rgbFg;
1155 HDC hBlendMaskDC = hImageListDC;
1156 HBITMAP hOldBitmap;
1158 /* Create the blend Mask */
1159 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1160 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1161 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1162 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1163 SelectObject(hBlendMaskDC, hOldBrush);
1165 /* Modify the blend mask if an Image Mask exist */
1166 if(himl->hbmMask) {
1167 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1168 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1171 /* now apply blend to the current image given the BlendMask */
1172 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1173 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1174 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1175 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1176 DeleteObject(SelectObject(hImageDC, hOldBrush));
1177 SelectObject(hBlendMaskDC, hOldBitmap);
1180 /* Now do the overlay image, if any */
1181 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1182 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1183 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1184 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1185 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1186 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1187 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1188 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1192 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1193 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1194 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1195 if (fState & ILS_ALPHA) FIXME("ILS_SHADOW: unimplemented!\n");
1197 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1198 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1199 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1201 /* now copy the image to the screen */
1202 dwRop = SRCCOPY;
1203 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1204 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1205 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1206 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1207 SetBkColor(pimldp->hdcDst, oldDstBk);
1208 SetTextColor(pimldp->hdcDst, oldDstFg);
1209 dwRop = SRCPAINT;
1211 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1212 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1214 bResult = TRUE;
1216 /* cleanup the mess */
1217 SetBkColor(hImageDC, oldImageBk);
1218 SetTextColor(hImageDC, oldImageFg);
1219 SelectObject(hImageDC, hOldImageBmp);
1220 SelectObject(hImageListDC, hOldImageListBmp);
1221 if (hMaskListDC) SelectObject(hMaskListDC, hOldMaskListBmp);
1222 cleanup:
1223 DeleteObject(hBlendMaskBmp);
1224 DeleteObject(hImageBmp);
1225 DeleteObject(hImageDC);
1226 DeleteObject(hImageListDC);
1227 DeleteObject(hMaskListDC);
1229 return bResult;
1233 /*************************************************************************
1234 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1236 * PARAMS
1237 * himlSrc [I] source image list handle
1239 * RETURNS
1240 * Success: Handle of duplicated image list.
1241 * Failure: NULL
1244 HIMAGELIST WINAPI
1245 ImageList_Duplicate (HIMAGELIST himlSrc)
1247 HIMAGELIST himlDst;
1248 HDC hdcSrc, hdcDst;
1250 if (himlSrc == NULL) {
1251 ERR("Invalid image list handle!\n");
1252 return NULL;
1255 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1256 himlSrc->cInitial, himlSrc->cGrow);
1258 if (himlDst)
1260 hdcSrc = CreateCompatibleDC (0);
1261 hdcDst = CreateCompatibleDC (0);
1262 SelectObject (hdcSrc, himlSrc->hbmImage);
1263 SelectObject (hdcDst, himlDst->hbmImage);
1264 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1265 hdcSrc, 0, 0, SRCCOPY);
1267 if (himlDst->hbmMask)
1269 SelectObject (hdcSrc, himlSrc->hbmMask);
1270 SelectObject (hdcDst, himlDst->hbmMask);
1271 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1272 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1275 DeleteDC (hdcDst);
1276 DeleteDC (hdcSrc);
1278 himlDst->cCurImage = himlSrc->cCurImage;
1279 himlDst->cMaxImage = himlSrc->cMaxImage;
1281 return himlDst;
1285 /*************************************************************************
1286 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1288 * Finishes a drag operation.
1290 * PARAMS
1291 * no Parameters
1293 * RETURNS
1294 * Success: TRUE
1295 * Failure: FALSE
1298 BOOL WINAPI
1299 ImageList_EndDrag (void)
1301 /* cleanup the InternalDrag struct */
1302 InternalDrag.hwnd = 0;
1303 ImageList_Destroy (InternalDrag.himl);
1304 InternalDrag.himl = 0;
1305 InternalDrag.x= 0;
1306 InternalDrag.y= 0;
1307 InternalDrag.dxHotspot = 0;
1308 InternalDrag.dyHotspot = 0;
1309 InternalDrag.bShow = FALSE;
1310 DeleteObject(InternalDrag.hbmBg);
1311 InternalDrag.hbmBg = 0;
1312 InternalDrag.bHSPending = FALSE;
1314 return TRUE;
1318 /*************************************************************************
1319 * ImageList_GetBkColor [COMCTL32.@]
1321 * Returns the background color of an image list.
1323 * PARAMS
1324 * himl [I] Image list handle.
1326 * RETURNS
1327 * Success: background color
1328 * Failure: CLR_NONE
1331 COLORREF WINAPI
1332 ImageList_GetBkColor (HIMAGELIST himl)
1334 return himl ? himl->clrBk : CLR_NONE;
1338 /*************************************************************************
1339 * ImageList_GetDragImage [COMCTL32.@]
1341 * Returns the handle to the internal drag image list.
1343 * PARAMS
1344 * ppt [O] Pointer to the drag position. Can be NULL.
1345 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1347 * RETURNS
1348 * Success: Handle of the drag image list.
1349 * Failure: NULL.
1352 HIMAGELIST WINAPI
1353 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1355 if (InternalDrag.himl) {
1356 if (ppt) {
1357 ppt->x = InternalDrag.x;
1358 ppt->y = InternalDrag.y;
1360 if (pptHotspot) {
1361 pptHotspot->x = InternalDrag.dxHotspot;
1362 pptHotspot->y = InternalDrag.dyHotspot;
1364 return (InternalDrag.himl);
1367 return NULL;
1371 /*************************************************************************
1372 * ImageList_GetFlags [COMCTL32.@]
1374 * BUGS
1375 * Stub.
1378 DWORD WINAPI
1379 ImageList_GetFlags(HIMAGELIST himl)
1381 FIXME("(%p):empty stub\n", himl);
1382 return 0;
1386 /*************************************************************************
1387 * ImageList_GetIcon [COMCTL32.@]
1389 * Creates an icon from a masked image of an image list.
1391 * PARAMS
1392 * himl [I] handle to image list
1393 * i [I] image index
1394 * flags [I] drawing style flags
1396 * RETURNS
1397 * Success: icon handle
1398 * Failure: NULL
1401 HICON WINAPI
1402 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1404 ICONINFO ii;
1405 HICON hIcon;
1406 HBITMAP hOldDstBitmap;
1407 HDC hdcDst;
1409 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) return 0;
1411 hdcDst = CreateCompatibleDC(0);
1413 ii.fIcon = TRUE;
1415 /* draw mask*/
1416 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1417 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1418 ImageList_Draw(himl, i, hdcDst, 0, 0, ILD_MASK);
1420 /* draw image*/
1421 SelectObject (hdcDst, himl->hbmImage);
1422 ii.hbmColor = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1423 SelectObject (hdcDst, ii.hbmColor);
1424 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle);
1427 * CreateIconIndirect requires us to deselect the bitmaps from
1428 * the DCs before calling
1430 SelectObject(hdcDst, hOldDstBitmap);
1432 hIcon = CreateIconIndirect (&ii);
1434 DeleteObject (ii.hbmMask);
1435 DeleteObject (ii.hbmColor);
1436 DeleteDC (hdcDst);
1438 return hIcon;
1442 /*************************************************************************
1443 * ImageList_GetIconSize [COMCTL32.@]
1445 * Retrieves the size of an image in an image list.
1447 * PARAMS
1448 * himl [I] handle to image list
1449 * cx [O] pointer to the image width.
1450 * cy [O] pointer to the image height.
1452 * RETURNS
1453 * Success: TRUE
1454 * Failure: FALSE
1456 * NOTES
1457 * All images in an image list have the same size.
1460 BOOL WINAPI
1461 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1463 if (himl == NULL)
1464 return FALSE;
1465 if ((himl->cx <= 0) || (himl->cy <= 0))
1466 return FALSE;
1468 if (cx)
1469 *cx = himl->cx;
1470 if (cy)
1471 *cy = himl->cy;
1473 return TRUE;
1477 /*************************************************************************
1478 * ImageList_GetImageCount [COMCTL32.@]
1480 * Returns the number of images in an image list.
1482 * PARAMS
1483 * himl [I] handle to image list
1485 * RETURNS
1486 * Success: Number of images.
1487 * Failure: 0
1490 INT WINAPI
1491 ImageList_GetImageCount (HIMAGELIST himl)
1493 if (himl == NULL)
1494 return 0;
1496 return himl->cCurImage;
1500 /*************************************************************************
1501 * ImageList_GetImageInfo [COMCTL32.@]
1503 * Returns information about an image in an image list.
1505 * PARAMS
1506 * himl [I] handle to image list
1507 * i [I] image index
1508 * pImageInfo [O] pointer to the image information
1510 * RETURNS
1511 * Success: TRUE
1512 * Failure: FALSE
1515 BOOL WINAPI
1516 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1518 if ((himl == NULL) || (pImageInfo == NULL))
1519 return FALSE;
1520 if ((i < 0) || (i >= himl->cCurImage))
1521 return FALSE;
1523 pImageInfo->hbmImage = himl->hbmImage;
1524 pImageInfo->hbmMask = himl->hbmMask;
1526 pImageInfo->rcImage.top = 0;
1527 pImageInfo->rcImage.bottom = himl->cy;
1528 pImageInfo->rcImage.left = i * himl->cx;
1529 pImageInfo->rcImage.right = (i+1) * himl->cx;
1531 return TRUE;
1535 /*************************************************************************
1536 * ImageList_GetImageRect [COMCTL32.@]
1538 * Retrieves the rectangle of the specified image in an image list.
1540 * PARAMS
1541 * himl [I] handle to image list
1542 * i [I] image index
1543 * lpRect [O] pointer to the image rectangle
1545 * RETURNS
1546 * Success: TRUE
1547 * Failure: FALSE
1549 * NOTES
1550 * This is an UNDOCUMENTED function!!!
1553 BOOL WINAPI
1554 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1556 if ((himl == NULL) || (lpRect == NULL))
1557 return FALSE;
1558 if ((i < 0) || (i >= himl->cCurImage))
1559 return FALSE;
1561 lpRect->left = i * himl->cx;
1562 lpRect->top = 0;
1563 lpRect->right = lpRect->left + himl->cx;
1564 lpRect->bottom = himl->cy;
1566 return TRUE;
1570 /*************************************************************************
1571 * ImageList_LoadImage [COMCTL32.@]
1572 * ImageList_LoadImageA [COMCTL32.@]
1574 * Creates an image list from a bitmap, icon or cursor.
1576 * PARAMS
1577 * hi [I] instance handle
1578 * lpbmp [I] name or id of the image
1579 * cx [I] width of each image
1580 * cGrow [I] number of images to expand
1581 * clrMask [I] mask color
1582 * uType [I] type of image to load
1583 * uFlags [I] loading flags
1585 * RETURNS
1586 * Success: handle to the loaded image list
1587 * Failure: NULL
1589 * SEE
1590 * LoadImage ()
1593 HIMAGELIST WINAPI
1594 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1595 COLORREF clrMask, UINT uType, UINT uFlags)
1597 HIMAGELIST himl = NULL;
1598 HANDLE handle;
1599 INT nImageCount;
1601 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1602 if (!handle) {
1603 ERR("Error loading image!\n");
1604 return NULL;
1607 if (uType == IMAGE_BITMAP) {
1608 BITMAP bmp;
1609 GetObjectA (handle, sizeof(BITMAP), &bmp);
1611 /* To match windows behavior, if cx is set to zero and
1612 the flag DI_DEFAULTSIZE is specified, cx becomes the
1613 system metric value for icons. If the flag is not specified
1614 the function sets the size to the height of the bitmap */
1615 if (cx == 0)
1617 if (uFlags & DI_DEFAULTSIZE)
1618 cx = GetSystemMetrics (SM_CXICON);
1619 else
1620 cx = bmp.bmHeight;
1623 nImageCount = bmp.bmWidth / cx;
1625 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1626 nImageCount, cGrow);
1627 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1629 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1630 ICONINFO ii;
1631 BITMAP bmp;
1633 GetIconInfo (handle, &ii);
1634 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1635 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1636 ILC_MASK | ILC_COLOR, 1, cGrow);
1637 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1638 DeleteObject (ii.hbmColor);
1639 DeleteObject (ii.hbmMask);
1642 DeleteObject (handle);
1644 return himl;
1648 /*************************************************************************
1649 * ImageList_LoadImageW [COMCTL32.@]
1651 * Creates an image list from a bitmap, icon or cursor.
1653 * PARAMS
1654 * hi [I] instance handle
1655 * lpbmp [I] name or id of the image
1656 * cx [I] width of each image
1657 * cGrow [I] number of images to expand
1658 * clrMask [I] mask color
1659 * uType [I] type of image to load
1660 * uFlags [I] loading flags
1662 * RETURNS
1663 * Success: handle to the loaded image list
1664 * Failure: NULL
1666 * SEE
1667 * LoadImage ()
1670 HIMAGELIST WINAPI
1671 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1672 COLORREF clrMask, UINT uType, UINT uFlags)
1674 HIMAGELIST himl = NULL;
1675 HANDLE handle;
1676 INT nImageCount;
1678 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1679 if (!handle) {
1680 ERR("Error loading image!\n");
1681 return NULL;
1684 if (uType == IMAGE_BITMAP) {
1685 BITMAP bmp;
1686 GetObjectA (handle, sizeof(BITMAP), &bmp);
1688 /* To match windows behavior, if cx is set to zero and
1689 the flag DI_DEFAULTSIZE is specified, cx becomes the
1690 system metric value for icons. If the flag is not specified
1691 the function sets the size to the height of the bitmap */
1692 if (cx == 0)
1694 if (uFlags & DI_DEFAULTSIZE)
1695 cx = GetSystemMetrics (SM_CXICON);
1696 else
1697 cx = bmp.bmHeight;
1700 nImageCount = bmp.bmWidth / cx;
1702 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1703 nImageCount, cGrow);
1704 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1706 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1707 ICONINFO ii;
1708 BITMAP bmp;
1710 GetIconInfo (handle, &ii);
1711 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1712 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1713 ILC_MASK | ILC_COLOR, 1, cGrow);
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 HDC hdcSrcImage, hdcDstImage;
1750 INT cxDst, cyDst;
1751 INT xOff1, yOff1, xOff2, yOff2;
1752 INT nX1, nX2;
1754 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1755 i2, dx, dy);
1757 if ((himl1 == NULL) || (himl2 == NULL))
1758 return NULL;
1760 /* check indices */
1761 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1762 ERR("Index 1 out of range! %d\n", i1);
1763 return NULL;
1766 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1767 ERR("Index 2 out of range! %d\n", i2);
1768 return NULL;
1771 if (dx > 0) {
1772 cxDst = max (himl1->cx, dx + himl2->cx);
1773 xOff1 = 0;
1774 xOff2 = dx;
1776 else if (dx < 0) {
1777 cxDst = max (himl2->cx, himl1->cx - dx);
1778 xOff1 = -dx;
1779 xOff2 = 0;
1781 else {
1782 cxDst = max (himl1->cx, himl2->cx);
1783 xOff1 = 0;
1784 xOff2 = 0;
1787 if (dy > 0) {
1788 cyDst = max (himl1->cy, dy + himl2->cy);
1789 yOff1 = 0;
1790 yOff2 = dy;
1792 else if (dy < 0) {
1793 cyDst = max (himl2->cy, himl1->cy - dy);
1794 yOff1 = -dy;
1795 yOff2 = 0;
1797 else {
1798 cyDst = max (himl1->cy, himl2->cy);
1799 yOff1 = 0;
1800 yOff2 = 0;
1803 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1805 if (himlDst) {
1806 hdcSrcImage = CreateCompatibleDC (0);
1807 hdcDstImage = CreateCompatibleDC (0);
1808 nX1 = i1 * himl1->cx;
1809 nX2 = i2 * himl2->cx;
1811 /* copy image */
1812 SelectObject (hdcSrcImage, himl1->hbmImage);
1813 SelectObject (hdcDstImage, himlDst->hbmImage);
1814 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1815 hdcSrcImage, 0, 0, BLACKNESS);
1816 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1817 hdcSrcImage, nX1, 0, SRCCOPY);
1819 SelectObject (hdcSrcImage, himl2->hbmMask);
1820 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1821 hdcSrcImage, nX2, 0, SRCAND);
1823 SelectObject (hdcSrcImage, himl2->hbmImage);
1824 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1825 hdcSrcImage, nX2, 0, SRCPAINT);
1827 /* copy mask */
1828 SelectObject (hdcSrcImage, himl1->hbmMask);
1829 SelectObject (hdcDstImage, himlDst->hbmMask);
1830 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1831 hdcSrcImage, 0, 0, WHITENESS);
1832 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1833 hdcSrcImage, nX1, 0, SRCCOPY);
1835 SelectObject (hdcSrcImage, himl2->hbmMask);
1836 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
1837 hdcSrcImage, nX2, 0, SRCAND);
1839 DeleteDC (hdcSrcImage);
1840 DeleteDC (hdcDstImage);
1841 himlDst->cCurImage = 1;
1844 return himlDst;
1848 /* helper for _read_bitmap currently unused */
1849 #if 0
1850 static int may_use_dibsection(HDC hdc) {
1851 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1852 if (bitspixel>8)
1853 return TRUE;
1854 if (bitspixel<=4)
1855 return FALSE;
1856 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1858 #endif
1860 /* helper for ImageList_Read, see comments below */
1861 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1862 HDC xdc = 0;
1863 BITMAPFILEHEADER bmfh;
1864 BITMAPINFOHEADER bmih;
1865 int bitsperpixel,palspace,longsperline,width,height;
1866 LPBITMAPINFOHEADER bmihc = NULL;
1867 int result = 0;
1868 HBITMAP hbitmap = 0;
1869 LPBYTE bits = NULL,nbits = NULL;
1870 int nbytesperline,bytesperline;
1872 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1873 (bmfh.bfType != (('M'<<8)|'B')) ||
1874 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1875 (bmih.biSize != sizeof(bmih))
1877 return 0;
1879 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1880 if (bitsperpixel<=8)
1881 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1882 else
1883 palspace = 0;
1884 width = bmih.biWidth;
1885 height = bmih.biHeight;
1886 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1887 memcpy(bmihc,&bmih,sizeof(bmih));
1888 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1889 bmihc->biSizeImage = (longsperline*height)<<2;
1891 /* read the palette right after the end of the bitmapinfoheader */
1892 if (palspace)
1893 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1894 goto ret1;
1896 xdc = GetDC(0);
1897 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1898 if ((bitsperpixel>1) &&
1899 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1901 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1902 if (!hbitmap)
1903 goto ret1;
1904 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1905 goto ret1;
1906 result = 1;
1907 } else
1908 #endif
1910 int i,nwidth,nheight;
1912 nwidth = width*(height/cy);
1913 nheight = cy;
1915 if (bitsperpixel==1)
1916 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1917 else
1918 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1920 /* Might be a bit excessive memory use here */
1921 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1922 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
1923 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
1924 goto ret1;
1926 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1927 /* Do not forget that windows bitmaps are bottom->top */
1928 bytesperline = longsperline*4;
1929 nbytesperline = (height/cy)*bytesperline;
1930 for (i=0;i<height;i++) {
1931 memcpy(
1932 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
1933 bits+bytesperline*(height-1-i),
1934 bytesperline
1937 bmihc->biWidth = nwidth;
1938 bmihc->biHeight = nheight;
1939 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
1940 goto ret1;
1941 LocalFree((HLOCAL)nbits);
1942 LocalFree((HLOCAL)bits);
1943 result = 1;
1945 ret1:
1946 if (xdc) ReleaseDC(0,xdc);
1947 if (bmihc) LocalFree((HLOCAL)bmihc);
1948 if (!result) {
1949 if (hbitmap) {
1950 DeleteObject(hbitmap);
1951 hbitmap = 0;
1954 return hbitmap;
1957 /*************************************************************************
1958 * ImageList_Read [COMCTL32.@]
1960 * Reads an image list from a stream.
1962 * PARAMS
1963 * pstm [I] pointer to a stream
1965 * RETURNS
1966 * Success: handle to image list
1967 * Failure: NULL
1969 * The format is like this:
1970 * ILHEAD ilheadstruct;
1972 * for the color image part:
1973 * BITMAPFILEHEADER bmfh;
1974 * BITMAPINFOHEADER bmih;
1975 * only if it has a palette:
1976 * RGBQUAD rgbs[nr_of_paletted_colors];
1978 * BYTE colorbits[imagesize];
1980 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1981 * BITMAPFILEHEADER bmfh_mask;
1982 * BITMAPINFOHEADER bmih_mask;
1983 * only if it has a palette (it usually does not):
1984 * RGBQUAD rgbs[nr_of_paletted_colors];
1986 * BYTE maskbits[imagesize];
1988 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1989 * _read_bitmap needs to convert them.
1991 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1993 ILHEAD ilHead;
1994 HIMAGELIST himl;
1995 HBITMAP hbmColor=0,hbmMask=0;
1996 int i;
1998 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1999 return NULL;
2000 if (ilHead.usMagic != (('L' << 8) | 'I'))
2001 return NULL;
2002 if (ilHead.usVersion != 0x101) /* probably version? */
2003 return NULL;
2005 #if 0
2006 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2007 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2008 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2009 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2010 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2011 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2012 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2013 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2014 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2015 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2016 #endif
2018 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2019 if (!hbmColor)
2020 return NULL;
2021 if (ilHead.flags & ILC_MASK) {
2022 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2023 if (!hbmMask) {
2024 DeleteObject(hbmColor);
2025 return NULL;
2029 himl = ImageList_Create (
2030 ilHead.cx,
2031 ilHead.cy,
2032 ilHead.flags,
2033 1, /* initial */
2034 ilHead.cGrow
2036 if (!himl) {
2037 DeleteObject(hbmColor);
2038 DeleteObject(hbmMask);
2039 return NULL;
2041 himl->hbmImage = hbmColor;
2042 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.@] Removes an image from an image list
2056 * PARAMS
2057 * himl [I] image list handle
2058 * i [I] image index
2060 * RETURNS
2061 * Success: TRUE
2062 * Failure: FALSE
2065 BOOL WINAPI
2066 ImageList_Remove (HIMAGELIST himl, INT i)
2068 HBITMAP hbmNewImage, hbmNewMask;
2069 HDC hdcSrc, hdcDst;
2070 INT cxNew, nCount;
2072 TRACE("(himl=%p i=%d)\n", himl, i);
2074 if (himl == NULL) {
2075 ERR("Invalid image list handle!\n");
2076 return FALSE;
2079 if ((i < -1) || (i >= himl->cCurImage)) {
2080 ERR("index out of range! %d\n", i);
2081 return FALSE;
2084 if (i == -1) {
2085 /* remove all */
2086 if (himl->cCurImage == 0) {
2087 /* remove all on empty ImageList is allowed */
2088 TRACE("remove all on empty ImageList!\n");
2089 return TRUE;
2092 himl->cMaxImage = himl->cInitial + himl->cGrow;
2093 himl->cCurImage = 0;
2094 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2095 himl->nOvlIdx[nCount] = -1;
2097 DeleteObject (himl->hbmImage);
2098 himl->hbmImage =
2099 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2100 1, himl->uBitsPixel, NULL);
2102 if (himl->hbmMask) {
2103 DeleteObject (himl->hbmMask);
2104 himl->hbmMask =
2105 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2106 1, 1, NULL);
2109 else {
2110 /* delete one image */
2111 TRACE("Remove single image! %d\n", i);
2113 /* create new bitmap(s) */
2114 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2116 TRACE(" - Number of images: %d / %d (Old/New)\n",
2117 himl->cCurImage, himl->cCurImage - 1);
2118 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2119 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2121 hbmNewImage =
2122 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2124 if (himl->hbmMask)
2125 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2126 else
2127 hbmNewMask = 0; /* Just to keep compiler happy! */
2129 hdcSrc = CreateCompatibleDC (0);
2130 hdcDst = CreateCompatibleDC (0);
2132 /* copy all images and masks prior to the "removed" image */
2133 if (i > 0) {
2134 TRACE("Pre image copy: Copy %d images\n", i);
2136 SelectObject (hdcSrc, himl->hbmImage);
2137 SelectObject (hdcDst, hbmNewImage);
2138 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2139 hdcSrc, 0, 0, SRCCOPY);
2141 if (himl->hbmMask) {
2142 SelectObject (hdcSrc, himl->hbmMask);
2143 SelectObject (hdcDst, hbmNewMask);
2144 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2145 hdcSrc, 0, 0, SRCCOPY);
2149 /* copy all images and masks behind the removed image */
2150 if (i < himl->cCurImage - 1) {
2151 TRACE("Post image copy!\n");
2152 SelectObject (hdcSrc, himl->hbmImage);
2153 SelectObject (hdcDst, hbmNewImage);
2154 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2155 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2157 if (himl->hbmMask) {
2158 SelectObject (hdcSrc, himl->hbmMask);
2159 SelectObject (hdcDst, hbmNewMask);
2160 BitBlt (hdcDst, i * himl->cx, 0,
2161 (himl->cCurImage - i - 1) * himl->cx,
2162 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2166 DeleteDC (hdcSrc);
2167 DeleteDC (hdcDst);
2169 /* delete old images and insert new ones */
2170 DeleteObject (himl->hbmImage);
2171 himl->hbmImage = hbmNewImage;
2172 if (himl->hbmMask) {
2173 DeleteObject (himl->hbmMask);
2174 himl->hbmMask = hbmNewMask;
2177 himl->cCurImage--;
2178 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2181 return TRUE;
2185 /*************************************************************************
2186 * ImageList_Replace [COMCTL32.@]
2188 * Replaces an image in an image list with a new image.
2190 * PARAMS
2191 * himl [I] handle to image list
2192 * i [I] image index
2193 * hbmImage [I] handle to image bitmap
2194 * hbmMask [I] handle to mask bitmap. Can be NULL.
2196 * RETURNS
2197 * Success: TRUE
2198 * Failure: FALSE
2201 BOOL WINAPI
2202 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2203 HBITMAP hbmMask)
2205 HDC hdcImageList, hdcImage;
2206 BITMAP bmp;
2208 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2210 if (himl == NULL) {
2211 ERR("Invalid image list handle!\n");
2212 return FALSE;
2215 if ((i >= himl->cMaxImage) || (i < 0)) {
2216 ERR("Invalid image index!\n");
2217 return FALSE;
2220 hdcImageList = CreateCompatibleDC (0);
2221 hdcImage = CreateCompatibleDC (0);
2222 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2224 /* Replace Image */
2225 SelectObject (hdcImageList, himl->hbmImage);
2226 SelectObject (hdcImage, hbmImage);
2228 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2229 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2231 if (himl->hbmMask)
2233 /* Replace Mask */
2234 SelectObject (hdcImageList, himl->hbmMask);
2235 SelectObject (hdcImage, hbmMask);
2237 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2238 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2241 /* Remove the background from the image
2243 SelectObject (hdcImageList, himl->hbmImage);
2244 StretchBlt (hdcImageList,
2245 i*himl->cx, 0, himl->cx, himl->cy,
2246 hdcImage,
2247 0, 0, bmp.bmWidth, bmp.bmHeight,
2248 0x220326); /* NOTSRCAND */
2251 DeleteDC (hdcImage);
2252 DeleteDC (hdcImageList);
2254 return TRUE;
2258 /*************************************************************************
2259 * ImageList_ReplaceIcon [COMCTL32.@]
2261 * Replaces an image in an image list using an icon.
2263 * PARAMS
2264 * himl [I] handle to image list
2265 * i [I] image index
2266 * hIcon [I] handle to icon
2268 * RETURNS
2269 * Success: index of the replaced image
2270 * Failure: -1
2273 INT WINAPI
2274 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2276 HDC hdcImageList, hdcImage;
2277 INT nIndex;
2278 HICON hBestFitIcon;
2279 HBITMAP hbmOldSrc, hbmOldDst;
2280 ICONINFO ii;
2281 BITMAP bmp;
2283 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2285 if (himl == NULL)
2286 return -1;
2287 if ((i >= himl->cMaxImage) || (i < -1))
2288 return -1;
2290 hBestFitIcon = CopyImage(
2291 hIcon, IMAGE_ICON,
2292 himl->cx, himl->cy,
2293 LR_COPYFROMRESOURCE);
2295 GetIconInfo (hBestFitIcon, &ii);
2296 if (ii.hbmMask == 0)
2297 ERR("no mask!\n");
2298 if (ii.hbmColor == 0)
2299 ERR("no color!\n");
2300 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2302 if (i == -1) {
2303 if (himl->cCurImage + 1 > himl->cMaxImage)
2304 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2306 nIndex = himl->cCurImage;
2307 himl->cCurImage++;
2309 else
2310 nIndex = i;
2312 hdcImageList = CreateCompatibleDC (0);
2313 TRACE("hdcImageList=%p!\n", hdcImageList);
2314 if (hdcImageList == 0)
2315 ERR("invalid hdcImageList!\n");
2317 hdcImage = CreateCompatibleDC (0);
2318 TRACE("hdcImage=%p!\n", hdcImage);
2319 if (hdcImage == 0)
2320 ERR("invalid hdcImage!\n");
2322 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2323 SetTextColor( hdcImageList, RGB(0,0,0));
2324 SetBkColor( hdcImageList, RGB(255,255,255));
2325 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2326 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2327 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2329 if (himl->hbmMask) {
2330 SelectObject (hdcImageList, himl->hbmMask);
2331 SelectObject (hdcImage, ii.hbmMask);
2332 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2333 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2336 SelectObject (hdcImage, hbmOldSrc);
2337 SelectObject (hdcImageList, hbmOldDst);
2339 if(hBestFitIcon)
2340 DestroyIcon(hBestFitIcon);
2341 if (hdcImageList)
2342 DeleteDC (hdcImageList);
2343 if (hdcImage)
2344 DeleteDC (hdcImage);
2345 if (ii.hbmColor)
2346 DeleteObject (ii.hbmColor);
2347 if (ii.hbmMask)
2348 DeleteObject (ii.hbmMask);
2350 return nIndex;
2354 /*************************************************************************
2355 * ImageList_SetBkColor [COMCTL32.@]
2357 * Sets the background color of an image list.
2359 * PARAMS
2360 * himl [I] handle to image list
2361 * clrBk [I] background color
2363 * RETURNS
2364 * Success: previous background color
2365 * Failure: CLR_NONE
2368 COLORREF WINAPI
2369 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2371 COLORREF clrOldBk;
2373 if (himl == NULL)
2374 return CLR_NONE;
2376 clrOldBk = himl->clrBk;
2377 himl->clrBk = clrBk;
2378 return clrOldBk;
2382 /*************************************************************************
2383 * ImageList_SetDragCursorImage [COMCTL32.@]
2385 * Combines the specified image with the current drag image
2387 * PARAMS
2388 * himlDrag [I] handle to drag image list
2389 * iDrag [I] drag image index
2390 * dxHotspot [I] X position of the hot spot
2391 * dyHotspot [I] Y position of the hot spot
2393 * RETURNS
2394 * Success: TRUE
2395 * Failure: FALSE
2397 * NOTES
2398 * When this function is called and the drag image is visible, a
2399 * short flickering occurs but this matches the Win9x behavior. It is
2400 * possible to fix the flickering using code like in ImageList_DragMove.
2403 BOOL WINAPI
2404 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2405 INT dxHotspot, INT dyHotspot)
2407 HIMAGELIST himlTemp;
2408 INT dx, dy;
2409 BOOL visible;
2411 if (InternalDrag.himl == NULL)
2412 return FALSE;
2414 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2415 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2417 visible = InternalDrag.bShow;
2419 /* Calculate the offset between the origin of the old image and the
2420 * origin of the second image.
2421 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2422 * hotspot) to the origin of the second image.
2423 * See M$DN for details */
2424 if(InternalDrag.bHSPending) {
2425 dx = 0;
2426 dy = 0;
2427 InternalDrag.bHSPending = FALSE;
2428 } else {
2429 dx = InternalDrag.dxHotspot - dxHotspot;
2430 dy = InternalDrag.dyHotspot - dyHotspot;
2432 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2434 if (visible) {
2435 /* hide the drag image */
2436 ImageList_DragShowNolock(FALSE);
2438 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2439 (InternalDrag.himl->cy != himlTemp->cy)) {
2440 /* the size of the drag image changed, invalidate the buffer */
2441 DeleteObject(InternalDrag.hbmBg);
2442 InternalDrag.hbmBg = 0;
2445 ImageList_Destroy (InternalDrag.himl);
2446 InternalDrag.himl = himlTemp;
2448 /* update the InternalDragOffset, if the origin of the
2449 * DragImage was changed by ImageList_Merge. */
2450 if (dx <= 0)
2451 InternalDrag.dxHotspot = dxHotspot;
2452 if (dy <= 0)
2453 InternalDrag.dyHotspot = dyHotspot;
2455 if (visible) {
2456 /* show the drag image */
2457 ImageList_DragShowNolock(TRUE);
2460 return TRUE;
2464 /*************************************************************************
2465 * ImageList_SetFilter [COMCTL32.@]
2467 * Sets a filter (or does something completely different)!!???
2468 * It removes 12 Bytes from the stack (3 Parameters).
2470 * PARAMS
2471 * himl [I] SHOULD be a handle to image list
2472 * i [I] COULD be an index?
2473 * dwFilter [I] ???
2475 * RETURNS
2476 * Success: TRUE ???
2477 * Failure: FALSE ???
2479 * BUGS
2480 * This is an UNDOCUMENTED function!!!!
2481 * empty stub.
2484 BOOL WINAPI
2485 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2487 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2489 return FALSE;
2493 /*************************************************************************
2494 * ImageList_SetFlags [COMCTL32.@]
2496 * BUGS
2497 * Stub.
2500 DWORD WINAPI
2501 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2503 FIXME("(%p %08lx):empty stub\n", himl, flags);
2504 return 0;
2508 /*************************************************************************
2509 * ImageList_SetIconSize [COMCTL32.@]
2511 * Sets the image size of the bitmap and deletes all images.
2513 * PARAMS
2514 * himl [I] handle to image list
2515 * cx [I] image width
2516 * cy [I] image height
2518 * RETURNS
2519 * Success: TRUE
2520 * Failure: FALSE
2523 BOOL WINAPI
2524 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2526 INT nCount;
2528 if (!himl)
2529 return FALSE;
2531 /* remove all images */
2532 himl->cMaxImage = himl->cInitial + himl->cGrow;
2533 himl->cCurImage = 0;
2534 himl->cx = cx;
2535 himl->cy = cy;
2537 /* initialize overlay mask indices */
2538 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2539 himl->nOvlIdx[nCount] = -1;
2541 DeleteObject (himl->hbmImage);
2542 himl->hbmImage =
2543 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2544 1, himl->uBitsPixel, NULL);
2546 if (himl->hbmMask) {
2547 DeleteObject (himl->hbmMask);
2548 himl->hbmMask =
2549 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2550 1, 1, NULL);
2553 return TRUE;
2557 /*************************************************************************
2558 * ImageList_SetImageCount [COMCTL32.@]
2560 * Resizes an image list to the specified number of images.
2562 * PARAMS
2563 * himl [I] handle to image list
2564 * iImageCount [I] number of images in the image list
2566 * RETURNS
2567 * Success: TRUE
2568 * Failure: FALSE
2571 BOOL WINAPI
2572 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2574 HDC hdcImageList, hdcBitmap;
2575 HBITMAP hbmNewBitmap;
2576 INT nNewCount, nCopyCount;
2578 TRACE("%p %d\n",himl,iImageCount);
2580 if (!himl)
2581 return FALSE;
2582 if (himl->cCurImage >= iImageCount)
2583 return FALSE;
2584 if (himl->cMaxImage > iImageCount)
2586 himl->cCurImage = iImageCount;
2587 return TRUE;
2590 nNewCount = iImageCount + himl->cGrow;
2591 nCopyCount = min(himl->cCurImage, iImageCount);
2593 hdcImageList = CreateCompatibleDC (0);
2594 hdcBitmap = CreateCompatibleDC (0);
2596 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2597 1, himl->uBitsPixel, NULL);
2598 if (hbmNewBitmap != 0)
2600 SelectObject (hdcImageList, himl->hbmImage);
2601 SelectObject (hdcBitmap, hbmNewBitmap);
2603 /* copy images */
2604 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2605 hdcImageList, 0, 0, SRCCOPY);
2606 #if 0
2607 /* delete 'empty' image space */
2608 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2609 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2610 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2611 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2612 #endif
2613 DeleteObject (himl->hbmImage);
2614 himl->hbmImage = hbmNewBitmap;
2616 else
2617 ERR("Could not create new image bitmap !\n");
2619 if (himl->hbmMask)
2621 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2622 1, 1, NULL);
2623 if (hbmNewBitmap != 0)
2625 SelectObject (hdcImageList, himl->hbmMask);
2626 SelectObject (hdcBitmap, hbmNewBitmap);
2628 /* copy images */
2629 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2630 hdcImageList, 0, 0, SRCCOPY);
2631 #if 0
2632 /* delete 'empty' image space */
2633 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2634 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2635 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2636 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2637 #endif
2638 DeleteObject (himl->hbmMask);
2639 himl->hbmMask = hbmNewBitmap;
2641 else
2642 ERR("Could not create new mask bitmap!\n");
2645 DeleteDC (hdcImageList);
2646 DeleteDC (hdcBitmap);
2648 /* Update max image count and current image count */
2649 himl->cMaxImage = nNewCount;
2650 himl->cCurImage = iImageCount;
2652 return TRUE;
2656 /*************************************************************************
2657 * ImageList_SetOverlayImage [COMCTL32.@]
2659 * Assigns an overlay mask index to an existing image in an image list.
2661 * PARAMS
2662 * himl [I] handle to image list
2663 * iImage [I] image index
2664 * iOverlay [I] overlay mask index
2666 * RETURNS
2667 * Success: TRUE
2668 * Failure: FALSE
2671 BOOL WINAPI
2672 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2674 if (!himl)
2675 return FALSE;
2676 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2677 return FALSE;
2678 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2679 return FALSE;
2680 himl->nOvlIdx[iOverlay - 1] = iImage;
2681 return TRUE;
2686 /* helper for ImageList_Write - write bitmap to pstm
2687 * currently everything is written as 24 bit RGB, except masks
2689 static BOOL
2690 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2692 LPBITMAPFILEHEADER bmfh;
2693 LPBITMAPINFOHEADER bmih;
2694 LPBYTE data, lpBits, lpBitsOrg;
2695 BITMAP bm;
2696 INT bitCount, sizeImage, offBits, totalSize;
2697 INT nwidth, nheight, nsizeImage, icount;
2698 HDC xdc;
2699 BOOL result = FALSE;
2702 xdc = GetDC(0);
2703 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2705 /* XXX is this always correct? */
2706 icount = bm.bmWidth / cx;
2707 nwidth = cx << 2;
2708 nheight = cy * ((icount+3)>>2);
2710 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2711 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2712 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2714 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2715 if(bitCount != 24)
2716 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2717 offBits = totalSize;
2718 totalSize += nsizeImage;
2720 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2721 bmfh = (LPBITMAPFILEHEADER)data;
2722 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2723 lpBits = data + offBits;
2725 /* setup BITMAPFILEHEADER */
2726 bmfh->bfType = (('M' << 8) | 'B');
2727 bmfh->bfSize = 0;
2728 bmfh->bfReserved1 = 0;
2729 bmfh->bfReserved2 = 0;
2730 bmfh->bfOffBits = offBits;
2732 /* setup BITMAPINFOHEADER */
2733 bmih->biSize = sizeof(BITMAPINFOHEADER);
2734 bmih->biWidth = bm.bmWidth;
2735 bmih->biHeight = bm.bmHeight;
2736 bmih->biPlanes = 1;
2737 bmih->biBitCount = bitCount;
2738 bmih->biCompression = BI_RGB;
2739 bmih->biSizeImage = nsizeImage;
2740 bmih->biXPelsPerMeter = 0;
2741 bmih->biYPelsPerMeter = 0;
2742 bmih->biClrUsed = 0;
2743 bmih->biClrImportant = 0;
2745 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2746 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2747 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2748 goto failed;
2749 else {
2750 int i;
2751 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2752 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2754 for(i = 0; i < nheight; i++) {
2755 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2756 int noff = (nbpl * (nheight-1-i));
2757 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2761 bmih->biWidth = nwidth;
2762 bmih->biHeight = nheight;
2764 if(bitCount == 1) {
2765 /* Hack. */
2766 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2767 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2768 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2771 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2772 goto failed;
2774 result = TRUE;
2776 failed:
2777 ReleaseDC(0, xdc);
2778 LocalFree((HLOCAL)lpBitsOrg);
2780 return result;
2784 /*************************************************************************
2785 * ImageList_Write [COMCTL32.@]
2787 * Writes an image list to a stream.
2789 * PARAMS
2790 * himl [I] handle to image list
2791 * pstm [O] Pointer to a stream.
2793 * RETURNS
2794 * Success: TRUE
2795 * Failure: FALSE
2797 * BUGS
2798 * probably.
2801 BOOL WINAPI
2802 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2804 ILHEAD ilHead;
2805 int i;
2807 if (!himl)
2808 return FALSE;
2810 ilHead.usMagic = (('L' << 8) | 'I');
2811 ilHead.usVersion = 0x101;
2812 ilHead.cCurImage = himl->cCurImage;
2813 ilHead.cMaxImage = himl->cMaxImage;
2814 ilHead.cGrow = himl->cGrow;
2815 ilHead.cx = himl->cx;
2816 ilHead.cy = himl->cy;
2817 ilHead.bkcolor = himl->clrBk;
2818 ilHead.flags = himl->flags;
2819 for(i = 0; i < 4; i++) {
2820 ilHead.ovls[i] = himl->nOvlIdx[i];
2823 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2824 return FALSE;
2826 /* write the bitmap */
2827 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2828 return FALSE;
2830 /* write the mask if we have one */
2831 if(himl->flags & ILC_MASK) {
2832 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2833 return FALSE;
2836 return TRUE;