wininet: Fixed grouping security error flags.
[wine] / dlls / gdi32 / bitmap.c
1 /*
2  * GDI bitmap objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1998 Huw D M Davies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "gdi_private.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(bitmap);
33
34
35 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc );
36 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
37 static BOOL BITMAP_DeleteObject( HGDIOBJ handle );
38
39 static const struct gdi_obj_funcs bitmap_funcs =
40 {
41     BITMAP_SelectObject,  /* pSelectObject */
42     BITMAP_GetObject,     /* pGetObjectA */
43     BITMAP_GetObject,     /* pGetObjectW */
44     NULL,                 /* pUnrealizeObject */
45     BITMAP_DeleteObject   /* pDeleteObject */
46 };
47
48
49 /***********************************************************************
50  *           null driver fallback implementations
51  */
52
53 DWORD nulldrv_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
54                         struct gdi_image_bits *bits, struct bitblt_coords *src )
55 {
56     if (!hbitmap) return ERROR_NOT_SUPPORTED;
57     return dib_driver.pGetImage( 0, hbitmap, info, bits, src );
58 }
59
60 DWORD nulldrv_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
61                         const struct gdi_image_bits *bits, struct bitblt_coords *src,
62                         struct bitblt_coords *dst, DWORD rop )
63 {
64     if (!hbitmap) return ERROR_SUCCESS;
65     return dib_driver.pPutImage( NULL, hbitmap, clip, info, bits, src, dst, rop );
66 }
67
68
69 /******************************************************************************
70  * CreateBitmap [GDI32.@]
71  *
72  * Creates a bitmap with the specified info.
73  *
74  * PARAMS
75  *    width  [I] bitmap width
76  *    height [I] bitmap height
77  *    planes [I] Number of color planes
78  *    bpp    [I] Number of bits to identify a color
79  *    bits   [I] Pointer to array containing color data
80  *
81  * RETURNS
82  *    Success: Handle to bitmap
83  *    Failure: 0
84  */
85 HBITMAP WINAPI CreateBitmap( INT width, INT height, UINT planes,
86                              UINT bpp, LPCVOID bits )
87 {
88     BITMAP bm;
89
90     bm.bmType = 0;
91     bm.bmWidth = width;
92     bm.bmHeight = height;
93     bm.bmWidthBytes = get_bitmap_stride( width, bpp );
94     bm.bmPlanes = planes;
95     bm.bmBitsPixel = bpp;
96     bm.bmBits = (LPVOID)bits;
97
98     return CreateBitmapIndirect( &bm );
99 }
100
101 /******************************************************************************
102  * CreateCompatibleBitmap [GDI32.@]
103  *
104  * Creates a bitmap compatible with the DC.
105  *
106  * PARAMS
107  *    hdc    [I] Handle to device context
108  *    width  [I] Width of bitmap
109  *    height [I] Height of bitmap
110  *
111  * RETURNS
112  *    Success: Handle to bitmap
113  *    Failure: 0
114  */
115 HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, INT width, INT height)
116 {
117     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
118     BITMAPINFO *bi = (BITMAPINFO *)buffer;
119     DIBSECTION dib;
120
121     TRACE("(%p,%d,%d)\n", hdc, width, height);
122
123     if (GetObjectType( hdc ) != OBJ_MEMDC)
124         return CreateBitmap( width, height,
125                              GetDeviceCaps(hdc, PLANES), GetDeviceCaps(hdc, BITSPIXEL), NULL );
126
127     switch (GetObjectW( GetCurrentObject( hdc, OBJ_BITMAP ), sizeof(dib), &dib ))
128     {
129     case sizeof(BITMAP): /* A device-dependent bitmap is selected in the DC */
130         return CreateBitmap( width, height, dib.dsBm.bmPlanes, dib.dsBm.bmBitsPixel, NULL );
131
132     case sizeof(DIBSECTION): /* A DIB section is selected in the DC */
133         bi->bmiHeader = dib.dsBmih;
134         bi->bmiHeader.biWidth  = width;
135         bi->bmiHeader.biHeight = height;
136         if (dib.dsBmih.biCompression == BI_BITFIELDS)  /* copy the color masks */
137             memcpy(bi->bmiColors, dib.dsBitfields, sizeof(dib.dsBitfields));
138         else if (dib.dsBmih.biBitCount <= 8)  /* copy the color table */
139             GetDIBColorTable(hdc, 0, 256, bi->bmiColors);
140         return CreateDIBSection( hdc, bi, DIB_RGB_COLORS, NULL, NULL, 0 );
141
142     default:
143         return 0;
144     }
145 }
146
147
148 /******************************************************************************
149  * CreateBitmapIndirect [GDI32.@]
150  *
151  * Creates a bitmap with the specified info.
152  *
153  * PARAMS
154  *  bmp [I] Pointer to the bitmap info describing the bitmap
155  *
156  * RETURNS
157  *    Success: Handle to bitmap
158  *    Failure: NULL. Use GetLastError() to determine the cause.
159  *
160  * NOTES
161  *  If a width or height of 0 are given, a 1x1 monochrome bitmap is returned.
162  */
163 HBITMAP WINAPI CreateBitmapIndirect( const BITMAP *bmp )
164 {
165     BITMAP bm;
166     BITMAPOBJ *bmpobj;
167     HBITMAP hbitmap;
168
169     if (!bmp || bmp->bmType)
170     {
171         SetLastError( ERROR_INVALID_PARAMETER );
172         return NULL;
173     }
174
175     if (bmp->bmWidth > 0x7ffffff || bmp->bmHeight > 0x7ffffff)
176     {
177         SetLastError( ERROR_INVALID_PARAMETER );
178         return 0;
179     }
180
181     bm = *bmp;
182
183     if (!bm.bmWidth || !bm.bmHeight)
184     {
185         return GetStockObject( DEFAULT_BITMAP );
186     }
187     else
188     {
189         if (bm.bmHeight < 0)
190             bm.bmHeight = -bm.bmHeight;
191         if (bm.bmWidth < 0)
192             bm.bmWidth = -bm.bmWidth;
193     }
194
195     if (bm.bmPlanes != 1)
196     {
197         FIXME("planes = %d\n", bm.bmPlanes);
198         SetLastError( ERROR_INVALID_PARAMETER );
199         return NULL;
200     }
201
202     /* Windows only uses 1, 4, 8, 16, 24 and 32 bpp */
203     if(bm.bmBitsPixel == 1)         bm.bmBitsPixel = 1;
204     else if(bm.bmBitsPixel <= 4)    bm.bmBitsPixel = 4;
205     else if(bm.bmBitsPixel <= 8)    bm.bmBitsPixel = 8;
206     else if(bm.bmBitsPixel <= 16)   bm.bmBitsPixel = 16;
207     else if(bm.bmBitsPixel <= 24)   bm.bmBitsPixel = 24;
208     else if(bm.bmBitsPixel <= 32)   bm.bmBitsPixel = 32;
209     else {
210         WARN("Invalid bmBitsPixel %d, returning ERROR_INVALID_PARAMETER\n", bm.bmBitsPixel);
211         SetLastError(ERROR_INVALID_PARAMETER);
212         return NULL;
213     }
214
215     /* Windows ignores the provided bm.bmWidthBytes */
216     bm.bmWidthBytes = get_bitmap_stride( bm.bmWidth, bm.bmBitsPixel );
217     /* XP doesn't allow to create bitmaps larger than 128 Mb */
218     if (bm.bmHeight > 128 * 1024 * 1024 / bm.bmWidthBytes)
219     {
220         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
221         return 0;
222     }
223
224     /* Create the BITMAPOBJ */
225     if (!(bmpobj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*bmpobj) )))
226     {
227         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
228         return 0;
229     }
230
231     bmpobj->dib.dsBm = bm;
232     bmpobj->dib.dsBm.bmBits = NULL;
233     bmpobj->funcs = &null_driver;
234
235     if (!(hbitmap = alloc_gdi_handle( &bmpobj->header, OBJ_BITMAP, &bitmap_funcs )))
236     {
237         HeapFree( GetProcessHeap(), 0, bmpobj );
238         return 0;
239     }
240
241     if (bm.bmBits)
242         SetBitmapBits( hbitmap, bm.bmHeight * bm.bmWidthBytes, bm.bmBits );
243
244     TRACE("%dx%d, bpp %d planes %d: returning %p\n", bm.bmWidth, bm.bmHeight,
245           bm.bmBitsPixel, bm.bmPlanes, hbitmap);
246
247     return hbitmap;
248 }
249
250
251 /***********************************************************************
252  * GetBitmapBits [GDI32.@]
253  *
254  * Copies bitmap bits of bitmap to buffer.
255  *
256  * RETURNS
257  *    Success: Number of bytes copied
258  *    Failure: 0
259  */
260 LONG WINAPI GetBitmapBits(
261     HBITMAP hbitmap, /* [in]  Handle to bitmap */
262     LONG count,        /* [in]  Number of bytes to copy */
263     LPVOID bits)       /* [out] Pointer to buffer to receive bits */
264 {
265     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
266     BITMAPINFO *info = (BITMAPINFO *)buffer;
267     struct gdi_image_bits src_bits;
268     struct bitblt_coords src;
269     int dst_stride, max, ret;
270     BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
271
272     if (!bmp) return 0;
273
274     dst_stride = get_bitmap_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
275     ret = max = dst_stride * bmp->dib.dsBm.bmHeight;
276     if (!bits) goto done;
277     if (count > max) count = max;
278     ret = count;
279
280     src.visrect.left = 0;
281     src.visrect.right = bmp->dib.dsBm.bmWidth;
282     src.visrect.top = 0;
283     src.visrect.bottom = (count + dst_stride - 1) / dst_stride;
284     src.x = src.y = 0;
285     src.width = src.visrect.right - src.visrect.left;
286     src.height = src.visrect.bottom - src.visrect.top;
287
288     if (!bmp->funcs->pGetImage( NULL, hbitmap, info, &src_bits, &src ))
289     {
290         const char *src_ptr = src_bits.ptr;
291         int src_stride = get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount );
292
293         /* GetBitmapBits returns 16-bit aligned data */
294
295         if (info->bmiHeader.biHeight > 0)
296         {
297             src_ptr += (info->bmiHeader.biHeight - 1) * src_stride;
298             src_stride = -src_stride;
299         }
300         src_ptr += src.visrect.top * src_stride;
301
302         if (src_stride == dst_stride) memcpy( bits, src_ptr, count );
303         else while (count > 0)
304         {
305             memcpy( bits, src_ptr, min( count, dst_stride ) );
306             src_ptr += src_stride;
307             bits = (char *)bits + dst_stride;
308             count -= dst_stride;
309         }
310         if (src_bits.free) src_bits.free( &src_bits );
311     }
312     else ret = 0;
313
314 done:
315     GDI_ReleaseObj( hbitmap );
316     return ret;
317 }
318
319
320 /******************************************************************************
321  * SetBitmapBits [GDI32.@]
322  *
323  * Sets bits of color data for a bitmap.
324  *
325  * RETURNS
326  *    Success: Number of bytes used in setting the bitmap bits
327  *    Failure: 0
328  */
329 LONG WINAPI SetBitmapBits(
330     HBITMAP hbitmap, /* [in] Handle to bitmap */
331     LONG count,        /* [in] Number of bytes in bitmap array */
332     LPCVOID bits)      /* [in] Address of array with bitmap bits */
333 {
334     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
335     BITMAPINFO *info = (BITMAPINFO *)buffer;
336     BITMAPOBJ *bmp;
337     DWORD err;
338     int i, src_stride, dst_stride;
339     struct bitblt_coords src, dst;
340     struct gdi_image_bits src_bits;
341     HRGN clip = NULL;
342
343     if (!bits) return 0;
344
345     bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
346     if (!bmp) return 0;
347
348     if (count < 0) {
349         WARN("(%d): Negative number of bytes passed???\n", count );
350         count = -count;
351     }
352
353     src_stride = get_bitmap_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
354     count = min( count, src_stride * bmp->dib.dsBm.bmHeight );
355
356     dst_stride = get_dib_stride( bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmBitsPixel );
357
358     src.visrect.left   = src.x = 0;
359     src.visrect.top    = src.y = 0;
360     src.visrect.right  = src.width = bmp->dib.dsBm.bmWidth;
361     src.visrect.bottom = src.height = (count + src_stride - 1 ) / src_stride;
362     dst = src;
363
364     if (count % src_stride)
365     {
366         HRGN last_row;
367         int extra_pixels = ((count % src_stride) << 3) / bmp->dib.dsBm.bmBitsPixel;
368
369         if ((count % src_stride << 3) % bmp->dib.dsBm.bmBitsPixel)
370             FIXME( "Unhandled partial pixel\n" );
371         clip = CreateRectRgn( src.visrect.left, src.visrect.top,
372                               src.visrect.right, src.visrect.bottom - 1 );
373         last_row = CreateRectRgn( src.visrect.left, src.visrect.bottom - 1,
374                                   src.visrect.left + extra_pixels, src.visrect.bottom );
375         CombineRgn( clip, clip, last_row, RGN_OR );
376         DeleteObject( last_row );
377     }
378
379     TRACE("(%p, %d, %p) %dx%d %d bpp fetched height: %d\n",
380           hbitmap, count, bits, bmp->dib.dsBm.bmWidth, bmp->dib.dsBm.bmHeight,
381           bmp->dib.dsBm.bmBitsPixel, src.height );
382
383     if (src_stride == dst_stride)
384     {
385         src_bits.ptr = (void *)bits;
386         src_bits.is_copy = FALSE;
387         src_bits.free = NULL;
388     }
389     else
390     {
391         if (!(src_bits.ptr = HeapAlloc( GetProcessHeap(), 0, dst.height * dst_stride )))
392         {
393             GDI_ReleaseObj( hbitmap );
394             return 0;
395         }
396         src_bits.is_copy = TRUE;
397         src_bits.free = free_heap_bits;
398         for (i = 0; i < count / src_stride; i++)
399             memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, src_stride );
400         if (count % src_stride)
401             memcpy( (char *)src_bits.ptr + i * dst_stride, (char *)bits + i * src_stride, count % src_stride );
402     }
403
404     /* query the color info */
405     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
406     info->bmiHeader.biPlanes        = 1;
407     info->bmiHeader.biBitCount      = bmp->dib.dsBm.bmBitsPixel;
408     info->bmiHeader.biCompression   = BI_RGB;
409     info->bmiHeader.biXPelsPerMeter = 0;
410     info->bmiHeader.biYPelsPerMeter = 0;
411     info->bmiHeader.biClrUsed       = 0;
412     info->bmiHeader.biClrImportant  = 0;
413     info->bmiHeader.biWidth         = 0;
414     info->bmiHeader.biHeight        = 0;
415     info->bmiHeader.biSizeImage     = 0;
416     err = bmp->funcs->pPutImage( NULL, hbitmap, 0, info, NULL, NULL, NULL, SRCCOPY );
417
418     if (!err || err == ERROR_BAD_FORMAT)
419     {
420         info->bmiHeader.biWidth     = bmp->dib.dsBm.bmWidth;
421         info->bmiHeader.biHeight    = -dst.height;
422         info->bmiHeader.biSizeImage = dst.height * dst_stride;
423         err = bmp->funcs->pPutImage( NULL, hbitmap, clip, info, &src_bits, &src, &dst, SRCCOPY );
424     }
425     if (err) count = 0;
426
427     if (clip) DeleteObject( clip );
428     if (src_bits.free) src_bits.free( &src_bits );
429     GDI_ReleaseObj( hbitmap );
430     return count;
431 }
432
433
434 static void set_initial_bitmap_bits( HBITMAP hbitmap, BITMAPOBJ *bmp )
435 {
436     char src_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
437     BITMAPINFO *src_info = (BITMAPINFO *)src_bmibuf;
438     char dst_bmibuf[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
439     BITMAPINFO *dst_info = (BITMAPINFO *)dst_bmibuf;
440     DWORD err;
441     struct gdi_image_bits bits;
442     struct bitblt_coords src, dst;
443
444     if (!bmp->dib.dsBm.bmBits) return;
445     if (bmp->funcs->pPutImage == nulldrv_PutImage) return;
446
447     get_ddb_bitmapinfo( bmp, src_info );
448
449     bits.ptr = bmp->dib.dsBm.bmBits;
450     bits.is_copy = FALSE;
451     bits.free = NULL;
452     bits.param = NULL;
453
454     src.x      = 0;
455     src.y      = 0;
456     src.width  = bmp->dib.dsBm.bmWidth;
457     src.height = bmp->dib.dsBm.bmHeight;
458     src.visrect.left   = 0;
459     src.visrect.top    = 0;
460     src.visrect.right  = bmp->dib.dsBm.bmWidth;
461     src.visrect.bottom = bmp->dib.dsBm.bmHeight;
462     dst = src;
463
464     copy_bitmapinfo( dst_info, src_info );
465
466     err = bmp->funcs->pPutImage( NULL, hbitmap, 0, dst_info, &bits, &src, &dst, 0 );
467     if (err == ERROR_BAD_FORMAT)
468     {
469         err = convert_bits( src_info, &src, dst_info, &bits, FALSE );
470         if (!err) err = bmp->funcs->pPutImage( NULL, hbitmap, 0, dst_info, &bits, &src, &dst, 0 );
471         if (bits.free) bits.free( &bits );
472     }
473 }
474
475
476 /***********************************************************************
477  *           BITMAP_SelectObject
478  */
479 static HGDIOBJ BITMAP_SelectObject( HGDIOBJ handle, HDC hdc )
480 {
481     HGDIOBJ ret;
482     BITMAPOBJ *bitmap;
483     DC *dc;
484     PHYSDEV physdev = NULL, old_physdev = NULL, createdev;
485
486     if (!(dc = get_dc_ptr( hdc ))) return 0;
487
488     if (GetObjectType( hdc ) != OBJ_MEMDC)
489     {
490         ret = 0;
491         goto done;
492     }
493     ret = dc->hBitmap;
494     if (handle == dc->hBitmap) goto done;  /* nothing to do */
495
496     if (!(bitmap = GDI_GetObjPtr( handle, OBJ_BITMAP )))
497     {
498         ret = 0;
499         goto done;
500     }
501
502     if (bitmap->header.selcount && (handle != GetStockObject(DEFAULT_BITMAP)))
503     {
504         WARN( "Bitmap already selected in another DC\n" );
505         GDI_ReleaseObj( handle );
506         ret = 0;
507         goto done;
508     }
509
510     if (bitmap->dib.dsBm.bmBitsPixel != 1 &&
511         bitmap->dib.dsBm.bmBitsPixel != GetDeviceCaps( hdc, BITSPIXEL ))
512     {
513         WARN( "Wrong format bitmap %u bpp\n", bitmap->dib.dsBm.bmBitsPixel );
514         GDI_ReleaseObj( handle );
515         ret = 0;
516         goto done;
517     }
518
519     if (dc->dibdrv) old_physdev = pop_dc_driver( dc, dc->dibdrv );
520
521     if (bitmap->dib.dsBm.bmBitsPixel > 1)
522     {
523         physdev = GET_DC_PHYSDEV( dc, pSelectBitmap );
524         createdev = GET_DC_PHYSDEV( dc, pCreateBitmap );
525     }
526     else physdev = createdev = &dc->nulldrv;  /* force use of the DIB engine for 1-bpp */
527
528     if (physdev->funcs == &null_driver)
529     {
530         physdev = dc->dibdrv;
531         if (physdev) push_dc_driver( &dc->physDev, physdev, physdev->funcs );
532         else
533         {
534             if (!dib_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) goto done;
535             dc->dibdrv = physdev = dc->physDev;
536         }
537     }
538
539     /* never set the owner of the stock bitmap since it can be selected in multiple DCs */
540     if (handle != GetStockObject(DEFAULT_BITMAP) && bitmap->funcs != createdev->funcs)
541     {
542         /* we can only change from the null driver to some other driver */
543         if (bitmap->funcs != &null_driver)
544         {
545             FIXME( "Trying to select bitmap %p in different DC type\n", handle );
546             GDI_ReleaseObj( handle );
547             ret = 0;
548             goto done;
549         }
550         if (createdev->funcs != &null_driver)
551         {
552             if (!createdev->funcs->pCreateBitmap( createdev, handle ))
553             {
554                 GDI_ReleaseObj( handle );
555                 ret = 0;
556                 goto done;
557             }
558             bitmap->funcs = createdev->funcs;
559             set_initial_bitmap_bits( handle, bitmap );
560         }
561         else bitmap->funcs = &dib_driver;  /* use the DIB driver to emulate DDB support */
562     }
563
564     if (!physdev->funcs->pSelectBitmap( physdev, handle ))
565     {
566         GDI_ReleaseObj( handle );
567         ret = 0;
568     }
569     else
570     {
571         dc->hBitmap = handle;
572         GDI_inc_ref_count( handle );
573         dc->dirty = 0;
574         dc->vis_rect.left   = 0;
575         dc->vis_rect.top    = 0;
576         dc->vis_rect.right  = bitmap->dib.dsBm.bmWidth;
577         dc->vis_rect.bottom = bitmap->dib.dsBm.bmHeight;
578         dc->device_rect = dc->vis_rect;
579         GDI_ReleaseObj( handle );
580         DC_InitDC( dc );
581         GDI_dec_ref_count( ret );
582     }
583
584  done:
585     if(!ret)
586     {
587         if (physdev && physdev == dc->dibdrv) pop_dc_driver( dc, dc->dibdrv );
588         if (old_physdev) push_dc_driver( &dc->physDev, old_physdev, old_physdev->funcs );
589     }
590     release_dc_ptr( dc );
591     return ret;
592 }
593
594
595 /***********************************************************************
596  *           BITMAP_DeleteObject
597  */
598 static BOOL BITMAP_DeleteObject( HGDIOBJ handle )
599 {
600     const struct gdi_dc_funcs *funcs;
601     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
602
603     if (!bmp) return FALSE;
604     funcs = bmp->funcs;
605     GDI_ReleaseObj( handle );
606
607     funcs->pDeleteBitmap( handle );
608
609     if (!(bmp = free_gdi_handle( handle ))) return FALSE;
610
611     HeapFree( GetProcessHeap(), 0, bmp->dib.dsBm.bmBits );
612     return HeapFree( GetProcessHeap(), 0, bmp );
613 }
614
615
616 /***********************************************************************
617  *           BITMAP_GetObject
618  */
619 static INT BITMAP_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
620 {
621     INT ret = 0;
622     BITMAPOBJ *bmp = GDI_GetObjPtr( handle, OBJ_BITMAP );
623
624     if (!bmp) return 0;
625
626     if (!buffer) ret = sizeof(BITMAP);
627     else if (count >= sizeof(BITMAP))
628     {
629         BITMAP *bitmap = buffer;
630         *bitmap = bmp->dib.dsBm;
631         bitmap->bmBits = NULL;
632         ret = sizeof(BITMAP);
633     }
634     GDI_ReleaseObj( handle );
635     return ret;
636 }
637
638
639 /******************************************************************************
640  * CreateDiscardableBitmap [GDI32.@]
641  *
642  * Creates a discardable bitmap.
643  *
644  * RETURNS
645  *    Success: Handle to bitmap
646  *    Failure: NULL
647  */
648 HBITMAP WINAPI CreateDiscardableBitmap(
649     HDC hdc,    /* [in] Handle to device context */
650     INT width,  /* [in] Bitmap width */
651     INT height) /* [in] Bitmap height */
652 {
653     return CreateCompatibleBitmap( hdc, width, height );
654 }
655
656
657 /******************************************************************************
658  * GetBitmapDimensionEx [GDI32.@]
659  *
660  * Retrieves dimensions of a bitmap.
661  *
662  * RETURNS
663  *    Success: TRUE
664  *    Failure: FALSE
665  */
666 BOOL WINAPI GetBitmapDimensionEx(
667     HBITMAP hbitmap, /* [in]  Handle to bitmap */
668     LPSIZE size)     /* [out] Address of struct receiving dimensions */
669 {
670     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
671     if (!bmp) return FALSE;
672     *size = bmp->size;
673     GDI_ReleaseObj( hbitmap );
674     return TRUE;
675 }
676
677
678 /******************************************************************************
679  * SetBitmapDimensionEx [GDI32.@]
680  *
681  * Assigns dimensions to a bitmap.
682  * MSDN says that this function will fail if hbitmap is a handle created by
683  * CreateDIBSection, but that's not true on Windows 2000.
684  *
685  * RETURNS
686  *    Success: TRUE
687  *    Failure: FALSE
688  */
689 BOOL WINAPI SetBitmapDimensionEx(
690     HBITMAP hbitmap, /* [in]  Handle to bitmap */
691     INT x,           /* [in]  Bitmap width */
692     INT y,           /* [in]  Bitmap height */
693     LPSIZE prevSize) /* [out] Address of structure for orig dims */
694 {
695     BITMAPOBJ * bmp = GDI_GetObjPtr( hbitmap, OBJ_BITMAP );
696     if (!bmp) return FALSE;
697     if (prevSize) *prevSize = bmp->size;
698     bmp->size.cx = x;
699     bmp->size.cy = y;
700     GDI_ReleaseObj( hbitmap );
701     return TRUE;
702 }