xref: /reactos/win32ss/gdi/ntgdi/bitmaps.c (revision 84344399)
1 /*
2  * COPYRIGHT:        GNU GPL, See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Bitmap functions
5  * FILE:             win32ss/gdi/ntgdi/bitmaps.c
6  * PROGRAMERS:       Timo Kreuzer <timo.kreuzer@reactos.org>
7  *                   Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
8  */
9 
10 #include <win32k.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 BOOL
16 NTAPI
17 GreSetBitmapOwner(
18     _In_ HBITMAP hbmp,
19     _In_ ULONG ulOwner)
20 {
21     /* Check if we have the correct object type */
22     if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE)
23     {
24         DPRINT1("Incorrect type for hbmp: %p\n", hbmp);
25         return FALSE;
26     }
27 
28     /// FIXME: this is a hack and doesn't handle a race condition properly.
29     /// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
30 
31     /* Check if we set public or none */
32     if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) ||
33         (ulOwner == GDI_OBJ_HMGR_NONE))
34     {
35         /* Only allow this for owned objects */
36         if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED)
37         {
38             DPRINT1("Cannot change owner for non-powned hbmp\n");
39             return FALSE;
40         }
41     }
42 
43     return GreSetObjectOwner(hbmp, ulOwner);
44 }
45 
46 LONG
47 NTAPI
48 UnsafeSetBitmapBits(
49     _Inout_ PSURFACE psurf,
50     _In_ ULONG cjBits,
51     _In_ const VOID *pvBits)
52 {
53     PUCHAR pjDst;
54     const UCHAR *pjSrc;
55     LONG lDeltaDst, lDeltaSrc, lDeltaDstAbs;
56     ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
57 
58     NT_ASSERT(psurf->flags & API_BITMAP);
59     NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP);
60 
61     nWidth = psurf->SurfObj.sizlBitmap.cx;
62     nHeight = psurf->SurfObj.sizlBitmap.cy;
63     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
64 
65     pjDst = psurf->SurfObj.pvScan0;
66     pjSrc = pvBits;
67     lDeltaDst = psurf->SurfObj.lDelta;
68     lDeltaDstAbs = labs(lDeltaDst);
69     lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
70     NT_ASSERT(lDeltaSrc <= lDeltaDstAbs);
71 
72     cbDst = lDeltaDstAbs * nHeight;
73     cbSrc = lDeltaSrc * nHeight;
74     cjBits = min(cjBits, cbSrc);
75 
76     iSrc = iDst = 0;
77     for (Y = 0; Y < nHeight; Y++)
78     {
79         if (iSrc + lDeltaSrc > cjBits || iDst + lDeltaDstAbs > cbDst)
80         {
81             LONG lDelta = min(cjBits - iSrc, cbDst - iDst);
82             NT_ASSERT(lDelta >= 0);
83             RtlCopyMemory(pjDst, pjSrc, lDelta);
84             iSrc += lDelta;
85             break;
86         }
87 
88         /* Copy one line */
89         RtlCopyMemory(pjDst, pjSrc, lDeltaSrc);
90         pjSrc += lDeltaSrc;
91         pjDst += lDeltaDst;
92         iSrc += lDeltaSrc;
93         iDst += lDeltaDstAbs;
94     }
95 
96     return iSrc;
97 }
98 
99 HBITMAP
100 NTAPI
101 GreCreateBitmapEx(
102     _In_ ULONG nWidth,
103     _In_ ULONG nHeight,
104     _In_ ULONG cjWidthBytes,
105     _In_ ULONG iFormat,
106     _In_ USHORT fjBitmap,
107     _In_ ULONG cjSizeImage,
108     _In_opt_ PVOID pvBits,
109     _In_ FLONG flags)
110 {
111     PSURFACE psurf;
112     HBITMAP hbmp;
113     PVOID pvCompressedBits = NULL;
114 
115     /* Verify format */
116     if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
117 
118     /* The infamous RLE hack */
119     if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE))
120     {
121         pvCompressedBits = pvBits;
122         pvBits = NULL;
123         iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
124     }
125 
126     /* Allocate a surface */
127     psurf = SURFACE_AllocSurface(STYPE_BITMAP,
128                                  nWidth,
129                                  nHeight,
130                                  iFormat,
131                                  fjBitmap,
132                                  cjWidthBytes,
133                                  pvCompressedBits ? 0 : cjSizeImage,
134                                  pvBits);
135     if (!psurf)
136     {
137         DPRINT1("SURFACE_AllocSurface failed.\n");
138         return NULL;
139     }
140 
141     /* The infamous RLE hack */
142     if (pvCompressedBits)
143     {
144         SIZEL sizl;
145         LONG lDelta;
146 
147         sizl.cx = nWidth;
148         sizl.cy = nHeight;
149         lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
150 
151         pvBits = psurf->SurfObj.pvBits;
152         DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage);
153     }
154 
155     /* Get the handle for the bitmap */
156     hbmp = (HBITMAP)psurf->SurfObj.hsurf;
157 
158     /* Mark as API bitmap */
159     psurf->flags |= (flags | API_BITMAP);
160 
161     /* Unlock the surface and return */
162     SURFACE_UnlockSurface(psurf);
163     return hbmp;
164 }
165 
166 /* Creates a DDB surface,
167  * as in CreateCompatibleBitmap or CreateBitmap.
168  * Note that each scanline must be 32bit aligned!
169  */
170 HBITMAP
171 NTAPI
172 GreCreateBitmap(
173     _In_ ULONG nWidth,
174     _In_ ULONG nHeight,
175     _In_ ULONG cPlanes,
176     _In_ ULONG cBitsPixel,
177     _In_opt_ PVOID pvBits)
178 {
179     /* Call the extended function */
180     return GreCreateBitmapEx(nWidth,
181                              nHeight,
182                              0, /* Auto width */
183                              BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
184                              0, /* No bitmap flags */
185                              0, /* Auto size */
186                              pvBits,
187                              DDB_SURFACE /* DDB */);
188 }
189 
190 HBITMAP
191 APIENTRY
192 NtGdiCreateBitmap(
193     IN INT nWidth,
194     IN INT nHeight,
195     IN UINT cPlanes,
196     IN UINT cBitsPixel,
197     IN OPTIONAL LPBYTE pUnsafeBits)
198 {
199     HBITMAP hbmp;
200     ULONG cRealBpp, cjWidthBytes, iFormat;
201     ULONGLONG cjSize;
202     PSURFACE psurf;
203 
204     /* Calculate bitmap format and real bits per pixel. */
205     iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB);
206     cRealBpp = gajBitsPerFormat[iFormat];
207 
208     /* Calculate width and image size in bytes */
209     cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp);
210     cjSize = (ULONGLONG)cjWidthBytes * nHeight;
211 
212     /* Check parameters (possible overflow of cjSize!) */
213     if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) ||
214         (cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL))
215     {
216         DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
217                 nWidth, nHeight, cBitsPixel, cPlanes);
218         EngSetLastError(ERROR_INVALID_PARAMETER);
219         return NULL;
220     }
221 
222     /* Allocate the surface (but don't set the bits) */
223     psurf = SURFACE_AllocSurface(STYPE_BITMAP,
224                                  nWidth,
225                                  nHeight,
226                                  iFormat,
227                                  0,
228                                  0,
229                                  0,
230                                  NULL);
231     if (!psurf)
232     {
233         DPRINT1("SURFACE_AllocSurface failed.\n");
234         return NULL;
235     }
236 
237     /* Mark as API and DDB bitmap */
238     psurf->flags |= (API_BITMAP | DDB_SURFACE);
239 
240     /* Check if we have bits to set */
241     if (pUnsafeBits)
242     {
243         /* Protect with SEH and copy the bits */
244         _SEH2_TRY
245         {
246             ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
247             UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits);
248         }
249         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
250         {
251             GDIOBJ_vDeleteObject(&psurf->BaseObject);
252             _SEH2_YIELD(return NULL;)
253         }
254         _SEH2_END
255     }
256     else
257     {
258         /* Zero the bits */
259         RtlZeroMemory(psurf->SurfObj.pvBits, psurf->SurfObj.cjBits);
260     }
261 
262     /* Get the handle for the bitmap */
263     hbmp = (HBITMAP)psurf->SurfObj.hsurf;
264 
265     /* Unlock the surface */
266     SURFACE_UnlockSurface(psurf);
267 
268     return hbmp;
269 }
270 
271 
272 HBITMAP FASTCALL
273 IntCreateCompatibleBitmap(
274     PDC Dc,
275     INT Width,
276     INT Height,
277     UINT Planes,
278     UINT Bpp)
279 {
280     HBITMAP Bmp = NULL;
281     PPALETTE ppal;
282 
283     /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
284     if (0 == Width || 0 == Height)
285     {
286         return NtGdiGetStockObject(DEFAULT_BITMAP);
287     }
288 
289     if (Dc->dctype != DCTYPE_MEMORY)
290     {
291         PSURFACE psurf;
292 
293         Bmp = GreCreateBitmap(abs(Width),
294                               abs(Height),
295                               Planes ? Planes : 1,
296                               Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel,
297                               NULL);
298         if (Bmp == NULL)
299         {
300             DPRINT1("Failed to allocate a bitmap!\n");
301             return NULL;
302         }
303 
304         psurf = SURFACE_ShareLockSurface(Bmp);
305         ASSERT(psurf);
306 
307         /* Dereference old palette and set new palette */
308         ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
309         ASSERT(ppal);
310         SURFACE_vSetPalette(psurf, ppal);
311         PALETTE_ShareUnlockPalette(ppal);
312 
313         /* Set flags */
314         psurf->flags = API_BITMAP;
315         psurf->hdc = NULL; // FIXME:
316         psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
317         SURFACE_ShareUnlockSurface(psurf);
318     }
319     else
320     {
321         DIBSECTION dibs;
322         INT Count;
323         PSURFACE psurf = Dc->dclevel.pSurface;
324         if(!psurf) psurf = psurfDefaultBitmap;
325         Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
326 
327         if (Count == sizeof(BITMAP))
328         {
329             PSURFACE psurfBmp;
330 
331             Bmp = GreCreateBitmap(abs(Width),
332                           abs(Height),
333                           Planes ? Planes : 1,
334                           Bpp ? Bpp : dibs.dsBm.bmBitsPixel,
335                           NULL);
336             if (Bmp == NULL)
337             {
338                 DPRINT1("Failed to allocate a bitmap!\n");
339                 return NULL;
340             }
341             psurfBmp = SURFACE_ShareLockSurface(Bmp);
342             ASSERT(psurfBmp);
343 
344             /* Dereference old palette and set new palette */
345             SURFACE_vSetPalette(psurfBmp, psurf->ppal);
346 
347             /* Set flags */
348             psurfBmp->flags = API_BITMAP;
349             psurfBmp->hdc = NULL; // FIXME:
350             psurfBmp->SurfObj.hdev = (HDEV)Dc->ppdev;
351             SURFACE_ShareUnlockSurface(psurfBmp);
352         }
353         else if (Count == sizeof(DIBSECTION))
354         {
355             /* A DIB section is selected in the DC */
356             BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
357             PVOID Bits;
358             BITMAPINFO* bi = (BITMAPINFO*)buf;
359 
360             bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
361             bi->bmiHeader.biWidth         = Width;
362             bi->bmiHeader.biHeight        = Height;
363             bi->bmiHeader.biPlanes        = Planes ? Planes : dibs.dsBmih.biPlanes;
364             bi->bmiHeader.biBitCount      = Bpp ? Bpp : dibs.dsBmih.biBitCount;
365             bi->bmiHeader.biCompression   = dibs.dsBmih.biCompression;
366             bi->bmiHeader.biSizeImage     = 0;
367             bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
368             bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
369             bi->bmiHeader.biClrUsed       = dibs.dsBmih.biClrUsed;
370             bi->bmiHeader.biClrImportant  = dibs.dsBmih.biClrImportant;
371 
372             if (bi->bmiHeader.biCompression == BI_BITFIELDS)
373             {
374                 /* Copy the color masks */
375                 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
376             }
377             else if (bi->bmiHeader.biBitCount <= 8)
378             {
379                 /* Copy the color table */
380                 UINT Index;
381                 PPALETTE PalGDI;
382 
383                 if (!psurf->ppal)
384                 {
385                     EngSetLastError(ERROR_INVALID_HANDLE);
386                     return 0;
387                 }
388 
389                 PalGDI = psurf->ppal;
390 
391                 for (Index = 0;
392                         Index < 256 && Index < PalGDI->NumColors;
393                         Index++)
394                 {
395                     bi->bmiColors[Index].rgbRed   = PalGDI->IndexedColors[Index].peRed;
396                     bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
397                     bi->bmiColors[Index].rgbBlue  = PalGDI->IndexedColors[Index].peBlue;
398                     bi->bmiColors[Index].rgbReserved = 0;
399                 }
400             }
401 
402             Bmp = DIB_CreateDIBSection(Dc,
403                                        bi,
404                                        DIB_RGB_COLORS,
405                                        &Bits,
406                                        NULL,
407                                        0,
408                                        0);
409             return Bmp;
410         }
411     }
412     return Bmp;
413 }
414 
415 HBITMAP APIENTRY
416 NtGdiCreateCompatibleBitmap(
417     HDC hDC,
418     INT Width,
419     INT Height)
420 {
421     HBITMAP Bmp;
422     PDC Dc;
423 
424     /* Check parameters */
425     if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF))
426     {
427         EngSetLastError(ERROR_INVALID_PARAMETER);
428         return NULL;
429     }
430 
431     if (!hDC)
432         return GreCreateBitmap(Width, Height, 1, 1, 0);
433 
434     Dc = DC_LockDc(hDC);
435 
436     DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
437            hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
438 
439     if (NULL == Dc)
440     {
441         EngSetLastError(ERROR_INVALID_HANDLE);
442         return NULL;
443     }
444 
445     Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
446 
447     DC_UnlockDc(Dc);
448     return Bmp;
449 }
450 
451 BOOL
452 NTAPI
453 GreGetBitmapDimension(
454     _In_ HBITMAP hBitmap,
455     _Out_ LPSIZE psizDim)
456 {
457     PSURFACE psurfBmp;
458 
459     if (hBitmap == NULL)
460         return FALSE;
461 
462     /* Lock the bitmap */
463     psurfBmp = SURFACE_ShareLockSurface(hBitmap);
464     if (psurfBmp == NULL)
465     {
466         EngSetLastError(ERROR_INVALID_HANDLE);
467         return FALSE;
468     }
469 
470     *psizDim = psurfBmp->sizlDim;
471 
472     /* Unlock the bitmap */
473     SURFACE_ShareUnlockSurface(psurfBmp);
474 
475     return TRUE;
476 }
477 
478 BOOL
479 APIENTRY
480 NtGdiGetBitmapDimension(
481     HBITMAP hBitmap,
482     LPSIZE psizDim)
483 {
484     SIZE dim;
485 
486     if (!GreGetBitmapDimension(hBitmap, &dim))
487         return FALSE;
488 
489     /* Use SEH to copy the data to the caller */
490     _SEH2_TRY
491     {
492         ProbeForWrite(psizDim, sizeof(*psizDim), 1);
493         *psizDim = dim;
494     }
495     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
496     {
497         _SEH2_YIELD(return FALSE);
498     }
499     _SEH2_END
500 
501     return TRUE;
502 }
503 
504 
505 LONG
506 FASTCALL
507 UnsafeGetBitmapBits(
508     PSURFACE psurf,
509     DWORD Bytes,
510     OUT PBYTE pvBits)
511 {
512     PUCHAR pjDst, pjSrc;
513     LONG lDeltaDst, lDeltaSrc, lDeltaSrcAbs;
514     ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
515 
516     nWidth = psurf->SurfObj.sizlBitmap.cx;
517     nHeight = psurf->SurfObj.sizlBitmap.cy;
518     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
519 
520     /* Get pointers */
521     pjSrc = psurf->SurfObj.pvScan0;
522     pjDst = pvBits;
523     lDeltaSrc = psurf->SurfObj.lDelta;
524     lDeltaSrcAbs = labs(lDeltaSrc);
525     lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
526     NT_ASSERT(lDeltaSrcAbs >= lDeltaDst);
527 
528     cbSrc = nHeight * lDeltaSrcAbs;
529     cbDst = nHeight * lDeltaDst;
530     Bytes = min(Bytes, cbDst);
531 
532     iSrc = iDst = 0;
533     for (Y = 0; Y < nHeight; Y++)
534     {
535         if (iSrc + lDeltaSrcAbs > cbSrc || iDst + lDeltaDst > Bytes)
536         {
537             LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
538             NT_ASSERT(lDelta >= 0);
539             RtlCopyMemory(pjDst, pjSrc, lDelta);
540             iDst += lDelta;
541             break;
542         }
543 
544         /* Copy one line */
545         RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
546         pjSrc += lDeltaSrc;
547         pjDst += lDeltaDst;
548         iSrc += lDeltaSrcAbs;
549         iDst += lDeltaDst;
550     }
551 
552     return iDst;
553 }
554 
555 LONG
556 APIENTRY
557 NtGdiGetBitmapBits(
558     HBITMAP hBitmap,
559     ULONG cjBuffer,
560     OUT OPTIONAL PBYTE pUnsafeBits)
561 {
562     PSURFACE psurf;
563     ULONG cjSize;
564     LONG ret;
565 
566     /* Check parameters */
567     if (pUnsafeBits != NULL && cjBuffer == 0)
568     {
569         return 0;
570     }
571 
572     /* Lock the bitmap */
573     psurf = SURFACE_ShareLockSurface(hBitmap);
574     if (!psurf)
575     {
576         EngSetLastError(ERROR_INVALID_HANDLE);
577         return 0;
578     }
579 
580     /* Calculate the size of the bitmap in bytes */
581     cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
582                 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
583                 psurf->SurfObj.sizlBitmap.cy;
584 
585     /* If the bits vector is null, the function should return the read size */
586     if (pUnsafeBits == NULL)
587     {
588         SURFACE_ShareUnlockSurface(psurf);
589         return cjSize;
590     }
591 
592     /* Don't copy more bytes than the buffer has */
593     cjBuffer = min(cjBuffer, cjSize);
594 
595     // FIXME: Use MmSecureVirtualMemory
596     _SEH2_TRY
597     {
598         ProbeForWrite(pUnsafeBits, cjBuffer, 1);
599         ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
600     }
601     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
602     {
603         ret = 0;
604     }
605     _SEH2_END
606 
607     SURFACE_ShareUnlockSurface(psurf);
608 
609     return ret;
610 }
611 
612 
613 LONG APIENTRY
614 NtGdiSetBitmapBits(
615     HBITMAP hBitmap,
616     DWORD Bytes,
617     IN PBYTE pUnsafeBits)
618 {
619     LONG ret;
620     PSURFACE psurf;
621 
622     if (pUnsafeBits == NULL || Bytes == 0)
623     {
624         return 0;
625     }
626 
627     if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
628     {
629         return 0;
630     }
631 
632     psurf = SURFACE_ShareLockSurface(hBitmap);
633     if (psurf == NULL)
634     {
635         EngSetLastError(ERROR_INVALID_HANDLE);
636         return 0;
637     }
638 
639     if (((psurf->flags & API_BITMAP) == 0) ||
640         (psurf->SurfObj.iBitmapFormat > BMF_32BPP))
641     {
642         DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
643                 psurf->SurfObj.iBitmapFormat,
644                 psurf->flags);
645         EngSetLastError(ERROR_INVALID_HANDLE);
646         SURFACE_ShareUnlockSurface(psurf);
647         return 0;
648     }
649 
650     _SEH2_TRY
651     {
652         /* NOTE: Win2k3 doesn't check WORD alignment here. */
653         ProbeForWrite(pUnsafeBits, Bytes, 1);
654         ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
655     }
656     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
657     {
658         ret = 0;
659     }
660     _SEH2_END
661 
662     SURFACE_ShareUnlockSurface(psurf);
663 
664     return ret;
665 }
666 
667 BOOL APIENTRY
668 NtGdiSetBitmapDimension(
669     HBITMAP hBitmap,
670     INT Width,
671     INT Height,
672     LPSIZE Size)
673 {
674     PSURFACE psurf;
675     BOOL Ret = TRUE;
676 
677     if (hBitmap == NULL)
678         return FALSE;
679 
680     psurf = SURFACE_ShareLockSurface(hBitmap);
681     if (psurf == NULL)
682     {
683         EngSetLastError(ERROR_INVALID_HANDLE);
684         return FALSE;
685     }
686 
687     if (Size)
688     {
689         _SEH2_TRY
690         {
691             ProbeForWrite(Size, sizeof(SIZE), 1);
692             *Size = psurf->sizlDim;
693         }
694         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
695         {
696             Ret = FALSE;
697         }
698         _SEH2_END
699     }
700 
701     /* The dimension is changed even if writing the old value failed */
702     psurf->sizlDim.cx = Width;
703     psurf->sizlDim.cy = Height;
704 
705     SURFACE_ShareUnlockSurface(psurf);
706 
707     return Ret;
708 }
709 
710 /*  Internal Functions  */
711 
712 HBITMAP
713 FASTCALL
714 BITMAP_CopyBitmap(HBITMAP hBitmap)
715 {
716     HBITMAP hbmNew;
717     SURFACE *psurfSrc, *psurfNew;
718 
719     /* Fail, if no source bitmap is given */
720     if (hBitmap == NULL) return 0;
721 
722     /* Lock the source bitmap */
723     psurfSrc = SURFACE_ShareLockSurface(hBitmap);
724     if (psurfSrc == NULL)
725     {
726         return 0;
727     }
728 
729     /* Allocate a new bitmap with the same dimensions as the source bmp */
730     hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
731                                psurfSrc->SurfObj.sizlBitmap.cy,
732                                abs(psurfSrc->SurfObj.lDelta),
733                                psurfSrc->SurfObj.iBitmapFormat,
734                                psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
735                                psurfSrc->SurfObj.cjBits,
736                                NULL,
737                                psurfSrc->flags);
738 
739     if (hbmNew)
740     {
741         /* Lock the new bitmap */
742         psurfNew = SURFACE_ShareLockSurface(hbmNew);
743         if (psurfNew)
744         {
745             /* Copy the bitmap bits to the new bitmap buffer */
746             RtlCopyMemory(psurfNew->SurfObj.pvBits,
747                           psurfSrc->SurfObj.pvBits,
748                           psurfNew->SurfObj.cjBits);
749 
750 
751             /* Reference the palette of the source bitmap and use it */
752             SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
753 
754             /* Unlock the new surface */
755             SURFACE_ShareUnlockSurface(psurfNew);
756         }
757         else
758         {
759             /* Failed to lock the bitmap, shouldn't happen */
760             GreDeleteObject(hbmNew);
761             hbmNew = NULL;
762         }
763     }
764 
765     /* Unlock the source bitmap and return the handle of the new bitmap */
766     SURFACE_ShareUnlockSurface(psurfSrc);
767     return hbmNew;
768 }
769 
770 INT APIENTRY
771 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
772 {
773     PBITMAP pBitmap;
774 
775     if (!buffer) return sizeof(BITMAP);
776     if ((UINT)Count < sizeof(BITMAP)) return 0;
777 
778     /* Always fill a basic BITMAP structure */
779     pBitmap = buffer;
780     pBitmap->bmType = 0;
781     pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
782     pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
783     pBitmap->bmPlanes = 1;
784     pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
785     pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
786 
787     /* Check for DIB section */
788     if (psurf->hSecure)
789     {
790         /* Set bmBits in this case */
791         pBitmap->bmBits = psurf->SurfObj.pvBits;
792         /* DIBs data are 32 bits aligned */
793         pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
794 
795         if (Count >= sizeof(DIBSECTION))
796         {
797             /* Fill rest of DIBSECTION */
798             PDIBSECTION pds = buffer;
799 
800             pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
801             pds->dsBmih.biWidth = pds->dsBm.bmWidth;
802             pds->dsBmih.biHeight = pds->dsBm.bmHeight;
803             pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
804             pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
805 
806             switch (psurf->SurfObj.iBitmapFormat)
807             {
808                 case BMF_1BPP:
809                 case BMF_4BPP:
810                 case BMF_8BPP:
811                    pds->dsBmih.biCompression = BI_RGB;
812                    break;
813 
814                 case BMF_16BPP:
815                     if (psurf->ppal->flFlags & PAL_RGB16_555)
816                         pds->dsBmih.biCompression = BI_RGB;
817                     else
818                         pds->dsBmih.biCompression = BI_BITFIELDS;
819                     break;
820 
821                 case BMF_24BPP:
822                 case BMF_32BPP:
823                     /* 24/32bpp BI_RGB is actually BGR format */
824                     if (psurf->ppal->flFlags & PAL_BGR)
825                         pds->dsBmih.biCompression = BI_RGB;
826                     else
827                         pds->dsBmih.biCompression = BI_BITFIELDS;
828                     break;
829 
830                 case BMF_4RLE:
831                    pds->dsBmih.biCompression = BI_RLE4;
832                    break;
833                 case BMF_8RLE:
834                    pds->dsBmih.biCompression = BI_RLE8;
835                    break;
836                 case BMF_JPEG:
837                    pds->dsBmih.biCompression = BI_JPEG;
838                    break;
839                 case BMF_PNG:
840                    pds->dsBmih.biCompression = BI_PNG;
841                    break;
842                 default:
843                     ASSERT(FALSE); /* This shouldn't happen */
844             }
845 
846             pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
847             pds->dsBmih.biXPelsPerMeter = 0;
848             pds->dsBmih.biYPelsPerMeter = 0;
849             pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
850             pds->dsBmih.biClrImportant = psurf->biClrImportant;
851             pds->dsBitfields[0] = psurf->ppal->RedMask;
852             pds->dsBitfields[1] = psurf->ppal->GreenMask;
853             pds->dsBitfields[2] = psurf->ppal->BlueMask;
854             pds->dshSection = psurf->hDIBSection;
855             pds->dsOffset = psurf->dwOffset;
856 
857             return sizeof(DIBSECTION);
858         }
859     }
860     else
861     {
862         /* Not set according to wine test, confirmed in win2k */
863         pBitmap->bmBits = NULL;
864     }
865 
866     return sizeof(BITMAP);
867 }
868 
869 /*
870  * @implemented
871  */
872 HDC
873 APIENTRY
874 NtGdiGetDCforBitmap(
875     IN HBITMAP hsurf)
876 {
877     HDC hdc = NULL;
878     PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
879     if (psurf)
880     {
881         hdc = psurf->hdc;
882         SURFACE_ShareUnlockSurface(psurf);
883     }
884     return hdc;
885 }
886 
887 
888 /* EOF */
889