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
11 static HGLOBAL
ClipboardReadMemoryBlock(HANDLE hFile
, DWORD dwOffset
, DWORD dwLength
)
17 hData
= GlobalAlloc(GHND
, dwLength
);
21 lpData
= GlobalLock(hData
);
28 if (SetFilePointer(hFile
, dwOffset
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
35 if (!ReadFile(hFile
, lpData
, dwLength
, &dwBytesRead
, NULL
))
47 static BOOL
ClipboardReadMemory(HANDLE hFile
, DWORD dwFormat
, DWORD dwOffset
, DWORD dwLength
, WORD FileIdentifier
, PVOID lpFormatName
)
52 hData
= ClipboardReadMemoryBlock(hFile
, dwOffset
, dwLength
);
56 if ((dwFormat
>= 0xC000) && (dwFormat
<= 0xFFFF))
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
);
74 if (!SetClipboardData(dwTemp
, hData
))
83 static BOOL
ClipboardWriteMemory(HANDLE hFile
, DWORD dwFormat
, DWORD dwOffset
, PDWORD pdwLength
)
89 hData
= GetClipboardData(dwFormat
);
93 lpData
= GlobalLock(hData
);
97 *pdwLength
= GlobalSize(hData
);
99 if (SetFilePointer(hFile
, dwOffset
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
105 if (!WriteFile(hFile
, lpData
, *pdwLength
, &dwBytesWritten
, NULL
))
116 static BOOL
ClipboardReadPalette(HANDLE hFile
, DWORD dwOffset
, DWORD dwLength
)
118 LPLOGPALETTE lpPalette
;
122 hData
= ClipboardReadMemoryBlock(hFile
, dwOffset
, dwLength
);
128 lpPalette
= GlobalLock(hData
);
135 hPalette
= CreatePalette(lpPalette
);
140 SetLastError(ERROR_OUTOFMEMORY
);
147 if (!SetClipboardData(CF_PALETTE
, hPalette
))
149 DeleteObject(hPalette
);
156 static BOOL
ClipboardReadMetafile(HANDLE hFile
, DWORD dwOffset
, DWORD dwLength
)
162 hData
= ClipboardReadMemoryBlock(hFile
, dwOffset
, dwLength
);
168 lpData
= GlobalLock(hData
);
175 hMf
= SetMetaFileBitsEx(dwLength
, lpData
);
182 SetLastError(ERROR_OUTOFMEMORY
);
186 if (!SetClipboardData(CF_METAFILEPICT
, hMf
))
195 static BOOL
ClipboardReadEnhMetafile(HANDLE hFile
, DWORD dwOffset
, DWORD dwLength
)
201 hData
= ClipboardReadMemoryBlock(hFile
, dwOffset
, dwLength
);
207 lpData
= GlobalLock(hData
);
214 hEmf
= SetEnhMetaFileBits(dwLength
, lpData
);
221 SetLastError(ERROR_OUTOFMEMORY
);
225 if (!SetClipboardData(CF_ENHMETAFILE
, hEmf
))
227 DeleteEnhMetaFile(hEmf
);
234 static BOOL
ClipboardReadBitmap(HANDLE hFile
, DWORD dwOffset
, DWORD dwLength
)
240 hData
= ClipboardReadMemoryBlock(hFile
, dwOffset
, dwLength
);
246 lpBitmap
= GlobalLock(hData
);
253 lpBitmap
->bmBits
= lpBitmap
+ sizeof(BITMAP
) + 1;
255 hBitmap
= CreateBitmapIndirect(lpBitmap
);
262 SetLastError(ERROR_OUTOFMEMORY
);
266 if (!SetClipboardData(CF_BITMAP
, hBitmap
))
268 DeleteObject(hBitmap
);
275 void ReadClipboardFile(LPCWSTR lpFileName
)
277 CLIPFILEHEADER ClipFileHeader
;
278 CLIPFORMATHEADER ClipFormatArray
;
279 NTCLIPFILEHEADER NtClipFileHeader
;
280 NTCLIPFORMATHEADER NtClipFormatArray
;
281 PVOID pClipFileHeader
;
282 PVOID pClipFormatArray
;
283 DWORD SizeOfFileHeader
, SizeOfFormatHeader
;
285 WORD wFileIdentifier
;
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
)
302 ShowLastWin32Error(Globals
.hMainWnd
);
306 /* Just read enough bytes to get the clipboard file format ID */
307 if (!ReadFile(hFile
, &wFileIdentifier
, sizeof(wFileIdentifier
), &dwBytesRead
, NULL
))
309 ShowLastWin32Error(Globals
.hMainWnd
);
313 /* Set data according to the clipboard file format ID */
314 switch (wFileIdentifier
)
317 SizeOfFileHeader
= sizeof(CLIPFILEHEADER
);
318 SizeOfFormatHeader
= sizeof(CLIPFORMATHEADER
);
319 pClipFileHeader
= &ClipFileHeader
;
320 pClipFormatArray
= &ClipFormatArray
;
325 SizeOfFileHeader
= sizeof(NTCLIPFILEHEADER
);
326 SizeOfFormatHeader
= sizeof(NTCLIPFORMATHEADER
);
327 pClipFileHeader
= &NtClipFileHeader
;
328 pClipFormatArray
= &NtClipFormatArray
;
332 MessageBoxRes(Globals
.hMainWnd
, Globals
.hInstance
, ERROR_INVALID_FILE_FORMAT
, 0, MB_ICONSTOP
| MB_OK
);
336 /* Completely read the header */
337 SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
);
338 if (!ReadFile(hFile
, pClipFileHeader
, SizeOfFileHeader
, &dwBytesRead
, NULL
) ||
339 dwBytesRead
!= SizeOfFileHeader
)
341 ShowLastWin32Error(Globals
.hMainWnd
);
345 /* Get header data */
346 switch (wFileIdentifier
)
349 assert(wFileIdentifier
== ((CLIPFILEHEADER
*)pClipFileHeader
)->wFileIdentifier
);
350 wFormatCount
= ((CLIPFILEHEADER
*)pClipFileHeader
)->wFormatCount
;
355 assert(wFileIdentifier
== ((NTCLIPFILEHEADER
*)pClipFileHeader
)->wFileIdentifier
);
356 wFormatCount
= ((NTCLIPFILEHEADER
*)pClipFileHeader
)->wFormatCount
;
360 /* Loop through the format data array */
361 for (i
= 0; i
< wFormatCount
; i
++)
363 if (SetFilePointer(hFile
, SizeOfFileHeader
+ i
* SizeOfFormatHeader
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
365 ShowLastWin32Error(Globals
.hMainWnd
);
369 if (!ReadFile(hFile
, pClipFormatArray
, SizeOfFormatHeader
, &dwBytesRead
, NULL
))
371 ShowLastWin32Error(Globals
.hMainWnd
);
375 /* Get format data */
376 switch (wFileIdentifier
)
379 dwFormatID
= ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwFormatID
;
380 dwLenData
= ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwLenData
;
381 dwOffData
= ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwOffData
;
382 szName
= ((CLIPFORMATHEADER
*)pClipFormatArray
)->szName
;
387 dwFormatID
= ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwFormatID
;
388 dwLenData
= ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwLenData
;
389 dwOffData
= ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwOffData
;
390 szName
= ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->szName
;
396 case CF_OWNERDISPLAY
:
404 bResult
= ClipboardReadBitmap(hFile
, dwOffData
, dwLenData
);
408 case CF_DSPMETAFILEPICT
:
409 case CF_METAFILEPICT
:
411 bResult
= ClipboardReadMetafile(hFile
, dwOffData
, dwLenData
);
415 case CF_DSPENHMETAFILE
:
418 bResult
= ClipboardReadEnhMetafile(hFile
, dwOffData
, dwLenData
);
424 bResult
= ClipboardReadPalette(hFile
, dwOffData
, dwLenData
);
430 if ((dwFormatID
< CF_PRIVATEFIRST
) || (dwFormatID
> CF_PRIVATELAST
))
432 bResult
= ClipboardReadMemory(hFile
, dwFormatID
, dwOffData
, dwLenData
, wFileIdentifier
, szName
);
439 ShowLastWin32Error(Globals
.hMainWnd
);
443 if (hFile
!= INVALID_HANDLE_VALUE
)
449 void WriteClipboardFile(LPCWSTR lpFileName
, WORD wFileIdentifier
)
451 CLIPFILEHEADER ClipFileHeader
;
452 CLIPFORMATHEADER ClipFormatArray
;
453 NTCLIPFILEHEADER NtClipFileHeader
;
454 NTCLIPFORMATHEADER NtClipFormatArray
;
455 PVOID pClipFileHeader
;
456 PVOID pClipFormatArray
;
457 DWORD SizeOfFileHeader
, SizeOfFormatHeader
;
466 DWORD dwBytesWritten
;
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
)
474 ShowLastWin32Error(Globals
.hMainWnd
);
478 wFormatCount
= CountClipboardFormats();
480 /* Select the file format and setup the header according to the clipboard file format ID */
481 switch (wFileIdentifier
)
484 SizeOfFileHeader
= sizeof(CLIPFILEHEADER
);
485 SizeOfFormatHeader
= sizeof(CLIPFORMATHEADER
);
486 pClipFileHeader
= &ClipFileHeader
;
487 pClipFormatArray
= &ClipFormatArray
;
489 ClipFileHeader
.wFileIdentifier
= CLIP_FMT_31
; // wFileIdentifier
490 ClipFileHeader
.wFormatCount
= wFormatCount
;
495 SizeOfFileHeader
= sizeof(NTCLIPFILEHEADER
);
496 SizeOfFormatHeader
= sizeof(NTCLIPFORMATHEADER
);
497 pClipFileHeader
= &NtClipFileHeader
;
498 pClipFormatArray
= &NtClipFormatArray
;
500 NtClipFileHeader
.wFileIdentifier
= CLIP_FMT_NT
; // wFileIdentifier
501 NtClipFileHeader
.wFormatCount
= wFormatCount
;
505 MessageBoxRes(Globals
.hMainWnd
, Globals
.hInstance
, ERROR_INVALID_FILE_FORMAT
, 0, MB_ICONSTOP
| MB_OK
);
509 /* Write the header */
510 SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
);
511 if (!WriteFile(hFile
, pClipFileHeader
, SizeOfFileHeader
, &dwBytesWritten
, NULL
) ||
512 dwBytesWritten
!= SizeOfFileHeader
)
514 ShowLastWin32Error(Globals
.hMainWnd
);
518 /* Compute where the data should start (after the file header and the format array) */
519 dwOffData
= SizeOfFileHeader
+ wFormatCount
* SizeOfFormatHeader
;
521 /* Loop through each format and save the data */
523 dwFormatID
= EnumClipboardFormats(0);
526 if (i
>= wFormatCount
)
528 /* Must never happen! */
533 /* Write the clipboard data at the specified offset, and retrieve its length */
534 if (!ClipboardWriteMemory(hFile
, dwFormatID
, dwOffData
, &dwLenData
))
537 /* Write the format data header */
538 switch (wFileIdentifier
)
541 ZeroMemory(pClipFormatArray
, sizeof(CLIPFORMATHEADER
));
542 ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwFormatID
= dwFormatID
;
543 ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwLenData
= dwLenData
;
544 ((CLIPFORMATHEADER
*)pClipFormatArray
)->dwOffData
= dwOffData
;
545 RetrieveClipboardFormatName(Globals
.hInstance
,
548 ((CLIPFORMATHEADER
*)pClipFormatArray
)->szName
,
549 ARRAYSIZE(((CLIPFORMATHEADER
*)pClipFormatArray
)->szName
));
554 ZeroMemory(pClipFormatArray
, sizeof(NTCLIPFORMATHEADER
));
555 ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwFormatID
= dwFormatID
;
556 ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwLenData
= dwLenData
;
557 ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->dwOffData
= dwOffData
;
558 RetrieveClipboardFormatName(Globals
.hInstance
,
561 ((NTCLIPFORMATHEADER
*)pClipFormatArray
)->szName
,
562 ARRAYSIZE(((NTCLIPFORMATHEADER
*)pClipFormatArray
)->szName
));
566 if (SetFilePointer(hFile
, SizeOfFileHeader
+ i
* SizeOfFormatHeader
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
)
568 ShowLastWin32Error(Globals
.hMainWnd
);
572 if (!WriteFile(hFile
, pClipFormatArray
, SizeOfFormatHeader
, &dwBytesWritten
, NULL
))
574 ShowLastWin32Error(Globals
.hMainWnd
);
578 /* Adjust the offset for the next data stream */
579 dwOffData
+= dwLenData
;
583 dwFormatID
= EnumClipboardFormats(dwFormatID
);
587 if (hFile
!= INVALID_HANDLE_VALUE
)