2 * PROJECT: ReactOS Clipboard Viewer
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Display helper functions.
5 * COPYRIGHT: Copyright 2015-2018 Ricardo Hanke
6 * Copyright 2015-2018 Hermes Belusca-Maito
11 void ShowLastWin32Error(HWND hwndParent
)
14 LPWSTR lpMsgBuf
= NULL
;
16 dwError
= GetLastError();
17 if (dwError
== ERROR_SUCCESS
)
20 if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
21 FORMAT_MESSAGE_FROM_SYSTEM
|
22 FORMAT_MESSAGE_IGNORE_INSERTS
,
32 MessageBoxW(hwndParent
, lpMsgBuf
, NULL
, MB_OK
| MB_ICONERROR
);
36 void BringWindowToFront(HWND hWnd
)
40 ShowWindow(hWnd
, SW_RESTORE
);
41 SetForegroundWindow(hWnd
);
45 SetForegroundWindow(hWnd
);
49 int MessageBoxRes(HWND hWnd
, HINSTANCE hInstance
, UINT uText
, UINT uCaption
, UINT uType
)
53 ZeroMemory(&mb
, sizeof(mb
));
54 mb
.cbSize
= sizeof(mb
);
56 mb
.hInstance
= hInstance
;
57 mb
.lpszText
= MAKEINTRESOURCEW(uText
);
58 mb
.lpszCaption
= MAKEINTRESOURCEW(uCaption
);
60 mb
.dwLanguageId
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
62 return MessageBoxIndirectW(&mb
);
65 void DrawTextFromResource(HINSTANCE hInstance
, UINT uID
, HDC hDC
, LPRECT lpRect
, UINT uFormat
)
70 nCount
= LoadStringW(hInstance
, uID
, (LPWSTR
)&lpBuffer
, 0);
72 DrawTextW(hDC
, lpBuffer
, nCount
, lpRect
, uFormat
);
75 void DrawTextFromClipboard(UINT uFormat
, PAINTSTRUCT ps
, SCROLLSTATE state
)
81 INT FirstLine
, LastLine
;
83 hGlobal
= GetClipboardData(uFormat
);
87 lpText
= GlobalLock(hGlobal
);
91 /* Find the first and last line indices to display (Note that CurrentX/Y are in pixels!) */
92 FirstLine
= max(0, (state
.CurrentY
+ ps
.rcPaint
.top
) / Globals
.CharHeight
);
93 // LastLine = min(LINES - 1, (state.CurrentY + ps.rcPaint.bottom) / Globals.CharHeight);
94 // NOTE: Can be less or greater than the actual number of lines in the text.
95 LastLine
= (state
.CurrentY
+ ps
.rcPaint
.bottom
) / Globals
.CharHeight
;
97 /* Find the first text line to display */
100 if (uFormat
== CF_UNICODETEXT
)
102 if (*(LPCWSTR
)lpText
== UNICODE_NULL
)
104 GetLineExtentW(lpText
, (LPCWSTR
*)&ptr
);
108 if (*(LPCSTR
)lpText
== ANSI_NULL
)
110 GetLineExtentA(lpText
, (LPCSTR
*)&ptr
);
119 ptOrg
.x
= ps
.rcPaint
.left
;
120 ptOrg
.y
= /* FirstLine */ max(0, (state
.CurrentY
+ ps
.rcPaint
.top
) / Globals
.CharHeight
)
121 * Globals
.CharHeight
- state
.CurrentY
;
123 /* Display each line from the current one up to the last one */
125 while (LastLine
>= 0)
127 if (uFormat
== CF_UNICODETEXT
)
129 if (*(LPCWSTR
)lpText
== UNICODE_NULL
)
131 lineSize
= GetLineExtentW(lpText
, (LPCWSTR
*)&ptr
);
132 TabbedTextOutW(ps
.hdc
, /*ptOrg.x*/0 - state
.CurrentX
, ptOrg
.y
,
133 lpText
, lineSize
, 0, NULL
,
134 /*ptOrg.x*/0 - state
.CurrentX
);
138 if (*(LPCSTR
)lpText
== ANSI_NULL
)
140 lineSize
= GetLineExtentA(lpText
, (LPCSTR
*)&ptr
);
141 TabbedTextOutA(ps
.hdc
, /*ptOrg.x*/0 - state
.CurrentX
, ptOrg
.y
,
142 lpText
, lineSize
, 0, NULL
,
143 /*ptOrg.x*/0 - state
.CurrentX
);
148 ptOrg
.y
+= Globals
.CharHeight
;
152 GlobalUnlock(hGlobal
);
155 void BitBltFromClipboard(PAINTSTRUCT ps
, SCROLLSTATE state
, DWORD dwRop
)
160 LONG bmWidth
, bmHeight
;
162 hdcMem
= CreateCompatibleDC(ps
.hdc
);
166 hBitmap
= (HBITMAP
)GetClipboardData(CF_BITMAP
);
167 GetObjectW(hBitmap
, sizeof(bmp
), &bmp
);
169 SelectObject(hdcMem
, hBitmap
);
171 bmWidth
= min(ps
.rcPaint
.right
- ps
.rcPaint
.left
, bmp
.bmWidth
- ps
.rcPaint
.left
- state
.CurrentX
);
172 bmHeight
= min(ps
.rcPaint
.bottom
- ps
.rcPaint
.top
, bmp
.bmHeight
- ps
.rcPaint
.top
- state
.CurrentY
);
180 ps
.rcPaint
.left
+ state
.CurrentX
,
181 ps
.rcPaint
.top
+ state
.CurrentY
,
187 void SetDIBitsToDeviceFromClipboard(UINT uFormat
, PAINTSTRUCT ps
, SCROLLSTATE state
, UINT fuColorUse
)
190 LPBITMAPINFOHEADER lpInfoHeader
;
192 LONG bmWidth
, bmHeight
;
195 hGlobal
= GetClipboardData(uFormat
);
199 lpInfoHeader
= GlobalLock(hGlobal
);
203 if (lpInfoHeader
->biSize
== sizeof(BITMAPCOREHEADER
))
205 LPBITMAPCOREHEADER lpCoreHeader
= (LPBITMAPCOREHEADER
)lpInfoHeader
;
209 if (lpCoreHeader
->bcBitCount
<= 8)
211 dwPalSize
= (1 << lpCoreHeader
->bcBitCount
);
213 if (fuColorUse
== DIB_RGB_COLORS
)
214 dwPalSize
*= sizeof(RGBTRIPLE
);
216 dwPalSize
*= sizeof(WORD
);
219 bmWidth
= lpCoreHeader
->bcWidth
;
220 bmHeight
= lpCoreHeader
->bcHeight
;
222 else if ((lpInfoHeader
->biSize
== sizeof(BITMAPINFOHEADER
)) ||
223 (lpInfoHeader
->biSize
== sizeof(BITMAPV4HEADER
)) ||
224 (lpInfoHeader
->biSize
== sizeof(BITMAPV5HEADER
)))
226 dwPalSize
= lpInfoHeader
->biClrUsed
;
228 if ((dwPalSize
== 0) && (lpInfoHeader
->biBitCount
<= 8))
229 dwPalSize
= (1 << lpInfoHeader
->biBitCount
);
231 if (fuColorUse
== DIB_RGB_COLORS
)
232 dwPalSize
*= sizeof(RGBQUAD
);
234 dwPalSize
*= sizeof(WORD
);
236 if (/*(lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) &&*/
237 (lpInfoHeader
->biCompression
== BI_BITFIELDS
))
239 dwPalSize
+= 3 * sizeof(DWORD
);
243 * This is a (disabled) hack for Windows, when uFormat == CF_DIB
244 * it needs yet another extra 3 DWORDs, in addition to the
245 * ones already taken into account in via the compression.
246 * This problem doesn't happen when uFormat == CF_DIBV5
247 * (in that case, when compression is taken into account,
248 * everything is nice).
250 * NOTE 1: This fix is only for us, because when one pastes DIBs
251 * directly in apps, the bitmap offset problem is still present.
253 * NOTE 2: The problem can be seen with Windows' clipbrd.exe if
254 * one copies a CF_DIB image in the clipboard. By default Windows'
255 * clipbrd.exe works with CF_DIBV5 and CF_BITMAP, so the problem
256 * is unseen, and the clipboard doesn't have to convert to CF_DIB.
258 * FIXME: investigate!!
259 * ANSWER: this is a Windows bug; part of the answer is there:
260 * https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/ac7ab3b5-8609-4478-b86a-976dab44c271/bug-clipboard-format-conversions-cfdib-cfdibv5-cfdib
262 * https://blog.talosintelligence.com/2015/10/dangerous-clipboard.html
265 if ((lpInfoHeader
->biSize
== sizeof(BITMAPINFOHEADER
)) &&
266 (lpInfoHeader
->biCompression
== BI_BITFIELDS
))
268 dwPalSize
+= 3 * sizeof(DWORD
);
272 bmWidth
= lpInfoHeader
->biWidth
;
273 /* NOTE: biHeight < 0 for bottom-up DIBs, or > 0 for top-down DIBs */
274 bmHeight
= lpInfoHeader
->biHeight
;
279 GlobalUnlock(hGlobal
);
283 lpBits
= (LPBYTE
)lpInfoHeader
+ lpInfoHeader
->biSize
+ dwPalSize
;
286 * The seventh parameter (YSrc) of SetDIBitsToDevice always designates
287 * the Y-coordinate of the "lower-left corner" of the image, be the DIB
288 * in bottom-up or top-down mode.
290 SetDIBitsToDevice(ps
.hdc
,
291 -state
.CurrentX
, // ps.rcPaint.left,
292 -state
.CurrentY
, // ps.rcPaint.top,
295 0, // ps.rcPaint.left + state.CurrentX,
296 0, // -(ps.rcPaint.top + state.CurrentY),
300 (LPBITMAPINFO
)lpInfoHeader
,
303 GlobalUnlock(hGlobal
);
306 void PlayMetaFileFromClipboard(HDC hdc
, const RECT
*lpRect
)
311 hGlobal
= GetClipboardData(CF_METAFILEPICT
);
315 mp
= (LPMETAFILEPICT
)GlobalLock(hGlobal
);
319 SetMapMode(hdc
, mp
->mm
);
320 SetViewportExtEx(hdc
, lpRect
->right
, lpRect
->bottom
, NULL
);
321 SetViewportOrgEx(hdc
, lpRect
->left
, lpRect
->top
, NULL
);
322 PlayMetaFile(hdc
, mp
->hMF
);
323 GlobalUnlock(hGlobal
);
326 void PlayEnhMetaFileFromClipboard(HDC hdc
, const RECT
*lpRect
)
330 hEmf
= GetClipboardData(CF_ENHMETAFILE
);
331 PlayEnhMetaFile(hdc
, hEmf
, lpRect
);
334 BOOL
RealizeClipboardPalette(HDC hdc
)
337 HPALETTE hPalette
, hOldPalette
;
339 if (!IsClipboardFormatAvailable(CF_PALETTE
))
342 hPalette
= GetClipboardData(CF_PALETTE
);
346 hOldPalette
= SelectPalette(hdc
, hPalette
, FALSE
);
350 Success
= (RealizePalette(hdc
) != GDI_ERROR
);
352 SelectPalette(hdc
, hOldPalette
, FALSE
);