1 /*
2 * PROJECT: ReactOS Clipboard Viewer
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Clipboard helper functions.
5 * COPYRIGHT: Copyright 2015-2018 Ricardo Hanke
6 * Copyright 2015-2018 Hermes Belusca-Maito
7 */
8
9 #include "precomp.h"
10
11 LRESULT
SendClipboardOwnerMessage(IN BOOL bUnicode,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)12 SendClipboardOwnerMessage(
13 IN BOOL bUnicode,
14 IN UINT uMsg,
15 IN WPARAM wParam,
16 IN LPARAM lParam)
17 {
18 HWND hwndOwner;
19
20 hwndOwner = GetClipboardOwner();
21 if (!hwndOwner)
22 return GetLastError();
23
24 if (bUnicode)
25 return SendMessageW(hwndOwner, uMsg, wParam, lParam);
26 else
27 return SendMessageA(hwndOwner, uMsg, wParam, lParam);
28 }
29
30 static int
GetPredefinedClipboardFormatName(HINSTANCE hInstance,UINT uFormat,BOOL Unicode,PVOID lpszFormat,UINT cch)31 GetPredefinedClipboardFormatName(HINSTANCE hInstance,
32 UINT uFormat,
33 BOOL Unicode,
34 PVOID lpszFormat,
35 UINT cch)
36 {
37 static
38 struct FORMAT_NAME
39 {
40 UINT uFormat;
41 UINT uResID;
42 } uFormatList[] = {
43 /* Table sorted in increasing order of CF_xxx values, please keep it this way! */
44 {CF_TEXT , STRING_CF_TEXT }, // 1
45 {CF_BITMAP , STRING_CF_BITMAP }, // 2
46 {CF_METAFILEPICT, STRING_CF_METAFILEPICT}, // 3
47 {CF_SYLK , STRING_CF_SYLK }, // 4
48 {CF_DIF , STRING_CF_DIF }, // 5
49 {CF_TIFF , 0/*STRING_CF_TIFF*/ }, // 6
50 {CF_OEMTEXT , STRING_CF_OEMTEXT }, // 7
51 {CF_DIB , STRING_CF_DIB }, // 8
52 {CF_PALETTE , STRING_CF_PALETTE }, // 9
53 {CF_PENDATA , 0/*STRING_CF_PENDATA*/ }, // 10
54 {CF_RIFF , 0/*STRING_CF_RIFF*/ }, // 11
55 {CF_WAVE , 0/*STRING_CF_WAVE*/ }, // 12
56 {CF_UNICODETEXT , STRING_CF_UNICODETEXT }, // 13
57 {CF_ENHMETAFILE , STRING_CF_ENHMETAFILE }, // 14
58 #if(WINVER >= 0x0400)
59 {CF_HDROP , STRING_CF_HDROP }, // 15
60 {CF_LOCALE , STRING_CF_LOCALE }, // 16
61 #endif
62 #if(WINVER >= 0x0500)
63 {CF_DIBV5 , STRING_CF_DIBV5 }, // 17
64 #endif
65 };
66
67 switch (uFormat)
68 {
69 case CF_TEXT: case CF_BITMAP: case CF_METAFILEPICT:
70 case CF_SYLK: case CF_DIF: // case CF_TIFF:
71 case CF_OEMTEXT: case CF_DIB: case CF_PALETTE:
72 // case CF_PENDATA: // case CF_RIFF: // case CF_WAVE:
73 case CF_UNICODETEXT: case CF_ENHMETAFILE:
74 #if(WINVER >= 0x0400)
75 case CF_HDROP: case CF_LOCALE:
76 #endif
77 #if(WINVER >= 0x0500)
78 case CF_DIBV5:
79 #endif
80 {
81 if (Unicode)
82 return LoadStringW(hInstance, uFormatList[uFormat-1].uResID, (LPWSTR)lpszFormat, cch);
83 else
84 return LoadStringA(hInstance, uFormatList[uFormat-1].uResID, (LPSTR)lpszFormat, cch);
85 }
86
87 default:
88 {
89 return 0;
90 }
91 }
92 }
93
94 void
RetrieveClipboardFormatName(HINSTANCE hInstance,UINT uFormat,BOOL Unicode,PVOID lpszFormat,UINT cch)95 RetrieveClipboardFormatName(HINSTANCE hInstance,
96 UINT uFormat,
97 BOOL Unicode,
98 PVOID lpszFormat,
99 UINT cch)
100 {
101 ZeroMemory(lpszFormat, cch * (Unicode ? sizeof(WCHAR) : sizeof(CHAR)));
102
103 /* Check for predefined clipboard format */
104 if (GetPredefinedClipboardFormatName(hInstance, uFormat, Unicode, lpszFormat, cch) != 0)
105 return;
106
107 /* Check for owner-display format */
108 if (uFormat == CF_OWNERDISPLAY)
109 {
110 if (SendClipboardOwnerMessage(Unicode, WM_ASKCBFORMATNAME,
111 (WPARAM)cch, (LPARAM)lpszFormat) != 0)
112 {
113 if (Unicode)
114 LoadStringW(hInstance, STRING_CF_UNKNOWN, (LPWSTR)lpszFormat, cch);
115 else
116 LoadStringA(hInstance, STRING_CF_UNKNOWN, (LPSTR)lpszFormat, cch);
117 }
118 return;
119 }
120
121 /* Fallback to registered clipboard format */
122 if (Unicode)
123 {
124 if (!GetClipboardFormatNameW(uFormat, (LPWSTR)lpszFormat, cch))
125 LoadStringW(hInstance, STRING_CF_UNKNOWN, (LPWSTR)lpszFormat, cch);
126 }
127 else
128 {
129 if (!GetClipboardFormatNameA(uFormat, (LPSTR)lpszFormat, cch))
130 LoadStringA(hInstance, STRING_CF_UNKNOWN, (LPSTR)lpszFormat, cch);
131 }
132 }
133
DeleteClipboardContent(void)134 void DeleteClipboardContent(void)
135 {
136 if (!OpenClipboard(Globals.hMainWnd))
137 {
138 ShowLastWin32Error(Globals.hMainWnd);
139 return;
140 }
141
142 if (!EmptyClipboard())
143 {
144 ShowLastWin32Error(Globals.hMainWnd);
145 }
146
147 CloseClipboard();
148 }
149
GetAutomaticClipboardFormat(void)150 UINT GetAutomaticClipboardFormat(void)
151 {
152 static UINT uFormatList[] =
153 {
154 CF_OWNERDISPLAY,
155 CF_UNICODETEXT,
156 CF_TEXT,
157 CF_OEMTEXT,
158 CF_ENHMETAFILE,
159 CF_METAFILEPICT,
160 CF_DIBV5,
161 CF_DIB,
162 CF_BITMAP,
163 CF_DSPTEXT,
164 CF_DSPBITMAP,
165 CF_DSPMETAFILEPICT,
166 CF_DSPENHMETAFILE,
167 CF_PALETTE,
168 CF_HDROP
169 };
170
171 return GetPriorityClipboardFormat(uFormatList, ARRAYSIZE(uFormatList));
172 }
173
IsClipboardFormatSupported(UINT uFormat)174 BOOL IsClipboardFormatSupported(UINT uFormat)
175 {
176 switch (uFormat)
177 {
178 case CF_OWNERDISPLAY:
179 case CF_UNICODETEXT:
180 case CF_TEXT:
181 case CF_OEMTEXT:
182 case CF_BITMAP:
183 case CF_ENHMETAFILE:
184 case CF_METAFILEPICT:
185 case CF_DIB:
186 case CF_DIBV5:
187 case CF_HDROP:
188 {
189 return TRUE;
190 }
191
192 default:
193 {
194 return FALSE;
195 }
196 }
197 }
198
199 SIZE_T
GetLineExtentW(IN LPCWSTR lpText,OUT LPCWSTR * lpNextLine)200 GetLineExtentW(
201 IN LPCWSTR lpText,
202 OUT LPCWSTR* lpNextLine)
203 {
204 LPCWSTR ptr;
205
206 /* Find the next line of text (lpText is NULL-terminated) */
207 /* For newlines, focus only on '\n', not on '\r' */
208 ptr = wcschr(lpText, L'\n'); // Find the end of this line.
209 if (ptr)
210 {
211 /* We have the end of this line, go to the next line (ignore the endline in the count) */
212 *lpNextLine = ptr + 1;
213 }
214 else
215 {
216 /* This line was the last one, go pointing to the terminating NULL */
217 ptr = lpText + wcslen(lpText);
218 *lpNextLine = ptr;
219 }
220
221 return (ptr - lpText);
222 }
223
224 SIZE_T
GetLineExtentA(IN LPCSTR lpText,OUT LPCSTR * lpNextLine)225 GetLineExtentA(
226 IN LPCSTR lpText,
227 OUT LPCSTR* lpNextLine)
228 {
229 LPCSTR ptr;
230
231 /* Find the next line of text (lpText is NULL-terminated) */
232 /* For newlines, focus only on '\n', not on '\r' */
233 ptr = strchr(lpText, '\n'); // Find the end of this line.
234 if (ptr)
235 {
236 /* We have the end of this line, go to the next line (ignore the endline in the count) */
237 *lpNextLine = ptr + 1;
238 }
239 else
240 {
241 /* This line was the last one, go pointing to the terminating NULL */
242 ptr = lpText + strlen(lpText);
243 *lpNextLine = ptr;
244 }
245
246 return (ptr - lpText);
247 }
248
GetClipboardDataDimensions(UINT uFormat,PRECT pRc)249 BOOL GetClipboardDataDimensions(UINT uFormat, PRECT pRc)
250 {
251 SetRectEmpty(pRc);
252
253 if (!OpenClipboard(Globals.hMainWnd))
254 {
255 return FALSE;
256 }
257
258 switch (uFormat)
259 {
260 case CF_DSPBITMAP:
261 case CF_BITMAP:
262 {
263 HBITMAP hBitmap;
264 BITMAP bmp;
265
266 hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP);
267 GetObjectW(hBitmap, sizeof(bmp), &bmp);
268 SetRect(pRc, 0, 0, bmp.bmWidth, bmp.bmHeight);
269 break;
270 }
271
272 case CF_DIB:
273 case CF_DIBV5:
274 {
275 HGLOBAL hGlobal;
276 LPBITMAPINFOHEADER lpInfoHeader;
277
278 hGlobal = GetClipboardData(uFormat);
279 if (!hGlobal)
280 break;
281
282 lpInfoHeader = GlobalLock(hGlobal);
283 if (!lpInfoHeader)
284 break;
285
286 if (lpInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
287 {
288 LPBITMAPCOREHEADER lpCoreHeader = (LPBITMAPCOREHEADER)lpInfoHeader;
289 SetRect(pRc, 0, 0,
290 lpCoreHeader->bcWidth,
291 lpCoreHeader->bcHeight);
292 }
293 else if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) ||
294 (lpInfoHeader->biSize == sizeof(BITMAPV4HEADER)) ||
295 (lpInfoHeader->biSize == sizeof(BITMAPV5HEADER)))
296 {
297 SetRect(pRc, 0, 0,
298 lpInfoHeader->biWidth,
299 /* NOTE: biHeight < 0 for bottom-up DIBs, or > 0 for top-down DIBs */
300 (lpInfoHeader->biHeight > 0) ? lpInfoHeader->biHeight
301 : -lpInfoHeader->biHeight);
302 }
303 else
304 {
305 /* Invalid format */
306 }
307
308 GlobalUnlock(hGlobal);
309 break;
310 }
311
312 case CF_DSPTEXT:
313 case CF_TEXT:
314 case CF_OEMTEXT:
315 case CF_UNICODETEXT:
316 {
317 HDC hDC;
318 HGLOBAL hGlobal;
319 PVOID lpText, ptr;
320 DWORD dwSize;
321 SIZE txtSize = {0, 0};
322 SIZE_T lineSize;
323
324 hGlobal = GetClipboardData(uFormat);
325 if (!hGlobal)
326 break;
327
328 lpText = GlobalLock(hGlobal);
329 if (!lpText)
330 break;
331
332 hDC = GetDC(Globals.hMainWnd);
333
334 /* Find the size of the rectangle enclosing the text */
335 for (;;)
336 {
337 if (uFormat == CF_UNICODETEXT)
338 {
339 if (*(LPCWSTR)lpText == UNICODE_NULL)
340 break;
341 lineSize = GetLineExtentW(lpText, (LPCWSTR*)&ptr);
342 dwSize = GetTabbedTextExtentW(hDC, lpText, lineSize, 0, NULL);
343 }
344 else
345 {
346 if (*(LPCSTR)lpText == ANSI_NULL)
347 break;
348 lineSize = GetLineExtentA(lpText, (LPCSTR*)&ptr);
349 dwSize = GetTabbedTextExtentA(hDC, lpText, lineSize, 0, NULL);
350 }
351 txtSize.cx = max(txtSize.cx, LOWORD(dwSize));
352 txtSize.cy += HIWORD(dwSize);
353 lpText = ptr;
354 }
355
356 ReleaseDC(Globals.hMainWnd, hDC);
357
358 GlobalUnlock(hGlobal);
359
360 SetRect(pRc, 0, 0, txtSize.cx, txtSize.cy);
361 break;
362 }
363
364 default:
365 {
366 break;
367 }
368 }
369
370 CloseClipboard();
371
372 return TRUE;
373 }
374