2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define IN_RECT(r,x,y) \
40 IN OPTIONAL LPBYTE pBits
)
47 /* NOTE: Windows also doesn't store nr. of planes separately! */
48 BitsPixel
= BITMAP_GetRealBitsPixel(BitsPixel
* Planes
);
50 /* Check parameters */
51 if (BitsPixel
== 0 || Width
<= 0 || Width
>= 0x8000000 || Height
== 0)
53 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
54 Width
, Height
, BitsPixel
);
55 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
59 WidthBytes
= BITMAP_GetWidthBytes(Width
, BitsPixel
);
62 Size
.cy
= abs(Height
);
64 /* Make sure that cjBits will not overflow */
65 if ((ULONGLONG
)WidthBytes
* Size
.cy
>= 0x100000000ULL
)
67 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n",
68 Width
, Height
, BitsPixel
);
69 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
73 /* Create the bitmap object. */
74 hBitmap
= IntCreateBitmap(Size
, WidthBytes
,
75 BitmapFormat(BitsPixel
, BI_RGB
),
76 (Height
< 0 ? BMF_TOPDOWN
: 0) |
77 (NULL
== pBits
? 0 : BMF_NOZEROINIT
), NULL
);
80 DPRINT("IntGdiCreateBitmap: returned 0\n");
84 psurfBmp
= SURFACE_LockSurface(hBitmap
);
87 NtGdiDeleteObject(hBitmap
);
91 psurfBmp
->flFlags
= BITMAPOBJ_IS_APIBITMAP
;
92 psurfBmp
->hDC
= NULL
; // Fixme
96 IntSetBitmapBits(psurfBmp
, psurfBmp
->SurfObj
.cjBits
, pBits
);
99 SURFACE_UnlockSurface(psurfBmp
);
101 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
102 Size
.cx
, Size
.cy
, BitsPixel
, (Height
< 0 ? 1 : 0), hBitmap
);
114 IN OPTIONAL LPBYTE pUnsafeBits
)
119 UINT cjBits
= BITMAP_GetWidthBytes(Width
, BitsPixel
) * abs(Height
);
121 // FIXME: Use MmSecureVirtualMemory
124 ProbeForRead(pUnsafeBits
, cjBits
, 1);
126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
135 return IntGdiCreateBitmap(Width
, Height
, Planes
, BitsPixel
, pUnsafeBits
);
139 IntCreateCompatibleBitmap(
146 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
147 if (0 == Width
|| 0 == Height
)
149 Bmp
= NtGdiGetStockObject(DEFAULT_BITMAP
);
153 if (Dc
->DC_Type
!= DC_TYPE_MEMORY
)
155 Bmp
= IntGdiCreateBitmap(abs(Width
),
157 IntGdiGetDeviceCaps(Dc
,PLANES
),
158 IntGdiGetDeviceCaps(Dc
,BITSPIXEL
),
165 PSURFACE psurf
= SURFACE_LockSurface(Dc
->w
.hBitmap
);
166 Count
= BITMAP_GetObject(psurf
, sizeof(dibs
), &dibs
);
170 if (Count
== sizeof(BITMAP
))
172 /* We have a bitmap bug!!! W/O the HACK, we have white icons.
174 MSDN Note: When a memory device context is created, it initially
175 has a 1-by-1 monochrome bitmap selected into it. If this memory
176 device context is used in CreateCompatibleBitmap, the bitmap that
177 is created is a monochrome bitmap. To create a color bitmap, use
178 the hDC that was used to create the memory device context, as
179 shown in the following code:
181 HDC memDC = CreateCompatibleDC(hDC);
182 HBITMAP memBM = CreateCompatibleBitmap(hDC, nWidth, nHeight);
183 SelectObject(memDC, memBM);
185 Bmp
= IntGdiCreateBitmap(abs(Width
),
188 IntGdiGetDeviceCaps(Dc
,BITSPIXEL
),//<-- HACK! dibs.dsBm.bmBitsPixel, // <-- Correct!
193 /* A DIB section is selected in the DC */
197 /* Allocate memory for a BITMAPINFOHEADER structure and a
198 color table. The maximum number of colors in a color table
199 is 256 which corresponds to a bitmap with depth 8.
200 Bitmaps with higher depths don't have color tables. */
201 bi
= ExAllocatePoolWithTag(PagedPool
,
202 sizeof(BITMAPINFOHEADER
) +
203 256 * sizeof(RGBQUAD
),
208 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
209 bi
->bmiHeader
.biWidth
= Width
;
210 bi
->bmiHeader
.biHeight
= Height
;
211 bi
->bmiHeader
.biPlanes
= dibs
.dsBmih
.biPlanes
;
212 bi
->bmiHeader
.biBitCount
= dibs
.dsBmih
.biBitCount
;
213 bi
->bmiHeader
.biCompression
= dibs
.dsBmih
.biCompression
;
214 bi
->bmiHeader
.biSizeImage
= 0;
215 bi
->bmiHeader
.biXPelsPerMeter
= dibs
.dsBmih
.biXPelsPerMeter
;
216 bi
->bmiHeader
.biYPelsPerMeter
= dibs
.dsBmih
.biYPelsPerMeter
;
217 bi
->bmiHeader
.biClrUsed
= dibs
.dsBmih
.biClrUsed
;
218 bi
->bmiHeader
.biClrImportant
= dibs
.dsBmih
.biClrImportant
;
220 if (bi
->bmiHeader
.biCompression
== BI_BITFIELDS
)
222 /* Copy the color masks */
223 RtlCopyMemory(bi
->bmiColors
, dibs
.dsBitfields
, 3 * sizeof(DWORD
));
225 else if (bi
->bmiHeader
.biBitCount
<= 8)
227 /* Copy the color table */
229 PPALGDI PalGDI
= PALETTE_LockPalette(psurf
->hDIBPalette
);
233 ExFreePoolWithTag(bi
, TAG_TEMP
);
234 SURFACE_UnlockSurface(psurf
);
235 SetLastWin32Error(ERROR_INVALID_HANDLE
);
240 Index
< 256 && Index
< PalGDI
->NumColors
;
243 bi
->bmiColors
[Index
].rgbRed
= PalGDI
->IndexedColors
[Index
].peRed
;
244 bi
->bmiColors
[Index
].rgbGreen
= PalGDI
->IndexedColors
[Index
].peGreen
;
245 bi
->bmiColors
[Index
].rgbBlue
= PalGDI
->IndexedColors
[Index
].peBlue
;
246 bi
->bmiColors
[Index
].rgbReserved
= 0;
248 PALETTE_UnlockPalette(PalGDI
);
250 SURFACE_UnlockSurface(psurf
);
252 Bmp
= DIB_CreateDIBSection(Dc
,
260 ExFreePoolWithTag(bi
, TAG_TEMP
);
265 SURFACE_UnlockSurface(psurf
);
272 NtGdiCreateCompatibleBitmap(
280 if (Width
<= 0 || Height
<= 0 || (Width
* Height
) > 0x3FFFFFFF)
282 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
287 return IntGdiCreateBitmap(Width
, Height
, 1, 1, 0);
291 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n",
292 hDC
, Width
, Height
, ((PGDIDEVICE
)Dc
->pPDev
)->GDIInfo
.cBitsPixel
);
296 SetLastWin32Error(ERROR_INVALID_HANDLE
);
300 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
);
302 DPRINT("\t\t%04x\n", Bmp
);
308 NtGdiGetBitmapDimension(
318 psurfBmp
= SURFACE_LockSurface(hBitmap
);
319 if (psurfBmp
== NULL
)
321 SetLastWin32Error(ERROR_INVALID_HANDLE
);
327 ProbeForWrite(Dimension
, sizeof(SIZE
), 1);
328 *Dimension
= psurfBmp
->dimension
;
330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
336 SURFACE_UnlockSurface(psurfBmp
);
342 NtGdiGetPixel(HDC hDC
, INT XPos
, INT YPos
)
345 COLORREF Result
= (COLORREF
)CLR_INVALID
; // default to failure
346 BOOL bInRect
= FALSE
;
357 SetLastWin32Error(ERROR_INVALID_HANDLE
);
361 if (dc
->DC_Type
== DC_TYPE_INFO
)
367 XPos
+= dc
->ptlDCOrig
.x
;
368 YPos
+= dc
->ptlDCOrig
.y
;
369 if (IN_RECT(dc
->CombinedClip
->rclBounds
,XPos
,YPos
))
372 psurf
= SURFACE_LockSurface(dc
->w
.hBitmap
);
373 pso
= &psurf
->SurfObj
;
376 Pal
= psurf
->hDIBPalette
;
377 if (!Pal
) Pal
= pPrimarySurface
->DevInfo
.hpalDefault
;
379 /* FIXME: Verify if it shouldn't be PAL_BGR! */
380 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(PAL_RGB
, 0, NULL
, Pal
);
383 // check if this DC has a DIB behind it...
384 if (pso
->pvScan0
) // STYPE_BITMAP == pso->iType
387 Result
= XLATEOBJ_iXlate(XlateObj
,
388 DibFunctionsForBitmapFormat
[pso
->iBitmapFormat
].DIB_GetPixel(pso
, XPos
, YPos
));
390 EngDeleteXlate(XlateObj
);
392 SURFACE_UnlockSurface(psurf
);
397 // if Result is still CLR_INVALID, then the "quick" method above didn't work
398 if (bInRect
&& Result
== CLR_INVALID
)
400 // FIXME: create a 1x1 32BPP DIB, and blit to it
401 HDC hDCTmp
= NtGdiCreateCompatibleDC(hDC
);
404 static const BITMAPINFOHEADER bih
= { sizeof(BITMAPINFOHEADER
), 1, 1, 1, 32, BI_RGB
, 0, 0, 0, 0, 0 };
406 RtlMoveMemory(&(bi
.bmiHeader
), &bih
, sizeof(bih
));
407 hBmpTmp
= NtGdiCreateDIBitmapInternal(hDC
,
408 bi
.bmiHeader
.biWidth
,
409 bi
.bmiHeader
.biHeight
,
414 bi
.bmiHeader
.biBitCount
,
415 bi
.bmiHeader
.biSizeImage
,
419 //HBITMAP hBmpTmp = IntGdiCreateBitmap(1, 1, 1, 32, NULL);
422 HBITMAP hBmpOld
= (HBITMAP
)NtGdiSelectBitmap(hDCTmp
, hBmpTmp
);
427 NtGdiBitBlt(hDCTmp
, 0, 0, 1, 1, hDC
, XPos
, YPos
, SRCCOPY
, 0, 0);
428 NtGdiSelectBitmap(hDCTmp
, hBmpOld
);
430 // our bitmap is no longer selected, so we can access it's stuff...
431 psurf
= SURFACE_LockSurface(hBmpTmp
);
434 // Dont you need to convert something here?
435 Result
= *(COLORREF
*)psurf
->SurfObj
.pvScan0
;
436 SURFACE_UnlockSurface(psurf
);
439 NtGdiDeleteObject(hBmpTmp
);
441 NtGdiDeleteObjectApp(hDCTmp
);
459 /* Don't copy more bytes than the buffer has */
460 Bytes
= min(Bytes
, psurf
->SurfObj
.cjBits
);
463 /* FIXME: Call DDI CopyBits here if available */
466 DPRINT("Calling device specific BitmapBits\n");
467 if (psurf
->DDBitmap
->funcs
->pBitmapBits
)
469 ret
= psurf
->DDBitmap
->funcs
->pBitmapBits(hbitmap
,
476 ERR_(bitmap
)("BitmapBits == NULL??\n");
483 RtlCopyMemory(Bits
, psurf
->SurfObj
.pvBits
, Bytes
);
493 OUT OPTIONAL PBYTE pUnsafeBits
)
498 if (pUnsafeBits
!= NULL
&& Bytes
== 0)
503 psurf
= SURFACE_LockSurface(hBitmap
);
506 SetLastWin32Error(ERROR_INVALID_HANDLE
);
510 /* If the bits vector is null, the function should return the read size */
511 if (pUnsafeBits
== NULL
)
513 ret
= psurf
->SurfObj
.cjBits
;
514 SURFACE_UnlockSurface(psurf
);
518 /* Don't copy more bytes than the buffer has */
519 Bytes
= min(Bytes
, psurf
->SurfObj
.cjBits
);
521 // FIXME: use MmSecureVirtualMemory
524 ProbeForWrite(pUnsafeBits
, Bytes
, 1);
525 ret
= IntGetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
533 SURFACE_UnlockSurface(psurf
);
547 /* Don't copy more bytes than the buffer has */
548 Bytes
= min(Bytes
, psurf
->SurfObj
.cjBits
);
551 /* FIXME: call DDI specific function here if available */
554 DPRINT("Calling device specific BitmapBits\n");
555 if (psurf
->DDBitmap
->funcs
->pBitmapBits
)
557 ret
= psurf
->DDBitmap
->funcs
->pBitmapBits(hBitmap
,
564 DPRINT("BitmapBits == NULL??\n");
571 RtlCopyMemory(psurf
->SurfObj
.pvBits
, Bits
, Bytes
);
583 IN PBYTE pUnsafeBits
)
588 if (pUnsafeBits
== NULL
|| Bytes
== 0)
593 psurf
= SURFACE_LockSurface(hBitmap
);
596 SetLastWin32Error(ERROR_INVALID_HANDLE
);
602 ProbeForRead(pUnsafeBits
, Bytes
, 1);
603 ret
= IntSetBitmapBits(psurf
, Bytes
, pUnsafeBits
);
605 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
611 SURFACE_UnlockSurface(psurf
);
617 NtGdiSetBitmapDimension(
629 psurf
= SURFACE_LockSurface(hBitmap
);
632 SetLastWin32Error(ERROR_INVALID_HANDLE
);
640 ProbeForWrite(Size
, sizeof(SIZE
), 1);
641 *Size
= psurf
->dimension
;
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
650 /* The dimension is changed even if writing the old value failed */
651 psurf
->dimension
.cx
= Width
;
652 psurf
->dimension
.cy
= Height
;
654 SURFACE_UnlockSurface(psurf
);
666 HBRUSH NewBrush
= NtGdiCreateSolidBrush(Color
, NULL
);
669 if (NewBrush
== NULL
)
672 OldBrush
= NtGdiSelectBrush(hDC
, NewBrush
);
673 if (OldBrush
== NULL
)
675 NtGdiDeleteObject(NewBrush
);
679 NtGdiPatBlt(hDC
, X
, Y
, 1, 1, PATCOPY
);
680 NtGdiSelectBrush(hDC
, OldBrush
);
681 NtGdiDeleteObject(NewBrush
);
693 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n", X
, Y
, Color
);
695 if (GdiSetPixelV(hDC
,X
,Y
,Color
))
697 Color
= NtGdiGetPixel(hDC
,X
,Y
);
698 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n", X
, Y
, Color
);
702 Color
= (COLORREF
)CLR_INVALID
;
703 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n", X
, Y
, Color
);
708 /* Internal Functions */
711 BITMAP_GetRealBitsPixel(UINT nBitsPixel
)
719 if (nBitsPixel
<= 16)
721 if (nBitsPixel
<= 24)
723 if (nBitsPixel
<= 32)
730 BITMAP_GetWidthBytes(INT bmWidth
, INT bpp
)
736 return 2 * ((bmWidth
+15) >> 4);
739 bmWidth
*= 3; /* fall through */
741 return bmWidth
+ (bmWidth
& 1);
751 return 2 * ((bmWidth
+3) >> 2);
760 return ((bmWidth
* bpp
+ 15) & ~15) >> 3;
764 BITMAP_CopyBitmap(HBITMAP hBitmap
)
768 SURFACE
*Bitmap
, *resBitmap
;
776 Bitmap
= GDIOBJ_LockObj(hBitmap
, GDI_OBJECT_TYPE_BITMAP
);
782 BITMAP_GetObject(Bitmap
, sizeof(BITMAP
), (PVOID
)&bm
);
784 if (Bitmap
->SurfObj
.lDelta
>= 0)
785 bm
.bmHeight
= -bm
.bmHeight
;
787 Size
.cx
= abs(bm
.bmWidth
);
788 Size
.cy
= abs(bm
.bmHeight
);
789 res
= IntCreateBitmap(Size
,
791 BitmapFormat(bm
.bmBitsPixel
* bm
.bmPlanes
, BI_RGB
),
792 (bm
.bmHeight
< 0 ? BMF_TOPDOWN
: 0) | BMF_NOZEROINIT
,
799 resBitmap
= GDIOBJ_LockObj(res
, GDI_OBJECT_TYPE_BITMAP
);
802 buf
= ExAllocatePoolWithTag(PagedPool
,
803 bm
.bmWidthBytes
* abs(bm
.bmHeight
),
807 GDIOBJ_UnlockObjByPtr((POBJ
)resBitmap
);
808 GDIOBJ_UnlockObjByPtr((POBJ
)Bitmap
);
809 NtGdiDeleteObject(res
);
812 IntGetBitmapBits(Bitmap
, bm
.bmWidthBytes
* abs(bm
.bmHeight
), buf
);
813 IntSetBitmapBits(resBitmap
, bm
.bmWidthBytes
* abs(bm
.bmHeight
), buf
);
814 ExFreePoolWithTag(buf
,TAG_BITMAP
);
815 resBitmap
->flFlags
= Bitmap
->flFlags
;
816 GDIOBJ_UnlockObjByPtr((POBJ
)resBitmap
);
820 NtGdiDeleteObject(res
);
825 GDIOBJ_UnlockObjByPtr((POBJ
)Bitmap
);
831 BITMAP_GetObject(SURFACE
*psurf
, INT Count
, LPVOID buffer
)
835 if (!buffer
) return sizeof(BITMAP
);
836 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
838 /* always fill a basic BITMAP structure */
841 pBitmap
->bmWidth
= psurf
->SurfObj
.sizlBitmap
.cx
;
842 pBitmap
->bmHeight
= psurf
->SurfObj
.sizlBitmap
.cy
;
843 pBitmap
->bmWidthBytes
= abs(psurf
->SurfObj
.lDelta
);
844 pBitmap
->bmPlanes
= 1;
845 pBitmap
->bmBitsPixel
= BitsPerFormat(psurf
->SurfObj
.iBitmapFormat
);
847 /* Check for DIB section */
850 /* Set bmBits in this case */
851 pBitmap
->bmBits
= psurf
->SurfObj
.pvBits
;
853 if (Count
>= sizeof(DIBSECTION
))
855 /* Fill rest of DIBSECTION */
856 PDIBSECTION pds
= buffer
;
858 pds
->dsBmih
.biSize
= sizeof(BITMAPINFOHEADER
);
859 pds
->dsBmih
.biWidth
= pds
->dsBm
.bmWidth
;
860 pds
->dsBmih
.biHeight
= pds
->dsBm
.bmHeight
;
861 pds
->dsBmih
.biPlanes
= pds
->dsBm
.bmPlanes
;
862 pds
->dsBmih
.biBitCount
= pds
->dsBm
.bmBitsPixel
;
863 pds
->dsBmih
.biCompression
= 0; // FIXME!
864 pds
->dsBmih
.biSizeImage
= psurf
->SurfObj
.cjBits
;
865 pds
->dsBmih
.biXPelsPerMeter
= 0;
866 pds
->dsBmih
.biYPelsPerMeter
= 0;
867 pds
->dsBmih
.biClrUsed
= psurf
->biClrUsed
;
868 pds
->dsBmih
.biClrImportant
= psurf
->biClrImportant
;
869 pds
->dsBitfields
[0] = psurf
->dsBitfields
[0];
870 pds
->dsBitfields
[1] = psurf
->dsBitfields
[1];
871 pds
->dsBitfields
[2] = psurf
->dsBitfields
[2];
872 pds
->dshSection
= psurf
->hDIBSection
;
873 pds
->dsOffset
= psurf
->dwOffset
;
875 return sizeof(DIBSECTION
);
880 /* not set according to wine test, confirmed in win2k */
881 pBitmap
->bmBits
= NULL
;
884 return sizeof(BITMAP
);
896 PSURFACE psurf
= SURFACE_LockSurface(hsurf
);
900 SURFACE_UnlockSurface(psurf
);
922 if (hDC
== NULL
|| hBmp
== NULL
) return NULL
;
924 pDC
= DC_LockDc(hDC
);
930 pDc_Attr
= pDC
->pDc_Attr
;
931 if (!pDc_Attr
) pDc_Attr
= &pDC
->Dc_Attr
;
933 /* must be memory dc to select bitmap */
934 if (pDC
->DC_Type
!= DC_TYPE_MEMORY
)
940 psurfBmp
= SURFACE_LockSurface(hBmp
);
946 hOrgBmp
= pDC
->w
.hBitmap
;
948 /* Release the old bitmap, lock the new one and convert it to a SURF */
949 pDC
->w
.hBitmap
= hBmp
;
951 // If Info DC this is zero and pSurface is moved to DC->pSurfInfo.
952 pDC
->DcLevel
.pSurface
= psurfBmp
;
955 // if we're working with a DIB, get the palette
956 // [fixme: only create if the selected palette is null]
957 if (psurfBmp
->hSecure
)
959 // pDC->w.bitsPerPixel = psurfBmp->dib->dsBmih.biBitCount; ???
960 pDC
->w
.bitsPerPixel
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
964 pDC
->w
.bitsPerPixel
= BitsPerFormat(psurfBmp
->SurfObj
.iBitmapFormat
);
967 hVisRgn
= NtGdiCreateRectRgn(0,
969 psurfBmp
->SurfObj
.sizlBitmap
.cx
,
970 psurfBmp
->SurfObj
.sizlBitmap
.cy
);
971 SURFACE_UnlockSurface(psurfBmp
);
973 /* Regenerate the XLATEOBJs. */
974 pBrush
= BRUSHOBJ_LockBrush(pDc_Attr
->hbrush
);
979 EngDeleteXlate(pDC
->XlateBrush
);
981 pDC
->XlateBrush
= IntGdiCreateBrushXlate(pDC
, pBrush
, &bFailed
);
982 BRUSHOBJ_UnlockBrush(pBrush
);
985 pBrush
= PENOBJ_LockPen(pDc_Attr
->hpen
);
990 EngDeleteXlate(pDC
->XlatePen
);
992 pDC
->XlatePen
= IntGdiCreateBrushXlate(pDC
, pBrush
, &bFailed
);
993 PENOBJ_UnlockPen(pBrush
);
1000 GdiSelectVisRgn(hDC
, hVisRgn
);
1001 NtGdiDeleteObject(hVisRgn
);