Author: hbelusca Date: Tue Dec 15 02:54:24 2015 New Revision: 70349
URL: http://svn.reactos.org/svn/reactos?rev=70349&view=rev Log: [CLIPBRD] Fix the computation of where bitmap pixels start, depending on whether we are dealing with DIBs or DIBs version 5+ (depending on the header BITMAPINFOHEADER or BITMAPV5HEADER etc...). I also noticed a bug in Windows that few other people already discovered, related to the automatic conversion of CF_DIBV5/CF_BITMAP to CF_DIB clipboard format. See the comment in the code. CORE-10679
Modified: trunk/reactos/base/applications/clipbrd/winutils.c
Modified: trunk/reactos/base/applications/clipbrd/winutils.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/clipbrd/w... ============================================================================== --- trunk/reactos/base/applications/clipbrd/winutils.c [iso-8859-1] (original) +++ trunk/reactos/base/applications/clipbrd/winutils.c [iso-8859-1] Tue Dec 15 02:54:24 2015 @@ -16,7 +16,7 @@ dwError = GetLastError();
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, dwError, 0, (LPWSTR)&lpMsgBuf, 0, NULL); + NULL, dwError, 0, (LPWSTR)&lpMsgBuf, 0, NULL); MessageBoxW(hwndParent, lpMsgBuf, NULL, MB_OK | MB_ICONERROR); LocalFree(lpMsgBuf); } @@ -102,8 +102,9 @@ { LPBITMAPINFOHEADER lpInfoHeader; LPBYTE lpBits; + LONG bmWidth, bmHeight; + DWORD dwPalSize = 0; HGLOBAL hGlobal; - INT iPalSize;
hGlobal = GetClipboardData(uFormat); if (!hGlobal) @@ -113,18 +114,96 @@ if (!lpInfoHeader) return;
- if (lpInfoHeader->biBitCount < 16) - { - iPalSize = (1 << lpInfoHeader->biBitCount) * 4; + if (lpInfoHeader->biSize == sizeof(BITMAPCOREHEADER)) + { + LPBITMAPCOREHEADER lpCoreHeader = (LPBITMAPCOREHEADER)lpInfoHeader; + + dwPalSize = 0; + + if (lpCoreHeader->bcBitCount <= 8) + { + dwPalSize = (1 << lpCoreHeader->bcBitCount); + + if (fuColorUse == DIB_RGB_COLORS) + dwPalSize *= sizeof(RGBTRIPLE); + else + dwPalSize *= sizeof(WORD); + } + + bmWidth = lpCoreHeader->bcWidth; + bmHeight = lpCoreHeader->bcHeight; + } + else if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) || + (lpInfoHeader->biSize == sizeof(BITMAPV4HEADER)) || + (lpInfoHeader->biSize == sizeof(BITMAPV5HEADER))) + { + dwPalSize = lpInfoHeader->biClrUsed; + + if ((dwPalSize == 0) && (lpInfoHeader->biBitCount <= 8)) + dwPalSize = (1 << lpInfoHeader->biBitCount); + + if (fuColorUse == DIB_RGB_COLORS) + dwPalSize *= sizeof(RGBQUAD); + else + dwPalSize *= sizeof(WORD); + + if (/*(lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) &&*/ + (lpInfoHeader->biCompression == BI_BITFIELDS)) + { + dwPalSize += 3 * sizeof(DWORD); + } + + /* + * This is a (disabled) hack for Windows, when uFormat == CF_DIB + * it needs yet another extra 3 DWORDs, in addition to the + * ones already taken into account in via the compression. + * This problem doesn't happen when uFormat == CF_DIBV5 + * (in that case, when compression is taken into account, + * everything is nice). + * + * NOTE 1: This fix is only for us, because when one pastes DIBs + * directly in apps, the bitmap offset problem is still present. + * + * NOTE 2: The problem can be seen with Windows' clipbrd.exe if + * one copies a CF_DIB image in the clipboard. By default Windows' + * clipbrd.exe works with CF_DIBV5 and CF_BITMAP, so the problem + * is unseen, and the clipboard doesn't have to convert to CF_DIB. + * + * FIXME: investigate!! + * ANSWER: this is a Windows bug; part of the answer is there: + * http://go4answers.webhost4life.com/Help/bug-clipboard-format-conversions-287... + * May be related: + * http://blog.talosintel.com/2015/10/dangerous-clipboard.html + */ +#if 0 + if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) && + (lpInfoHeader->biCompression == BI_BITFIELDS)) + { + dwPalSize += 3 * sizeof(DWORD); + } +#endif + + bmWidth = lpInfoHeader->biWidth; + bmHeight = lpInfoHeader->biHeight; } else { - iPalSize = 0; - } - - lpBits = (LPBYTE)lpInfoHeader + lpInfoHeader->biSize + iPalSize; - - SetDIBitsToDevice(hdc, XDest, YDest, lpInfoHeader->biWidth, lpInfoHeader->biHeight, XSrc, YSrc, uStartScan, lpInfoHeader->biHeight, lpBits, (LPBITMAPINFO)lpInfoHeader, fuColorUse); + /* Invalid format */ + GlobalUnlock(hGlobal); + return; + } + + lpBits = (LPBYTE)lpInfoHeader + lpInfoHeader->biSize + dwPalSize; + + SetDIBitsToDevice(hdc, + XDest, YDest, + bmWidth, bmHeight, + XSrc, YSrc, + uStartScan, + bmHeight, + lpBits, + (LPBITMAPINFO)lpInfoHeader, + fuColorUse);
GlobalUnlock(hGlobal); }