Don't return overflow if no class buffer was specified.
[wine/dcerpc.git] / dlls / comctl32 / imagelist.c
blobb4ed6f0efaeeb2b79e53dec1effe8111d1644f3e
1 /*
2 * ImageList implementation
4 * Copyright 1998 Eric Kohl
5 * 2000 Jason Mawdsley.
6 * 2001 Michael Stefaniuc
7 * 2001 Charles Loep for CodeWeavers
9 * TODO:
10 * - Fix ImageList_DrawIndirect (xBitmap, yBitmap, rgbFg, rgbBk, dwRop).
11 * - Fix ImageList_GetIcon.
12 * - Fix ImageList_SetFilter (undocumented).
13 * BTW does anybody know anything about this function???
14 * - It removes 12 Bytes from the stack (3 Parameters).
15 * - First parameter SHOULD be a HIMAGELIST.
16 * - Second parameter COULD be an index?????
17 * - Third parameter.... ?????????????????????
19 * Comments:
20 * - ImageList_Draw, ImageList_DrawEx and ImageList_GetIcon use
21 * ImageList_DrawIndirect. Since ImageList_DrawIndirect is still
22 * partially implemented, the functions mentioned above will be
23 * limited in functionality too.
26 #include <stdlib.h>
27 #include <string.h>
28 #include "winerror.h"
29 #include "winbase.h"
30 #include "wine/obj_base.h"
31 #include "wine/obj_storage.h"
32 #include "commctrl.h"
33 #include "imagelist.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(imagelist);
39 #define MAX_OVERLAYIMAGE 15
41 /* internal image list data used for Drag & Drop operations */
42 typedef struct
44 HWND hwnd;
45 HIMAGELIST himl;
46 /* position of the drag image relative to the window */
47 INT x;
48 INT y;
49 /* offset of the hotspot relative to the origin of the image */
50 INT dxHotspot;
51 INT dyHotspot;
52 /* is the drag image visible */
53 BOOL bShow;
54 /* saved background */
55 HBITMAP hbmBg;
56 } INTERNALDRAG;
58 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
62 /*************************************************************************
63 * IMAGELIST_InternalExpandBitmaps [Internal]
65 * Expands the bitmaps of an image list by the given number of images.
67 * PARAMS
68 * himl [I] handle to image list
69 * nImageCount [I] number of images to add
71 * RETURNS
72 * nothing
74 * NOTES
75 * This function can NOT be used to reduce the number of images.
77 static VOID
78 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
80 HDC hdcImageList, hdcBitmap;
81 HBITMAP hbmNewBitmap;
82 INT nNewWidth, nNewCount;
84 if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
85 && (himl->cy >= cy))
86 return;
88 if (cy == 0) cy = himl->cy;
89 nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
90 nNewWidth = nNewCount * himl->cx;
92 TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount);
93 hdcImageList = CreateCompatibleDC (0);
94 hdcBitmap = CreateCompatibleDC (0);
96 hbmNewBitmap =
97 CreateBitmap (nNewWidth, cy, 1, himl->uBitsPixel, NULL);
98 if (hbmNewBitmap == 0)
99 ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy);
101 SelectObject (hdcImageList, himl->hbmImage);
102 SelectObject (hdcBitmap, hbmNewBitmap);
103 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
104 hdcImageList, 0, 0, SRCCOPY);
106 DeleteObject (himl->hbmImage);
107 himl->hbmImage = hbmNewBitmap;
109 if (himl->hbmMask) {
110 hbmNewBitmap =
111 CreateBitmap (nNewWidth, cy, 1, 1, NULL);
113 if (hbmNewBitmap == 0)
114 ERR("creating new mask bitmap!\n");
116 SelectObject (hdcImageList, himl->hbmMask);
117 SelectObject (hdcBitmap, hbmNewBitmap);
118 BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy,
119 hdcImageList, 0, 0, SRCCOPY);
120 DeleteObject (himl->hbmMask);
121 himl->hbmMask = hbmNewBitmap;
124 himl->cMaxImage = nNewCount;
126 DeleteDC (hdcImageList);
127 DeleteDC (hdcBitmap);
131 /*************************************************************************
132 * IMAGELIST_InternalDraw [Internal]
134 * Draws the image in the ImageList (without the mask)
136 * PARAMS
137 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
138 * cx [I] the width of the image to display
139 * cy............[I] the height of the image to display
141 * RETURNS
142 * nothing
144 * NOTES
145 * This function is used by ImageList_DrawIndirect, when it is
146 * required to draw only the Image (without the mask) to the screen.
148 * Blending and Overlays styles are accomplished by another function
150 static VOID
151 IMAGELIST_InternalDraw(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
153 HDC hImageDC;
154 HBITMAP hOldBitmap;
156 hImageDC = CreateCompatibleDC(0);
157 hOldBitmap = SelectObject(hImageDC, pimldp->himl->hbmImage);
158 BitBlt(pimldp->hdcDst,
159 pimldp->x, pimldp->y, cx, cy,
160 hImageDC,
161 pimldp->himl->cx * pimldp->i, 0,
162 SRCCOPY);
164 SelectObject(hImageDC, hOldBitmap);
165 DeleteDC(hImageDC);
169 /*************************************************************************
170 * IMAGELIST_InternalDrawMask [Internal]
172 * Draws the image in the ImageList with the mask
174 * PARAMS
175 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
176 * cx [I] the width of the image to display
177 * cy............[I] the height of the image to display
179 * RETURNS
180 * nothing
182 * NOTES
183 * This function is used by ImageList_DrawIndirect, when it is
184 * required to draw the Image with the mask to the screen.
186 * Blending and Overlays styles are accomplished by another function.
188 static VOID
189 IMAGELIST_InternalDrawMask(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
191 BOOL bUseCustomBackground, bBlendFlag;
192 HBRUSH hBrush, hOldBrush;
193 HDC hMaskDC, hImageDC;
194 HBITMAP hOldBitmapImage, hOldBitmapMask;
195 HIMAGELIST himlLocal = pimldp->himl;
196 COLORREF oldBkColor, oldFgColor;
197 UINT fStyle = pimldp->fStyle & (~ILD_OVERLAYMASK);
200 * We need a dc and bitmap to draw on that is
201 * not on the screen.
203 HDC hOffScreenDC = 0;
204 HBITMAP hOffScreenBmp = 0;
206 bUseCustomBackground = (himlLocal->clrBk != CLR_NONE);
207 bBlendFlag = (fStyle & ILD_BLEND50 ) || (fStyle & ILD_BLEND25);
209 hImageDC = CreateCompatibleDC(0);
210 hMaskDC = CreateCompatibleDC(0);
212 /* Create a compatible DC. */
213 hOffScreenDC = CreateCompatibleDC( pimldp->hdcDst );
215 if ( hOffScreenDC )
217 hOffScreenBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy );
219 if ( hOffScreenBmp )
220 SelectObject( hOffScreenDC, hOffScreenBmp );
221 else
222 goto cleanup;
224 else
225 goto cleanup;
227 hOldBitmapImage = SelectObject(hImageDC, himlLocal->hbmImage);
228 hOldBitmapMask = SelectObject(hMaskDC, himlLocal->hbmMask);
231 * Get a copy of the image for the masking operations.
232 * We will use the copy, and this dc for all the various
233 * blitting, and then do one final blit to the screen dc.
234 * This should clean up most of the flickering.
236 BitBlt( hOffScreenDC, 0, 0, cx, cy, pimldp->hdcDst, pimldp->x,
237 pimldp->y, SRCCOPY);
240 * Draw the Background for the appropriate Styles
242 if( bUseCustomBackground && (fStyle == ILD_NORMAL || fStyle & ILD_IMAGE
243 || bBlendFlag) )
246 hBrush = CreateSolidBrush (himlLocal->clrBk);
247 hOldBrush = SelectObject (pimldp->hdcDst, hBrush);
249 PatBlt( hOffScreenDC, pimldp->x, pimldp->y, cx, cy, PATCOPY );
251 DeleteObject (SelectObject (pimldp->hdcDst, hOldBrush));
255 * Draw Image Transparently over the current background
257 if(fStyle == ILD_NORMAL || (fStyle & ILD_TRANSPARENT) ||
258 ((fStyle & ILD_IMAGE) && bUseCustomBackground) || bBlendFlag)
259 { /*
260 * To obtain a transparent look, background color should be set
261 * to white and foreground color to black when blting the
262 * monochrome mask.
265 oldBkColor = SetBkColor( hOffScreenDC, RGB( 0xff, 0xff, 0xff ) );
266 oldFgColor = SetTextColor( hOffScreenDC, RGB( 0, 0, 0 ) );
268 BitBlt( hOffScreenDC, 0, 0, cx, cy,hMaskDC, himlLocal->cx * pimldp->i,
269 0, SRCAND );
271 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,himlLocal->cx * pimldp->i,
272 0, SRCPAINT );
277 * Draw the image when no Background is specified
279 else if((fStyle & ILD_IMAGE) && !bUseCustomBackground)
281 BitBlt( hOffScreenDC, 0, 0, cx, cy, hImageDC,
282 himlLocal->cx * pimldp->i, 0, SRCCOPY);
285 * Draw the mask with or without a background
287 else if(fStyle & ILD_MASK)
289 BitBlt( hOffScreenDC, 0, 0, cx, cy, hMaskDC, himlLocal->cx * pimldp->i,
290 0, bUseCustomBackground ? SRCCOPY : SRCAND);
294 * Blit the bitmap to the screen now.
296 BitBlt( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy,
297 hOffScreenDC, 0, 0, SRCCOPY);
300 SelectObject(hImageDC, hOldBitmapImage);
301 SelectObject(hMaskDC, hOldBitmapMask);
303 cleanup:
305 DeleteDC(hImageDC);
306 DeleteDC(hMaskDC);
308 DeleteDC( hOffScreenDC );
309 DeleteObject( hOffScreenBmp );
311 return;
314 /*************************************************************************
315 * IMAGELIST_InternalDrawBlend [Internal]
317 * Draws the Blend over the current image
319 * PARAMS
320 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
321 * cx [I] the width of the image to display
322 * cy............[I] the height of the image to display
324 * RETURNS
325 * nothing
327 * NOTES
328 * This functions is used by ImageList_DrawIndirect, when it is
329 * required to add the blend to the current image.
332 static VOID
333 IMAGELIST_InternalDrawBlend(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
336 HDC hBlendMaskDC,hMaskDC;
337 HBRUSH hBlendColorBrush, hBlendBrush, hOldBrush;
338 HBITMAP hBlendMaskBitmap, hOldBitmap;
339 COLORREF clrBlend, OldTextColor, OldBkColor;
340 HIMAGELIST himlLocal = pimldp->himl;
342 clrBlend = GetSysColor (COLOR_HIGHLIGHT);
343 if (!(pimldp->rgbFg == CLR_DEFAULT))
345 clrBlend = pimldp->rgbFg;
347 /* Create the blend Mask
349 hBlendMaskDC = CreateCompatibleDC(0);
350 hBlendBrush = pimldp->fStyle & ILD_BLEND50 ?
351 himlLocal->hbrBlend50 : himlLocal->hbrBlend25;
353 hBlendMaskBitmap = CreateBitmap(cx, cy, 1, 1, NULL);
354 hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBitmap);
356 hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush);
357 PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY);
358 SelectObject(hBlendMaskDC, hOldBrush);
360 /* Modify the blend mask if an Image Mask exist
362 if(pimldp->himl->hbmMask != 0)
364 HBITMAP hOldMaskBitmap;
365 hMaskDC = CreateCompatibleDC(0);
366 hOldMaskBitmap = (HBITMAP) SelectObject(hMaskDC, himlLocal->hbmMask);
368 BitBlt(hBlendMaskDC,
369 0,0, cx, cy,
370 hMaskDC,
371 himlLocal->cx * pimldp->i,0,
372 0x220326); /* NOTSRCAND */
374 BitBlt(hBlendMaskDC,
375 0,0, cx, cy,
376 hBlendMaskDC,
377 0,0,
378 NOTSRCCOPY);
380 SelectObject(hMaskDC, hOldMaskBitmap);
381 DeleteDC(hMaskDC);
384 /* Apply blend to the current image given the BlendMask
386 OldTextColor = SetTextColor(pimldp->hdcDst, 0);
387 OldBkColor = SetBkColor(pimldp->hdcDst, RGB(255,255,255));
388 hBlendColorBrush = CreateSolidBrush(clrBlend);
389 hOldBrush = (HBRUSH) SelectObject (pimldp->hdcDst, hBlendColorBrush);
391 BitBlt (pimldp->hdcDst,
392 pimldp->x, pimldp->y, cx, cy,
393 hBlendMaskDC,
394 0, 0,
395 0xB8074A); /* PSDPxax */
397 SelectObject(pimldp->hdcDst, hOldBrush);
398 SetTextColor(pimldp->hdcDst, OldTextColor);
399 SetBkColor(pimldp->hdcDst, OldBkColor);
400 SelectObject(hBlendMaskDC, hOldBitmap);
401 DeleteDC(hBlendMaskDC);
402 DeleteObject(hBlendMaskBitmap);
403 DeleteObject(hBlendColorBrush);
406 /*************************************************************************
407 * IMAGELIST_InternalDrawOverlay [Internal]
409 * Draws the overlay image
411 * PARAMS
412 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
413 * cx [I] the width of the image to display
414 * cy............[I] the height of the image to display
416 * RETURNS
417 * nothing
419 * NOTES
420 * This functions is used by ImageList_DrawIndirect, when it is
421 * required to draw the overlay
425 static VOID
426 IMAGELIST_InternalDrawOverlay(IMAGELISTDRAWPARAMS *pimldp, INT cx, INT cy)
428 INT nOvlIdx;
429 HDC hImageDC;
430 HBITMAP hOldBitmap;
432 nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8;
433 if ((nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE))
435 nOvlIdx = pimldp->himl->nOvlIdx[nOvlIdx - 1];
436 if ((nOvlIdx >= 0) && (nOvlIdx <= pimldp->himl->cCurImage))
438 hImageDC = CreateCompatibleDC(0);
439 if (pimldp->himl->hbmMask)
441 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
442 pimldp->himl->hbmMask);
444 BitBlt (pimldp->hdcDst,
445 pimldp->x, pimldp->y, cx, cy,
446 hImageDC, pimldp->himl->cx * nOvlIdx, 0,
447 SRCAND);
449 SelectObject(hImageDC, hOldBitmap);
451 hOldBitmap = (HBITMAP) SelectObject (hImageDC,
452 pimldp->himl->hbmImage);
454 BitBlt (pimldp->hdcDst,
455 pimldp->x, pimldp->y, cx, cy,
456 hImageDC,
457 pimldp->himl->cx * nOvlIdx, 0,
458 SRCPAINT);
460 SelectObject(hImageDC, hOldBitmap);
461 DeleteDC(hImageDC);
467 /*************************************************************************
468 * ImageList_Add [COMCTL32.40]
470 * Add an image or images to an image list.
472 * PARAMS
473 * himl [I] handle to image list
474 * hbmImage [I] handle to image bitmap
475 * hbmMask [I] handle to mask bitmap
477 * RETURNS
478 * Success: Index of the first new image.
479 * Failure: -1
482 INT WINAPI
483 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
485 HDC hdcImage, hdcBitmap;
486 INT nFirstIndex, nImageCount;
487 INT nStartX;
488 BITMAP bmp;
489 HBITMAP hOldBitmapImage, hOldBitmap;
491 TRACE("himl=%p hbmimage=%x hbmmask=%x\n", himl, hbmImage, hbmMask);
492 if (!himl || !hbmImage)
493 return -1;
495 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
496 nImageCount = bmp.bmWidth / himl->cx;
498 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
500 nStartX = himl->cCurImage * himl->cx;
502 hdcImage = CreateCompatibleDC(0);
503 hdcBitmap = CreateCompatibleDC(0);
505 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
506 hOldBitmap = SelectObject(hdcBitmap, hbmImage);
508 /* Copy result to the imagelist
510 BitBlt (hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight,
511 hdcBitmap, 0, 0, SRCCOPY);
513 if(himl->hbmMask)
515 HDC hdcMask, hdcTemp, hOldBitmapMask, hOldBitmapTemp;
517 hdcMask = CreateCompatibleDC (0);
518 hdcTemp = CreateCompatibleDC(0);
519 hOldBitmapMask = (HBITMAP) SelectObject(hdcMask, himl->hbmMask);
520 hOldBitmapTemp = (HBITMAP) SelectObject(hdcTemp, hbmMask);
522 BitBlt (hdcMask,
523 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
524 hdcTemp,
525 0, 0,
526 SRCCOPY);
528 SelectObject(hdcTemp, hOldBitmapTemp);
529 DeleteDC(hdcTemp);
531 /* Remove the background from the image
533 BitBlt (hdcImage,
534 nStartX, 0, bmp.bmWidth, bmp.bmHeight,
535 hdcMask,
536 nStartX, 0,
537 0x220326); /* NOTSRCAND */
539 SelectObject(hdcMask, hOldBitmapMask);
540 DeleteDC(hdcMask);
543 SelectObject(hdcImage, hOldBitmapImage);
544 SelectObject(hdcBitmap, hOldBitmap);
545 DeleteDC(hdcImage);
546 DeleteDC(hdcBitmap);
548 nFirstIndex = himl->cCurImage;
549 himl->cCurImage += nImageCount;
551 return nFirstIndex;
555 /*************************************************************************
556 * ImageList_AddIcon [COMCTL32.41]
558 * Adds an icon to an image list.
560 * PARAMS
561 * himl [I] handle to image list
562 * hIcon [I] handle to icon
564 * RETURNS
565 * Success: index of the new image
566 * Failure: -1
569 INT WINAPI
570 ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
572 return ImageList_ReplaceIcon (himl, -1, hIcon);
576 /*************************************************************************
577 * ImageList_AddMasked [COMCTL32.42]
579 * Adds an image or images to an image list and creates a mask from the
580 * specified bitmap using the mask color.
582 * PARAMS
583 * himl [I] handle to image list.
584 * hBitmap [I] handle to bitmap
585 * clrMask [I] mask color.
587 * RETURNS
588 * Success: Index of the first new image.
589 * Failure: -1
592 INT WINAPI
593 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
595 HDC hdcImage, hdcMask, hdcBitmap;
596 INT nIndex, nImageCount, nMaskXOffset=0;
597 BITMAP bmp;
598 HBITMAP hOldBitmap, hOldBitmapMask, hOldBitmapImage;
599 HBITMAP hMaskBitmap=0;
600 COLORREF bkColor;
602 TRACE("himl=%p hbitmap=%x clrmask=%lx\n", himl, hBitmap, clrMask);
603 if (himl == NULL)
604 return -1;
606 if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp))
607 return -1;
609 nImageCount = bmp.bmWidth / himl->cx;
611 IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
613 nIndex = himl->cCurImage;
614 himl->cCurImage += nImageCount;
616 hdcMask = CreateCompatibleDC (0);
617 hdcImage = CreateCompatibleDC(0);
618 hdcBitmap = CreateCompatibleDC(0);
621 hOldBitmapImage = SelectObject(hdcImage, himl->hbmImage);
622 hOldBitmap = SelectObject(hdcBitmap, hBitmap);
623 if(himl->hbmMask)
625 hOldBitmapMask = SelectObject(hdcMask, himl->hbmMask);
626 nMaskXOffset = nIndex * himl->cx;
628 else
631 Create a temp Mask so we can remove the background of
632 the Image (Windows does this even if there is no mask)
634 hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
635 hOldBitmapMask = SelectObject(hdcMask, hMaskBitmap);
636 nMaskXOffset = 0;
638 /* create monochrome image to the mask bitmap */
639 bkColor = (clrMask != CLR_DEFAULT) ? clrMask :
640 GetPixel (hdcBitmap, 0, 0);
641 SetBkColor (hdcBitmap, bkColor);
642 BitBlt (hdcMask,
643 nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight,
644 hdcBitmap, 0, 0,
645 SRCCOPY);
647 SetBkColor(hdcBitmap, RGB(255,255,255));
648 /*Remove the background from the image
651 WINDOWS BUG ALERT!!!!!!
652 The statement below should not be done in common practice
653 but this is how ImageList_AddMasked works in Windows.
654 It overwrites the original bitmap passed, this was discovered
655 by using the same bitmap to iterate the different styles
656 on windows where it failed (BUT ImageList_Add is OK)
657 This is here in case some apps rely on this bug
659 BitBlt(hdcBitmap,
660 0, 0, bmp.bmWidth, bmp.bmHeight,
661 hdcMask,
662 nMaskXOffset, 0,
663 0x220326); /* NOTSRCAND */
664 /* Copy result to the imagelist
666 BitBlt (hdcImage,
667 nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight,
668 hdcBitmap,
669 0, 0,
670 SRCCOPY);
671 /* Clean up
673 SelectObject(hdcMask,hOldBitmapMask);
674 SelectObject(hdcImage, hOldBitmapImage);
675 SelectObject(hdcBitmap, hOldBitmap);
676 DeleteDC(hdcMask);
677 DeleteDC(hdcImage);
678 DeleteDC(hdcBitmap);
679 if(!himl->hbmMask)
681 DeleteObject(hMaskBitmap);
684 return nIndex;
688 /*************************************************************************
689 * ImageList_BeginDrag [COMCTL32.43]
691 * Creates a temporary image list that contains one image. It will be used
692 * as a drag image.
694 * PARAMS
695 * himlTrack [I] handle to the source image list
696 * iTrack [I] index of the drag image in the source image list
697 * dxHotspot [I] X position of the hot spot of the drag image
698 * dyHotspot [I] Y position of the hot spot of the drag image
700 * RETURNS
701 * Success: TRUE
702 * Failure: FALSE
705 BOOL WINAPI
706 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
707 INT dxHotspot, INT dyHotspot)
709 HDC hdcSrc, hdcDst;
710 INT cx, cy;
712 TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
713 dxHotspot, dyHotspot);
715 if (himlTrack == NULL)
716 return FALSE;
718 if (InternalDrag.himl)
719 ImageList_EndDrag ();
721 cx = himlTrack->cx;
722 cy = himlTrack->cy;
724 InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
725 if (InternalDrag.himl == NULL) {
726 ERR("Error creating drag image list!\n");
727 return FALSE;
730 InternalDrag.dxHotspot = dxHotspot;
731 InternalDrag.dyHotspot = dyHotspot;
733 hdcSrc = CreateCompatibleDC (0);
734 hdcDst = CreateCompatibleDC (0);
736 /* copy image */
737 SelectObject (hdcSrc, himlTrack->hbmImage);
738 SelectObject (hdcDst, InternalDrag.himl->hbmImage);
739 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
741 /* copy mask */
742 SelectObject (hdcSrc, himlTrack->hbmMask);
743 SelectObject (hdcDst, InternalDrag.himl->hbmMask);
744 BitBlt (hdcDst, 0, 0, cx, cy, hdcSrc, iTrack * cx, 0, SRCCOPY);
746 DeleteDC (hdcSrc);
747 DeleteDC (hdcDst);
749 InternalDrag.himl->cCurImage = 1;
751 return TRUE;
755 /*************************************************************************
756 * ImageList_Copy [COMCTL32.44]
758 * Copies an image of the source image list to an image of the
759 * destination image list. Images can be copied or swapped.
761 * PARAMS
762 * himlDst [I] handle to the destination image list
763 * iDst [I] destination image index.
764 * himlSrc [I] handle to the source image list
765 * iSrc [I] source image index
766 * uFlags [I] flags for the copy operation
768 * RETURNS
769 * Success: TRUE
770 * Failure: FALSE
772 * NOTES
773 * Copying from one image list to another is possible. The original
774 * implementation just copies or swaps within one image list.
775 * Could this feature become a bug??? ;-)
778 BOOL WINAPI
779 ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc,
780 INT iSrc, INT uFlags)
782 HDC hdcSrc, hdcDst;
784 TRACE("iDst=%d iSrc=%d\n", iDst, iSrc);
786 if ((himlSrc == NULL) || (himlDst == NULL))
787 return FALSE;
788 if ((iDst < 0) || (iDst >= himlDst->cCurImage))
789 return FALSE;
790 if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
791 return FALSE;
793 hdcSrc = CreateCompatibleDC (0);
794 if (himlDst == himlSrc)
795 hdcDst = hdcSrc;
796 else
797 hdcDst = CreateCompatibleDC (0);
799 if (uFlags & ILCF_SWAP) {
800 /* swap */
801 HBITMAP hbmTempImage, hbmTempMask;
803 /* create temporary bitmaps */
804 hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
805 himlSrc->uBitsPixel, NULL);
806 hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
807 1, NULL);
809 /* copy (and stretch) destination to temporary bitmaps.(save) */
810 /* image */
811 SelectObject (hdcSrc, himlDst->hbmImage);
812 SelectObject (hdcDst, hbmTempImage);
813 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
814 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
815 SRCCOPY);
816 /* mask */
817 SelectObject (hdcSrc, himlDst->hbmMask);
818 SelectObject (hdcDst, hbmTempMask);
819 StretchBlt (hdcDst, 0, 0, himlSrc->cx, himlSrc->cy,
820 hdcSrc, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
821 SRCCOPY);
823 /* copy (and stretch) source to destination */
824 /* image */
825 SelectObject (hdcSrc, himlSrc->hbmImage);
826 SelectObject (hdcDst, himlDst->hbmImage);
827 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
828 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
829 SRCCOPY);
830 /* mask */
831 SelectObject (hdcSrc, himlSrc->hbmMask);
832 SelectObject (hdcDst, himlDst->hbmMask);
833 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
834 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
835 SRCCOPY);
837 /* copy (without stretching) temporary bitmaps to source (restore) */
838 /* image */
839 SelectObject (hdcSrc, hbmTempImage);
840 SelectObject (hdcDst, himlSrc->hbmImage);
841 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
842 hdcSrc, 0, 0, SRCCOPY);
843 /* mask */
844 SelectObject (hdcSrc, hbmTempMask);
845 SelectObject (hdcDst, himlSrc->hbmMask);
846 BitBlt (hdcDst, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
847 hdcSrc, 0, 0, SRCCOPY);
849 /* delete temporary bitmaps */
850 DeleteObject (hbmTempMask);
851 DeleteObject (hbmTempImage);
853 else {
854 /* copy image */
855 SelectObject (hdcSrc, himlSrc->hbmImage);
856 if (himlSrc == himlDst)
857 hdcDst = hdcSrc;
858 else
859 SelectObject (hdcDst, himlDst->hbmImage);
860 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
861 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
862 SRCCOPY);
864 /* copy mask */
865 SelectObject (hdcSrc, himlSrc->hbmMask);
866 if (himlSrc == himlDst)
867 hdcDst = hdcSrc;
868 else
869 SelectObject (hdcDst, himlDst->hbmMask);
870 StretchBlt (hdcDst, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy,
871 hdcSrc, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy,
872 SRCCOPY);
875 DeleteDC (hdcSrc);
876 if (himlSrc != himlDst)
877 DeleteDC (hdcDst);
879 return TRUE;
883 /*************************************************************************
884 * ImageList_Create [COMCTL32.45] Creates a new image list.
886 * PARAMS
887 * cx [I] image height
888 * cy [I] image width
889 * flags [I] creation flags
890 * cInitial [I] initial number of images in the image list
891 * cGrow [I] number of images by which image list grows
893 * RETURNS
894 * Success: Handle to the created image list
895 * Failure: NULL
898 HIMAGELIST WINAPI
899 ImageList_Create (INT cx, INT cy, UINT flags,
900 INT cInitial, INT cGrow)
902 HIMAGELIST himl;
903 HDC hdc;
904 INT nCount;
905 HBITMAP hbmTemp;
906 static WORD aBitBlend25[] =
907 {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
909 static WORD aBitBlend50[] =
910 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
912 TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
914 himl = (HIMAGELIST)COMCTL32_Alloc (sizeof(struct _IMAGELIST));
915 if (!himl)
916 return NULL;
918 himl->cx = cx;
919 himl->cy = cy;
920 himl->flags = flags;
921 himl->cMaxImage = cInitial + cGrow;
922 himl->cInitial = cInitial;
923 himl->cGrow = cGrow;
924 himl->cCurImage = 0;
925 himl->clrFg = CLR_DEFAULT;
926 himl->clrBk = CLR_NONE;
928 /* initialize overlay mask indices */
929 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
930 himl->nOvlIdx[nCount] = -1;
932 hdc = CreateCompatibleDC (0);
933 himl->uBitsPixel = (UINT)GetDeviceCaps (hdc, BITSPIXEL);
934 DeleteDC (hdc);
936 TRACE("Image: %d Bits per Pixel\n", himl->uBitsPixel);
938 if (himl->cMaxImage > 0) {
939 himl->hbmImage =
940 CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
941 1, himl->uBitsPixel, NULL);
942 if (himl->hbmImage == 0) {
943 ERR("Error creating image bitmap!\n");
944 return NULL;
947 else
948 himl->hbmImage = 0;
950 if ( (himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
951 himl->hbmMask = CreateBitmap (himl->cx * himl->cMaxImage, himl->cy,
952 1, 1, NULL);
953 if (himl->hbmMask == 0) {
954 ERR("Error creating mask bitmap!\n");
955 if (himl->hbmImage)
956 DeleteObject (himl->hbmImage);
957 return NULL;
960 else
961 himl->hbmMask = 0;
963 /* create blending brushes */
964 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
965 himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
966 DeleteObject (hbmTemp);
968 hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
969 himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
970 DeleteObject (hbmTemp);
972 TRACE("created imagelist %p\n", himl);
973 return himl;
977 /*************************************************************************
978 * ImageList_Destroy [COMCTL32.46]
980 * Destroys an image list.
982 * PARAMS
983 * himl [I] handle to image list
985 * RETURNS
986 * Success: TRUE
987 * Failure: FALSE
990 BOOL WINAPI
991 ImageList_Destroy (HIMAGELIST himl)
993 if (!himl)
994 return FALSE;
996 /* delete image bitmaps */
997 if (himl->hbmImage)
998 DeleteObject (himl->hbmImage);
999 if (himl->hbmMask)
1000 DeleteObject (himl->hbmMask);
1002 /* delete blending brushes */
1003 if (himl->hbrBlend25)
1004 DeleteObject (himl->hbrBlend25);
1005 if (himl->hbrBlend50)
1006 DeleteObject (himl->hbrBlend50);
1008 COMCTL32_Free (himl);
1010 return TRUE;
1014 /*************************************************************************
1015 * ImageList_DragEnter [COMCTL32.47]
1017 * Locks window update and displays the drag image at the given position.
1019 * PARAMS
1020 * hwndLock [I] handle of the window that owns the drag image.
1021 * x [I] X position of the drag image.
1022 * y [I] Y position of the drag image.
1024 * RETURNS
1025 * Success: TRUE
1026 * Failure: FALSE
1028 * NOTES
1029 * The position of the drag image is relative to the window, not
1030 * the client area.
1033 BOOL WINAPI
1034 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
1036 TRACE("(hwnd=%#x x=%d y=%d)\n", hwndLock, x, y);
1038 if (InternalDrag.himl == NULL)
1039 return FALSE;
1041 if (hwndLock)
1042 InternalDrag.hwnd = hwndLock;
1043 else
1044 InternalDrag.hwnd = GetDesktopWindow ();
1046 InternalDrag.x = x;
1047 InternalDrag.y = y;
1049 /* draw the drag image and save the background */
1050 if (!ImageList_DragShowNolock(TRUE)) {
1051 return FALSE;
1054 return TRUE;
1058 /*************************************************************************
1059 * ImageList_DragLeave [COMCTL32.48]
1061 * Unlocks window update and hides the drag image.
1063 * PARAMS
1064 * hwndLock [I] handle of the window that owns the drag image.
1066 * RETURNS
1067 * Success: TRUE
1068 * Failure: FALSE
1071 BOOL WINAPI
1072 ImageList_DragLeave (HWND hwndLock)
1074 if (hwndLock)
1075 InternalDrag.hwnd = hwndLock;
1076 else
1077 InternalDrag.hwnd = GetDesktopWindow ();
1079 ImageList_DragShowNolock (FALSE);
1081 return TRUE;
1085 /*************************************************************************
1086 * ImageList_DragMove [COMCTL32.49]
1088 * Moves the drag image.
1090 * PARAMS
1091 * x [I] X position of the drag image.
1092 * y [I] Y position of the drag image.
1094 * RETURNS
1095 * Success: TRUE
1096 * Failure: FALSE
1098 * NOTES
1099 * The position of the drag image is relative to the window, not
1100 * the client area.
1102 * BUGS
1103 * The drag image should be drawn semitransparent.
1106 BOOL WINAPI
1107 ImageList_DragMove (INT x, INT y)
1109 TRACE("(x=%d y=%d)\n", x, y);
1111 if (!InternalDrag.himl) {
1112 return FALSE;
1115 /* draw/update the drag image */
1116 if (InternalDrag.bShow) {
1117 HDC hdcDrag;
1118 HDC hdcOffScreen;
1119 HDC hdcBg;
1120 HBITMAP hbmOffScreen;
1121 INT origNewX, origNewY;
1122 INT origOldX, origOldY;
1123 INT origRegX, origRegY;
1124 INT sizeRegX, sizeRegY;
1127 /* calculate the update region */
1128 origNewX = x - InternalDrag.dxHotspot;
1129 origNewY = y - InternalDrag.dyHotspot;
1130 origOldX = InternalDrag.x - InternalDrag.dxHotspot;
1131 origOldY = InternalDrag.y - InternalDrag.dyHotspot;
1132 origRegX = min(origNewX, origOldX);
1133 origRegY = min(origNewY, origOldY);
1134 sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
1135 sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
1137 hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
1138 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1139 hdcOffScreen = CreateCompatibleDC(hdcDrag);
1140 hdcBg = CreateCompatibleDC(hdcDrag);
1142 hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
1143 SelectObject(hdcOffScreen, hbmOffScreen);
1144 SelectObject(hdcBg, InternalDrag.hbmBg);
1146 /* get the actual background of the update region */
1147 BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
1148 origRegX, origRegY, SRCCOPY);
1149 /* erase the old image */
1150 BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
1151 InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
1152 SRCCOPY);
1153 /* save the background */
1154 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1155 hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
1156 /* draw the image */
1157 /* FIXME: image should be drawn semitransparent */
1158 ImageList_Draw(InternalDrag.himl, 0, hdcOffScreen, origNewX - origRegX,
1159 origNewY - origRegY, ILD_NORMAL);
1160 /* draw the update region to the screen */
1161 BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
1162 hdcOffScreen, 0, 0, SRCCOPY);
1164 DeleteDC(hdcBg);
1165 DeleteDC(hdcOffScreen);
1166 DeleteObject(hbmOffScreen);
1167 ReleaseDC(InternalDrag.hwnd, hdcDrag);
1170 /* update the image position */
1171 InternalDrag.x = x;
1172 InternalDrag.y = y;
1174 return TRUE;
1178 /*************************************************************************
1179 * ImageList_DragShowNolock [COMCTL32.50]
1181 * Shows or hides the drag image.
1183 * PARAMS
1184 * bShow [I] TRUE shows the drag image, FALSE hides it.
1186 * RETURNS
1187 * Success: TRUE
1188 * Failure: FALSE
1190 * BUGS
1191 * The drag image should be drawn semitransparent.
1194 BOOL WINAPI
1195 ImageList_DragShowNolock (BOOL bShow)
1197 HDC hdcDrag;
1198 HDC hdcBg;
1199 INT x, y;
1201 TRACE("bShow=0x%X!\n", bShow);
1203 /* DragImage is already visible/hidden */
1204 if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
1205 return FALSE;
1208 /* position of the origin of the DragImage */
1209 x = InternalDrag.x - InternalDrag.dxHotspot;
1210 y = InternalDrag.y - InternalDrag.dyHotspot;
1212 hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
1213 DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
1214 if (!hdcDrag) {
1215 return FALSE;
1218 hdcBg = CreateCompatibleDC(hdcDrag);
1219 if (!InternalDrag.hbmBg) {
1220 InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
1221 InternalDrag.himl->cx, InternalDrag.himl->cy);
1223 SelectObject(hdcBg, InternalDrag.hbmBg);
1225 if (bShow) {
1226 /* save the background */
1227 BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
1228 hdcDrag, x, y, SRCCOPY);
1229 /* show the image */
1230 /* FIXME: this should be drawn semitransparent */
1231 ImageList_Draw(InternalDrag.himl, 0, hdcDrag, x, y, ILD_NORMAL);
1232 } else {
1233 /* hide the image */
1234 BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
1235 hdcBg, 0, 0, SRCCOPY);
1238 InternalDrag.bShow = !InternalDrag.bShow;
1240 DeleteDC(hdcBg);
1241 ReleaseDC (InternalDrag.hwnd, hdcDrag);
1242 return TRUE;
1246 /*************************************************************************
1247 * ImageList_Draw [COMCTL32.51] Draws an image.
1249 * PARAMS
1250 * himl [I] handle to image list
1251 * i [I] image index
1252 * hdc [I] handle to device context
1253 * x [I] x position
1254 * y [I] y position
1255 * fStyle [I] drawing flags
1257 * RETURNS
1258 * Success: TRUE
1259 * Failure: FALSE
1261 * NOTES
1262 * Calls ImageList_DrawIndirect.
1264 * SEE
1265 * ImageList_DrawIndirect.
1268 BOOL WINAPI
1269 ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc,
1270 INT x, INT y, UINT fStyle)
1272 IMAGELISTDRAWPARAMS imldp;
1274 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1275 imldp.himl = himl;
1276 imldp.i = i;
1277 imldp.hdcDst = hdc,
1278 imldp.x = x;
1279 imldp.y = y;
1280 imldp.cx = 0;
1281 imldp.cy = 0;
1282 imldp.xBitmap = 0;
1283 imldp.yBitmap = 0;
1284 imldp.rgbBk = CLR_DEFAULT;
1285 imldp.rgbFg = CLR_DEFAULT;
1286 imldp.fStyle = fStyle;
1287 imldp.dwRop = 0;
1289 return ImageList_DrawIndirect (&imldp);
1293 /*************************************************************************
1294 * ImageList_DrawEx [COMCTL32.52]
1296 * Draws an image and allows to use extended drawing features.
1298 * PARAMS
1299 * himl [I] handle to image list
1300 * i [I] image index
1301 * hdc [I] handle to device context
1302 * x [I] X position
1303 * y [I] Y position
1304 * xOffs [I] X offset
1305 * yOffs [I] Y offset
1306 * rgbBk [I] background color
1307 * rgbFg [I] foreground color
1308 * fStyle [I] drawing flags
1310 * RETURNS
1311 * Success: TRUE
1312 * Failure: FALSE
1314 * NOTES
1315 * Calls ImageList_DrawIndirect.
1317 * SEE
1318 * ImageList_DrawIndirect.
1321 BOOL WINAPI
1322 ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
1323 INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg,
1324 UINT fStyle)
1326 IMAGELISTDRAWPARAMS imldp;
1328 imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
1329 imldp.himl = himl;
1330 imldp.i = i;
1331 imldp.hdcDst = hdc,
1332 imldp.x = x;
1333 imldp.y = y;
1334 imldp.cx = dx;
1335 imldp.cy = dy;
1336 imldp.xBitmap = 0;
1337 imldp.yBitmap = 0;
1338 imldp.rgbBk = rgbBk;
1339 imldp.rgbFg = rgbFg;
1340 imldp.fStyle = fStyle;
1341 imldp.dwRop = 0;
1343 return ImageList_DrawIndirect (&imldp);
1347 /*************************************************************************
1348 * ImageList_DrawIndirect [COMCTL32.53]
1350 * Draws an image using ...
1352 * PARAMS
1353 * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure.
1355 * RETURNS
1356 * Success: TRUE
1357 * Failure: FALSE
1360 BOOL WINAPI
1361 ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
1363 INT cx, cy;
1365 Do some Error Checking
1367 if (pimldp == NULL)
1368 return FALSE;
1369 if (pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS))
1370 return FALSE;
1371 if (pimldp->himl == NULL)
1372 return FALSE;
1373 if ((pimldp->i < 0) || (pimldp->i >= pimldp->himl->cCurImage)) {
1374 ERR("%d not within range (max %d)\n",pimldp->i,pimldp->himl->cCurImage-1);
1375 return FALSE;
1378 Get the Height and Width to display
1380 cx = (pimldp->cx == 0) ? pimldp->himl->cx : pimldp->cx;
1381 cy = (pimldp->cy == 0) ? pimldp->himl->cy : pimldp->cy;
1383 Draw the image
1385 if(pimldp->himl->hbmMask != 0)
1387 IMAGELIST_InternalDrawMask(pimldp, cx, cy);
1389 else
1391 IMAGELIST_InternalDraw(pimldp, cx, cy);
1394 Apply the blend if needed to the Image
1396 if((pimldp->fStyle & ILD_BLEND50)
1397 || (pimldp->fStyle & ILD_BLEND25))
1399 IMAGELIST_InternalDrawBlend(pimldp, cx, cy);
1402 Apply the Overlay if needed
1404 if (pimldp->fStyle & ILD_OVERLAYMASK)
1406 IMAGELIST_InternalDrawOverlay(pimldp, cx, cy);
1409 return TRUE;
1413 /*************************************************************************
1414 * ImageList_Duplicate [COMCTL32.54] Duplicates an image list.
1416 * PARAMS
1417 * himlSrc [I] source image list handle
1419 * RETURNS
1420 * Success: Handle of duplicated image list.
1421 * Failure: NULL
1424 HIMAGELIST WINAPI
1425 ImageList_Duplicate (HIMAGELIST himlSrc)
1427 HIMAGELIST himlDst;
1428 HDC hdcSrc, hdcDst;
1430 if (himlSrc == NULL) {
1431 ERR("Invalid image list handle!\n");
1432 return NULL;
1435 himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
1436 himlSrc->cInitial, himlSrc->cGrow);
1438 if (himlDst)
1440 hdcSrc = CreateCompatibleDC (0);
1441 hdcDst = CreateCompatibleDC (0);
1442 SelectObject (hdcSrc, himlSrc->hbmImage);
1443 SelectObject (hdcDst, himlDst->hbmImage);
1444 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy,
1445 hdcSrc, 0, 0, SRCCOPY);
1447 if (himlDst->hbmMask)
1449 SelectObject (hdcSrc, himlSrc->hbmMask);
1450 SelectObject (hdcDst, himlDst->hbmMask);
1451 BitBlt (hdcDst, 0, 0, himlSrc->cCurImage * himlSrc->cx,
1452 himlSrc->cy, hdcSrc, 0, 0, SRCCOPY);
1455 DeleteDC (hdcDst);
1456 DeleteDC (hdcSrc);
1458 himlDst->cCurImage = himlSrc->cCurImage;
1459 himlDst->cMaxImage = himlSrc->cMaxImage;
1461 return himlDst;
1465 /*************************************************************************
1466 * ImageList_EndDrag [COMCTL32.55] Finishes a drag operation.
1468 * Finishes a drag operation.
1470 * PARAMS
1471 * no Parameters
1473 * RETURNS
1474 * Success: TRUE
1475 * Failure: FALSE
1478 BOOL WINAPI
1479 ImageList_EndDrag (void)
1481 /* cleanup the InternalDrag struct */
1482 InternalDrag.hwnd = 0;
1483 ImageList_Destroy (InternalDrag.himl);
1484 InternalDrag.himl = 0;
1485 InternalDrag.x= 0;
1486 InternalDrag.y= 0;
1487 InternalDrag.dxHotspot = 0;
1488 InternalDrag.dyHotspot = 0;
1489 InternalDrag.bShow = FALSE;
1490 DeleteObject(InternalDrag.hbmBg);
1491 InternalDrag.hbmBg = 0;
1493 return TRUE;
1497 /*************************************************************************
1498 * ImageList_GetBkColor [COMCTL32.56]
1500 * Returns the background color of an image list.
1502 * PARAMS
1503 * himl [I] Image list handle.
1505 * RETURNS
1506 * Success: background color
1507 * Failure: CLR_NONE
1510 COLORREF WINAPI
1511 ImageList_GetBkColor (HIMAGELIST himl)
1513 if (himl == NULL)
1514 return CLR_NONE;
1516 return himl->clrBk;
1520 /*************************************************************************
1521 * ImageList_GetDragImage [COMCTL32.57]
1523 * Returns the handle to the internal drag image list.
1525 * PARAMS
1526 * ppt [O] Pointer to the drag position. Can be NULL.
1527 * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL.
1529 * RETURNS
1530 * Success: Handle of the drag image list.
1531 * Failure: NULL.
1534 HIMAGELIST WINAPI
1535 ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot)
1537 if (InternalDrag.himl) {
1538 if (ppt) {
1539 ppt->x = InternalDrag.x;
1540 ppt->y = InternalDrag.y;
1542 if (pptHotspot) {
1543 pptHotspot->x = InternalDrag.dxHotspot;
1544 pptHotspot->y = InternalDrag.dyHotspot;
1546 return (InternalDrag.himl);
1549 return NULL;
1553 /*************************************************************************
1554 * ImageList_GetFlags [COMCTL32.58]
1556 * BUGS
1557 * Stub.
1560 DWORD WINAPI
1561 ImageList_GetFlags(HIMAGELIST himl)
1563 FIXME("(%p):empty stub\n", himl);
1564 return 0;
1568 /*************************************************************************
1569 * ImageList_GetIcon [COMCTL32.59]
1571 * Creates an icon from a masked image of an image list.
1573 * PARAMS
1574 * himl [I] handle to image list
1575 * i [I] image index
1576 * flags [I] drawing style flags
1578 * RETURNS
1579 * Success: icon handle
1580 * Failure: NULL
1583 HICON WINAPI
1584 ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle)
1586 ICONINFO ii;
1587 HICON hIcon;
1588 HBITMAP hOldSrcBitmap,hOldDstBitmap;
1589 HDC hdcSrc, hdcDst;
1591 if ((himl == NULL) || (i < 0) || (i >= himl->cCurImage)) {
1592 FIXME("(%p,%d,%x), params out of range!\n",himl,i,fStyle);
1593 return 0;
1596 hdcSrc = CreateCompatibleDC(0);
1597 hdcDst = CreateCompatibleDC(0);
1599 ii.fIcon = TRUE;
1600 ii.hbmMask = CreateCompatibleBitmap (hdcDst, himl->cx, himl->cy);
1602 /* draw mask*/
1603 hOldDstBitmap = (HBITMAP)SelectObject (hdcDst, ii.hbmMask);
1604 if (himl->hbmMask) {
1605 SelectObject (hdcSrc, himl->hbmMask);
1606 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1607 hdcSrc, i * himl->cx, 0, SRCCOPY);
1609 else
1610 PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS);
1612 /* draw image*/
1613 hOldSrcBitmap = (HBITMAP)SelectObject (hdcSrc, himl->hbmImage);
1614 ii.hbmColor = CreateCompatibleBitmap (hdcSrc, himl->cx, himl->cy);
1615 SelectObject (hdcDst, ii.hbmColor);
1616 BitBlt (hdcDst, 0, 0, himl->cx, himl->cy,
1617 hdcSrc, i * himl->cx, 0, SRCCOPY);
1620 * CreateIconIndirect requires us to deselect the bitmaps from
1621 * the DCs before calling
1623 SelectObject(hdcSrc, hOldSrcBitmap);
1624 SelectObject(hdcDst, hOldDstBitmap);
1626 hIcon = CreateIconIndirect (&ii);
1628 DeleteDC (hdcSrc);
1629 DeleteDC (hdcDst);
1630 DeleteObject (ii.hbmMask);
1631 DeleteObject (ii.hbmColor);
1633 return hIcon;
1637 /*************************************************************************
1638 * ImageList_GetIconSize [COMCTL32.60]
1640 * Retrieves the size of an image in an image list.
1642 * PARAMS
1643 * himl [I] handle to image list
1644 * cx [O] pointer to the image width.
1645 * cy [O] pointer to the image height.
1647 * RETURNS
1648 * Success: TRUE
1649 * Failure: FALSE
1651 * NOTES
1652 * All images in an image list have the same size.
1655 BOOL WINAPI
1656 ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy)
1658 if (himl == NULL)
1659 return FALSE;
1660 if ((himl->cx <= 0) || (himl->cy <= 0))
1661 return FALSE;
1663 if (cx)
1664 *cx = himl->cx;
1665 if (cy)
1666 *cy = himl->cy;
1668 return TRUE;
1672 /*************************************************************************
1673 * ImageList_GetImageCount [COMCTL32.61]
1675 * Returns the number of images in an image list.
1677 * PARAMS
1678 * himl [I] handle to image list
1680 * RETURNS
1681 * Success: Number of images.
1682 * Failure: 0
1685 INT WINAPI
1686 ImageList_GetImageCount (HIMAGELIST himl)
1688 if (himl == NULL)
1689 return 0;
1691 return himl->cCurImage;
1695 /*************************************************************************
1696 * ImageList_GetImageInfo [COMCTL32.62]
1698 * Returns information about an image in an image list.
1700 * PARAMS
1701 * himl [I] handle to image list
1702 * i [I] image index
1703 * pImageInfo [O] pointer to the image information
1705 * RETURNS
1706 * Success: TRUE
1707 * Failure: FALSE
1710 BOOL WINAPI
1711 ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo)
1713 if ((himl == NULL) || (pImageInfo == NULL))
1714 return FALSE;
1715 if ((i < 0) || (i >= himl->cCurImage))
1716 return FALSE;
1718 pImageInfo->hbmImage = himl->hbmImage;
1719 pImageInfo->hbmMask = himl->hbmMask;
1721 pImageInfo->rcImage.top = 0;
1722 pImageInfo->rcImage.bottom = himl->cy;
1723 pImageInfo->rcImage.left = i * himl->cx;
1724 pImageInfo->rcImage.right = (i+1) * himl->cx;
1726 return TRUE;
1730 /*************************************************************************
1731 * ImageList_GetImageRect [COMCTL32.63]
1733 * Retrieves the rectangle of the specified image in an image list.
1735 * PARAMS
1736 * himl [I] handle to image list
1737 * i [I] image index
1738 * lpRect [O] pointer to the image rectangle
1740 * RETURNS
1741 * Success: TRUE
1742 * Failure: FALSE
1744 * NOTES
1745 * This is an UNDOCUMENTED function!!!
1748 BOOL WINAPI
1749 ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect)
1751 if ((himl == NULL) || (lpRect == NULL))
1752 return FALSE;
1753 if ((i < 0) || (i >= himl->cCurImage))
1754 return FALSE;
1756 lpRect->left = i * himl->cx;
1757 lpRect->top = 0;
1758 lpRect->right = lpRect->left + himl->cx;
1759 lpRect->bottom = himl->cy;
1761 return TRUE;
1765 /*************************************************************************
1766 * ImageList_LoadImage [COMCTL32.64]
1767 * ImageList_LoadImageA [COMCTL32.65]
1769 * Creates an image list from a bitmap, icon or cursor.
1771 * PARAMS
1772 * hi [I] instance handle
1773 * lpbmp [I] name or id of the image
1774 * cx [I] width of each image
1775 * cGrow [I] number of images to expand
1776 * clrMask [I] mask color
1777 * uType [I] type of image to load
1778 * uFlags [I] loading flags
1780 * RETURNS
1781 * Success: handle to the loaded image list
1782 * Failure: NULL
1784 * SEE
1785 * LoadImage ()
1788 HIMAGELIST WINAPI
1789 ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
1790 COLORREF clrMask, UINT uType, UINT uFlags)
1792 HIMAGELIST himl = NULL;
1793 HANDLE handle;
1794 INT nImageCount;
1796 handle = LoadImageA (hi, lpbmp, uType, 0, 0, uFlags);
1797 if (!handle) {
1798 ERR("Error loading image!\n");
1799 return NULL;
1802 if (uType == IMAGE_BITMAP) {
1803 BITMAP bmp;
1804 GetObjectA (handle, sizeof(BITMAP), &bmp);
1806 /* To match windows behavior, if cx is set to zero and
1807 the flag DI_DEFAULTSIZE is specified, cx becomes the
1808 system metric value for icons. If the flag is not specified
1809 the function sets the size to the height of the bitmap */
1810 if (cx == 0)
1812 if (uFlags & DI_DEFAULTSIZE)
1813 cx = GetSystemMetrics (SM_CXICON);
1814 else
1815 cx = bmp.bmHeight;
1818 nImageCount = bmp.bmWidth / cx;
1820 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1821 nImageCount, cGrow);
1822 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1824 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1825 ICONINFO ii;
1826 BITMAP bmp;
1828 GetIconInfo (handle, &ii);
1829 GetObjectA (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp);
1830 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1831 ILC_MASK | ILC_COLOR, 1, cGrow);
1832 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1833 DeleteObject (ii.hbmColor);
1834 DeleteObject (ii.hbmMask);
1837 DeleteObject (handle);
1839 return himl;
1843 /*************************************************************************
1844 * ImageList_LoadImageW [COMCTL32.66]
1846 * Creates an image list from a bitmap, icon or cursor.
1848 * PARAMS
1849 * hi [I] instance handle
1850 * lpbmp [I] name or id of the image
1851 * cx [I] width of each image
1852 * cGrow [I] number of images to expand
1853 * clrMask [I] mask color
1854 * uType [I] type of image to load
1855 * uFlags [I] loading flags
1857 * RETURNS
1858 * Success: handle to the loaded image list
1859 * Failure: NULL
1861 * SEE
1862 * LoadImage ()
1865 HIMAGELIST WINAPI
1866 ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow,
1867 COLORREF clrMask, UINT uType, UINT uFlags)
1869 HIMAGELIST himl = NULL;
1870 HANDLE handle;
1871 INT nImageCount;
1873 handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags);
1874 if (!handle) {
1875 ERR("Error loading image!\n");
1876 return NULL;
1879 if (uType == IMAGE_BITMAP) {
1880 BITMAP bmp;
1881 GetObjectA (handle, sizeof(BITMAP), &bmp);
1882 nImageCount = bmp.bmWidth / cx;
1884 himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR,
1885 nImageCount, cGrow);
1886 ImageList_AddMasked (himl, (HBITMAP)handle, clrMask);
1888 else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) {
1889 ICONINFO ii;
1890 BITMAP bmp;
1892 GetIconInfo (handle, &ii);
1893 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
1894 himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight,
1895 ILC_MASK | ILC_COLOR, 1, cGrow);
1896 ImageList_Add (himl, ii.hbmColor, ii.hbmMask);
1897 DeleteObject (ii.hbmColor);
1898 DeleteObject (ii.hbmMask);
1901 DeleteObject (handle);
1903 return himl;
1907 /*************************************************************************
1908 * ImageList_Merge [COMCTL32.67]
1910 * Creates a new image list that contains a merged image from the specified
1911 * images of both source image lists.
1913 * PARAMS
1914 * himl1 [I] handle to first image list
1915 * i1 [I] first image index
1916 * himl2 [I] handle to second image list
1917 * i2 [I] second image index
1918 * dx [I] X offset of the second image relative to the first.
1919 * dy [I] Y offset of the second image relative to the first.
1921 * RETURNS
1922 * Success: handle of the merged image list.
1923 * Failure: NULL
1926 HIMAGELIST WINAPI
1927 ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2,
1928 INT dx, INT dy)
1930 HIMAGELIST himlDst = NULL;
1931 HDC hdcSrcImage, hdcDstImage;
1932 INT cxDst, cyDst;
1933 INT xOff1, yOff1, xOff2, yOff2;
1934 INT nX1, nX2;
1936 TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2,
1937 i2, dx, dy);
1939 if ((himl1 == NULL) || (himl2 == NULL))
1940 return NULL;
1942 /* check indices */
1943 if ((i1 < 0) || (i1 >= himl1->cCurImage)) {
1944 ERR("Index 1 out of range! %d\n", i1);
1945 return NULL;
1948 if ((i2 < 0) || (i2 >= himl2->cCurImage)) {
1949 ERR("Index 2 out of range! %d\n", i2);
1950 return NULL;
1953 if (dx > 0) {
1954 cxDst = max (himl1->cx, dx + himl2->cx);
1955 xOff1 = 0;
1956 xOff2 = dx;
1958 else if (dx < 0) {
1959 cxDst = max (himl2->cx, himl1->cx - dx);
1960 xOff1 = -dx;
1961 xOff2 = 0;
1963 else {
1964 cxDst = max (himl1->cx, himl2->cx);
1965 xOff1 = 0;
1966 xOff2 = 0;
1969 if (dy > 0) {
1970 cyDst = max (himl1->cy, dy + himl2->cy);
1971 yOff1 = 0;
1972 yOff2 = dy;
1974 else if (dy < 0) {
1975 cyDst = max (himl2->cy, himl1->cy - dy);
1976 yOff1 = -dy;
1977 yOff2 = 0;
1979 else {
1980 cyDst = max (himl1->cy, himl2->cy);
1981 yOff1 = 0;
1982 yOff2 = 0;
1985 himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1);
1987 if (himlDst) {
1988 hdcSrcImage = CreateCompatibleDC (0);
1989 hdcDstImage = CreateCompatibleDC (0);
1990 nX1 = i1 * himl1->cx;
1991 nX2 = i2 * himl2->cx;
1993 /* copy image */
1994 SelectObject (hdcSrcImage, himl1->hbmImage);
1995 SelectObject (hdcDstImage, himlDst->hbmImage);
1996 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
1997 hdcSrcImage, 0, 0, BLACKNESS);
1998 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
1999 hdcSrcImage, nX1, 0, SRCCOPY);
2001 SelectObject (hdcSrcImage, himl2->hbmMask);
2002 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2003 hdcSrcImage, nX2, 0, SRCAND);
2005 SelectObject (hdcSrcImage, himl2->hbmImage);
2006 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2007 hdcSrcImage, nX2, 0, SRCPAINT);
2009 /* copy mask */
2010 SelectObject (hdcSrcImage, himl1->hbmMask);
2011 SelectObject (hdcDstImage, himlDst->hbmMask);
2012 BitBlt (hdcDstImage, 0, 0, cxDst, cyDst,
2013 hdcSrcImage, 0, 0, WHITENESS);
2014 BitBlt (hdcDstImage, xOff1, yOff1, himl1->cx, himl1->cy,
2015 hdcSrcImage, nX1, 0, SRCCOPY);
2017 SelectObject (hdcSrcImage, himl2->hbmMask);
2018 BitBlt (hdcDstImage, xOff2, yOff2, himl2->cx, himl2->cy,
2019 hdcSrcImage, nX2, 0, SRCAND);
2021 DeleteDC (hdcSrcImage);
2022 DeleteDC (hdcDstImage);
2023 himlDst->cCurImage = 1;
2026 return himlDst;
2030 /* helper for _read_bitmap currently unused */
2031 #if 0
2032 static int may_use_dibsection(HDC hdc) {
2033 int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
2034 if (bitspixel>8)
2035 return TRUE;
2036 if (bitspixel<=4)
2037 return FALSE;
2038 return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE;
2040 #endif
2042 /* helper for ImageList_Read, see comments below */
2043 static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) {
2044 HDC xdc = 0;
2045 BITMAPFILEHEADER bmfh;
2046 BITMAPINFOHEADER bmih;
2047 int bitsperpixel,palspace,longsperline,width,height;
2048 LPBITMAPINFOHEADER bmihc = NULL;
2049 int result = 0;
2050 HBITMAP hbitmap = 0;
2051 LPBYTE bits = NULL,nbits = NULL;
2052 int nbytesperline,bytesperline;
2054 if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) ||
2055 (bmfh.bfType != (('M'<<8)|'B')) ||
2056 !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) ||
2057 (bmih.biSize != sizeof(bmih))
2059 return 0;
2061 bitsperpixel = bmih.biPlanes * bmih.biBitCount;
2062 if (bitsperpixel<=8)
2063 palspace = (1<<bitsperpixel)*sizeof(RGBQUAD);
2064 else
2065 palspace = 0;
2066 width = bmih.biWidth;
2067 height = bmih.biHeight;
2068 bmihc = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_ZEROINIT,sizeof(bmih)+palspace);
2069 memcpy(bmihc,&bmih,sizeof(bmih));
2070 longsperline = ((width*bitsperpixel+31)&~0x1f)>>5;
2071 bmihc->biSizeImage = (longsperline*height)<<2;
2073 /* read the palette right after the end of the bitmapinfoheader */
2074 if (palspace)
2075 if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL)))
2076 goto ret1;
2078 xdc = GetDC(0);
2079 #if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */
2080 if ((bitsperpixel>1) &&
2081 ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc)))
2083 hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0);
2084 if (!hbitmap)
2085 goto ret1;
2086 if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL)))
2087 goto ret1;
2088 result = 1;
2089 } else
2090 #endif
2092 int i,nwidth,nheight;
2094 nwidth = width*(height/cy);
2095 nheight = cy;
2097 if (bitsperpixel==1)
2098 hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL);
2099 else
2100 hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight);
2102 /* Might be a bit excessive memory use here */
2103 bits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2104 nbits = (LPBYTE)LocalAlloc(LMEM_ZEROINIT,bmihc->biSizeImage);
2105 if (!SUCCEEDED(IStream_Read ( pstm, bits, bmihc->biSizeImage, NULL)))
2106 goto ret1;
2108 /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */
2109 /* Do not forget that windows bitmaps are bottom->top */
2110 bytesperline = longsperline*4;
2111 nbytesperline = (height/cy)*bytesperline;
2112 for (i=0;i<height;i++) {
2113 memcpy(
2114 nbits+((height-1-i)%cy)*nbytesperline+(i/cy)*bytesperline,
2115 bits+bytesperline*(height-1-i),
2116 bytesperline
2119 bmihc->biWidth = nwidth;
2120 bmihc->biHeight = nheight;
2121 if (!SetDIBits(xdc,hbitmap,0,nheight,nbits,(BITMAPINFO*)bmihc,0))
2122 goto ret1;
2123 LocalFree((HLOCAL)nbits);
2124 LocalFree((HLOCAL)bits);
2125 result = 1;
2127 ret1:
2128 if (xdc) ReleaseDC(0,xdc);
2129 if (bmihc) LocalFree((HLOCAL)bmihc);
2130 if (!result) {
2131 if (hbitmap) {
2132 DeleteObject(hbitmap);
2133 hbitmap = 0;
2136 return hbitmap;
2139 /*************************************************************************
2140 * ImageList_Read [COMCTL32.68]
2142 * Reads an image list from a stream.
2144 * PARAMS
2145 * pstm [I] pointer to a stream
2147 * RETURNS
2148 * Success: handle to image list
2149 * Failure: NULL
2151 * The format is like this:
2152 * ILHEAD ilheadstruct;
2154 * for the color image part:
2155 * BITMAPFILEHEADER bmfh;
2156 * BITMAPINFOHEADER bmih;
2157 * only if it has a palette:
2158 * RGBQUAD rgbs[nr_of_paletted_colors];
2160 * BYTE colorbits[imagesize];
2162 * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags:
2163 * BITMAPFILEHEADER bmfh_mask;
2164 * BITMAPINFOHEADER bmih_mask;
2165 * only if it has a palette (it usually does not):
2166 * RGBQUAD rgbs[nr_of_paletted_colors];
2168 * BYTE maskbits[imagesize];
2170 * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect.
2171 * _read_bitmap needs to convert them.
2173 HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm)
2175 ILHEAD ilHead;
2176 HIMAGELIST himl;
2177 HBITMAP hbmColor=0,hbmMask=0;
2178 int i;
2180 if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL)))
2181 return NULL;
2182 if (ilHead.usMagic != (('L' << 8) | 'I'))
2183 return NULL;
2184 if (ilHead.usVersion != 0x101) /* probably version? */
2185 return NULL;
2187 #if 0
2188 FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage);
2189 FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage);
2190 FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow);
2191 FIXME(" ilHead.cx = %d\n",ilHead.cx);
2192 FIXME(" ilHead.cy = %d\n",ilHead.cy);
2193 FIXME(" ilHead.flags = %x\n",ilHead.flags);
2194 FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]);
2195 FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]);
2196 FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]);
2197 FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]);
2198 #endif
2200 hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy);
2201 if (!hbmColor)
2202 return NULL;
2203 if (ilHead.flags & ILC_MASK) {
2204 hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy);
2205 if (!hbmMask) {
2206 DeleteObject(hbmColor);
2207 return NULL;
2211 himl = ImageList_Create (
2212 ilHead.cx,
2213 ilHead.cy,
2214 ilHead.flags,
2215 1, /* initial */
2216 ilHead.cGrow
2218 if (!himl) {
2219 DeleteObject(hbmColor);
2220 DeleteObject(hbmMask);
2221 return NULL;
2223 himl->hbmImage = hbmColor;
2224 himl->hbmMask = hbmMask;
2225 himl->cCurImage = ilHead.cCurImage;
2226 himl->cMaxImage = ilHead.cMaxImage;
2228 ImageList_SetBkColor(himl,ilHead.bkcolor);
2229 for (i=0;i<4;i++)
2230 ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1);
2231 return himl;
2235 /*************************************************************************
2236 * ImageList_Remove [COMCTL32.69] Removes an image from an image list
2238 * PARAMS
2239 * himl [I] image list handle
2240 * i [I] image index
2242 * RETURNS
2243 * Success: TRUE
2244 * Failure: FALSE
2247 BOOL WINAPI
2248 ImageList_Remove (HIMAGELIST himl, INT i)
2250 HBITMAP hbmNewImage, hbmNewMask;
2251 HDC hdcSrc, hdcDst;
2252 INT cxNew, nCount;
2254 if (himl == NULL) {
2255 ERR("Invalid image list handle!\n");
2256 return FALSE;
2259 if ((i < -1) || (i >= himl->cCurImage)) {
2260 ERR("index out of range! %d\n", i);
2261 return FALSE;
2264 if (himl->cCurImage == 0) {
2265 ERR("image list is already empty!\n");
2266 return FALSE;
2269 if (i == -1) {
2270 /* remove all */
2271 TRACE("remove all!\n");
2273 himl->cMaxImage = himl->cInitial + himl->cGrow;
2274 himl->cCurImage = 0;
2275 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2276 himl->nOvlIdx[nCount] = -1;
2278 DeleteObject (himl->hbmImage);
2279 himl->hbmImage =
2280 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2281 1, himl->uBitsPixel, NULL);
2283 if (himl->hbmMask) {
2284 DeleteObject (himl->hbmMask);
2285 himl->hbmMask =
2286 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2287 1, 1, NULL);
2290 else {
2291 /* delete one image */
2292 TRACE("Remove single image! %d\n", i);
2294 /* create new bitmap(s) */
2295 cxNew = (himl->cCurImage + himl->cGrow - 1) * himl->cx;
2297 TRACE(" - Number of images: %d / %d (Old/New)\n",
2298 himl->cCurImage, himl->cCurImage - 1);
2299 TRACE(" - Max. number of images: %d / %d (Old/New)\n",
2300 himl->cMaxImage, himl->cCurImage + himl->cGrow - 1);
2302 hbmNewImage =
2303 CreateBitmap (cxNew, himl->cy, 1, himl->uBitsPixel, NULL);
2305 if (himl->hbmMask)
2306 hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL);
2307 else
2308 hbmNewMask = 0; /* Just to keep compiler happy! */
2310 hdcSrc = CreateCompatibleDC (0);
2311 hdcDst = CreateCompatibleDC (0);
2313 /* copy all images and masks prior to the "removed" image */
2314 if (i > 0) {
2315 TRACE("Pre image copy: Copy %d images\n", i);
2317 SelectObject (hdcSrc, himl->hbmImage);
2318 SelectObject (hdcDst, hbmNewImage);
2319 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2320 hdcSrc, 0, 0, SRCCOPY);
2322 if (himl->hbmMask) {
2323 SelectObject (hdcSrc, himl->hbmMask);
2324 SelectObject (hdcDst, hbmNewMask);
2325 BitBlt (hdcDst, 0, 0, i * himl->cx, himl->cy,
2326 hdcSrc, 0, 0, SRCCOPY);
2330 /* copy all images and masks behind the removed image */
2331 if (i < himl->cCurImage - 1) {
2332 TRACE("Post image copy!\n");
2333 SelectObject (hdcSrc, himl->hbmImage);
2334 SelectObject (hdcDst, hbmNewImage);
2335 BitBlt (hdcDst, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx,
2336 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2338 if (himl->hbmMask) {
2339 SelectObject (hdcSrc, himl->hbmMask);
2340 SelectObject (hdcDst, hbmNewMask);
2341 BitBlt (hdcDst, i * himl->cx, 0,
2342 (himl->cCurImage - i - 1) * himl->cx,
2343 himl->cy, hdcSrc, (i + 1) * himl->cx, 0, SRCCOPY);
2347 DeleteDC (hdcSrc);
2348 DeleteDC (hdcDst);
2350 /* delete old images and insert new ones */
2351 DeleteObject (himl->hbmImage);
2352 himl->hbmImage = hbmNewImage;
2353 if (himl->hbmMask) {
2354 DeleteObject (himl->hbmMask);
2355 himl->hbmMask = hbmNewMask;
2358 himl->cCurImage--;
2359 himl->cMaxImage = himl->cCurImage + himl->cGrow;
2362 return TRUE;
2366 /*************************************************************************
2367 * ImageList_Replace [COMCTL32.70]
2369 * Replaces an image in an image list with a new image.
2371 * PARAMS
2372 * himl [I] handle to image list
2373 * i [I] image index
2374 * hbmImage [I] handle to image bitmap
2375 * hbmMask [I] handle to mask bitmap. Can be NULL.
2377 * RETURNS
2378 * Success: TRUE
2379 * Failure: FALSE
2382 BOOL WINAPI
2383 ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
2384 HBITMAP hbmMask)
2386 HDC hdcImageList, hdcImage;
2387 BITMAP bmp;
2389 if (himl == NULL) {
2390 ERR("Invalid image list handle!\n");
2391 return FALSE;
2394 if ((i >= himl->cMaxImage) || (i < 0)) {
2395 ERR("Invalid image index!\n");
2396 return FALSE;
2399 hdcImageList = CreateCompatibleDC (0);
2400 hdcImage = CreateCompatibleDC (0);
2401 GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp);
2403 /* Replace Image */
2404 SelectObject (hdcImageList, himl->hbmImage);
2405 SelectObject (hdcImage, hbmImage);
2407 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2408 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2410 if (himl->hbmMask)
2412 /* Replace Mask */
2413 SelectObject (hdcImageList, himl->hbmMask);
2414 SelectObject (hdcImage, hbmMask);
2416 StretchBlt (hdcImageList, i * himl->cx, 0, himl->cx, himl->cy,
2417 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2420 /* Remove the background from the image
2422 SelectObject (hdcImageList, himl->hbmImage);
2423 StretchBlt (hdcImageList,
2424 i*himl->cx, 0, himl->cx, himl->cy,
2425 hdcImage,
2426 0, 0, bmp.bmWidth, bmp.bmHeight,
2427 0x220326); /* NOTSRCAND */
2430 DeleteDC (hdcImage);
2431 DeleteDC (hdcImageList);
2433 return TRUE;
2437 /*************************************************************************
2438 * ImageList_ReplaceIcon [COMCTL32.75]
2440 * Replaces an image in an image list using an icon.
2442 * PARAMS
2443 * himl [I] handle to image list
2444 * i [I] image index
2445 * hIcon [I] handle to icon
2447 * RETURNS
2448 * Success: index of the replaced image
2449 * Failure: -1
2452 INT WINAPI
2453 ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon)
2455 HDC hdcImageList, hdcImage;
2456 INT nIndex;
2457 HICON hBestFitIcon;
2458 HBITMAP hbmOldSrc, hbmOldDst;
2459 ICONINFO ii;
2460 BITMAP bmp;
2462 TRACE("(0x%lx 0x%x 0x%x)\n", (DWORD)himl, i, hIcon);
2464 if (himl == NULL)
2465 return -1;
2466 if ((i >= himl->cMaxImage) || (i < -1))
2467 return -1;
2469 hBestFitIcon = CopyImage(
2470 hIcon, IMAGE_ICON,
2471 himl->cx, himl->cy,
2472 LR_COPYFROMRESOURCE);
2474 GetIconInfo (hBestFitIcon, &ii);
2475 if (ii.hbmMask == 0)
2476 ERR("no mask!\n");
2477 if (ii.hbmColor == 0)
2478 ERR("no color!\n");
2479 GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp);
2481 if (i == -1) {
2482 if (himl->cCurImage + 1 > himl->cMaxImage)
2483 IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0);
2485 nIndex = himl->cCurImage;
2486 himl->cCurImage++;
2488 else
2489 nIndex = i;
2491 hdcImageList = CreateCompatibleDC (0);
2492 TRACE("hdcImageList=0x%x!\n", hdcImageList);
2493 if (hdcImageList == 0)
2494 ERR("invalid hdcImageList!\n");
2496 hdcImage = CreateCompatibleDC (0);
2497 TRACE("hdcImage=0x%x!\n", hdcImage);
2498 if (hdcImage == 0)
2499 ERR("invalid hdcImage!\n");
2501 hbmOldDst = SelectObject (hdcImageList, himl->hbmImage);
2502 SetTextColor( hdcImageList, RGB(0,0,0));
2503 SetBkColor( hdcImageList, RGB(255,255,255));
2504 hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
2505 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2506 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2508 if (himl->hbmMask) {
2509 SelectObject (hdcImageList, himl->hbmMask);
2510 SelectObject (hdcImage, ii.hbmMask);
2511 StretchBlt (hdcImageList, nIndex * himl->cx, 0, himl->cx, himl->cy,
2512 hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
2515 SelectObject (hdcImage, hbmOldSrc);
2516 SelectObject (hdcImageList, hbmOldDst);
2518 if(hBestFitIcon)
2519 DestroyIcon(hBestFitIcon);
2520 if (hdcImageList)
2521 DeleteDC (hdcImageList);
2522 if (hdcImage)
2523 DeleteDC (hdcImage);
2524 if (ii.hbmColor)
2525 DeleteObject (ii.hbmColor);
2526 if (ii.hbmMask)
2527 DeleteObject (ii.hbmMask);
2529 return nIndex;
2533 /*************************************************************************
2534 * ImageList_SetBkColor [COMCTL32.76]
2536 * Sets the background color of an image list.
2538 * PARAMS
2539 * himl [I] handle to image list
2540 * clrBk [I] background color
2542 * RETURNS
2543 * Success: previous background color
2544 * Failure: CLR_NONE
2547 COLORREF WINAPI
2548 ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk)
2550 COLORREF clrOldBk;
2552 if (himl == NULL)
2553 return CLR_NONE;
2555 clrOldBk = himl->clrBk;
2556 himl->clrBk = clrBk;
2557 return clrOldBk;
2561 /*************************************************************************
2562 * ImageList_SetDragCursorImage [COMCTL32.77]
2564 * Combines the specified image with the current drag image
2566 * PARAMS
2567 * himlDrag [I] handle to drag image list
2568 * iDrag [I] drag image index
2569 * dxHotspot [I] X position of the hot spot
2570 * dyHotspot [I] Y position of the hot spot
2572 * RETURNS
2573 * Success: TRUE
2574 * Failure: FALSE
2576 * NOTES
2577 * When this function is called and the drag image is visible, a
2578 * short flickering occurs but this matches the Win9x behavior. It is
2579 * possible to fix the flickering using code like in ImageList_DragMove.
2582 BOOL WINAPI
2583 ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag,
2584 INT dxHotspot, INT dyHotspot)
2586 HIMAGELIST himlTemp;
2587 INT dx, dy;
2588 BOOL visible;
2590 if (InternalDrag.himl == NULL)
2591 return FALSE;
2593 TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n",
2594 dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot);
2596 visible = InternalDrag.bShow;
2598 /* Calculate the offset between the origin of the old image and the
2599 * origin of the second image.
2600 * dxHotspot, dyHotspot is the offset of THE Hotspot (there is only one
2601 * hotspot) to the origin of the second image.
2602 * See M$DN for details */
2603 dx = InternalDrag.dxHotspot - dxHotspot;
2604 dy = InternalDrag.dyHotspot - dyHotspot;
2605 himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, dx, dy);
2607 if (visible) {
2608 /* hide the drag image */
2609 ImageList_DragShowNolock(FALSE);
2611 if ((InternalDrag.himl->cx != himlTemp->cx) ||
2612 (InternalDrag.himl->cy != himlTemp->cy)) {
2613 /* the size of the drag image changed, invalidate the buffer */
2614 DeleteObject(InternalDrag.hbmBg);
2615 InternalDrag.hbmBg = 0;
2618 ImageList_Destroy (InternalDrag.himl);
2619 InternalDrag.himl = himlTemp;
2621 /* update the InternalDragOffset, if the origin of the
2622 * DragImage was changed by ImageList_Merge. */
2623 if (dx > InternalDrag.dxHotspot) {
2624 InternalDrag.dxHotspot = dx;
2626 if (dy > InternalDrag.dyHotspot) {
2627 InternalDrag.dyHotspot = dy;
2630 if (visible) {
2631 /* show the drag image */
2632 ImageList_DragShowNolock(TRUE);
2635 return TRUE;
2639 /*************************************************************************
2640 * ImageList_SetFilter [COMCTL32.78]
2642 * Sets a filter (or does something completely different)!!???
2644 * PARAMS
2645 * himl [I] handle to image list
2646 * i [I] ???
2647 * dwFilter [I] ???
2649 * RETURNS
2650 * Success: TRUE ???
2651 * Failure: FALSE ???
2653 * BUGS
2654 * This is an UNDOCUMENTED function!!!!
2655 * empty stub.
2658 BOOL WINAPI
2659 ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter)
2661 FIXME("(%p 0x%x 0x%lx):empty stub!\n",
2662 himl, i, dwFilter);
2664 return FALSE;
2668 /*************************************************************************
2669 * ImageList_SetFlags [COMCTL32.79]
2671 * BUGS
2672 * Stub.
2675 DWORD WINAPI
2676 ImageList_SetFlags(HIMAGELIST himl, DWORD flags)
2678 FIXME("(%p %08lx):empty stub\n", himl, flags);
2679 return 0;
2683 /*************************************************************************
2684 * ImageList_SetIconSize [COMCTL32.80]
2686 * Sets the image size of the bitmap and deletes all images.
2688 * PARAMS
2689 * himl [I] handle to image list
2690 * cx [I] image width
2691 * cy [I] image height
2693 * RETURNS
2694 * Success: TRUE
2695 * Failure: FALSE
2698 BOOL WINAPI
2699 ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
2701 INT nCount;
2703 if (!himl)
2704 return FALSE;
2706 /* remove all images */
2707 himl->cMaxImage = himl->cInitial + himl->cGrow;
2708 himl->cCurImage = 0;
2709 himl->cx = cx;
2710 himl->cy = cy;
2712 /* initialize overlay mask indices */
2713 for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
2714 himl->nOvlIdx[nCount] = -1;
2716 DeleteObject (himl->hbmImage);
2717 himl->hbmImage =
2718 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2719 1, himl->uBitsPixel, NULL);
2721 if (himl->hbmMask) {
2722 DeleteObject (himl->hbmMask);
2723 himl->hbmMask =
2724 CreateBitmap (himl->cMaxImage * himl->cx, himl->cy,
2725 1, 1, NULL);
2728 return TRUE;
2732 /*************************************************************************
2733 * ImageList_SetImageCount [COMCTL32.81]
2735 * Resizes an image list to the specified number of images.
2737 * PARAMS
2738 * himl [I] handle to image list
2739 * iImageCount [I] number of images in the image list
2741 * RETURNS
2742 * Success: TRUE
2743 * Failure: FALSE
2746 BOOL WINAPI
2747 ImageList_SetImageCount (HIMAGELIST himl, INT iImageCount)
2749 HDC hdcImageList, hdcBitmap;
2750 HBITMAP hbmNewBitmap;
2751 INT nNewCount, nCopyCount;
2753 if (!himl)
2754 return FALSE;
2755 if (himl->cCurImage >= iImageCount)
2756 return FALSE;
2757 if (himl->cMaxImage > iImageCount)
2758 return TRUE;
2760 nNewCount = iImageCount + himl->cGrow;
2761 nCopyCount = min(himl->cCurImage, iImageCount);
2763 hdcImageList = CreateCompatibleDC (0);
2764 hdcBitmap = CreateCompatibleDC (0);
2766 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2767 1, himl->uBitsPixel, NULL);
2768 if (hbmNewBitmap != 0)
2770 SelectObject (hdcImageList, himl->hbmImage);
2771 SelectObject (hdcBitmap, hbmNewBitmap);
2773 /* copy images */
2774 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2775 hdcImageList, 0, 0, SRCCOPY);
2776 #if 0
2777 /* delete 'empty' image space */
2778 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2779 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2780 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2781 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2782 #endif
2783 DeleteObject (himl->hbmImage);
2784 himl->hbmImage = hbmNewBitmap;
2786 else
2787 ERR("Could not create new image bitmap !\n");
2789 if (himl->hbmMask)
2791 hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy,
2792 1, 1, NULL);
2793 if (hbmNewBitmap != 0)
2795 SelectObject (hdcImageList, himl->hbmMask);
2796 SelectObject (hdcBitmap, hbmNewBitmap);
2798 /* copy images */
2799 BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy,
2800 hdcImageList, 0, 0, SRCCOPY);
2801 #if 0
2802 /* delete 'empty' image space */
2803 SetBkColor (hdcBitmap, RGB(255, 255, 255));
2804 SetTextColor (hdcBitmap, RGB(0, 0, 0));
2805 PatBlt (hdcBitmap, nCopyCount * himl->cx, 0,
2806 (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS);
2807 #endif
2808 DeleteObject (himl->hbmMask);
2809 himl->hbmMask = hbmNewBitmap;
2811 else
2812 ERR("Could not create new mask bitmap!\n");
2815 DeleteDC (hdcImageList);
2816 DeleteDC (hdcBitmap);
2818 /* Update max image count and current image count */
2819 himl->cMaxImage = nNewCount;
2820 if (himl->cCurImage > nCopyCount)
2821 himl->cCurImage = nCopyCount;
2823 return TRUE;
2827 /*************************************************************************
2828 * ImageList_SetOverlayImage [COMCTL32.82]
2830 * Assigns an overlay mask index to an existing image in an image list.
2832 * PARAMS
2833 * himl [I] handle to image list
2834 * iImage [I] image index
2835 * iOverlay [I] overlay mask index
2837 * RETURNS
2838 * Success: TRUE
2839 * Failure: FALSE
2842 BOOL WINAPI
2843 ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay)
2845 if (!himl)
2846 return FALSE;
2847 if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE))
2848 return FALSE;
2849 if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage)))
2850 return FALSE;
2851 himl->nOvlIdx[iOverlay - 1] = iImage;
2852 return TRUE;
2857 /* helper for ImageList_Write - write bitmap to pstm
2858 * currently everything is written as 24 bit RGB, except masks
2860 static BOOL
2861 _write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy)
2863 LPBITMAPFILEHEADER bmfh;
2864 LPBITMAPINFOHEADER bmih;
2865 LPBYTE data, lpBits, lpBitsOrg;
2866 BITMAP bm;
2867 INT bitCount, sizeImage, offBits, totalSize;
2868 INT nwidth, nheight, nsizeImage, icount;
2869 HDC xdc;
2870 BOOL result = FALSE;
2873 xdc = GetDC(0);
2874 GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
2876 /* XXX is this always correct? */
2877 icount = bm.bmWidth / cx;
2878 nwidth = cx << 2;
2879 nheight = cy * ((icount+3)>>2);
2881 bitCount = bm.bmBitsPixel == 1 ? 1 : 24;
2882 sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight;
2883 nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight;
2885 totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
2886 if(bitCount != 24)
2887 totalSize += (1 << bitCount) * sizeof(RGBQUAD);
2888 offBits = totalSize;
2889 totalSize += nsizeImage;
2891 data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize);
2892 bmfh = (LPBITMAPFILEHEADER)data;
2893 bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER));
2894 lpBits = data + offBits;
2896 /* setup BITMAPFILEHEADER */
2897 bmfh->bfType = (('M' << 8) | 'B');
2898 bmfh->bfSize = 0;
2899 bmfh->bfReserved1 = 0;
2900 bmfh->bfReserved2 = 0;
2901 bmfh->bfOffBits = offBits;
2903 /* setup BITMAPINFOHEADER */
2904 bmih->biSize = sizeof(BITMAPINFOHEADER);
2905 bmih->biWidth = bm.bmWidth;
2906 bmih->biHeight = bm.bmHeight;
2907 bmih->biPlanes = 1;
2908 bmih->biBitCount = bitCount;
2909 bmih->biCompression = BI_RGB;
2910 bmih->biSizeImage = nsizeImage;
2911 bmih->biXPelsPerMeter = 0;
2912 bmih->biYPelsPerMeter = 0;
2913 bmih->biClrUsed = 0;
2914 bmih->biClrImportant = 0;
2916 lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, nsizeImage);
2917 if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg,
2918 (BITMAPINFO *)bmih, DIB_RGB_COLORS))
2919 goto failed;
2920 else {
2921 int i;
2922 int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3);
2923 int nbpl = (((nwidth*bitCount+31) & ~31)>>3);
2925 for(i = 0; i < nheight; i++) {
2926 int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl);
2927 int noff = (nbpl * (nheight-1-i));
2928 memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl);
2932 bmih->biWidth = nwidth;
2933 bmih->biHeight = nheight;
2935 if(bitCount == 1) {
2936 //Hack.
2937 LPBITMAPINFO inf = (LPBITMAPINFO)bmih;
2938 inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0;
2939 inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff;
2942 if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL)))
2943 goto failed;
2945 result = TRUE;
2947 failed:
2948 ReleaseDC(0, xdc);
2949 LocalFree((HLOCAL)lpBitsOrg);
2951 return result;
2955 /*************************************************************************
2956 * ImageList_Write [COMCTL32.83]
2958 * Writes an image list to a stream.
2960 * PARAMS
2961 * himl [I] handle to image list
2962 * pstm [O] Pointer to a stream.
2964 * RETURNS
2965 * Success: TRUE
2966 * Failure: FALSE
2968 * BUGS
2969 * probably.
2972 BOOL WINAPI
2973 ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
2975 ILHEAD ilHead;
2976 int i;
2978 if (!himl)
2979 return FALSE;
2981 ilHead.usMagic = (('L' << 8) | 'I');
2982 ilHead.usVersion = 0x101;
2983 ilHead.cCurImage = himl->cCurImage;
2984 ilHead.cMaxImage = himl->cMaxImage;
2985 ilHead.cGrow = himl->cGrow;
2986 ilHead.cx = himl->cx;
2987 ilHead.cy = himl->cy;
2988 ilHead.bkcolor = himl->clrBk;
2989 ilHead.flags = himl->flags;
2990 for(i = 0; i < 4; i++) {
2991 ilHead.ovls[i] = himl->nOvlIdx[i];
2994 if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL)))
2995 return FALSE;
2997 /* write the bitmap */
2998 if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy))
2999 return FALSE;
3001 /* write the mask if we have one */
3002 if(himl->flags & ILC_MASK) {
3003 if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy))
3004 return FALSE;
3007 return TRUE;