diff --git a/win32ss/gdi/ntgdi/dibobj.c b/win32ss/gdi/ntgdi/dibobj.c index 3d88101c8a..a1df0f610d 100644 --- a/win32ss/gdi/ntgdi/dibobj.c +++ b/win32ss/gdi/ntgdi/dibobj.c @@ -1180,10 +1180,9 @@ cleanup: } -W32KAPI +/* RLE4 or RLE8 bitmaps are handled here. */ INT -APIENTRY -NtGdiStretchDIBitsInternal( +NtGdiStretchDIBitsInternalEx( IN HDC hdc, IN INT xDst, IN INT yDst, @@ -1210,6 +1209,7 @@ NtGdiStretchDIBitsInternal( PPALETTE ppalDIB = 0; EXLATEOBJ exlo; PVOID pvBits; + INT LinesCopied = 0; if (!(pdc = DC_LockDc(hdc))) { @@ -1258,6 +1258,8 @@ NtGdiStretchDIBitsInternal( pvBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, 'pmeT'); if (!pvBits) { + DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits); + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } @@ -1371,7 +1373,169 @@ cleanup: if (pdc) DC_UnlockDc(pdc); if (pvBits) ExFreePoolWithTag(pvBits, 'pmeT'); - return bResult; + if (!bResult) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* This is not what MSDN says is returned from this function, but it + * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits */ + if (dwRop == SRCCOPY) + LinesCopied = abs(pbmi->bmiHeader.biHeight); + else + LinesCopied = pbmi->bmiHeader.biHeight;; + + return LinesCopied; +} + + +W32KAPI +INT +APIENTRY +NtGdiStretchDIBitsInternal( + HDC hDC, + INT XDest, + INT YDest, + INT DestWidth, + INT DestHeight, + INT XSrc, + INT YSrc, + INT SrcWidth, + INT SrcHeight, + LPBYTE Bits, + LPBITMAPINFO BitsInfo, + DWORD Usage, + DWORD ROP, + UINT cjMaxInfo, + UINT cjMaxBits, + HANDLE hcmXform) +{ + HBITMAP hBitmap, hOldBitmap = NULL; + HDC hdcMem; + HPALETTE hPal = NULL; + PDC pDC; + BOOL Hit = FALSE; + INT LinesCopied = 0; + + if (!Bits || !BitsInfo) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* If we have RLE Compression, use special code */ + + if (BitsInfo->bmiHeader.biCompression == BI_RLE4 || + BitsInfo->bmiHeader.biCompression == BI_RLE8) + { + DPRINT("We have an BI_RLE4 or BI_RLE8 bitmap.\n"); + return NtGdiStretchDIBitsInternalEx( + hDC, + XDest, + YDest, + DestWidth, + DestHeight, + XSrc, + YSrc, + SrcWidth, + SrcHeight, + Bits, + BitsInfo, + Usage, + ROP, + cjMaxInfo, + cjMaxBits, + hcmXform); + } + + _SEH2_TRY + { + ProbeForRead(BitsInfo, cjMaxInfo, 1); + ProbeForRead(Bits, cjMaxBits, 1); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Hit = TRUE; + } + _SEH2_END + + if (Hit) + { + DPRINT1("NtGdiStretchDIBitsInternal failed to read the BitMapInfo: %x or Bits: %x.\n",BitsInfo,Bits); + EngSetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + hdcMem = NtGdiCreateCompatibleDC(hDC); + if (hdcMem == NULL) + { + DPRINT1("NtGdiCreateCompatibleDC failed to create hdc.\n"); + EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); + return 0; + } + + hBitmap = NtGdiCreateCompatibleBitmap(hDC, + abs(BitsInfo->bmiHeader.biWidth), + abs(BitsInfo->bmiHeader.biHeight)); + if (hBitmap == NULL) + { + DPRINT1("NtGdiCreateCompatibleBitmap failed to create bitmap.\n"); + DPRINT1("hDC : 0x%08x \n", hDC); + DPRINT1("BitsInfo->bmiHeader.biWidth : 0x%08x \n", BitsInfo->bmiHeader.biWidth); + DPRINT1("BitsInfo->bmiHeader.biHeight : 0x%08x \n", BitsInfo->bmiHeader.biHeight); + EngSetLastError(ERROR_NO_SYSTEM_RESOURCES); + return 0; + } + + /* Select the bitmap into hdcMem, and save a handle to the old bitmap */ + hOldBitmap = NtGdiSelectBitmap(hdcMem, hBitmap); + + if (Usage == DIB_PAL_COLORS) + { + hPal = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_PALETTE); + hPal = GdiSelectPalette(hdcMem, hPal, FALSE); + } + + pDC = DC_LockDc(hdcMem); + if (pDC != NULL) + { + IntSetDIBits(pDC, hBitmap, 0, abs(BitsInfo->bmiHeader.biHeight), Bits, + cjMaxBits, BitsInfo, Usage); + + DC_UnlockDc(pDC); + } + + /* Origin for DIBitmap may be bottom left (positive biHeight) or top + left (negative biHeight) */ + if (SrcWidth == DestWidth && SrcHeight == DestHeight) + NtGdiBitBlt(hDC, XDest, YDest, DestWidth, DestHeight, + hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc, + ROP, 0, 0); + else + NtGdiStretchBlt(hDC, XDest, YDest, DestWidth, DestHeight, + hdcMem, XSrc, abs(BitsInfo->bmiHeader.biHeight) - SrcHeight - YSrc, + SrcWidth, SrcHeight, ROP, 0); + + /* cleanup */ + if (hPal) + GdiSelectPalette(hdcMem, hPal, FALSE); + + if (hOldBitmap) + NtGdiSelectBitmap(hdcMem, hOldBitmap); + + NtGdiDeleteObjectApp(hdcMem); + + GreDeleteObject(hBitmap); + + /* This is not what MSDN says is returned from this function, but it + * follows Wine's dlls/gdi32/dib.c function nulldrv_StretchDIBits */ + if (ROP == SRCCOPY) + LinesCopied = abs(BitsInfo->bmiHeader.biHeight); + else + LinesCopied = BitsInfo->bmiHeader.biHeight; + + return LinesCopied; }