/* * COPYRIGHT: GNU GPL, See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Bitmap functions * FILE: win32ss/gdi/ntgdi/bitmaps.c * PROGRAMERS: Timo Kreuzer * Katayama Hirofumi MZ */ #include #define NDEBUG #include BOOL NTAPI GreSetBitmapOwner( _In_ HBITMAP hbmp, _In_ ULONG ulOwner) { /* Check if we have the correct object type */ if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE) { DPRINT1("Incorrect type for hbmp: %p\n", hbmp); return FALSE; } /// FIXME: this is a hack and doesn't handle a race condition properly. /// It needs to be done in GDIOBJ_vSetObjectOwner atomically. /* Check if we set public or none */ if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) || (ulOwner == GDI_OBJ_HMGR_NONE)) { /* Only allow this for owned objects */ if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED) { DPRINT1("Cannot change owner for non-powned hbmp\n"); return FALSE; } } return GreSetObjectOwner(hbmp, ulOwner); } LONG NTAPI UnsafeSetBitmapBits( _Inout_ PSURFACE psurf, _In_ ULONG cjBits, _In_ const VOID *pvBits) { PUCHAR pjDst; const UCHAR *pjSrc; LONG lDeltaDst, lDeltaSrc, lDeltaDstAbs; ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel; NT_ASSERT(psurf->flags & API_BITMAP); NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP); nWidth = psurf->SurfObj.sizlBitmap.cx; nHeight = psurf->SurfObj.sizlBitmap.cy; cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat); pjDst = psurf->SurfObj.pvScan0; pjSrc = pvBits; lDeltaDst = psurf->SurfObj.lDelta; lDeltaDstAbs = labs(lDeltaDst); lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel); NT_ASSERT(lDeltaSrc <= lDeltaDstAbs); cbDst = lDeltaDstAbs * nHeight; cbSrc = lDeltaSrc * nHeight; cjBits = min(cjBits, cbSrc); iSrc = iDst = 0; for (Y = 0; Y < nHeight; Y++) { if (iSrc + lDeltaSrc > cjBits || iDst + lDeltaDstAbs > cbDst) { LONG lDelta = min(cjBits - iSrc, cbDst - iDst); NT_ASSERT(lDelta >= 0); RtlCopyMemory(pjDst, pjSrc, lDelta); iSrc += lDelta; break; } /* Copy one line */ RtlCopyMemory(pjDst, pjSrc, lDeltaSrc); pjSrc += lDeltaSrc; pjDst += lDeltaDst; iSrc += lDeltaSrc; iDst += lDeltaDstAbs; } return iSrc; } HBITMAP NTAPI GreCreateBitmapEx( _In_ ULONG nWidth, _In_ ULONG nHeight, _In_ ULONG cjWidthBytes, _In_ ULONG iFormat, _In_ USHORT fjBitmap, _In_ ULONG cjSizeImage, _In_opt_ PVOID pvBits, _In_ FLONG flags) { PSURFACE psurf; HBITMAP hbmp; PVOID pvCompressedBits = NULL; /* Verify format */ if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL; /* The infamous RLE hack */ if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE)) { pvCompressedBits = pvBits; pvBits = NULL; iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP; } /* Allocate a surface */ psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat, fjBitmap, cjWidthBytes, pvCompressedBits ? 0 : cjSizeImage, pvBits); if (!psurf) { DPRINT1("SURFACE_AllocSurface failed.\n"); return NULL; } /* The infamous RLE hack */ if (pvCompressedBits) { SIZEL sizl; LONG lDelta; sizl.cx = nWidth; sizl.cy = nHeight; lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]); pvBits = psurf->SurfObj.pvBits; DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage); } /* Get the handle for the bitmap */ hbmp = (HBITMAP)psurf->SurfObj.hsurf; /* Mark as API bitmap */ psurf->flags |= (flags | API_BITMAP); /* Unlock the surface and return */ SURFACE_UnlockSurface(psurf); return hbmp; } /* Creates a DDB surface, * as in CreateCompatibleBitmap or CreateBitmap. * Note that each scanline must be 32bit aligned! */ HBITMAP NTAPI GreCreateBitmap( _In_ ULONG nWidth, _In_ ULONG nHeight, _In_ ULONG cPlanes, _In_ ULONG cBitsPixel, _In_opt_ PVOID pvBits) { /* Call the extended function */ return GreCreateBitmapEx(nWidth, nHeight, 0, /* Auto width */ BitmapFormat(cBitsPixel * cPlanes, BI_RGB), 0, /* No bitmap flags */ 0, /* Auto size */ pvBits, DDB_SURFACE /* DDB */); } HBITMAP APIENTRY NtGdiCreateBitmap( IN INT nWidth, IN INT nHeight, IN UINT cPlanes, IN UINT cBitsPixel, IN OPTIONAL LPBYTE pUnsafeBits) { HBITMAP hbmp; ULONG cRealBpp, cjWidthBytes, iFormat; ULONGLONG cjSize; PSURFACE psurf; /* Calculate bitmap format and real bits per pixel. */ iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB); cRealBpp = gajBitsPerFormat[iFormat]; /* Calculate width and image size in bytes */ cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp); cjSize = (ULONGLONG)cjWidthBytes * nHeight; /* Check parameters (possible overflow of cjSize!) */ if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) || (cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL)) { DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n", nWidth, nHeight, cBitsPixel, cPlanes); EngSetLastError(ERROR_INVALID_PARAMETER); return NULL; } /* Allocate the surface (but don't set the bits) */ psurf = SURFACE_AllocSurface(STYPE_BITMAP, nWidth, nHeight, iFormat, 0, 0, 0, NULL); if (!psurf) { DPRINT1("SURFACE_AllocSurface failed.\n"); return NULL; } /* Mark as API and DDB bitmap */ psurf->flags |= (API_BITMAP | DDB_SURFACE); /* Check if we have bits to set */ if (pUnsafeBits) { /* Protect with SEH and copy the bits */ _SEH2_TRY { ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1); UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { GDIOBJ_vDeleteObject(&psurf->BaseObject); _SEH2_YIELD(return NULL;) } _SEH2_END } else { /* Zero the bits */ RtlZeroMemory(psurf->SurfObj.pvBits, psurf->SurfObj.cjBits); } /* Get the handle for the bitmap */ hbmp = (HBITMAP)psurf->SurfObj.hsurf; /* Unlock the surface */ SURFACE_UnlockSurface(psurf); return hbmp; } HBITMAP FASTCALL IntCreateCompatibleBitmap( PDC Dc, INT Width, INT Height, UINT Planes, UINT Bpp) { HBITMAP Bmp = NULL; PPALETTE ppal; /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */ if (0 == Width || 0 == Height) { return NtGdiGetStockObject(DEFAULT_BITMAP); } if (Dc->dctype != DCTYPE_MEMORY) { PSURFACE psurf; Bmp = GreCreateBitmap(abs(Width), abs(Height), Planes ? Planes : 1, Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel, NULL); if (Bmp == NULL) { DPRINT1("Failed to allocate a bitmap!\n"); return NULL; } psurf = SURFACE_ShareLockSurface(Bmp); ASSERT(psurf); /* Dereference old palette and set new palette */ ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault); ASSERT(ppal); SURFACE_vSetPalette(psurf, ppal); PALETTE_ShareUnlockPalette(ppal); /* Set flags */ psurf->flags = API_BITMAP; psurf->hdc = NULL; // FIXME: psurf->SurfObj.hdev = (HDEV)Dc->ppdev; SURFACE_ShareUnlockSurface(psurf); } else { DIBSECTION dibs; INT Count; PSURFACE psurf = Dc->dclevel.pSurface; if(!psurf) psurf = psurfDefaultBitmap; Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs); if (Count == sizeof(BITMAP)) { PSURFACE psurfBmp; Bmp = GreCreateBitmap(abs(Width), abs(Height), Planes ? Planes : 1, Bpp ? Bpp : dibs.dsBm.bmBitsPixel, NULL); if (Bmp == NULL) { DPRINT1("Failed to allocate a bitmap!\n"); return NULL; } psurfBmp = SURFACE_ShareLockSurface(Bmp); ASSERT(psurfBmp); /* Dereference old palette and set new palette */ SURFACE_vSetPalette(psurfBmp, psurf->ppal); /* Set flags */ psurfBmp->flags = API_BITMAP; psurfBmp->hdc = NULL; // FIXME: psurfBmp->SurfObj.hdev = (HDEV)Dc->ppdev; SURFACE_ShareUnlockSurface(psurfBmp); } else if (Count == sizeof(DIBSECTION)) { /* A DIB section is selected in the DC */ BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0}; PVOID Bits; BITMAPINFO* bi = (BITMAPINFO*)buf; bi->bmiHeader.biSize = sizeof(bi->bmiHeader); bi->bmiHeader.biWidth = Width; bi->bmiHeader.biHeight = Height; bi->bmiHeader.biPlanes = Planes ? Planes : dibs.dsBmih.biPlanes; bi->bmiHeader.biBitCount = Bpp ? Bpp : dibs.dsBmih.biBitCount; bi->bmiHeader.biCompression = dibs.dsBmih.biCompression; bi->bmiHeader.biSizeImage = 0; bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter; bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter; bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed; bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant; if (bi->bmiHeader.biCompression == BI_BITFIELDS) { /* Copy the color masks */ RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD)); } else if (bi->bmiHeader.biBitCount <= 8) { /* Copy the color table */ UINT Index; PPALETTE PalGDI; if (!psurf->ppal) { EngSetLastError(ERROR_INVALID_HANDLE); return 0; } PalGDI = psurf->ppal; for (Index = 0; Index < 256 && Index < PalGDI->NumColors; Index++) { bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed; bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen; bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue; bi->bmiColors[Index].rgbReserved = 0; } } Bmp = DIB_CreateDIBSection(Dc, bi, DIB_RGB_COLORS, &Bits, NULL, 0, 0); return Bmp; } } return Bmp; } HBITMAP APIENTRY NtGdiCreateCompatibleBitmap( HDC hDC, INT Width, INT Height) { HBITMAP Bmp; PDC Dc; /* Check parameters */ if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF)) { EngSetLastError(ERROR_INVALID_PARAMETER); return NULL; } if (!hDC) return GreCreateBitmap(Width, Height, 1, 1, 0); Dc = DC_LockDc(hDC); DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n", hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel); if (NULL == Dc) { EngSetLastError(ERROR_INVALID_HANDLE); return NULL; } Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0); DC_UnlockDc(Dc); return Bmp; } BOOL NTAPI GreGetBitmapDimension( _In_ HBITMAP hBitmap, _Out_ LPSIZE psizDim) { PSURFACE psurfBmp; if (hBitmap == NULL) return FALSE; /* Lock the bitmap */ psurfBmp = SURFACE_ShareLockSurface(hBitmap); if (psurfBmp == NULL) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } *psizDim = psurfBmp->sizlDim; /* Unlock the bitmap */ SURFACE_ShareUnlockSurface(psurfBmp); return TRUE; } BOOL APIENTRY NtGdiGetBitmapDimension( HBITMAP hBitmap, LPSIZE psizDim) { SIZE dim; if (!GreGetBitmapDimension(hBitmap, &dim)) return FALSE; /* Use SEH to copy the data to the caller */ _SEH2_TRY { ProbeForWrite(psizDim, sizeof(*psizDim), 1); *psizDim = dim; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return FALSE); } _SEH2_END return TRUE; } LONG FASTCALL UnsafeGetBitmapBits( PSURFACE psurf, DWORD Bytes, OUT PBYTE pvBits) { PUCHAR pjDst, pjSrc; LONG lDeltaDst, lDeltaSrc, lDeltaSrcAbs; ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel; nWidth = psurf->SurfObj.sizlBitmap.cx; nHeight = psurf->SurfObj.sizlBitmap.cy; cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat); /* Get pointers */ pjSrc = psurf->SurfObj.pvScan0; pjDst = pvBits; lDeltaSrc = psurf->SurfObj.lDelta; lDeltaSrcAbs = labs(lDeltaSrc); lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel); NT_ASSERT(lDeltaSrcAbs >= lDeltaDst); cbSrc = nHeight * lDeltaSrcAbs; cbDst = nHeight * lDeltaDst; Bytes = min(Bytes, cbDst); iSrc = iDst = 0; for (Y = 0; Y < nHeight; Y++) { if (iSrc + lDeltaSrcAbs > cbSrc || iDst + lDeltaDst > Bytes) { LONG lDelta = min(cbSrc - iSrc, Bytes - iDst); NT_ASSERT(lDelta >= 0); RtlCopyMemory(pjDst, pjSrc, lDelta); iDst += lDelta; break; } /* Copy one line */ RtlCopyMemory(pjDst, pjSrc, lDeltaDst); pjSrc += lDeltaSrc; pjDst += lDeltaDst; iSrc += lDeltaSrcAbs; iDst += lDeltaDst; } return iDst; } LONG APIENTRY NtGdiGetBitmapBits( HBITMAP hBitmap, ULONG cjBuffer, OUT OPTIONAL PBYTE pUnsafeBits) { PSURFACE psurf; ULONG cjSize; LONG ret; /* Check parameters */ if (pUnsafeBits != NULL && cjBuffer == 0) { return 0; } /* Lock the bitmap */ psurf = SURFACE_ShareLockSurface(hBitmap); if (!psurf) { EngSetLastError(ERROR_INVALID_HANDLE); return 0; } /* Calculate the size of the bitmap in bytes */ cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx, BitsPerFormat(psurf->SurfObj.iBitmapFormat)) * psurf->SurfObj.sizlBitmap.cy; /* If the bits vector is null, the function should return the read size */ if (pUnsafeBits == NULL) { SURFACE_ShareUnlockSurface(psurf); return cjSize; } /* Don't copy more bytes than the buffer has */ cjBuffer = min(cjBuffer, cjSize); // FIXME: Use MmSecureVirtualMemory _SEH2_TRY { ProbeForWrite(pUnsafeBits, cjBuffer, 1); ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ret = 0; } _SEH2_END SURFACE_ShareUnlockSurface(psurf); return ret; } LONG APIENTRY NtGdiSetBitmapBits( HBITMAP hBitmap, DWORD Bytes, IN PBYTE pUnsafeBits) { LONG ret; PSURFACE psurf; if (pUnsafeBits == NULL || Bytes == 0) { return 0; } if (GDI_HANDLE_IS_STOCKOBJ(hBitmap)) { return 0; } psurf = SURFACE_ShareLockSurface(hBitmap); if (psurf == NULL) { EngSetLastError(ERROR_INVALID_HANDLE); return 0; } if (((psurf->flags & API_BITMAP) == 0) || (psurf->SurfObj.iBitmapFormat > BMF_32BPP)) { DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n", psurf->SurfObj.iBitmapFormat, psurf->flags); EngSetLastError(ERROR_INVALID_HANDLE); SURFACE_ShareUnlockSurface(psurf); return 0; } _SEH2_TRY { /* NOTE: Win2k3 doesn't check WORD alignment here. */ ProbeForWrite(pUnsafeBits, Bytes, 1); ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ret = 0; } _SEH2_END SURFACE_ShareUnlockSurface(psurf); return ret; } BOOL APIENTRY NtGdiSetBitmapDimension( HBITMAP hBitmap, INT Width, INT Height, LPSIZE Size) { PSURFACE psurf; BOOL Ret = TRUE; if (hBitmap == NULL) return FALSE; psurf = SURFACE_ShareLockSurface(hBitmap); if (psurf == NULL) { EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } if (Size) { _SEH2_TRY { ProbeForWrite(Size, sizeof(SIZE), 1); *Size = psurf->sizlDim; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Ret = FALSE; } _SEH2_END } /* The dimension is changed even if writing the old value failed */ psurf->sizlDim.cx = Width; psurf->sizlDim.cy = Height; SURFACE_ShareUnlockSurface(psurf); return Ret; } /* Internal Functions */ HBITMAP FASTCALL BITMAP_CopyBitmap(HBITMAP hBitmap) { HBITMAP hbmNew; SURFACE *psurfSrc, *psurfNew; /* Fail, if no source bitmap is given */ if (hBitmap == NULL) return 0; /* Lock the source bitmap */ psurfSrc = SURFACE_ShareLockSurface(hBitmap); if (psurfSrc == NULL) { return 0; } /* Allocate a new bitmap with the same dimensions as the source bmp */ hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx, psurfSrc->SurfObj.sizlBitmap.cy, abs(psurfSrc->SurfObj.lDelta), psurfSrc->SurfObj.iBitmapFormat, psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN, psurfSrc->SurfObj.cjBits, NULL, psurfSrc->flags); if (hbmNew) { /* Lock the new bitmap */ psurfNew = SURFACE_ShareLockSurface(hbmNew); if (psurfNew) { /* Copy the bitmap bits to the new bitmap buffer */ RtlCopyMemory(psurfNew->SurfObj.pvBits, psurfSrc->SurfObj.pvBits, psurfNew->SurfObj.cjBits); /* Reference the palette of the source bitmap and use it */ SURFACE_vSetPalette(psurfNew, psurfSrc->ppal); /* Unlock the new surface */ SURFACE_ShareUnlockSurface(psurfNew); } else { /* Failed to lock the bitmap, shouldn't happen */ GreDeleteObject(hbmNew); hbmNew = NULL; } } /* Unlock the source bitmap and return the handle of the new bitmap */ SURFACE_ShareUnlockSurface(psurfSrc); return hbmNew; } INT APIENTRY BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer) { PBITMAP pBitmap; if (!buffer) return sizeof(BITMAP); if ((UINT)Count < sizeof(BITMAP)) return 0; /* Always fill a basic BITMAP structure */ pBitmap = buffer; pBitmap->bmType = 0; pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx; pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy; pBitmap->bmPlanes = 1; pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat); pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel); /* Check for DIB section */ if (psurf->hSecure) { /* Set bmBits in this case */ pBitmap->bmBits = psurf->SurfObj.pvBits; /* DIBs data are 32 bits aligned */ pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel); if (Count >= sizeof(DIBSECTION)) { /* Fill rest of DIBSECTION */ PDIBSECTION pds = buffer; pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER); pds->dsBmih.biWidth = pds->dsBm.bmWidth; pds->dsBmih.biHeight = pds->dsBm.bmHeight; pds->dsBmih.biPlanes = pds->dsBm.bmPlanes; pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel; switch (psurf->SurfObj.iBitmapFormat) { case BMF_1BPP: case BMF_4BPP: case BMF_8BPP: pds->dsBmih.biCompression = BI_RGB; break; case BMF_16BPP: if (psurf->ppal->flFlags & PAL_RGB16_555) pds->dsBmih.biCompression = BI_RGB; else pds->dsBmih.biCompression = BI_BITFIELDS; break; case BMF_24BPP: case BMF_32BPP: /* 24/32bpp BI_RGB is actually BGR format */ if (psurf->ppal->flFlags & PAL_BGR) pds->dsBmih.biCompression = BI_RGB; else pds->dsBmih.biCompression = BI_BITFIELDS; break; case BMF_4RLE: pds->dsBmih.biCompression = BI_RLE4; break; case BMF_8RLE: pds->dsBmih.biCompression = BI_RLE8; break; case BMF_JPEG: pds->dsBmih.biCompression = BI_JPEG; break; case BMF_PNG: pds->dsBmih.biCompression = BI_PNG; break; default: ASSERT(FALSE); /* This shouldn't happen */ } pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits; pds->dsBmih.biXPelsPerMeter = 0; pds->dsBmih.biYPelsPerMeter = 0; pds->dsBmih.biClrUsed = psurf->ppal->NumColors; pds->dsBmih.biClrImportant = psurf->biClrImportant; pds->dsBitfields[0] = psurf->ppal->RedMask; pds->dsBitfields[1] = psurf->ppal->GreenMask; pds->dsBitfields[2] = psurf->ppal->BlueMask; pds->dshSection = psurf->hDIBSection; pds->dsOffset = psurf->dwOffset; return sizeof(DIBSECTION); } } else { /* Not set according to wine test, confirmed in win2k */ pBitmap->bmBits = NULL; } return sizeof(BITMAP); } /* * @implemented */ HDC APIENTRY NtGdiGetDCforBitmap( IN HBITMAP hsurf) { HDC hdc = NULL; PSURFACE psurf = SURFACE_ShareLockSurface(hsurf); if (psurf) { hdc = psurf->hdc; SURFACE_ShareUnlockSurface(psurf); } return hdc; } /* EOF */