xref: /reactos/win32ss/gdi/ntgdi/bitmaps.c (revision 8a978a17)
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 != DC_TYPE_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             psurfBmp = SURFACE_ShareLockSurface(Bmp);
337             ASSERT(psurfBmp);
338 
339             /* Dereference old palette and set new palette */
340             SURFACE_vSetPalette(psurfBmp, psurf->ppal);
341 
342             /* Set flags */
343             psurfBmp->flags = API_BITMAP;
344             psurfBmp->hdc = NULL; // FIXME:
345             psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
346             SURFACE_ShareUnlockSurface(psurfBmp);
347         }
348         else if (Count == sizeof(DIBSECTION))
349         {
350             /* A DIB section is selected in the DC */
351             BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
352             PVOID Bits;
353             BITMAPINFO* bi = (BITMAPINFO*)buf;
354 
355             bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);
356             bi->bmiHeader.biWidth         = Width;
357             bi->bmiHeader.biHeight        = Height;
358             bi->bmiHeader.biPlanes        = Planes ? Planes : dibs.dsBmih.biPlanes;
359             bi->bmiHeader.biBitCount      = Bpp ? Bpp : dibs.dsBmih.biBitCount;
360             bi->bmiHeader.biCompression   = dibs.dsBmih.biCompression;
361             bi->bmiHeader.biSizeImage     = 0;
362             bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
363             bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
364             bi->bmiHeader.biClrUsed       = dibs.dsBmih.biClrUsed;
365             bi->bmiHeader.biClrImportant  = dibs.dsBmih.biClrImportant;
366 
367             if (bi->bmiHeader.biCompression == BI_BITFIELDS)
368             {
369                 /* Copy the color masks */
370                 RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
371             }
372             else if (bi->bmiHeader.biBitCount <= 8)
373             {
374                 /* Copy the color table */
375                 UINT Index;
376                 PPALETTE PalGDI;
377 
378                 if (!psurf->ppal)
379                 {
380                     EngSetLastError(ERROR_INVALID_HANDLE);
381                     return 0;
382                 }
383 
384                 PalGDI = psurf->ppal;
385 
386                 for (Index = 0;
387                         Index < 256 && Index < PalGDI->NumColors;
388                         Index++)
389                 {
390                     bi->bmiColors[Index].rgbRed   = PalGDI->IndexedColors[Index].peRed;
391                     bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
392                     bi->bmiColors[Index].rgbBlue  = PalGDI->IndexedColors[Index].peBlue;
393                     bi->bmiColors[Index].rgbReserved = 0;
394                 }
395             }
396 
397             Bmp = DIB_CreateDIBSection(Dc,
398                                        bi,
399                                        DIB_RGB_COLORS,
400                                        &Bits,
401                                        NULL,
402                                        0,
403                                        0);
404             return Bmp;
405         }
406     }
407     return Bmp;
408 }
409 
410 HBITMAP APIENTRY
411 NtGdiCreateCompatibleBitmap(
412     HDC hDC,
413     INT Width,
414     INT Height)
415 {
416     HBITMAP Bmp;
417     PDC Dc;
418 
419     /* Check parameters */
420     if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF))
421     {
422         EngSetLastError(ERROR_INVALID_PARAMETER);
423         return NULL;
424     }
425 
426     if (!hDC)
427         return GreCreateBitmap(Width, Height, 1, 1, 0);
428 
429     Dc = DC_LockDc(hDC);
430 
431     DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
432            hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
433 
434     if (NULL == Dc)
435     {
436         EngSetLastError(ERROR_INVALID_HANDLE);
437         return NULL;
438     }
439 
440     Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
441 
442     DC_UnlockDc(Dc);
443     return Bmp;
444 }
445 
446 BOOL
447 NTAPI
448 GreGetBitmapDimension(
449     _In_ HBITMAP hBitmap,
450     _Out_ LPSIZE psizDim)
451 {
452     PSURFACE psurfBmp;
453 
454     if (hBitmap == NULL)
455         return FALSE;
456 
457     /* Lock the bitmap */
458     psurfBmp = SURFACE_ShareLockSurface(hBitmap);
459     if (psurfBmp == NULL)
460     {
461         EngSetLastError(ERROR_INVALID_HANDLE);
462         return FALSE;
463     }
464 
465     *psizDim = psurfBmp->sizlDim;
466 
467     /* Unlock the bitmap */
468     SURFACE_ShareUnlockSurface(psurfBmp);
469 
470     return TRUE;
471 }
472 
473 BOOL
474 APIENTRY
475 NtGdiGetBitmapDimension(
476     HBITMAP hBitmap,
477     LPSIZE psizDim)
478 {
479     SIZE dim;
480 
481     if (!GreGetBitmapDimension(hBitmap, &dim))
482         return FALSE;
483 
484     /* Use SEH to copy the data to the caller */
485     _SEH2_TRY
486     {
487         ProbeForWrite(psizDim, sizeof(*psizDim), 1);
488         *psizDim = dim;
489     }
490     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
491     {
492         _SEH2_YIELD(return FALSE);
493     }
494     _SEH2_END
495 
496     return TRUE;
497 }
498 
499 
500 LONG
501 FASTCALL
502 UnsafeGetBitmapBits(
503     PSURFACE psurf,
504     DWORD Bytes,
505     OUT PBYTE pvBits)
506 {
507     PUCHAR pjDst, pjSrc;
508     LONG lDeltaDst, lDeltaSrc, lDeltaSrcAbs;
509     ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
510 
511     nWidth = psurf->SurfObj.sizlBitmap.cx;
512     nHeight = psurf->SurfObj.sizlBitmap.cy;
513     cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
514 
515     /* Get pointers */
516     pjSrc = psurf->SurfObj.pvScan0;
517     pjDst = pvBits;
518     lDeltaSrc = psurf->SurfObj.lDelta;
519     lDeltaSrcAbs = labs(lDeltaSrc);
520     lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
521     NT_ASSERT(lDeltaSrcAbs >= lDeltaDst);
522 
523     cbSrc = nHeight * lDeltaSrcAbs;
524     cbDst = nHeight * lDeltaDst;
525     Bytes = min(Bytes, cbDst);
526 
527     iSrc = iDst = 0;
528     for (Y = 0; Y < nHeight; Y++)
529     {
530         if (iSrc + lDeltaSrcAbs > cbSrc || iDst + lDeltaDst > Bytes)
531         {
532             LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
533             NT_ASSERT(lDelta >= 0);
534             RtlCopyMemory(pjDst, pjSrc, lDelta);
535             iDst += lDelta;
536             break;
537         }
538 
539         /* Copy one line */
540         RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
541         pjSrc += lDeltaSrc;
542         pjDst += lDeltaDst;
543         iSrc += lDeltaSrcAbs;
544         iDst += lDeltaDst;
545     }
546 
547     return iDst;
548 }
549 
550 LONG
551 APIENTRY
552 NtGdiGetBitmapBits(
553     HBITMAP hBitmap,
554     ULONG cjBuffer,
555     OUT OPTIONAL PBYTE pUnsafeBits)
556 {
557     PSURFACE psurf;
558     ULONG cjSize;
559     LONG ret;
560 
561     /* Check parameters */
562     if (pUnsafeBits != NULL && cjBuffer == 0)
563     {
564         return 0;
565     }
566 
567     /* Lock the bitmap */
568     psurf = SURFACE_ShareLockSurface(hBitmap);
569     if (!psurf)
570     {
571         EngSetLastError(ERROR_INVALID_HANDLE);
572         return 0;
573     }
574 
575     /* Calculate the size of the bitmap in bytes */
576     cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
577                 BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
578                 psurf->SurfObj.sizlBitmap.cy;
579 
580     /* If the bits vector is null, the function should return the read size */
581     if (pUnsafeBits == NULL)
582     {
583         SURFACE_ShareUnlockSurface(psurf);
584         return cjSize;
585     }
586 
587     /* Don't copy more bytes than the buffer has */
588     cjBuffer = min(cjBuffer, cjSize);
589 
590     // FIXME: Use MmSecureVirtualMemory
591     _SEH2_TRY
592     {
593         ProbeForWrite(pUnsafeBits, cjBuffer, 1);
594         ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
595     }
596     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
597     {
598         ret = 0;
599     }
600     _SEH2_END
601 
602     SURFACE_ShareUnlockSurface(psurf);
603 
604     return ret;
605 }
606 
607 
608 LONG APIENTRY
609 NtGdiSetBitmapBits(
610     HBITMAP hBitmap,
611     DWORD Bytes,
612     IN PBYTE pUnsafeBits)
613 {
614     LONG ret;
615     PSURFACE psurf;
616 
617     if (pUnsafeBits == NULL || Bytes == 0)
618     {
619         return 0;
620     }
621 
622     if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
623     {
624         return 0;
625     }
626 
627     psurf = SURFACE_ShareLockSurface(hBitmap);
628     if (psurf == NULL)
629     {
630         EngSetLastError(ERROR_INVALID_HANDLE);
631         return 0;
632     }
633 
634     if (((psurf->flags & API_BITMAP) == 0) ||
635         (psurf->SurfObj.iBitmapFormat > BMF_32BPP))
636     {
637         DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
638                 psurf->SurfObj.iBitmapFormat,
639                 psurf->flags);
640         EngSetLastError(ERROR_INVALID_HANDLE);
641         SURFACE_ShareUnlockSurface(psurf);
642         return 0;
643     }
644 
645     _SEH2_TRY
646     {
647         /* NOTE: Win2k3 doesn't check WORD alignment here. */
648         ProbeForWrite(pUnsafeBits, Bytes, 1);
649         ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
650     }
651     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
652     {
653         ret = 0;
654     }
655     _SEH2_END
656 
657     SURFACE_ShareUnlockSurface(psurf);
658 
659     return ret;
660 }
661 
662 BOOL APIENTRY
663 NtGdiSetBitmapDimension(
664     HBITMAP hBitmap,
665     INT Width,
666     INT Height,
667     LPSIZE Size)
668 {
669     PSURFACE psurf;
670     BOOL Ret = TRUE;
671 
672     if (hBitmap == NULL)
673         return FALSE;
674 
675     psurf = SURFACE_ShareLockSurface(hBitmap);
676     if (psurf == NULL)
677     {
678         EngSetLastError(ERROR_INVALID_HANDLE);
679         return FALSE;
680     }
681 
682     if (Size)
683     {
684         _SEH2_TRY
685         {
686             ProbeForWrite(Size, sizeof(SIZE), 1);
687             *Size = psurf->sizlDim;
688         }
689         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
690         {
691             Ret = FALSE;
692         }
693         _SEH2_END
694     }
695 
696     /* The dimension is changed even if writing the old value failed */
697     psurf->sizlDim.cx = Width;
698     psurf->sizlDim.cy = Height;
699 
700     SURFACE_ShareUnlockSurface(psurf);
701 
702     return Ret;
703 }
704 
705 /*  Internal Functions  */
706 
707 HBITMAP
708 FASTCALL
709 BITMAP_CopyBitmap(HBITMAP hBitmap)
710 {
711     HBITMAP hbmNew;
712     SURFACE *psurfSrc, *psurfNew;
713 
714     /* Fail, if no source bitmap is given */
715     if (hBitmap == NULL) return 0;
716 
717     /* Lock the source bitmap */
718     psurfSrc = SURFACE_ShareLockSurface(hBitmap);
719     if (psurfSrc == NULL)
720     {
721         return 0;
722     }
723 
724     /* Allocate a new bitmap with the same dimensions as the source bmp */
725     hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
726                                psurfSrc->SurfObj.sizlBitmap.cy,
727                                abs(psurfSrc->SurfObj.lDelta),
728                                psurfSrc->SurfObj.iBitmapFormat,
729                                psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
730                                psurfSrc->SurfObj.cjBits,
731                                NULL,
732                                psurfSrc->flags);
733 
734     if (hbmNew)
735     {
736         /* Lock the new bitmap */
737         psurfNew = SURFACE_ShareLockSurface(hbmNew);
738         if (psurfNew)
739         {
740             /* Copy the bitmap bits to the new bitmap buffer */
741             RtlCopyMemory(psurfNew->SurfObj.pvBits,
742                           psurfSrc->SurfObj.pvBits,
743                           psurfNew->SurfObj.cjBits);
744 
745 
746             /* Reference the palette of the source bitmap and use it */
747             SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
748 
749             /* Unlock the new surface */
750             SURFACE_ShareUnlockSurface(psurfNew);
751         }
752         else
753         {
754             /* Failed to lock the bitmap, shouldn't happen */
755             GreDeleteObject(hbmNew);
756             hbmNew = NULL;
757         }
758     }
759 
760     /* Unlock the source bitmap and return the handle of the new bitmap */
761     SURFACE_ShareUnlockSurface(psurfSrc);
762     return hbmNew;
763 }
764 
765 INT APIENTRY
766 BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
767 {
768     PBITMAP pBitmap;
769 
770     if (!buffer) return sizeof(BITMAP);
771     if ((UINT)Count < sizeof(BITMAP)) return 0;
772 
773     /* Always fill a basic BITMAP structure */
774     pBitmap = buffer;
775     pBitmap->bmType = 0;
776     pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
777     pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
778     pBitmap->bmPlanes = 1;
779     pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
780     pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
781 
782     /* Check for DIB section */
783     if (psurf->hSecure)
784     {
785         /* Set bmBits in this case */
786         pBitmap->bmBits = psurf->SurfObj.pvBits;
787         /* DIBs data are 32 bits aligned */
788         pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
789 
790         if (Count >= sizeof(DIBSECTION))
791         {
792             /* Fill rest of DIBSECTION */
793             PDIBSECTION pds = buffer;
794 
795             pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
796             pds->dsBmih.biWidth = pds->dsBm.bmWidth;
797             pds->dsBmih.biHeight = pds->dsBm.bmHeight;
798             pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
799             pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
800 
801             switch (psurf->SurfObj.iBitmapFormat)
802             {
803                 case BMF_1BPP:
804                 case BMF_4BPP:
805                 case BMF_8BPP:
806                    pds->dsBmih.biCompression = BI_RGB;
807                    break;
808 
809                 case BMF_16BPP:
810                     if (psurf->ppal->flFlags & PAL_RGB16_555)
811                         pds->dsBmih.biCompression = BI_RGB;
812                     else
813                         pds->dsBmih.biCompression = BI_BITFIELDS;
814                     break;
815 
816                 case BMF_24BPP:
817                 case BMF_32BPP:
818                     /* 24/32bpp BI_RGB is actually BGR format */
819                     if (psurf->ppal->flFlags & PAL_BGR)
820                         pds->dsBmih.biCompression = BI_RGB;
821                     else
822                         pds->dsBmih.biCompression = BI_BITFIELDS;
823                     break;
824 
825                 case BMF_4RLE:
826                    pds->dsBmih.biCompression = BI_RLE4;
827                    break;
828                 case BMF_8RLE:
829                    pds->dsBmih.biCompression = BI_RLE8;
830                    break;
831                 case BMF_JPEG:
832                    pds->dsBmih.biCompression = BI_JPEG;
833                    break;
834                 case BMF_PNG:
835                    pds->dsBmih.biCompression = BI_PNG;
836                    break;
837                 default:
838                     ASSERT(FALSE); /* This shouldn't happen */
839             }
840 
841             pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
842             pds->dsBmih.biXPelsPerMeter = 0;
843             pds->dsBmih.biYPelsPerMeter = 0;
844             pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
845             pds->dsBmih.biClrImportant = psurf->biClrImportant;
846             pds->dsBitfields[0] = psurf->ppal->RedMask;
847             pds->dsBitfields[1] = psurf->ppal->GreenMask;
848             pds->dsBitfields[2] = psurf->ppal->BlueMask;
849             pds->dshSection = psurf->hDIBSection;
850             pds->dsOffset = psurf->dwOffset;
851 
852             return sizeof(DIBSECTION);
853         }
854     }
855     else
856     {
857         /* Not set according to wine test, confirmed in win2k */
858         pBitmap->bmBits = NULL;
859     }
860 
861     return sizeof(BITMAP);
862 }
863 
864 /*
865  * @implemented
866  */
867 HDC
868 APIENTRY
869 NtGdiGetDCforBitmap(
870     IN HBITMAP hsurf)
871 {
872     HDC hdc = NULL;
873     PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
874     if (psurf)
875     {
876         hdc = psurf->hdc;
877         SURFACE_ShareUnlockSurface(psurf);
878     }
879     return hdc;
880 }
881 
882 
883 /* EOF */
884