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 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 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 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 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 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 }; 169 170 return GetPriorityClipboardFormat(uFormatList, ARRAYSIZE(uFormatList)); 171 } 172 173 BOOL IsClipboardFormatSupported(UINT uFormat) 174 { 175 switch (uFormat) 176 { 177 case CF_OWNERDISPLAY: 178 case CF_UNICODETEXT: 179 case CF_TEXT: 180 case CF_OEMTEXT: 181 case CF_BITMAP: 182 case CF_ENHMETAFILE: 183 case CF_METAFILEPICT: 184 case CF_DIB: 185 case CF_DIBV5: 186 case CF_HDROP: 187 { 188 return TRUE; 189 } 190 191 default: 192 { 193 return FALSE; 194 } 195 } 196 } 197 198 SIZE_T 199 GetLineExtentW( 200 IN LPCWSTR lpText, 201 OUT LPCWSTR* lpNextLine) 202 { 203 LPCWSTR ptr; 204 205 /* Find the next line of text (lpText is NULL-terminated) */ 206 /* For newlines, focus only on '\n', not on '\r' */ 207 ptr = wcschr(lpText, L'\n'); // Find the end of this line. 208 if (ptr) 209 { 210 /* We have the end of this line, go to the next line (ignore the endline in the count) */ 211 *lpNextLine = ptr + 1; 212 } 213 else 214 { 215 /* This line was the last one, go pointing to the terminating NULL */ 216 ptr = lpText + wcslen(lpText); 217 *lpNextLine = ptr; 218 } 219 220 return (ptr - lpText); 221 } 222 223 SIZE_T 224 GetLineExtentA( 225 IN LPCSTR lpText, 226 OUT LPCSTR* lpNextLine) 227 { 228 LPCSTR ptr; 229 230 /* Find the next line of text (lpText is NULL-terminated) */ 231 /* For newlines, focus only on '\n', not on '\r' */ 232 ptr = strchr(lpText, '\n'); // Find the end of this line. 233 if (ptr) 234 { 235 /* We have the end of this line, go to the next line (ignore the endline in the count) */ 236 *lpNextLine = ptr + 1; 237 } 238 else 239 { 240 /* This line was the last one, go pointing to the terminating NULL */ 241 ptr = lpText + strlen(lpText); 242 *lpNextLine = ptr; 243 } 244 245 return (ptr - lpText); 246 } 247 248 BOOL GetClipboardDataDimensions(UINT uFormat, PRECT pRc) 249 { 250 SetRectEmpty(pRc); 251 252 if (!OpenClipboard(Globals.hMainWnd)) 253 { 254 return FALSE; 255 } 256 257 switch (uFormat) 258 { 259 case CF_DSPBITMAP: 260 case CF_BITMAP: 261 { 262 HBITMAP hBitmap; 263 BITMAP bmp; 264 265 hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP); 266 GetObjectW(hBitmap, sizeof(bmp), &bmp); 267 SetRect(pRc, 0, 0, bmp.bmWidth, bmp.bmHeight); 268 break; 269 } 270 271 case CF_DIB: 272 case CF_DIBV5: 273 { 274 HGLOBAL hGlobal; 275 LPBITMAPINFOHEADER lpInfoHeader; 276 277 hGlobal = GetClipboardData(uFormat); 278 if (!hGlobal) 279 break; 280 281 lpInfoHeader = GlobalLock(hGlobal); 282 if (!lpInfoHeader) 283 break; 284 285 if (lpInfoHeader->biSize == sizeof(BITMAPCOREHEADER)) 286 { 287 LPBITMAPCOREHEADER lpCoreHeader = (LPBITMAPCOREHEADER)lpInfoHeader; 288 SetRect(pRc, 0, 0, 289 lpCoreHeader->bcWidth, 290 lpCoreHeader->bcHeight); 291 } 292 else if ((lpInfoHeader->biSize == sizeof(BITMAPINFOHEADER)) || 293 (lpInfoHeader->biSize == sizeof(BITMAPV4HEADER)) || 294 (lpInfoHeader->biSize == sizeof(BITMAPV5HEADER))) 295 { 296 SetRect(pRc, 0, 0, 297 lpInfoHeader->biWidth, 298 /* NOTE: biHeight < 0 for bottom-up DIBs, or > 0 for top-down DIBs */ 299 (lpInfoHeader->biHeight > 0) ? lpInfoHeader->biHeight 300 : -lpInfoHeader->biHeight); 301 } 302 else 303 { 304 /* Invalid format */ 305 } 306 307 GlobalUnlock(hGlobal); 308 break; 309 } 310 311 case CF_DSPTEXT: 312 case CF_TEXT: 313 case CF_OEMTEXT: 314 case CF_UNICODETEXT: 315 { 316 HDC hDC; 317 HGLOBAL hGlobal; 318 PVOID lpText, ptr; 319 DWORD dwSize; 320 SIZE txtSize = {0, 0}; 321 SIZE_T lineSize; 322 323 hGlobal = GetClipboardData(uFormat); 324 if (!hGlobal) 325 break; 326 327 lpText = GlobalLock(hGlobal); 328 if (!lpText) 329 break; 330 331 hDC = GetDC(Globals.hMainWnd); 332 333 /* Find the size of the rectangle enclosing the text */ 334 for (;;) 335 { 336 if (uFormat == CF_UNICODETEXT) 337 { 338 if (*(LPCWSTR)lpText == UNICODE_NULL) 339 break; 340 lineSize = GetLineExtentW(lpText, (LPCWSTR*)&ptr); 341 dwSize = GetTabbedTextExtentW(hDC, lpText, lineSize, 0, NULL); 342 } 343 else 344 { 345 if (*(LPCSTR)lpText == ANSI_NULL) 346 break; 347 lineSize = GetLineExtentA(lpText, (LPCSTR*)&ptr); 348 dwSize = GetTabbedTextExtentA(hDC, lpText, lineSize, 0, NULL); 349 } 350 txtSize.cx = max(txtSize.cx, LOWORD(dwSize)); 351 txtSize.cy += HIWORD(dwSize); 352 lpText = ptr; 353 } 354 355 ReleaseDC(Globals.hMainWnd, hDC); 356 357 GlobalUnlock(hGlobal); 358 359 SetRect(pRc, 0, 0, txtSize.cx, txtSize.cy); 360 break; 361 } 362 363 default: 364 { 365 break; 366 } 367 } 368 369 CloseClipboard(); 370 371 return TRUE; 372 } 373