From 8b028fbdc87a2f31e813d0dac6bb4aafb7bd3d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sat, 13 Feb 2016 16:08:09 +0000 Subject: [PATCH] [CLIPBRD]: Complete the read support from .clp clipboard files to be actually able to read files saved with the Windows 2k3 clipboard. There actually exist two clipboard file formats, so-called "Win3.1" and a "WinNT" formats. Strangely enough Win2k (and Win2k3) clipboard viewer always save the files under the "Win3.1" format, whichever one you select. I discovered the subtle difference between those two formats by looking at a very old MSDN sample program "EMFDCODE (Enhanced Metafile Decoder)" by Dennis Crain (see https://web.archive.org/web/20080406095812/http://msdn.microsoft.com/archive/en-us/dnargdi/html/msdn_emfdcode.asp? ) that still can be found on the Internet... CORE-10550 #comment Read support fixed in r70730. svn path=/trunk/; revision=70730 --- reactos/base/applications/clipbrd/clipbrd.c | 12 +- reactos/base/applications/clipbrd/fileutils.c | 202 ++++++++++++++---- reactos/base/applications/clipbrd/fileutils.h | 37 +++- reactos/base/applications/clipbrd/precomp.h | 2 + 4 files changed, 195 insertions(+), 58 deletions(-) diff --git a/reactos/base/applications/clipbrd/clipbrd.c b/reactos/base/applications/clipbrd/clipbrd.c index 28f85f51cdf..78e4eb35043 100644 --- a/reactos/base/applications/clipbrd/clipbrd.c +++ b/reactos/base/applications/clipbrd/clipbrd.c @@ -318,18 +318,18 @@ static void ClipboardPaintHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP break; } - case CF_ENHMETAFILE: - { - PlayEnhMetaFileFromClipboard(hdc, &rc); - break; - } - case CF_METAFILEPICT: { PlayMetaFileFromClipboard(hdc, &rc); break; } + case CF_ENHMETAFILE: + { + PlayEnhMetaFileFromClipboard(hdc, &rc); + break; + } + default: { DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT, hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX); diff --git a/reactos/base/applications/clipbrd/fileutils.c b/reactos/base/applications/clipbrd/fileutils.c index dd0cc967cc1..2dfca5d87f6 100644 --- a/reactos/base/applications/clipbrd/fileutils.c +++ b/reactos/base/applications/clipbrd/fileutils.c @@ -4,6 +4,7 @@ * FILE: base/applications/clipbrd/fileutils.c * PURPOSE: Clipboard file format helper functions. * PROGRAMMERS: Ricardo Hanke + * Hermes Belusca-Maito */ #include "precomp.h" @@ -16,9 +17,7 @@ static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLe hData = GlobalAlloc(GHND, dwLength); if (!hData) - { return NULL; - } lpData = GlobalLock(hData); if (!lpData) @@ -46,20 +45,22 @@ static HGLOBAL ClipboardReadMemoryBlock(HANDLE hFile, DWORD dwOffset, DWORD dwLe return hData; } -static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, LPCWSTR lpFormatName) +static BOOL ClipboardReadMemory(HANDLE hFile, DWORD dwFormat, DWORD dwOffset, DWORD dwLength, WORD FileIdentifier, PVOID lpFormatName) { HGLOBAL hData; DWORD dwTemp; hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); if (!hData) - { return FALSE; - } if ((dwFormat >= 0xC000) && (dwFormat <= 0xFFFF)) { - dwTemp = RegisterClipboardFormatW(lpFormatName); + if (FileIdentifier == CLIP_FMT_31) + dwTemp = RegisterClipboardFormatA((LPCSTR)lpFormatName); + else if ((FileIdentifier == CLIP_FMT_NT) || (FileIdentifier == CLIP_FMT_BK)) + dwTemp = RegisterClipboardFormatW((LPCWSTR)lpFormatName); + if (!dwTemp) { GlobalFree(hData); @@ -120,6 +121,45 @@ static BOOL ClipboardReadPalette(HANDLE hFile, DWORD dwOffset, DWORD dwLength) return TRUE; } +static BOOL ClipboardReadMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength) +{ + HMETAFILE hMf; + HGLOBAL hData; + LPVOID lpData; + + hData = ClipboardReadMemoryBlock(hFile, dwOffset, dwLength); + if (!hData) + { + return FALSE; + } + + lpData = GlobalLock(hData); + if (!lpData) + { + GlobalFree(hData); + return FALSE; + } + + hMf = SetMetaFileBitsEx(dwLength, lpData); + + GlobalUnlock(hData); + GlobalFree(hData); + + if (!hMf) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + if (!SetClipboardData(CF_METAFILEPICT, hMf)) + { + DeleteMetaFile(hMf); + return FALSE; + } + + return TRUE; +} + static BOOL ClipboardReadEnhMetafile(HANDLE hFile, DWORD dwOffset, DWORD dwLength) { HENHMETAFILE hEmf; @@ -202,13 +242,27 @@ static BOOL ClipboardReadBitmap(HANDLE hFile, DWORD dwOffset, DWORD dwLength) void ReadClipboardFile(LPCWSTR lpFileName) { - CLIPBOARDFILEHEADER cfhFileHeader; - CLIPBOARDFORMATHEADER *cfhFormatArray = NULL; + CLIPFILEHEADER ClipFileHeader; + CLIPFORMATHEADER ClipFormatArray; + NTCLIPFILEHEADER NtClipFileHeader; + NTCLIPFORMATHEADER NtClipFormatArray; + PVOID pClipFileHeader; + PVOID pClipFormatArray; + DWORD SizeOfFileHeader, SizeOfFormatHeader; + + WORD wFileIdentifier; + WORD wFormatCount; + DWORD dwFormatID; + DWORD dwLenData; + DWORD dwOffData; + PVOID szName; + HANDLE hFile; DWORD dwBytesRead; BOOL bResult; int i; + /* Open the file */ hFile = CreateFileW(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { @@ -216,39 +270,99 @@ void ReadClipboardFile(LPCWSTR lpFileName) goto done; } - if (!ReadFile(hFile, &cfhFileHeader, sizeof(cfhFileHeader), &dwBytesRead, NULL)) + /* Just read enough bytes to get the clipboard file format ID */ + if (!ReadFile(hFile, &wFileIdentifier, sizeof(wFileIdentifier), &dwBytesRead, NULL)) + { + ShowLastWin32Error(Globals.hMainWnd); + goto done; + } + SetFilePointer(hFile, 0, NULL, FILE_BEGIN); + + /* Set data according to the clipboard file format ID */ + switch (wFileIdentifier) + { + case CLIP_FMT_31: + SizeOfFileHeader = sizeof(CLIPFILEHEADER); + SizeOfFormatHeader = sizeof(CLIPFORMATHEADER); + pClipFileHeader = &ClipFileHeader; + pClipFormatArray = &ClipFormatArray; + MessageBox(Globals.hMainWnd, L"We have a Win3.11 clipboard file!", L"File format", 0); + break; + + case CLIP_FMT_NT: + case CLIP_FMT_BK: + SizeOfFileHeader = sizeof(NTCLIPFILEHEADER); + SizeOfFormatHeader = sizeof(NTCLIPFORMATHEADER); + pClipFileHeader = &NtClipFileHeader; + pClipFormatArray = &NtClipFormatArray; + MessageBox(Globals.hMainWnd, L"We have a WinNT clipboard file!", L"File format", 0); + break; + + default: + MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK); + goto done; + } + + /* Completely read the header */ + if (!ReadFile(hFile, pClipFileHeader, SizeOfFileHeader, &dwBytesRead, NULL) || + dwBytesRead != SizeOfFileHeader) { ShowLastWin32Error(Globals.hMainWnd); goto done; } - if ((cfhFileHeader.wFileIdentifier != CLIPBOARD_FORMAT_NT) && (cfhFileHeader.wFileIdentifier != CLIPBOARD_FORMAT_BK)) + /* Get header data */ + switch (wFileIdentifier) { - MessageBoxRes(Globals.hMainWnd, Globals.hInstance, ERROR_INVALID_FILE_FORMAT, 0, MB_ICONSTOP | MB_OK); - goto done; - } + case CLIP_FMT_31: + assert(wFileIdentifier == ((CLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier); + wFormatCount = ((CLIPFILEHEADER*)pClipFileHeader)->wFormatCount; + break; - cfhFormatArray = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cfhFileHeader.wFormatCount * sizeof(CLIPBOARDFORMATHEADER)); - if (!cfhFormatArray) - { - SetLastError(ERROR_OUTOFMEMORY); - ShowLastWin32Error(Globals.hMainWnd); - goto done; + case CLIP_FMT_NT: + case CLIP_FMT_BK: + assert(wFileIdentifier == ((NTCLIPFILEHEADER*)pClipFileHeader)->wFileIdentifier); + wFormatCount = ((NTCLIPFILEHEADER*)pClipFileHeader)->wFormatCount; + break; } - - if (!ReadFile(hFile, cfhFormatArray, cfhFileHeader.wFormatCount * sizeof(CLIPBOARDFORMATHEADER), &dwBytesRead, NULL)) + + /* Loop through the data array */ + for (i = 0; i < wFormatCount; i++) { - ShowLastWin32Error(Globals.hMainWnd); - goto done; - } + if (SetFilePointer(hFile, SizeOfFileHeader + i * SizeOfFormatHeader, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + { + ShowLastWin32Error(Globals.hMainWnd); + goto done; + } - for (i = 0; i < cfhFileHeader.wFormatCount; i++) - { - switch (cfhFormatArray[i].dwFormatID) + if (!ReadFile(hFile, pClipFormatArray, SizeOfFormatHeader, &dwBytesRead, NULL)) + { + ShowLastWin32Error(Globals.hMainWnd); + goto done; + } + + /* Get format data */ + switch (wFileIdentifier) + { + case CLIP_FMT_31: + dwFormatID = ((CLIPFORMATHEADER*)pClipFormatArray)->dwFormatID; + dwLenData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwLenData; + dwOffData = ((CLIPFORMATHEADER*)pClipFormatArray)->dwOffData; + szName = ((CLIPFORMATHEADER*)pClipFormatArray)->szName; + break; + + case CLIP_FMT_NT: + case CLIP_FMT_BK: + dwFormatID = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwFormatID; + dwLenData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwLenData; + dwOffData = ((NTCLIPFORMATHEADER*)pClipFormatArray)->dwOffData; + szName = ((NTCLIPFORMATHEADER*)pClipFormatArray)->szName; + break; + } + + switch (dwFormatID) { case CF_OWNERDISPLAY: - case CF_DSPMETAFILEPICT: - case CF_METAFILEPICT: { break; } @@ -256,49 +370,47 @@ void ReadClipboardFile(LPCWSTR lpFileName) case CF_BITMAP: case CF_DSPBITMAP: { - bResult = ClipboardReadBitmap(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData); + bResult = ClipboardReadBitmap(hFile, dwOffData, dwLenData); break; } - case CF_DSPENHMETAFILE: - case CF_ENHMETAFILE: + case CF_METAFILEPICT: + case CF_DSPMETAFILEPICT: { - bResult = ClipboardReadEnhMetafile(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData); + bResult = ClipboardReadMetafile(hFile, dwOffData, dwLenData); + break; + } + + case CF_ENHMETAFILE: + case CF_DSPENHMETAFILE: + { + bResult = ClipboardReadEnhMetafile(hFile, dwOffData, dwLenData); break; } case CF_PALETTE: { - bResult = ClipboardReadPalette(hFile, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData); + bResult = ClipboardReadPalette(hFile, dwOffData, dwLenData); break; } default: { - if ((cfhFormatArray[i].dwFormatID < CF_PRIVATEFIRST) || (cfhFormatArray[i].dwFormatID > CF_PRIVATELAST)) + if ((dwFormatID < CF_PRIVATEFIRST) || (dwFormatID > CF_PRIVATELAST)) { - bResult = ClipboardReadMemory(hFile, cfhFormatArray[i].dwFormatID, cfhFormatArray[i].dwOffData, cfhFormatArray[i].dwLenData, cfhFormatArray[i].szName); + bResult = ClipboardReadMemory(hFile, dwFormatID, dwOffData, dwLenData, wFileIdentifier, szName); } break; } } if (!bResult) - { ShowLastWin32Error(Globals.hMainWnd); - } } done: if (hFile != INVALID_HANDLE_VALUE) - { CloseHandle(hFile); - } - - if (cfhFormatArray) - { - HeapFree(GetProcessHeap(), 0, cfhFormatArray); - } return; } diff --git a/reactos/base/applications/clipbrd/fileutils.h b/reactos/base/applications/clipbrd/fileutils.h index e9055ba5089..b74c0c33474 100644 --- a/reactos/base/applications/clipbrd/fileutils.h +++ b/reactos/base/applications/clipbrd/fileutils.h @@ -4,26 +4,49 @@ * FILE: base/applications/clipbrd/fileutils.h * PURPOSE: Clipboard file format helper functions. * PROGRAMMERS: Ricardo Hanke + * Hermes Belusca-Maito */ -#define CLIPBOARD_FORMAT_31 0xC350 -#define CLIPBOARD_FORMAT_NT 0xC351 -#define CLIPBOARD_FORMAT_BK 0xC352 +#define CLIP_FMT_31 0xC350 +#define CLIP_FMT_NT 0xC351 +#define CLIP_FMT_BK 0xC352 #define MAX_FMT_NAME_LEN 79 -typedef struct _CLIPBOARDFILEHEADER +/* + * Win3.1 Clipboard File Format (default) + */ +#pragma pack(push, 1) +typedef struct _CLIPFILEHEADER { WORD wFileIdentifier; WORD wFormatCount; -} CLIPBOARDFILEHEADER; +} CLIPFILEHEADER; -typedef struct _CLIPBOARDFORMATHEADER +typedef struct _CLIPFORMATHEADER +{ + WORD dwFormatID; + DWORD dwLenData; + DWORD dwOffData; + CHAR szName[MAX_FMT_NAME_LEN]; +} CLIPFORMATHEADER; +#pragma pack(pop) + +/* + * NT Clipboard File Format + */ +typedef struct _NTCLIPFILEHEADER +{ + WORD wFileIdentifier; + WORD wFormatCount; +} NTCLIPFILEHEADER; + +typedef struct _NTCLIPFORMATHEADER { DWORD dwFormatID; DWORD dwLenData; DWORD dwOffData; WCHAR szName[MAX_FMT_NAME_LEN]; -} CLIPBOARDFORMATHEADER; +} NTCLIPFORMATHEADER; void ReadClipboardFile(LPCWSTR lpFileName); void WriteClipboardFile(LPCWSTR lpFileName); diff --git a/reactos/base/applications/clipbrd/precomp.h b/reactos/base/applications/clipbrd/precomp.h index c03b2b90116..acea48a9c80 100644 --- a/reactos/base/applications/clipbrd/precomp.h +++ b/reactos/base/applications/clipbrd/precomp.h @@ -5,6 +5,8 @@ #include +#include + #include #include #include