Get rid of a W->A cross call in ImageList_LoadImageW.
[wine.git] / dlls / comctl32 / imagelist.c
blobdbcfb07eaf28851f88b516e319efd2667aeba590
1 /*
2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Jason Mawdsley
6 * Copyright 2001 Michael Stefaniuc
7 * Copyright 2001 Charles Loep for CodeWeavers
8 * Copyright 2002 Dimitrie O. Paun
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * NOTE
26 * This code was audited for completeness against the documented features
27 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
29 * Unless otherwise noted, we believe this code to be complete, as per
30 * the specification mentioned above.
31 * If you discover missing features, or bugs, please note them below.
33 * TODO:
34 * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
35 * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
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 <stdarg.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "winerror.h"
48 #include "windef.h"
49 #include "winbase.h"
50 #include "objbase.h"
51 #include "wingdi.h"
52 #include "winuser.h"
53 #include "commctrl.h"
54 #include "comctl32.h"
55 #include "imagelist.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
61 #define MAX_OVERLAYIMAGE 15
63 /* internal image list data used for Drag & Drop operations */
64 typedef struct
66 HWND hwnd;
67 HIMAGELIST himl;
68 /* position of the drag image relative to the window */
69 INT x;
70 INT y;
71 /* offset of the hotspot relative to the origin of the image */
72 INT dxHotspot;
73 INT dyHotspot;
74 /* is the drag image visible */
75 BOOL bShow;
76 /* saved background */
77 HBITMAP hbmBg;
78 BOOL bHSPending;
79 } INTERNALDRAG;
81 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0, FALSE };
84 static inline BOOL is_valid(HIMAGELIST himl)
86 return himl && himl->magic == IMAGELIST_MAGIC;
90 /*************************************************************************
91 * IMAGELIST_InternalExpandBitmaps [Internal]
93 * Expands the bitmaps of an image list by the given number of images.
95 * PARAMS
96 * himl [I] handle to image list
97 * nImageCount [I] number of images to add
99 * RETURNS
100 * nothing
102 * NOTES
103 * This function can NOT be used to reduce the number of images.
105 static void
106 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
108 HDC hdcBitmap;
109 HBITMAP hbmNewBitmap, hbmNull;
110 INT nNewWidth, nNewCount;
112 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
113 && (himl->cy >= cy))
114 return;
116 if (cy == 0) cy = himl->cy;
117 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
118 nNewWidth = nNewCount * himl->cx;
120 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
121 hdcBitmap = CreateCompatibleDC (0);
123 hbmNewBitmap =
124 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
125 if (hbmNewBitmap == 0)
126 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
128 hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
129 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
130 himl->hdcImage, 0, 0, SRCCOPY);
132 SelectObject (hdcBitmap, hbmNull);
133 SelectObject (himl->hdcImage, hbmNewBitmap);
134 DeleteObject (himl->hbmImage);
135 himl->hbmImage = hbmNewBitmap;
137 if (himl->hbmMask) {
138 hbmNewBitmap =
139 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
141 if (hbmNewBitmap == 0)
142 ERR("creating new mask bitmap!\n");
144 SelectObject (hdcBitmap, hbmNewBitmap);
145 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
146 himl->hdcMask, 0, 0, SRCCOPY);
147 SelectObject (hdcBitmap, hbmNull);
148 SelectObject (himl->hdcMask, hbmNewBitmap);
149 DeleteObject (himl->hbmMask);
150 himl->hbmMask = hbmNewBitmap;
153 himl->cMaxImage = nNewCount;
155 DeleteDC (hdcBitmap);
159 /*************************************************************************
160 * ImageList_Add [COMCTL32.@]
162 * Add an image or images to an image list.
164 * PARAMS
165 * himl [I] handle to image list
166 * hbmImage [I] handle to image bitmap
167 * hbmMask [I] handle to mask bitmap
169 * RETURNS
170 * Success: Index of the first new image.
171 * Failure: -1
174 INT WINAPI
175 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
177 HDC hdcBitmap;
178 INT nFirstIndex, nImageCount;
179 INT nStartX;
180 BITMAP bmp;
181 HBITMAP hOldBitmap;
183 TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
184 if (!is_valid(himl))
185 return -1;
187 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
188 nImageCount = bmp.bmWidth / himl->cx;
190 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
192 nStartX = himl->cCurImage * himl->cx;
194 hdcBitmap = CreateCompatibleDC(0);
196 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
198 /* Copy result to the imagelist
200 BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
201 hdcBitmap, 0, 0, SRCCOPY);
203 if(himl->hbmMask)
205 HDC hdcTemp;
206 HBITMAP hOldBitmapTemp;
208 hdcTemp = CreateCompatibleDC(0);
209 hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
211 BitBlt (himl->hdcMask,
212 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
213 hdcTemp,
214 0, 0,
215 SRCCOPY);
217 SelectObject(hdcTemp, hOldBitmapTemp);
218 DeleteDC(hdcTemp);
220 /* Remove the background from the image
222 BitBlt (himl->hdcImage,
223 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
224 himl->hdcMask,
225 nStartX, 0,
226 0x220326); /* NOTSRCAND */
229 SelectObject(hdcBitmap, hOldBitmap);
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
252 #undef ImageList_AddIcon
253 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
255 return ImageList_ReplaceIcon (himl, -1, hIcon);
259 /*************************************************************************
260 * ImageList_AddMasked [COMCTL32.@]
262 * Adds an image or images to an image list and creates a mask from the
263 * specified bitmap using the mask color.
265 * PARAMS
266 * himl [I] handle to image list.
267 * hBitmap [I] handle to bitmap
268 * clrMask [I] mask color.
270 * RETURNS
271 * Success: Index of the first new image.
272 * Failure: -1
275 INT WINAPI
276 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
278 HDC hdcMask, hdcBitmap;
279 INT nIndex, nImageCount, nMaskXOffset=0;
280 BITMAP bmp;
281 HBITMAP hOldBitmap;
282 HBITMAP hMaskBitmap=0;
283 COLORREF bkColor;
285 TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask);
286 if (!is_valid(himl))
287 return -1;
289 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
290 return -1;
292 if (himl->cx > 0)
293 nImageCount = bmp.bmWidth / himl->cx;
294 else
295 nImageCount = 0;
297 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
299 nIndex = himl->cCurImage;
300 himl->cCurImage += nImageCount;
302 hdcBitmap = CreateCompatibleDC(0);
305 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
306 if(himl->hbmMask)
308 hdcMask = himl->hdcMask;
309 nMaskXOffset = nIndex * himl->cx;
311 else
314 Create a temp Mask so we can remove the background of
315 the Image (Windows does this even if there is no mask)
317 hdcMask = CreateCompatibleDC(0);
318 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
319 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 (himl->hdcImage,
351 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
352 hdcBitmap,
353 0, 0,
354 SRCCOPY);
355 /* Clean up
357 SelectObject(hdcBitmap, hOldBitmap);
358 DeleteDC(hdcBitmap);
359 if(!himl->hbmMask)
361 DeleteObject(hMaskBitmap);
362 DeleteDC(hdcMask);
365 return nIndex;
369 /*************************************************************************
370 * ImageList_BeginDrag [COMCTL32.@]
372 * Creates a temporary image list that contains one image. It will be used
373 * as a drag image.
375 * PARAMS
376 * himlTrack [I] handle to the source image list
377 * iTrack [I] index of the drag image in the source image list
378 * dxHotspot [I] X position of the hot spot of the drag image
379 * dyHotspot [I] Y position of the hot spot of the drag image
381 * RETURNS
382 * Success: TRUE
383 * Failure: FALSE
386 BOOL WINAPI
387 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
388 INT dxHotspot, INT dyHotspot)
390 INT cx, cy;
392 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
393 dxHotspot, dyHotspot);
395 if (!is_valid(himlTrack))
396 return FALSE;
398 if (InternalDrag.himl)
399 ImageList_EndDrag ();
401 cx = himlTrack->cx;
402 cy = himlTrack->cy;
404 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
405 if (InternalDrag.himl == NULL) {
406 WARN("Error creating drag image list!\n");
407 return FALSE;
410 InternalDrag.dxHotspot = dxHotspot;
411 InternalDrag.dyHotspot = dyHotspot;
413 /* copy image */
414 BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
416 /* copy mask */
417 BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
419 InternalDrag.himl->cCurImage = 1;
420 InternalDrag.bHSPending = TRUE;
422 return TRUE;
426 /*************************************************************************
427 * ImageList_Copy [COMCTL32.@]
429 * Copies an image of the source image list to an image of the
430 * destination image list. Images can be copied or swapped.
432 * PARAMS
433 * himlDst [I] handle to the destination image list
434 * iDst [I] destination image index.
435 * himlSrc [I] handle to the source image list
436 * iSrc [I] source image index
437 * uFlags [I] flags for the copy operation
439 * RETURNS
440 * Success: TRUE
441 * Failure: FALSE
443 * NOTES
444 * Copying from one image list to another is possible. The original
445 * implementation just copies or swaps within one image list.
446 * Could this feature become a bug??? ;-)
449 BOOL WINAPI
450 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
451 INT iSrc, UINT uFlags)
453 TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
455 if (!is_valid(himlSrc) || !is_valid(himlDst))
456 return FALSE;
457 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
458 return FALSE;
459 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
460 return FALSE;
462 if (uFlags & ILCF_SWAP) {
463 /* swap */
464 HDC hdcBmp;
465 HBITMAP hbmTempImage, hbmTempMask;
467 hdcBmp = CreateCompatibleDC (0);
469 /* create temporary bitmaps */
470 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
471 himlSrc->uBitsPixel, NULL);
472 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
473 1, NULL);
475 /* copy (and stretch) destination to temporary bitmaps.(save) */
476 /* image */
477 SelectObject (hdcBmp, hbmTempImage);
478 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
479 himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
480 SRCCOPY);
481 /* mask */
482 SelectObject (hdcBmp, hbmTempMask);
483 StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
484 himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
485 SRCCOPY);
487 /* copy (and stretch) source to destination */
488 /* image */
489 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
490 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
491 SRCCOPY);
492 /* mask */
493 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
494 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
495 SRCCOPY);
497 /* copy (without stretching) temporary bitmaps to source (restore) */
498 /* mask */
499 BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
500 hdcBmp, 0, 0, SRCCOPY);
502 /* image */
503 BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
504 hdcBmp, 0, 0, SRCCOPY);
505 /* delete temporary bitmaps */
506 DeleteObject (hbmTempMask);
507 DeleteObject (hbmTempImage);
508 DeleteDC(hdcBmp);
510 else {
511 /* copy image */
512 StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
513 himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
514 SRCCOPY);
516 /* copy mask */
517 StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
518 himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
519 SRCCOPY);
522 return TRUE;
526 /*************************************************************************
527 * ImageList_Create [COMCTL32.@] Creates a new image list.
529 * PARAMS
530 * cx [I] image height
531 * cy [I] image width
532 * flags [I] creation flags
533 * cInitial [I] initial number of images in the image list
534 * cGrow [I] number of images by which image list grows
536 * RETURNS
537 * Success: Handle to the created image list
538 * Failure: NULL
541 HIMAGELIST WINAPI
542 ImageList_Create (INT cx, INT cy, UINT flags,
543 INT cInitial, INT cGrow)
545 HIMAGELIST himl;
546 INT nCount;
547 HBITMAP hbmTemp;
548 static WORD aBitBlend25[] =
549 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
551 static WORD aBitBlend50[] =
552 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
554 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
556 himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
557 if (!himl)
558 return NULL;
560 cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
562 himl->magic = IMAGELIST_MAGIC;
563 himl->cx = cx;
564 himl->cy = cy;
565 himl->flags = flags;
566 himl->cMaxImage = cInitial + cGrow;
567 himl->cInitial = cInitial;
568 himl->cGrow = cGrow;
569 himl->clrFg = CLR_DEFAULT;
570 himl->clrBk = CLR_NONE;
572 /* initialize overlay mask indices */
573 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
574 himl->nOvlIdx[nCount] = -1;
576 /* Create Image & Mask DCs */
577 himl->hdcImage = CreateCompatibleDC (0);
578 if (!himl->hdcImage)
579 goto cleanup;
580 if (himl->flags & ILC_MASK){
581 himl->hdcMask = CreateCompatibleDC(0);
582 if (!himl->hdcMask)
583 goto cleanup;
586 himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
588 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
590 if (himl->cMaxImage > 0) {
591 himl->hbmImage =
592 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
593 1, himl->uBitsPixel, NULL);
594 if (himl->hbmImage == 0) {
595 ERR("Error creating image bitmap!\n");
596 goto cleanup;
598 SelectObject(himl->hdcImage, himl->hbmImage);
601 if (himl->flags & ILC_MASK) {
602 himl->hbmMask =
603 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
604 1, 1, NULL);
605 if (himl->hbmMask == 0) {
606 ERR("Error creating mask bitmap!\n");
607 goto cleanup;
609 SelectObject(himl->hdcMask, himl->hbmMask);
612 /* create blending brushes */
613 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
614 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
615 DeleteObject (hbmTemp);
617 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
618 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
619 DeleteObject (hbmTemp);
621 TRACE("created imagelist %p\n", himl);
622 return himl;
624 cleanup:
625 if (himl) ImageList_Destroy(himl);
626 return NULL;
630 /*************************************************************************
631 * ImageList_Destroy [COMCTL32.@]
633 * Destroys an image list.
635 * PARAMS
636 * himl [I] handle to image list
638 * RETURNS
639 * Success: TRUE
640 * Failure: FALSE
643 BOOL WINAPI
644 ImageList_Destroy (HIMAGELIST himl)
646 if (!is_valid(himl))
647 return FALSE;
649 /* delete image bitmaps */
650 if (himl->hbmImage)
651 DeleteObject (himl->hbmImage);
652 if (himl->hbmMask)
653 DeleteObject (himl->hbmMask);
655 /* delete image & mask DCs */
656 if (himl->hdcImage)
657 DeleteDC(himl->hdcImage);
658 if (himl->hdcMask)
659 DeleteDC(himl->hdcMask);
661 /* delete blending brushes */
662 if (himl->hbrBlend25)
663 DeleteObject (himl->hbrBlend25);
664 if (himl->hbrBlend50)
665 DeleteObject (himl->hbrBlend50);
667 ZeroMemory(himl, sizeof(*himl));
668 Free (himl);
670 return TRUE;
674 /*************************************************************************
675 * ImageList_DragEnter [COMCTL32.@]
677 * Locks window update and displays the drag image at the given position.
679 * PARAMS
680 * hwndLock [I] handle of the window that owns the drag image.
681 * x [I] X position of the drag image.
682 * y [I] Y position of the drag image.
684 * RETURNS
685 * Success: TRUE
686 * Failure: FALSE
688 * NOTES
689 * The position of the drag image is relative to the window, not
690 * the client area.
693 BOOL WINAPI
694 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
696 TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
698 if (!is_valid(InternalDrag.himl))
699 return FALSE;
701 if (hwndLock)
702 InternalDrag.hwnd = hwndLock;
703 else
704 InternalDrag.hwnd = GetDesktopWindow ();
706 InternalDrag.x = x;
707 InternalDrag.y = y;
709 /* draw the drag image and save the background */
710 if (!ImageList_DragShowNolock(TRUE)) {
711 return FALSE;
714 return TRUE;
718 /*************************************************************************
719 * ImageList_DragLeave [COMCTL32.@]
721 * Unlocks window update and hides the drag image.
723 * PARAMS
724 * hwndLock [I] handle of the window that owns the drag image.
726 * RETURNS
727 * Success: TRUE
728 * Failure: FALSE
731 BOOL WINAPI
732 ImageList_DragLeave (HWND hwndLock)
734 /* As we don't save drag info in the window this can lead to problems if
735 an app does not supply the same window as DragEnter */
736 /* if (hwndLock)
737 InternalDrag.hwnd = hwndLock;
738 else
739 InternalDrag.hwnd = GetDesktopWindow (); */
740 if(!hwndLock)
741 hwndLock = GetDesktopWindow();
742 if(InternalDrag.hwnd != hwndLock)
743 FIXME("DragLeave hWnd != DragEnter hWnd\n");
745 ImageList_DragShowNolock (FALSE);
747 return TRUE;
751 /*************************************************************************
752 * ImageList_InternalDragDraw [Internal]
754 * Draws the drag image.
756 * PARAMS
757 * hdc [I] device context to draw into.
758 * x [I] X position of the drag image.
759 * y [I] Y position of the drag image.
761 * RETURNS
762 * Success: TRUE
763 * Failure: FALSE
765 * NOTES
766 * The position of the drag image is relative to the window, not
767 * the client area.
771 static inline void
772 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
774 IMAGELISTDRAWPARAMS imldp;
776 ZeroMemory (&imldp, sizeof(imldp));
777 imldp.cbSize = sizeof(imldp);
778 imldp.himl = InternalDrag.himl;
779 imldp.i = 0;
780 imldp.hdcDst = hdc,
781 imldp.x = x;
782 imldp.y = y;
783 imldp.rgbBk = CLR_DEFAULT;
784 imldp.rgbFg = CLR_DEFAULT;
785 imldp.fStyle = ILD_NORMAL;
786 imldp.fState = ILS_ALPHA;
787 imldp.Frame = 128;
789 /* FIXME: instead of using the alpha blending, we should
790 * create a 50% mask, and draw it semitransparantly that way */
791 ImageList_DrawIndirect (&imldp);
794 /*************************************************************************
795 * ImageList_DragMove [COMCTL32.@]
797 * Moves the drag image.
799 * PARAMS
800 * x [I] X position of the drag image.
801 * y [I] Y position of the drag image.
803 * RETURNS
804 * Success: TRUE
805 * Failure: FALSE
807 * NOTES
808 * The position of the drag image is relative to the window, not
809 * the client area.
811 * BUGS
812 * The drag image should be drawn semitransparent.
815 BOOL WINAPI
816 ImageList_DragMove (INT x, INT y)
818 TRACE("(x=%d y=%d)\n", x, y);
820 if (!is_valid(InternalDrag.himl))
821 return FALSE;
823 /* draw/update the drag image */
824 if (InternalDrag.bShow) {
825 HDC hdcDrag;
826 HDC hdcOffScreen;
827 HDC hdcBg;
828 HBITMAP hbmOffScreen;
829 INT origNewX, origNewY;
830 INT origOldX, origOldY;
831 INT origRegX, origRegY;
832 INT sizeRegX, sizeRegY;
835 /* calculate the update region */
836 origNewX = x - InternalDrag.dxHotspot;
837 origNewY = y - InternalDrag.dyHotspot;
838 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
839 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
840 origRegX = min(origNewX, origOldX);
841 origRegY = min(origNewY, origOldY);
842 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
843 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
845 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
846 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
847 hdcOffScreen = CreateCompatibleDC(hdcDrag);
848 hdcBg = CreateCompatibleDC(hdcDrag);
850 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
851 SelectObject(hdcOffScreen, hbmOffScreen);
852 SelectObject(hdcBg, InternalDrag.hbmBg);
854 /* get the actual background of the update region */
855 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
856 origRegX, origRegY, SRCCOPY);
857 /* erase the old image */
858 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
859 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
860 SRCCOPY);
861 /* save the background */
862 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
863 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
864 /* draw the image */
865 ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX,
866 origNewY - origRegY);
867 /* draw the update region to the screen */
868 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
869 hdcOffScreen, 0, 0, SRCCOPY);
871 DeleteDC(hdcBg);
872 DeleteDC(hdcOffScreen);
873 DeleteObject(hbmOffScreen);
874 ReleaseDC(InternalDrag.hwnd, hdcDrag);
877 /* update the image position */
878 InternalDrag.x = x;
879 InternalDrag.y = y;
881 return TRUE;
885 /*************************************************************************
886 * ImageList_DragShowNolock [COMCTL32.@]
888 * Shows or hides the drag image.
890 * PARAMS
891 * bShow [I] TRUE shows the drag image, FALSE hides it.
893 * RETURNS
894 * Success: TRUE
895 * Failure: FALSE
897 * BUGS
898 * The drag image should be drawn semitransparent.
901 BOOL WINAPI
902 ImageList_DragShowNolock (BOOL bShow)
904 HDC hdcDrag;
905 HDC hdcBg;
906 INT x, y;
908 if (!is_valid(InternalDrag.himl))
909 return FALSE;
911 TRACE("bShow=0x%X!\n", bShow);
913 /* DragImage is already visible/hidden */
914 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
915 return FALSE;
918 /* position of the origin of the DragImage */
919 x = InternalDrag.x - InternalDrag.dxHotspot;
920 y = InternalDrag.y - InternalDrag.dyHotspot;
922 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
923 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
924 if (!hdcDrag) {
925 return FALSE;
928 hdcBg = CreateCompatibleDC(hdcDrag);
929 if (!InternalDrag.hbmBg) {
930 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
931 InternalDrag.himl->cx, InternalDrag.himl->cy);
933 SelectObject(hdcBg, InternalDrag.hbmBg);
935 if (bShow) {
936 /* save the background */
937 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
938 hdcDrag, x, y, SRCCOPY);
939 /* show the image */
940 ImageList_InternalDragDraw(hdcDrag, x, y);
941 } else {
942 /* hide the image */
943 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
944 hdcBg, 0, 0, SRCCOPY);
947 InternalDrag.bShow = !InternalDrag.bShow;
949 DeleteDC(hdcBg);
950 ReleaseDC (InternalDrag.hwnd, hdcDrag);
951 return TRUE;
955 /*************************************************************************
956 * ImageList_Draw [COMCTL32.@] Draws an image.
958 * PARAMS
959 * himl [I] handle to image list
960 * i [I] image index
961 * hdc [I] handle to device context
962 * x [I] x position
963 * y [I] y position
964 * fStyle [I] drawing flags
966 * RETURNS
967 * Success: TRUE
968 * Failure: FALSE
970 * SEE
971 * ImageList_DrawEx.
974 BOOL WINAPI
975 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
977 return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0,
978 CLR_DEFAULT, CLR_DEFAULT, fStyle);
982 /*************************************************************************
983 * ImageList_DrawEx [COMCTL32.@]
985 * Draws an image and allows to use extended drawing features.
987 * PARAMS
988 * himl [I] handle to image list
989 * i [I] image index
990 * hdc [I] handle to device context
991 * x [I] X position
992 * y [I] Y position
993 * dx [I] X offset
994 * dy [I] Y offset
995 * rgbBk [I] background color
996 * rgbFg [I] foreground color
997 * fStyle [I] drawing flags
999 * RETURNS
1000 * Success: TRUE
1001 * Failure: FALSE
1003 * NOTES
1004 * Calls ImageList_DrawIndirect.
1006 * SEE
1007 * ImageList_DrawIndirect.
1010 BOOL WINAPI
1011 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1012 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1013 UINT fStyle)
1015 IMAGELISTDRAWPARAMS imldp;
1017 ZeroMemory (&imldp, sizeof(imldp));
1018 imldp.cbSize = sizeof(imldp);
1019 imldp.himl = himl;
1020 imldp.i = i;
1021 imldp.hdcDst = hdc,
1022 imldp.x = x;
1023 imldp.y = y;
1024 imldp.cx = dx;
1025 imldp.cy = dy;
1026 imldp.rgbBk = rgbBk;
1027 imldp.rgbFg = rgbFg;
1028 imldp.fStyle = fStyle;
1030 return ImageList_DrawIndirect (&imldp);
1034 /*************************************************************************
1035 * ImageList_DrawIndirect [COMCTL32.@]
1037 * Draws an image using ...
1039 * PARAMS
1040 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1042 * RETURNS
1043 * Success: TRUE
1044 * Failure: FALSE
1047 BOOL WINAPI
1048 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1050 INT cx, cy, lx, ly, nOvlIdx;
1051 DWORD fState, dwRop;
1052 UINT fStyle;
1053 COLORREF clrBk, oldImageBk, oldImageFg;
1054 HDC hImageDC, hImageListDC, hMaskListDC;
1055 HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
1056 BOOL bIsTransparent, bBlend, bResult = FALSE;
1057 HIMAGELIST himl;
1059 if (!pimldp || !(himl = pimldp->himl)) return FALSE;
1060 if (!is_valid(himl)) return FALSE;
1061 if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE;
1063 lx = himl->cx * pimldp->i + pimldp->xBitmap;
1064 ly = pimldp->yBitmap;
1066 fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState;
1067 fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK;
1068 cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx;
1069 cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy;
1070 clrBk = (pimldp->rgbBk == CLR_DEFAULT) ? himl->clrBk : pimldp->rgbBk;
1071 bIsTransparent = (fStyle & ILD_TRANSPARENT) || clrBk == CLR_NONE;
1072 bBlend = fStyle & (ILD_BLEND25 | ILD_BLEND50);
1074 TRACE("hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n",
1075 himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy);
1077 /* we will use these DCs to access the images and masks in the ImageList */
1078 hImageListDC = himl->hdcImage;
1079 hMaskListDC = himl->hdcMask;
1081 /* these will accumulate the image and mask for the image we're drawing */
1082 hImageDC = CreateCompatibleDC( pimldp->hdcDst );
1083 hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
1084 hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0;
1086 /* Create a compatible DC. */
1087 if (!hImageListDC || !hImageDC || !hImageBmp ||
1088 (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC))
1089 goto cleanup;
1091 hOldImageBmp = SelectObject(hImageDC, hImageBmp);
1094 * To obtain a transparent look, background color should be set
1095 * to white and foreground color to black when blting the
1096 * monochrome mask.
1098 oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
1099 oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
1102 * Draw the initial image
1104 if(fStyle & ILD_MASK) {
1105 if (himl->hbmMask) {
1106 BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCCOPY);
1107 } else {
1108 HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
1109 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
1110 SelectObject(hImageDC, hOldBrush);
1112 } else if (himl->hbmMask && !bIsTransparent) {
1113 /* blend the image with the needed solid background */
1114 HBRUSH hOldBrush = SelectObject (hImageDC, CreateSolidBrush (clrBk));
1115 PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
1116 BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND );
1117 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT );
1118 DeleteObject (SelectObject (hImageDC, hOldBrush));
1119 } else {
1120 /* start off with the image, if we have a mask, we'll use it later */
1121 BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCCOPY);
1124 /* Time for blending, if required */
1125 if (bBlend) {
1126 HBRUSH hBlendBrush, hOldBrush;
1127 COLORREF clrBlend = pimldp->rgbFg;
1128 HDC hBlendMaskDC = hImageListDC;
1129 HBITMAP hOldBitmap;
1131 /* Create the blend Mask */
1132 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp);
1133 hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25;
1134 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
1135 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
1136 SelectObject(hBlendMaskDC, hOldBrush);
1138 /* Modify the blend mask if an Image Mask exist */
1139 if(himl->hbmMask) {
1140 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */
1141 BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY);
1144 /* now apply blend to the current image given the BlendMask */
1145 if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT);
1146 else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst);
1147 hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend));
1148 BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */
1149 DeleteObject(SelectObject(hImageDC, hOldBrush));
1150 SelectObject(hBlendMaskDC, hOldBitmap);
1153 /* Now do the overlay image, if any */
1154 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
1155 if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) {
1156 nOvlIdx = himl->nOvlIdx[nOvlIdx - 1];
1157 if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) {
1158 const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap;
1159 if (himl->hbmMask && !(fStyle & ILD_IMAGE))
1160 BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND);
1161 BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT);
1165 if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
1166 if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
1167 if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
1168 if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
1170 if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
1171 if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
1172 if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n");
1174 /* now copy the image to the screen */
1175 dwRop = SRCCOPY;
1176 if (himl->hbmMask && bIsTransparent && !(fStyle & ILD_MASK)) {
1177 COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) );
1178 COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff ));
1179 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND);
1180 SetBkColor(pimldp->hdcDst, oldDstBk);
1181 SetTextColor(pimldp->hdcDst, oldDstFg);
1182 dwRop = SRCPAINT;
1184 if (fStyle & ILD_ROP) dwRop = pimldp->dwRop;
1185 BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop);
1187 bResult = TRUE;
1189 /* cleanup the mess */
1190 SetBkColor(hImageDC, oldImageBk);
1191 SetTextColor(hImageDC, oldImageFg);
1192 SelectObject(hImageDC, hOldImageBmp);
1193 cleanup:
1194 DeleteObject(hBlendMaskBmp);
1195 DeleteObject(hImageBmp);
1196 DeleteDC(hImageDC);
1198 return bResult;
1202 /*************************************************************************
1203 * ImageList_Duplicate [COMCTL32.@] Duplicates an image list.
1205 * PARAMS
1206 * himlSrc [I] source image list handle
1208 * RETURNS
1209 * Success: Handle of duplicated image list.
1210 * Failure: NULL
1213 HIMAGELIST WINAPI
1214 ImageList_Duplicate (HIMAGELIST himlSrc)
1216 HIMAGELIST himlDst;
1218 if (!is_valid(himlSrc)) {
1219 ERR("Invalid image list handle!\n");
1220 return NULL;
1223 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1224 himlSrc->cInitial, himlSrc->cGrow);
1226 if (himlDst)
1228 BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1229 himlSrc->hdcImage, 0, 0, SRCCOPY);
1231 if (himlDst->hbmMask)
1232 BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1233 himlSrc->hdcMask, 0, 0, SRCCOPY);
1235 himlDst->cCurImage = himlSrc->cCurImage;
1236 himlDst->cMaxImage = himlSrc->cMaxImage;
1238 return himlDst;
1242 /*************************************************************************
1243 * ImageList_EndDrag [COMCTL32.@] Finishes a drag operation.
1245 * Finishes a drag operation.
1247 * PARAMS
1248 * no Parameters
1250 * RETURNS
1251 * Success: TRUE
1252 * Failure: FALSE
1255 VOID WINAPI
1256 ImageList_EndDrag (void)
1258 /* cleanup the InternalDrag struct */
1259 InternalDrag.hwnd = 0;
1260 ImageList_Destroy (InternalDrag.himl);
1261 InternalDrag.himl = 0;
1262 InternalDrag.x= 0;
1263 InternalDrag.y= 0;
1264 InternalDrag.dxHotspot = 0;
1265 InternalDrag.dyHotspot = 0;
1266 InternalDrag.bShow = FALSE;
1267 DeleteObject(InternalDrag.hbmBg);
1268 InternalDrag.hbmBg = 0;
1269 InternalDrag.bHSPending = FALSE;
1273 /*************************************************************************
1274 * ImageList_GetBkColor [COMCTL32.@]
1276 * Returns the background color of an image list.
1278 * PARAMS
1279 * himl [I] Image list handle.
1281 * RETURNS
1282 * Success: background color
1283 * Failure: CLR_NONE
1286 COLORREF WINAPI
1287 ImageList_GetBkColor (HIMAGELIST himl)
1289 return himl ? himl->clrBk : CLR_NONE;
1293 /*************************************************************************
1294 * ImageList_GetDragImage [COMCTL32.@]
1296 * Returns the handle to the internal drag image list.
1298 * PARAMS
1299 * ppt [O] Pointer to the drag position. Can be NULL.
1300 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1302 * RETURNS
1303 * Success: Handle of the drag image list.
1304 * Failure: NULL.
1307 HIMAGELIST WINAPI
1308 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1310 if (is_valid(InternalDrag.himl)) {
1311 if (ppt) {
1312 ppt->x = InternalDrag.x;
1313 ppt->y = InternalDrag.y;
1315 if (pptHotspot) {
1316 pptHotspot->x = InternalDrag.dxHotspot;
1317 pptHotspot->y = InternalDrag.dyHotspot;
1319 return (InternalDrag.himl);
1322 return NULL;
1326 /*************************************************************************
1327 * ImageList_GetFlags [COMCTL32.@]
1329 * BUGS
1330 * Stub.
1333 DWORD WINAPI
1334 ImageList_GetFlags(HIMAGELIST himl)
1336 FIXME("(%p):empty stub\n", himl);
1337 return 0;
1341 /*************************************************************************
1342 * ImageList_GetIcon [COMCTL32.@]
1344 * Creates an icon from a masked image of an image list.
1346 * PARAMS
1347 * himl [I] handle to image list
1348 * i [I] image index
1349 * flags [I] drawing style flags
1351 * RETURNS
1352 * Success: icon handle
1353 * Failure: NULL
1356 HICON WINAPI
1357 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1359 ICONINFO ii;
1360 HICON hIcon;
1361 HBITMAP hOldDstBitmap;
1362 HDC hdcDst;
1364 TRACE("%p %d %d\n", himl, i, fStyle);
1365 if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL;
1367 hdcDst = CreateCompatibleDC(0);
1369 ii.fIcon = TRUE;
1370 ii.xHotspot = 0;
1371 ii.yHotspot = 0;
1373 /* draw mask*/
1374 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1375 hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask);
1376 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, WHITENESS);
1377 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_MASK);
1379 /* draw image*/
1380 ii.hbmColor = CreateCompatibleBitmap (himl->hdcImage, himl->cx, himl->cy);
1381 SelectObject (hdcDst, ii.hbmColor);
1382 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1383 ImageList_Draw(himl, i, hdcDst, 0, 0, fStyle | ILD_TRANSPARENT);
1386 * CreateIconIndirect requires us to deselect the bitmaps from
1387 * the DCs before calling
1389 SelectObject(hdcDst, hOldDstBitmap);
1391 hIcon = CreateIconIndirect (&ii);
1393 DeleteObject (ii.hbmMask);
1394 DeleteObject (ii.hbmColor);
1395 DeleteDC (hdcDst);
1397 return hIcon;
1401 /*************************************************************************
1402 * ImageList_GetIconSize [COMCTL32.@]
1404 * Retrieves the size of an image in an image list.
1406 * PARAMS
1407 * himl [I] handle to image list
1408 * cx [O] pointer to the image width.
1409 * cy [O] pointer to the image height.
1411 * RETURNS
1412 * Success: TRUE
1413 * Failure: FALSE
1415 * NOTES
1416 * All images in an image list have the same size.
1419 BOOL WINAPI
1420 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1422 if (!is_valid(himl))
1423 return FALSE;
1424 if ((himl->cx <= 0) || (himl->cy <= 0))
1425 return FALSE;
1427 if (cx)
1428 *cx = himl->cx;
1429 if (cy)
1430 *cy = himl->cy;
1432 return TRUE;
1436 /*************************************************************************
1437 * ImageList_GetImageCount [COMCTL32.@]
1439 * Returns the number of images in an image list.
1441 * PARAMS
1442 * himl [I] handle to image list
1444 * RETURNS
1445 * Success: Number of images.
1446 * Failure: 0
1449 INT WINAPI
1450 ImageList_GetImageCount (HIMAGELIST himl)
1452 if (!is_valid(himl))
1453 return 0;
1455 return himl->cCurImage;
1459 /*************************************************************************
1460 * ImageList_GetImageInfo [COMCTL32.@]
1462 * Returns information about an image in an image list.
1464 * PARAMS
1465 * himl [I] handle to image list
1466 * i [I] image index
1467 * pImageInfo [O] pointer to the image information
1469 * RETURNS
1470 * Success: TRUE
1471 * Failure: FALSE
1474 BOOL WINAPI
1475 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1477 if (!is_valid(himl) || (pImageInfo == NULL))
1478 return FALSE;
1479 if ((i < 0) || (i >= himl->cCurImage))
1480 return FALSE;
1482 pImageInfo->hbmImage = himl->hbmImage;
1483 pImageInfo->hbmMask = himl->hbmMask;
1485 pImageInfo->rcImage.top = 0;
1486 pImageInfo->rcImage.bottom = himl->cy;
1487 pImageInfo->rcImage.left = i * himl->cx;
1488 pImageInfo->rcImage.right = (i+1) * himl->cx;
1490 return TRUE;
1494 /*************************************************************************
1495 * ImageList_GetImageRect [COMCTL32.@]
1497 * Retrieves the rectangle of the specified image in an image list.
1499 * PARAMS
1500 * himl [I] handle to image list
1501 * i [I] image index
1502 * lpRect [O] pointer to the image rectangle
1504 * RETURNS
1505 * Success: TRUE
1506 * Failure: FALSE
1508 * NOTES
1509 * This is an UNDOCUMENTED function!!!
1512 BOOL WINAPI
1513 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1515 if (!is_valid(himl) || (lpRect == NULL))
1516 return FALSE;
1517 if ((i < 0) || (i >= himl->cCurImage))
1518 return FALSE;
1520 lpRect->left = i * himl->cx;
1521 lpRect->top = 0;
1522 lpRect->right = lpRect->left + himl->cx;
1523 lpRect->bottom = himl->cy;
1525 return TRUE;
1529 /*************************************************************************
1530 * ImageList_LoadImage [COMCTL32.@]
1531 * ImageList_LoadImageA [COMCTL32.@]
1533 * Creates an image list from a bitmap, icon or cursor.
1535 * PARAMS
1536 * hi [I] instance handle
1537 * lpbmp [I] name or id of the image
1538 * cx [I] width of each image
1539 * cGrow [I] number of images to expand
1540 * clrMask [I] mask color
1541 * uType [I] type of image to load
1542 * uFlags [I] loading flags
1544 * RETURNS
1545 * Success: handle to the loaded image list
1546 * Failure: NULL
1548 * SEE
1549 * LoadImage ()
1552 HIMAGELIST WINAPI
1553 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1554 COLORREF clrMask, UINT uType, UINT uFlags)
1556 HIMAGELIST himl = NULL;
1557 HANDLE handle;
1558 INT nImageCount;
1560 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1561 if (!handle) {
1562 ERR("Error loading image!\n");
1563 return NULL;
1566 if (uType == IMAGE_BITMAP) {
1567 BITMAP bmp;
1568 GetObjectA (handle, sizeof(BITMAP), &bmp);
1570 /* To match windows behavior, if cx is set to zero and
1571 the flag DI_DEFAULTSIZE is specified, cx becomes the
1572 system metric value for icons. If the flag is not specified
1573 the function sets the size to the height of the bitmap */
1574 if (cx == 0)
1576 if (uFlags & DI_DEFAULTSIZE)
1577 cx = GetSystemMetrics (SM_CXICON);
1578 else
1579 cx = bmp.bmHeight;
1582 nImageCount = bmp.bmWidth / cx;
1584 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1585 nImageCount, cGrow);
1586 if (!himl) {
1587 DeleteObject (handle);
1588 return NULL;
1590 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1592 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1593 ICONINFO ii;
1594 BITMAP bmp;
1596 GetIconInfo (handle, &ii);
1597 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1598 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1599 ILC_MASK | ILC_COLOR, 1, cGrow);
1600 if (!himl) {
1601 DeleteObject (ii.hbmColor);
1602 DeleteObject (ii.hbmMask);
1603 DeleteObject (handle);
1604 return NULL;
1606 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1607 DeleteObject (ii.hbmColor);
1608 DeleteObject (ii.hbmMask);
1611 DeleteObject (handle);
1613 return himl;
1617 /*************************************************************************
1618 * ImageList_LoadImageW [COMCTL32.@]
1620 * Creates an image list from a bitmap, icon or cursor.
1622 * PARAMS
1623 * hi [I] instance handle
1624 * lpbmp [I] name or id of the image
1625 * cx [I] width of each image
1626 * cGrow [I] number of images to expand
1627 * clrMask [I] mask color
1628 * uType [I] type of image to load
1629 * uFlags [I] loading flags
1631 * RETURNS
1632 * Success: handle to the loaded image list
1633 * Failure: NULL
1635 * SEE
1636 * LoadImage ()
1639 HIMAGELIST WINAPI
1640 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1641 COLORREF clrMask, UINT uType, UINT uFlags)
1643 HIMAGELIST himl = NULL;
1644 HANDLE handle;
1645 INT nImageCount;
1647 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1648 if (!handle) {
1649 ERR("Error loading image!\n");
1650 return NULL;
1653 if (uType == IMAGE_BITMAP) {
1654 BITMAP bmp;
1655 GetObjectW (handle, sizeof(BITMAP), &bmp);
1657 /* To match windows behavior, if cx is set to zero and
1658 the flag DI_DEFAULTSIZE is specified, cx becomes the
1659 system metric value for icons. If the flag is not specified
1660 the function sets the size to the height of the bitmap */
1661 if (cx == 0)
1663 if (uFlags & DI_DEFAULTSIZE)
1664 cx = GetSystemMetrics (SM_CXICON);
1665 else
1666 cx = bmp.bmHeight;
1669 nImageCount = bmp.bmWidth / cx;
1671 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1672 nImageCount, cGrow);
1673 if (!himl) {
1674 DeleteObject (handle);
1675 return NULL;
1677 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1679 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1680 ICONINFO ii;
1681 BITMAP bmp;
1683 GetIconInfo (handle, &ii);
1684 GetObjectW (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1685 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1686 ILC_MASK | ILC_COLOR, 1, cGrow);
1687 if (!himl) {
1688 DeleteObject (ii.hbmColor);
1689 DeleteObject (ii.hbmMask);
1690 DeleteObject (handle);
1691 return NULL;
1693 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1694 DeleteObject (ii.hbmColor);
1695 DeleteObject (ii.hbmMask);
1698 DeleteObject (handle);
1700 return himl;
1704 /*************************************************************************
1705 * ImageList_Merge [COMCTL32.@]
1707 * Creates a new image list that contains a merged image from the specified
1708 * images of both source image lists.
1710 * PARAMS
1711 * himl1 [I] handle to first image list
1712 * i1 [I] first image index
1713 * himl2 [I] handle to second image list
1714 * i2 [I] second image index
1715 * dx [I] X offset of the second image relative to the first.
1716 * dy [I] Y offset of the second image relative to the first.
1718 * RETURNS
1719 * Success: handle of the merged image list.
1720 * Failure: NULL
1723 HIMAGELIST WINAPI
1724 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1725 INT dx, INT dy)
1727 HIMAGELIST himlDst = NULL;
1728 INT cxDst, cyDst;
1729 INT xOff1, yOff1, xOff2, yOff2;
1730 INT nX1, nX2;
1732 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1733 i2, dx, dy);
1735 if (!is_valid(himl1) || !is_valid(himl2))
1736 return NULL;
1738 /* check indices */
1739 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1740 ERR("Index 1 out of range! %d\n", i1);
1741 return NULL;
1744 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1745 ERR("Index 2 out of range! %d\n", i2);
1746 return NULL;
1749 if (dx > 0) {
1750 cxDst = max (himl1->cx, dx + himl2->cx);
1751 xOff1 = 0;
1752 xOff2 = dx;
1754 else if (dx < 0) {
1755 cxDst = max (himl2->cx, himl1->cx - dx);
1756 xOff1 = -dx;
1757 xOff2 = 0;
1759 else {
1760 cxDst = max (himl1->cx, himl2->cx);
1761 xOff1 = 0;
1762 xOff2 = 0;
1765 if (dy > 0) {
1766 cyDst = max (himl1->cy, dy + himl2->cy);
1767 yOff1 = 0;
1768 yOff2 = dy;
1770 else if (dy < 0) {
1771 cyDst = max (himl2->cy, himl1->cy - dy);
1772 yOff1 = -dy;
1773 yOff2 = 0;
1775 else {
1776 cyDst = max (himl1->cy, himl2->cy);
1777 yOff1 = 0;
1778 yOff2 = 0;
1781 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1782 if (!himlDst)
1783 return NULL;
1785 if (himlDst) {
1786 nX1 = i1 * himl1->cx;
1787 nX2 = i2 * himl2->cx;
1789 /* copy image */
1790 BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS);
1791 BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY);
1792 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND);
1793 BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT);
1795 /* copy mask */
1796 BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS);
1797 BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY);
1798 BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND);
1800 himlDst->cCurImage = 1;
1803 return himlDst;
1807 /* helper for _read_bitmap currently unused */
1808 #if 0
1809 static int may_use_dibsection(HDC hdc) {
1810 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
1811 if (bitspixel>8)
1812 return TRUE;
1813 if (bitspixel<=4)
1814 return FALSE;
1815 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
1817 #endif
1819 /* helper for ImageList_Read, see comments below */
1820 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
1821 HDC xdc = 0, hBitmapDC =0;
1822 BITMAPFILEHEADER bmfh;
1823 BITMAPINFOHEADER bmih;
1824 int bitsperpixel,palspace,longsperline,width,height;
1825 LPBITMAPINFOHEADER bmihc = NULL;
1826 int result = 0;
1827 HBITMAP hbitmap = 0, hDIB = 0;
1828 LPBYTE bits = NULL;
1830 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
1831 (bmfh.bfType != (('M'<<8)|'B')) ||
1832 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
1833 (bmih.biSize != sizeof(bmih))
1835 return 0;
1837 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
1838 if (bitsperpixel<=8)
1839 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
1840 else
1841 palspace = 0;
1842 width = bmih.biWidth;
1843 height = bmih.biHeight;
1844 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
1845 memcpy(bmihc,&bmih,sizeof(bmih));
1846 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
1847 bmihc->biSizeImage = (longsperline*height)<<2;
1849 /* read the palette right after the end of the bitmapinfoheader */
1850 if (palspace)
1851 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
1852 goto ret1;
1854 xdc = GetDC(0);
1855 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
1856 if ((bitsperpixel>1) &&
1857 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
1859 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1860 if (!hbitmap)
1861 goto ret1;
1862 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1863 goto ret1;
1864 result = 1;
1865 } else
1866 #endif
1868 int i,nwidth,nheight,nRows;
1870 nwidth = width*(height/cy);
1871 nheight = cy;
1872 nRows = (height/cy);
1874 if (bitsperpixel==1)
1875 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
1876 else
1877 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
1879 hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
1880 if (!hDIB)
1881 goto ret1;
1882 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
1883 goto ret1;
1885 hBitmapDC = CreateCompatibleDC(0);
1886 SelectObject(hBitmapDC, hbitmap);
1888 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
1889 /* Do not forget that windows bitmaps are bottom->top */
1890 TRACE("nRows=%d\n", nRows);
1891 for (i=0; i < nRows; i++){
1892 StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits,
1893 (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY);
1896 result = 1;
1898 ret1:
1899 if (xdc) ReleaseDC(0,xdc);
1900 if (bmihc) LocalFree((HLOCAL)bmihc);
1901 if (hDIB) DeleteObject(hDIB);
1902 if (hBitmapDC) DeleteDC(hBitmapDC);
1903 if (!result) {
1904 if (hbitmap) {
1905 DeleteObject(hbitmap);
1906 hbitmap = 0;
1909 return hbitmap;
1912 /*************************************************************************
1913 * ImageList_Read [COMCTL32.@]
1915 * Reads an image list from a stream.
1917 * PARAMS
1918 * pstm [I] pointer to a stream
1920 * RETURNS
1921 * Success: handle to image list
1922 * Failure: NULL
1924 * The format is like this:
1925 * ILHEAD ilheadstruct;
1927 * for the color image part:
1928 * BITMAPFILEHEADER bmfh;
1929 * BITMAPINFOHEADER bmih;
1930 * only if it has a palette:
1931 * RGBQUAD rgbs[nr_of_paletted_colors];
1933 * BYTE colorbits[imagesize];
1935 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
1936 * BITMAPFILEHEADER bmfh_mask;
1937 * BITMAPINFOHEADER bmih_mask;
1938 * only if it has a palette (it usually does not):
1939 * RGBQUAD rgbs[nr_of_paletted_colors];
1941 * BYTE maskbits[imagesize];
1943 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
1944 * _read_bitmap needs to convert them.
1946 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
1948 ILHEAD ilHead;
1949 HIMAGELIST himl;
1950 HBITMAP hbmColor=0,hbmMask=0;
1951 int i;
1953 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
1954 return NULL;
1955 if (ilHead.usMagic != (('L' << 8) | 'I'))
1956 return NULL;
1957 if (ilHead.usVersion != 0x101) /* probably version? */
1958 return NULL;
1960 #if 0
1961 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
1962 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
1963 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
1964 FIXME(" ilHead.cx = %d\n",ilHead.cx);
1965 FIXME(" ilHead.cy = %d\n",ilHead.cy);
1966 FIXME(" ilHead.flags = %x\n",ilHead.flags);
1967 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
1968 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
1969 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
1970 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
1971 #endif
1973 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
1974 if (!hbmColor)
1975 return NULL;
1976 if (ilHead.flags & ILC_MASK) {
1977 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
1978 if (!hbmMask) {
1979 DeleteObject(hbmColor);
1980 return NULL;
1984 himl = ImageList_Create (
1985 ilHead.cx,
1986 ilHead.cy,
1987 ilHead.flags,
1988 1, /* initial */
1989 ilHead.cGrow
1991 if (!himl) {
1992 DeleteObject(hbmColor);
1993 DeleteObject(hbmMask);
1994 return NULL;
1996 SelectObject(himl->hdcImage, hbmColor);
1997 DeleteObject(himl->hbmImage);
1998 himl->hbmImage = hbmColor;
1999 if (hbmMask){
2000 SelectObject(himl->hdcMask, hbmMask);
2001 DeleteObject(himl->hbmMask);
2002 himl->hbmMask = hbmMask;
2004 himl->cCurImage = ilHead.cCurImage;
2005 himl->cMaxImage = ilHead.cMaxImage;
2007 ImageList_SetBkColor(himl,ilHead.bkcolor);
2008 for (i=0;i<4;i++)
2009 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2010 return himl;
2014 /*************************************************************************
2015 * ImageList_Remove [COMCTL32.@] Removes an image from an image list
2017 * PARAMS
2018 * himl [I] image list handle
2019 * i [I] image index
2021 * RETURNS
2022 * Success: TRUE
2023 * Failure: FALSE
2026 BOOL WINAPI
2027 ImageList_Remove (HIMAGELIST himl, INT i)
2029 HBITMAP hbmNewImage, hbmNewMask;
2030 HDC hdcBmp;
2031 INT cxNew, nCount;
2033 TRACE("(himl=%p i=%d)\n", himl, i);
2035 if (!is_valid(himl)) {
2036 ERR("Invalid image list handle!\n");
2037 return FALSE;
2040 if ((i < -1) || (i >= himl->cCurImage)) {
2041 ERR("index out of range! %d\n", i);
2042 return FALSE;
2045 if (i == -1) {
2046 /* remove all */
2047 if (himl->cCurImage == 0) {
2048 /* remove all on empty ImageList is allowed */
2049 TRACE("remove all on empty ImageList!\n");
2050 return TRUE;
2053 himl->cMaxImage = himl->cInitial + himl->cGrow;
2054 himl->cCurImage = 0;
2055 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2056 himl->nOvlIdx[nCount] = -1;
2058 hbmNewImage = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2059 1, himl->uBitsPixel, NULL);
2060 SelectObject (himl->hdcImage, hbmNewImage);
2061 DeleteObject (himl->hbmImage);
2062 himl->hbmImage = hbmNewImage;
2064 if (himl->hbmMask) {
2065 hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2066 1, 1, NULL);
2067 SelectObject (himl->hdcMask, hbmNewMask);
2068 DeleteObject (himl->hbmMask);
2069 himl->hbmMask = hbmNewMask;
2072 else {
2073 /* delete one image */
2074 TRACE("Remove single image! %d\n", i);
2076 /* create new bitmap(s) */
2077 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2079 TRACE(" - Number of images: %d / %d (Old/New)\n",
2080 himl->cCurImage, himl->cCurImage - 1);
2081 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2082 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2084 hbmNewImage =
2085 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2087 if (himl->hbmMask)
2088 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2089 else
2090 hbmNewMask = 0; /* Just to keep compiler happy! */
2092 hdcBmp = CreateCompatibleDC (0);
2094 /* copy all images and masks prior to the "removed" image */
2095 if (i > 0) {
2096 TRACE("Pre image copy: Copy %d images\n", i);
2098 SelectObject (hdcBmp, hbmNewImage);
2099 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2100 himl->hdcImage, 0, 0, SRCCOPY);
2102 if (himl->hbmMask) {
2103 SelectObject (hdcBmp, hbmNewMask);
2104 BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy,
2105 himl->hdcMask, 0, 0, SRCCOPY);
2109 /* copy all images and masks behind the removed image */
2110 if (i < himl->cCurImage - 1) {
2111 TRACE("Post image copy!\n");
2112 SelectObject (hdcBmp, hbmNewImage);
2113 BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2114 himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY);
2116 if (himl->hbmMask) {
2117 SelectObject (hdcBmp, hbmNewMask);
2118 BitBlt (hdcBmp, i * himl->cx, 0,
2119 (himl->cCurImage - i - 1) * himl->cx,
2120 himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY);
2124 DeleteDC (hdcBmp);
2126 /* delete old images and insert new ones */
2127 SelectObject (himl->hdcImage, hbmNewImage);
2128 DeleteObject (himl->hbmImage);
2129 himl->hbmImage = hbmNewImage;
2130 if (himl->hbmMask) {
2131 SelectObject (himl->hdcMask, hbmNewMask);
2132 DeleteObject (himl->hbmMask);
2133 himl->hbmMask = hbmNewMask;
2136 himl->cCurImage--;
2137 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2140 return TRUE;
2144 /*************************************************************************
2145 * ImageList_Replace [COMCTL32.@]
2147 * Replaces an image in an image list with a new image.
2149 * PARAMS
2150 * himl [I] handle to image list
2151 * i [I] image index
2152 * hbmImage [I] handle to image bitmap
2153 * hbmMask [I] handle to mask bitmap. Can be NULL.
2155 * RETURNS
2156 * Success: TRUE
2157 * Failure: FALSE
2160 BOOL WINAPI
2161 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2162 HBITMAP hbmMask)
2164 HDC hdcImage;
2165 BITMAP bmp;
2167 TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
2169 if (!is_valid(himl)) {
2170 ERR("Invalid image list handle!\n");
2171 return FALSE;
2174 if ((i >= himl->cMaxImage) || (i < 0)) {
2175 ERR("Invalid image index!\n");
2176 return FALSE;
2179 hdcImage = CreateCompatibleDC (0);
2180 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2182 /* Replace Image */
2183 SelectObject (hdcImage, hbmImage);
2185 StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy,
2186 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2188 if (himl->hbmMask)
2190 /* Replace Mask */
2191 SelectObject (hdcImage, hbmMask);
2193 StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy,
2194 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2197 /* Remove the background from the image
2199 StretchBlt (himl->hdcImage,
2200 i*himl->cx, 0, himl->cx, himl->cy,
2201 hdcImage,
2202 0, 0, bmp.bmWidth, bmp.bmHeight,
2203 0x220326); /* NOTSRCAND */
2206 DeleteDC (hdcImage);
2208 return TRUE;
2212 /*************************************************************************
2213 * ImageList_ReplaceIcon [COMCTL32.@]
2215 * Replaces an image in an image list using an icon.
2217 * PARAMS
2218 * himl [I] handle to image list
2219 * i [I] image index
2220 * hIcon [I] handle to icon
2222 * RETURNS
2223 * Success: index of the replaced image
2224 * Failure: -1
2227 INT WINAPI
2228 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2230 HDC hdcImage;
2231 INT nIndex;
2232 HICON hBestFitIcon;
2233 HBITMAP hbmOldSrc;
2234 ICONINFO ii;
2235 BITMAP bmp;
2237 TRACE("(0x%lx 0x%x %p)\n", (DWORD)himl, i, hIcon);
2239 if (!is_valid(himl))
2240 return -1;
2241 if ((i >= himl->cMaxImage) || (i < -1))
2242 return -1;
2244 hBestFitIcon = CopyImage(
2245 hIcon, IMAGE_ICON,
2246 himl->cx, himl->cy,
2247 LR_COPYFROMRESOURCE);
2249 GetIconInfo (hBestFitIcon, &ii);
2250 if (ii.hbmMask == 0)
2251 ERR("no mask!\n");
2252 if (ii.hbmColor == 0)
2253 ERR("no color!\n");
2254 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2256 if (i == -1) {
2257 if (himl->cCurImage + 1 > himl->cMaxImage)
2258 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2260 nIndex = himl->cCurImage;
2261 himl->cCurImage++;
2263 else
2264 nIndex = i;
2266 hdcImage = CreateCompatibleDC (0);
2267 TRACE("hdcImage=%p\n", hdcImage);
2268 if (hdcImage == 0)
2269 ERR("invalid hdcImage!\n");
2271 SetTextColor(himl->hdcImage, RGB(0,0,0));
2272 SetBkColor (himl->hdcImage, RGB(255,255,255));
2273 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2275 StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy,
2276 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2278 if (himl->hbmMask) {
2279 SelectObject (hdcImage, ii.hbmMask);
2280 StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy,
2281 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2284 SelectObject (hdcImage, hbmOldSrc);
2286 if(hBestFitIcon)
2287 DestroyIcon(hBestFitIcon);
2288 if (hdcImage)
2289 DeleteDC (hdcImage);
2290 if (ii.hbmColor)
2291 DeleteObject (ii.hbmColor);
2292 if (ii.hbmMask)
2293 DeleteObject (ii.hbmMask);
2295 return nIndex;
2299 /*************************************************************************
2300 * ImageList_SetBkColor [COMCTL32.@]
2302 * Sets the background color of an image list.
2304 * PARAMS
2305 * himl [I] handle to image list
2306 * clrBk [I] background color
2308 * RETURNS
2309 * Success: previous background color
2310 * Failure: CLR_NONE
2313 COLORREF WINAPI
2314 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2316 COLORREF clrOldBk;
2318 if (!is_valid(himl))
2319 return CLR_NONE;
2321 clrOldBk = himl->clrBk;
2322 himl->clrBk = clrBk;
2323 return clrOldBk;
2327 /*************************************************************************
2328 * ImageList_SetDragCursorImage [COMCTL32.@]
2330 * Combines the specified image with the current drag image
2332 * PARAMS
2333 * himlDrag [I] handle to drag image list
2334 * iDrag [I] drag image index
2335 * dxHotspot [I] X position of the hot spot
2336 * dyHotspot [I] Y position of the hot spot
2338 * RETURNS
2339 * Success: TRUE
2340 * Failure: FALSE
2342 * NOTES
2343 * When this function is called and the drag image is visible, a
2344 * short flickering occurs but this matches the Win9x behavior. It is
2345 * possible to fix the flickering using code like in ImageList_DragMove.
2348 BOOL WINAPI
2349 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2350 INT dxHotspot, INT dyHotspot)
2352 HIMAGELIST himlTemp;
2353 INT dx, dy;
2354 BOOL visible;
2356 if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag))
2357 return FALSE;
2359 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2360 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2362 visible = InternalDrag.bShow;
2364 /* Calculate the offset between the origin of the old image and the
2365 * origin of the second image.
2366 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2367 * hotspot) to the origin of the second image.
2368 * See M$DN for details */
2369 if(InternalDrag.bHSPending) {
2370 dx = 0;
2371 dy = 0;
2372 InternalDrag.bHSPending = FALSE;
2373 } else {
2374 dx = InternalDrag.dxHotspot - dxHotspot;
2375 dy = InternalDrag.dyHotspot - dyHotspot;
2377 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2379 if (visible) {
2380 /* hide the drag image */
2381 ImageList_DragShowNolock(FALSE);
2383 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2384 (InternalDrag.himl->cy != himlTemp->cy)) {
2385 /* the size of the drag image changed, invalidate the buffer */
2386 DeleteObject(InternalDrag.hbmBg);
2387 InternalDrag.hbmBg = 0;
2390 ImageList_Destroy (InternalDrag.himl);
2391 InternalDrag.himl = himlTemp;
2393 /* update the InternalDragOffset, if the origin of the
2394 * DragImage was changed by ImageList_Merge. */
2395 if (dx <= 0)
2396 InternalDrag.dxHotspot = dxHotspot;
2397 if (dy <= 0)
2398 InternalDrag.dyHotspot = dyHotspot;
2400 if (visible) {
2401 /* show the drag image */
2402 ImageList_DragShowNolock(TRUE);
2405 return TRUE;
2409 /*************************************************************************
2410 * ImageList_SetFilter [COMCTL32.@]
2412 * Sets a filter (or does something completely different)!!???
2413 * It removes 12 Bytes from the stack (3 Parameters).
2415 * PARAMS
2416 * himl [I] SHOULD be a handle to image list
2417 * i [I] COULD be an index?
2418 * dwFilter [I] ???
2420 * RETURNS
2421 * Success: TRUE ???
2422 * Failure: FALSE ???
2424 * BUGS
2425 * This is an UNDOCUMENTED function!!!!
2426 * empty stub.
2429 BOOL WINAPI
2430 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2432 FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter);
2434 return FALSE;
2438 /*************************************************************************
2439 * ImageList_SetFlags [COMCTL32.@]
2441 * BUGS
2442 * Stub.
2445 DWORD WINAPI
2446 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2448 FIXME("(%p %08lx):empty stub\n", himl, flags);
2449 return 0;
2453 /*************************************************************************
2454 * ImageList_SetIconSize [COMCTL32.@]
2456 * Sets the image size of the bitmap and deletes all images.
2458 * PARAMS
2459 * himl [I] handle to image list
2460 * cx [I] image width
2461 * cy [I] image height
2463 * RETURNS
2464 * Success: TRUE
2465 * Failure: FALSE
2468 BOOL WINAPI
2469 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2471 INT nCount;
2472 HBITMAP hbmNew;
2474 if (!is_valid(himl))
2475 return FALSE;
2477 /* remove all images */
2478 himl->cMaxImage = himl->cInitial + himl->cGrow;
2479 himl->cCurImage = 0;
2480 himl->cx = cx;
2481 himl->cy = cy;
2483 /* initialize overlay mask indices */
2484 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2485 himl->nOvlIdx[nCount] = -1;
2487 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2488 1, himl->uBitsPixel, NULL);
2489 SelectObject (himl->hdcImage, hbmNew);
2490 DeleteObject (himl->hbmImage);
2491 himl->hbmImage = hbmNew;
2493 if (himl->hbmMask) {
2494 hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2495 1, 1, NULL);
2496 SelectObject (himl->hdcMask, hbmNew);
2497 DeleteObject (himl->hbmMask);
2498 himl->hbmMask = hbmNew;
2501 return TRUE;
2505 /*************************************************************************
2506 * ImageList_SetImageCount [COMCTL32.@]
2508 * Resizes an image list to the specified number of images.
2510 * PARAMS
2511 * himl [I] handle to image list
2512 * iImageCount [I] number of images in the image list
2514 * RETURNS
2515 * Success: TRUE
2516 * Failure: FALSE
2519 BOOL WINAPI
2520 ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
2522 HDC hdcBitmap;
2523 HBITMAP hbmNewBitmap;
2524 INT nNewCount, nCopyCount;
2526 TRACE("%p %d\n",himl,iImageCount);
2528 if (!is_valid(himl))
2529 return FALSE;
2530 if (himl->cCurImage >= iImageCount)
2531 return FALSE;
2532 if (himl->cMaxImage > iImageCount)
2534 himl->cCurImage = iImageCount;
2535 return TRUE;
2538 nNewCount = iImageCount + himl->cGrow;
2539 nCopyCount = min(himl->cCurImage, iImageCount);
2541 hdcBitmap = CreateCompatibleDC (0);
2543 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2544 1, himl->uBitsPixel, NULL);
2545 if (hbmNewBitmap != 0)
2547 SelectObject (hdcBitmap, hbmNewBitmap);
2549 /* copy images */
2550 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2551 himl->hdcImage, 0, 0, SRCCOPY);
2552 #if 0
2553 /* delete 'empty' image space */
2554 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2555 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2556 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2557 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2558 #endif
2559 SelectObject (himl->hdcImage, hbmNewBitmap);
2560 DeleteObject (himl->hbmImage);
2561 himl->hbmImage = hbmNewBitmap;
2563 else
2564 ERR("Could not create new image bitmap !\n");
2566 if (himl->hbmMask)
2568 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2569 1, 1, NULL);
2570 if (hbmNewBitmap != 0)
2572 SelectObject (hdcBitmap, hbmNewBitmap);
2574 /* copy images */
2575 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2576 himl->hdcMask, 0, 0, SRCCOPY);
2577 #if 0
2578 /* delete 'empty' image space */
2579 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2580 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2581 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2582 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2583 #endif
2584 SelectObject (himl->hdcMask, hbmNewBitmap);
2585 DeleteObject (himl->hbmMask);
2586 himl->hbmMask = hbmNewBitmap;
2588 else
2589 ERR("Could not create new mask bitmap!\n");
2592 DeleteDC (hdcBitmap);
2594 /* Update max image count and current image count */
2595 himl->cMaxImage = nNewCount;
2596 himl->cCurImage = iImageCount;
2598 return TRUE;
2602 /*************************************************************************
2603 * ImageList_SetOverlayImage [COMCTL32.@]
2605 * Assigns an overlay mask index to an existing image in an image list.
2607 * PARAMS
2608 * himl [I] handle to image list
2609 * iImage [I] image index
2610 * iOverlay [I] overlay mask index
2612 * RETURNS
2613 * Success: TRUE
2614 * Failure: FALSE
2617 BOOL WINAPI
2618 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2620 if (!is_valid(himl))
2621 return FALSE;
2622 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2623 return FALSE;
2624 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2625 return FALSE;
2626 himl->nOvlIdx[iOverlay - 1] = iImage;
2627 return TRUE;
2632 /* helper for ImageList_Write - write bitmap to pstm
2633 * currently everything is written as 24 bit RGB, except masks
2635 static BOOL
2636 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2638 LPBITMAPFILEHEADER bmfh;
2639 LPBITMAPINFOHEADER bmih;
2640 LPBYTE data, lpBits, lpBitsOrg;
2641 BITMAP bm;
2642 INT bitCount, sizeImage, offBits, totalSize;
2643 INT nwidth, nheight, nsizeImage, icount;
2644 HDC xdc;
2645 BOOL result = FALSE;
2648 xdc = GetDC(0);
2649 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2651 /* XXX is this always correct? */
2652 icount = bm.bmWidth / cx;
2653 nwidth = cx;
2654 nheight = cy * icount;
2656 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2657 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2658 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2660 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2661 if(bitCount != 24)
2662 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2663 offBits = totalSize;
2664 totalSize += nsizeImage;
2666 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2667 bmfh = (LPBITMAPFILEHEADER)data;
2668 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2669 lpBits = data + offBits;
2671 /* setup BITMAPFILEHEADER */
2672 bmfh->bfType = (('M' << 8) | 'B');
2673 bmfh->bfSize = 0;
2674 bmfh->bfReserved1 = 0;
2675 bmfh->bfReserved2 = 0;
2676 bmfh->bfOffBits = offBits;
2678 /* setup BITMAPINFOHEADER */
2679 bmih->biSize = sizeof(BITMAPINFOHEADER);
2680 bmih->biWidth = bm.bmWidth;
2681 bmih->biHeight = bm.bmHeight;
2682 bmih->biPlanes = 1;
2683 bmih->biBitCount = bitCount;
2684 bmih->biCompression = BI_RGB;
2685 bmih->biSizeImage = sizeImage;
2686 bmih->biXPelsPerMeter = 0;
2687 bmih->biYPelsPerMeter = 0;
2688 bmih->biClrUsed = 0;
2689 bmih->biClrImportant = 0;
2691 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage);
2692 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2693 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2694 goto failed;
2695 else {
2696 int i;
2697 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2698 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2700 for(i = 0; i < nheight; i++) {
2701 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2702 int noff = (nbpl * (nheight-1-i));
2703 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2707 bmih->biWidth = nwidth;
2708 bmih->biHeight = nheight;
2709 bmih->biSizeImage = nsizeImage;
2711 if(bitCount == 1) {
2712 /* Hack. */
2713 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2714 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2715 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2718 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2719 goto failed;
2721 result = TRUE;
2723 failed:
2724 ReleaseDC(0, xdc);
2725 LocalFree((HLOCAL)lpBitsOrg);
2727 return result;
2731 /*************************************************************************
2732 * ImageList_Write [COMCTL32.@]
2734 * Writes an image list to a stream.
2736 * PARAMS
2737 * himl [I] handle to image list
2738 * pstm [O] Pointer to a stream.
2740 * RETURNS
2741 * Success: TRUE
2742 * Failure: FALSE
2744 * BUGS
2745 * probably.
2748 BOOL WINAPI
2749 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2751 ILHEAD ilHead;
2752 int i;
2754 if (!is_valid(himl))
2755 return FALSE;
2757 ilHead.usMagic = (('L' << 8) | 'I');
2758 ilHead.usVersion = 0x101;
2759 ilHead.cCurImage = himl->cCurImage;
2760 ilHead.cMaxImage = himl->cMaxImage;
2761 ilHead.cGrow = himl->cGrow;
2762 ilHead.cx = himl->cx;
2763 ilHead.cy = himl->cy;
2764 ilHead.bkcolor = himl->clrBk;
2765 ilHead.flags = himl->flags;
2766 for(i = 0; i < 4; i++) {
2767 ilHead.ovls[i] = himl->nOvlIdx[i];
2770 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2771 return FALSE;
2773 /* write the bitmap */
2774 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2775 return FALSE;
2777 /* write the mask if we have one */
2778 if(himl->flags & ILC_MASK) {
2779 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
2780 return FALSE;
2783 return TRUE;