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 CF_HDROP 169 }; 170 171 return GetPriorityClipboardFormat(uFormatList, ARRAYSIZE(uFormatList)); 172 } 173 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 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 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 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