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