1 /* 2 * PROJECT: ReactOS Clipboard Viewer 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Clipboard file format helper functions. 5 * COPYRIGHT: Copyright 2015-2018 Ricardo Hanke 6 * Copyright 2015-2018 Hermes Belusca-Maito 7 */ 8 9 #include "precomp.h" 10 11 static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLength) 12 { 13 HGLOBAL hData; 14 LPVOID lpData; 15 DWORD dwBytesRead; 16 17 hData = GlobalAlloc(GHND, dwLength); 18 if (!hData) 19 return NULL; 20 21 lpData = GlobalLock(hData); 22 if (!lpData) 23 { 24 GlobalFree(hData); 25 return NULL; 26 } 27 28 if (SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 29 { 30 GlobalUnlock(hData); 31 GlobalFree(hData); 32 return NULL; 33 } 34 35 if (!ReadFile(hFile, lpData, dwLength, &dwBytesRead, NULL)) 36 { 37 GlobalUnlock(hData); 38 GlobalFree(hData); 39 return NULL; 40 } 41 42 GlobalUnlock(hData); 43 44 return hData; 45 } 46 47 static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, WORD FileIdentifier, PVOID lpFormatName) 48 { 49 HGLOBAL hData; 50 DWORD dwTemp = 0; 51 52 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); 53 if (!hData) 54 return FALSE; 55 56 if ((dwFormat >= 0xC000) && (dwFormat <= 0xFFFF)) 57 { 58 if (FileIdentifier == CLIP_FMT_31) 59 dwTemp = RegisterClipboardFormatA((LPCSTR)lpFormatName); 60 else if ((FileIdentifier == CLIP_FMT_NT) || (FileIdentifier == CLIP_FMT_BK)) 61 dwTemp = RegisterClipboardFormatW((LPCWSTR)lpFormatName); 62 63 if (!dwTemp) 64 { 65 GlobalFree(hData); 66 return FALSE; 67 } 68 } 69 else 70 { 71 dwTemp = dwFormat; 72 } 73 74 if (!SetClipboardData(dwTemp, hData)) 75 { 76 GlobalFree(hData); 77 return FALSE; 78 } 79 80 return TRUE; 81 } 82 83 static BOOL ClipboardWriteMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, PDWORD pdwLength) 84 { 85 HGLOBAL hData; 86 LPVOID lpData; 87 DWORD dwBytesWritten; 88 89 hData = GetClipboardData(dwFormat); 90 if (!hData) 91 return FALSE; 92 93 lpData = GlobalLock(hData); 94 if (!lpData) 95 return FALSE; 96 97 *pdwLength = GlobalSize(hData); 98 99 if (SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 100 { 101 GlobalUnlock(hData); 102 return FALSE; 103 } 104 105 if (!WriteFile(hFile, lpData, *pdwLength, &dwBytesWritten, NULL)) 106 { 107 GlobalUnlock(hData); 108 return FALSE; 109 } 110 111 GlobalUnlock(hData); 112 113 return TRUE; 114 } 115 116 static BOOL ClipboardReadPalette(HANDLE hFile, DWORD dwOffset, DWORD dwLength) 117 { 118 LPLOGPALETTE lpPalette; 119 HPALETTE hPalette; 120 HGLOBAL hData; 121 122 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); 123 if (!hData) 124 { 125 return FALSE; 126 } 127 128 lpPalette = GlobalLock(hData); 129 if (!lpPalette) 130 { 131 GlobalFree(hData); 132 return FALSE; 133 } 134 135 hPalette = CreatePalette(lpPalette); 136 if (!hPalette) 137 { 138 GlobalUnlock(hData); 139 GlobalFree(hData); 140 SetLastError(ERROR_OUTOFMEMORY); 141 return FALSE; 142 } 143 144 GlobalUnlock(hData); 145 GlobalFree(hData); 146 147 if (!SetClipboardData(CF_PALETTE, hPalette)) 148 { 149 DeleteObject(hPalette); 150 return FALSE; 151 } 152 153 return TRUE; 154 } 155 156 static BOOL ClipboardReadMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength) 157 { 158 HMETAFILE hMf; 159 HGLOBAL hData; 160 LPVOID lpData; 161 162 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); 163 if (!hData) 164 { 165 return FALSE; 166 } 167 168 lpData = GlobalLock(hData); 169 if (!lpData) 170 { 171 GlobalFree(hData); 172 return FALSE; 173 } 174 175 hMf = SetMetaFileBitsEx(dwLength, lpData); 176 177 GlobalUnlock(hData); 178 GlobalFree(hData); 179 180 if (!hMf) 181 { 182 SetLastError(ERROR_OUTOFMEMORY); 183 return FALSE; 184 } 185 186 if (!SetClipboardData(CF_METAFILEPICT, hMf)) 187 { 188 DeleteMetaFile(hMf); 189 return FALSE; 190 } 191 192 return TRUE; 193 } 194 195 static BOOL ClipboardReadEnhMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength) 196 { 197 HENHMETAFILE hEmf; 198 HGLOBAL hData; 199 LPVOID lpData; 200 201 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); 202 if (!hData) 203 { 204 return FALSE; 205 } 206 207 lpData = GlobalLock(hData); 208 if (!lpData) 209 { 210 GlobalFree(hData); 211 return FALSE; 212 } 213 214 hEmf = SetEnhMetaFileBits(dwLength, lpData); 215 216 GlobalUnlock(hData); 217 GlobalFree(hData); 218 219 if (!hEmf) 220 { 221 SetLastError(ERROR_OUTOFMEMORY); 222 return FALSE; 223 } 224 225 if (!SetClipboardData(CF_ENHMETAFILE, hEmf)) 226 { 227 DeleteEnhMetaFile(hEmf); 228 return FALSE; 229 } 230 231 return TRUE; 232 } 233 234 static BOOL ClipboardReadBitmap(HANDLE hFile, DWORD dwOffset, DWORD dwLength) 235 { 236 HGLOBAL hData; 237 HBITMAP hBitmap; 238 LPBITMAP lpBitmap; 239 240 hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); 241 if (!hData) 242 { 243 return FALSE; 244 } 245 246 lpBitmap = GlobalLock(hData); 247 if (!lpBitmap) 248 { 249 GlobalFree(hData); 250 return FALSE; 251 } 252 253 lpBitmap->bmBits = lpBitmap + sizeof(BITMAP) + 1; 254 255 hBitmap = CreateBitmapIndirect(lpBitmap); 256 257 GlobalUnlock(hData); 258 GlobalFree(hData); 259 260 if (!hBitmap) 261 { 262 SetLastError(ERROR_OUTOFMEMORY); 263 return FALSE; 264 } 265 266 if (!SetClipboardData(CF_BITMAP, hBitmap)) 267 { 268 DeleteObject(hBitmap); 269 return FALSE; 270 } 271 272 return TRUE; 273 } 274 275 void ReadClipboardFile(LPCWSTR lpFileName) 276 { 277 CLIPFILEHEADER ClipFileHeader; 278 CLIPFORMATHEADER ClipFormatArray; 279 NTCLIPFILEHEADER NtClipFileHeader; 280 NTCLIPFORMATHEADER NtClipFormatArray; 281 PVOID pClipFileHeader; 282 PVOID pClipFormatArray; 283 DWORD SizeOfFileHeader, SizeOfFormatHeader; 284 285 WORD wFileIdentifier; 286 WORD wFormatCount; 287 DWORD dwFormatID; 288 DWORD dwLenData; 289 DWORD dwOffData; 290 PVOID szName; 291 292 HANDLE hFile; 293 DWORD dwBytesRead; 294 BOOL bResult; 295 int i; 296 297 /* Open the file for read access */ 298 hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, 299 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 300 if (hFile == INVALID_HANDLE_VALUE) 301 { 302 ShowLastWin32Error(Globals.hMainWnd); 303 goto done; 304 } 305 306 /* Just read enough bytes to get the clipboard file format ID */ 307 if (!ReadFile(hFile, &wFileIdentifier, sizeof(wFileIdentifier), &dwBytesRead, NULL)) 308 { 309 ShowLastWin32Error(Globals.hMainWnd); 310 goto done; 311 } 312 313 /* Set data according to the clipboard file format ID */ 314 switch (wFileIdentifier) 315 { 316 case CLIP_FMT_31: 317 SizeOfFileHeader = sizeof(CLIPFILEHEADER); 318 SizeOfFormatHeader = sizeof(CLIPFORMATHEADER); 319 pClipFileHeader = &ClipFileHeader; 320 pClipFormatArray = &ClipFormatArray; 321 break; 322 323 case CLIP_FMT_NT: 324 case CLIP_FMT_BK: 325 SizeOfFileHeader = sizeof(NTCLIPFILEHEADER); 326 SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER); 327 pClipFileHeader = &NtClipFileHeader; 328 pClipFormatArray = &NtClipFormatArray; 329 break; 330 331 default: 332 MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK); 333 goto done; 334 } 335 336 /* Completely read the header */ 337 SetFilePointer(hFile, 0, NULL, FILE_BEGIN); 338 if (!ReadFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesRead, NULL) || 339 dwBytesRead != SizeOfFileHeader) 340 { 341 ShowLastWin32Error(Globals.hMainWnd); 342 goto done; 343 } 344 345 /* Get header data */ 346 switch (wFileIdentifier) 347 { 348 case CLIP_FMT_31: 349 assert(wFileIdentifier == ((CLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier); 350 wFormatCount = ((CLIPFILEHEADER*)pClipFileHeader)->wFormatCount; 351 break; 352 353 case CLIP_FMT_NT: 354 case CLIP_FMT_BK: 355 assert(wFileIdentifier == ((NTCLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier); 356 wFormatCount = ((NTCLIPFILEHEADER*)pClipFileHeader)->wFormatCount; 357 break; 358 } 359 360 /* Loop through the format data array */ 361 for (i = 0; i < wFormatCount; i++) 362 { 363 if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 364 { 365 ShowLastWin32Error(Globals.hMainWnd); 366 goto done; 367 } 368 369 if (!ReadFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesRead, NULL)) 370 { 371 ShowLastWin32Error(Globals.hMainWnd); 372 goto done; 373 } 374 375 /* Get format data */ 376 switch (wFileIdentifier) 377 { 378 case CLIP_FMT_31: 379 dwFormatID = ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID; 380 dwLenData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData; 381 dwOffData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData; 382 szName = ((CLIPFORMATHEADER*)pClipFormatArray)->szName; 383 break; 384 385 case CLIP_FMT_NT: 386 case CLIP_FMT_BK: 387 dwFormatID = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID; 388 dwLenData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData; 389 dwOffData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData; 390 szName = ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName; 391 break; 392 } 393 394 switch (dwFormatID) 395 { 396 case CF_OWNERDISPLAY: 397 { 398 break; 399 } 400 401 case CF_DSPBITMAP: 402 case CF_BITMAP: 403 { 404 bResult = ClipboardReadBitmap(hFile, dwOffData, dwLenData); 405 break; 406 } 407 408 case CF_DSPMETAFILEPICT: 409 case CF_METAFILEPICT: 410 { 411 bResult = ClipboardReadMetafile(hFile, dwOffData, dwLenData); 412 break; 413 } 414 415 case CF_DSPENHMETAFILE: 416 case CF_ENHMETAFILE: 417 { 418 bResult = ClipboardReadEnhMetafile(hFile, dwOffData, dwLenData); 419 break; 420 } 421 422 case CF_PALETTE: 423 { 424 bResult = ClipboardReadPalette(hFile, dwOffData, dwLenData); 425 break; 426 } 427 428 default: 429 { 430 if ((dwFormatID < CF_PRIVATEFIRST) || (dwFormatID > CF_PRIVATELAST)) 431 { 432 bResult = ClipboardReadMemory(hFile, dwFormatID, dwOffData, dwLenData, wFileIdentifier, szName); 433 } 434 break; 435 } 436 } 437 438 if (!bResult) 439 ShowLastWin32Error(Globals.hMainWnd); 440 } 441 442 done: 443 if (hFile != INVALID_HANDLE_VALUE) 444 CloseHandle(hFile); 445 446 return; 447 } 448 449 void WriteClipboardFile(LPCWSTR lpFileName, WORD wFileIdentifier) 450 { 451 CLIPFILEHEADER ClipFileHeader; 452 CLIPFORMATHEADER ClipFormatArray; 453 NTCLIPFILEHEADER NtClipFileHeader; 454 NTCLIPFORMATHEADER NtClipFormatArray; 455 PVOID pClipFileHeader; 456 PVOID pClipFormatArray; 457 DWORD SizeOfFileHeader, SizeOfFormatHeader; 458 459 WORD wFormatCount; 460 DWORD dwFormatID; 461 DWORD dwLenData; 462 DWORD dwOffData; 463 // PVOID szName; 464 465 HANDLE hFile; 466 DWORD dwBytesWritten; 467 int i; 468 469 /* Create the file for write access */ 470 hFile = CreateFileW(lpFileName, GENERIC_WRITE, 0, NULL, 471 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 472 if (hFile == INVALID_HANDLE_VALUE) 473 { 474 ShowLastWin32Error(Globals.hMainWnd); 475 goto done; 476 } 477 478 wFormatCount = CountClipboardFormats(); 479 480 /* Select the file format and setup the header according to the clipboard file format ID */ 481 switch (wFileIdentifier) 482 { 483 case CLIP_FMT_31: 484 SizeOfFileHeader = sizeof(CLIPFILEHEADER); 485 SizeOfFormatHeader = sizeof(CLIPFORMATHEADER); 486 pClipFileHeader = &ClipFileHeader; 487 pClipFormatArray = &ClipFormatArray; 488 489 ClipFileHeader.wFileIdentifier = CLIP_FMT_31; // wFileIdentifier 490 ClipFileHeader.wFormatCount = wFormatCount; 491 break; 492 493 case CLIP_FMT_NT: 494 case CLIP_FMT_BK: 495 SizeOfFileHeader = sizeof(NTCLIPFILEHEADER); 496 SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER); 497 pClipFileHeader = &NtClipFileHeader; 498 pClipFormatArray = &NtClipFormatArray; 499 500 NtClipFileHeader.wFileIdentifier = CLIP_FMT_NT; // wFileIdentifier 501 NtClipFileHeader.wFormatCount = wFormatCount; 502 break; 503 504 default: 505 MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK); 506 goto done; 507 } 508 509 /* Write the header */ 510 SetFilePointer(hFile, 0, NULL, FILE_BEGIN); 511 if (!WriteFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesWritten, NULL) || 512 dwBytesWritten != SizeOfFileHeader) 513 { 514 ShowLastWin32Error(Globals.hMainWnd); 515 goto done; 516 } 517 518 /* Compute where the data should start (after the file header and the format array) */ 519 dwOffData = SizeOfFileHeader + wFormatCount * SizeOfFormatHeader; 520 521 /* Loop through each format and save the data */ 522 i = 0; 523 dwFormatID = EnumClipboardFormats(0); 524 while (dwFormatID) 525 { 526 if (i >= wFormatCount) 527 { 528 /* Must never happen! */ 529 assert(FALSE); 530 break; 531 } 532 533 /* Write the clipboard data at the specified offset, and retrieve its length */ 534 if (!ClipboardWriteMemory(hFile, dwFormatID, dwOffData, &dwLenData)) 535 goto Cont; 536 537 /* Write the format data header */ 538 switch (wFileIdentifier) 539 { 540 case CLIP_FMT_31: 541 ZeroMemory(pClipFormatArray, sizeof(CLIPFORMATHEADER)); 542 ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID; 543 ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData = dwLenData; 544 ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData = dwOffData; 545 RetrieveClipboardFormatName(Globals.hInstance, 546 dwFormatID, 547 FALSE, 548 ((CLIPFORMATHEADER*)pClipFormatArray)->szName, 549 ARRAYSIZE(((CLIPFORMATHEADER*)pClipFormatArray)->szName)); 550 break; 551 552 case CLIP_FMT_NT: 553 case CLIP_FMT_BK: 554 ZeroMemory(pClipFormatArray, sizeof(NTCLIPFORMATHEADER)); 555 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID = dwFormatID; 556 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData = dwLenData; 557 ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData = dwOffData; 558 RetrieveClipboardFormatName(Globals.hInstance, 559 dwFormatID, 560 TRUE, 561 ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName, 562 ARRAYSIZE(((NTCLIPFORMATHEADER*)pClipFormatArray)->szName)); 563 break; 564 } 565 566 if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 567 { 568 ShowLastWin32Error(Globals.hMainWnd); 569 goto done; 570 } 571 572 if (!WriteFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesWritten, NULL)) 573 { 574 ShowLastWin32Error(Globals.hMainWnd); 575 goto done; 576 } 577 578 /* Adjust the offset for the next data stream */ 579 dwOffData += dwLenData; 580 581 Cont: 582 i++; 583 dwFormatID = EnumClipboardFormats(dwFormatID); 584 } 585 586 done: 587 if (hFile != INVALID_HANDLE_VALUE) 588 CloseHandle(hFile); 589 590 return; 591 } 592