diff --git a/dlls/gdi32/enhmetafile.c b/dlls/gdi32/enhmetafile.c index 17ccd1f5a02..c251b4ef7ca 100644 --- a/dlls/gdi32/enhmetafile.c +++ b/dlls/gdi32/enhmetafile.c @@ -2686,6 +2686,59 @@ UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf, return infoForCallBack.cEntries; } +/****************************************************************** + * extract_emf_from_comment + * + * If the WMF was created by GetWinMetaFileBits, then extract the + * original EMF that is stored in MFCOMMENT chunks. + */ +static HENHMETAFILE extract_emf_from_comment( const BYTE *buf, UINT mf_size ) +{ + METAHEADER *mh = (METAHEADER *)buf; + METARECORD *mr; + emf_in_wmf_comment *chunk; + WORD checksum = 0; + DWORD size = 0, remaining, chunks; + BYTE *emf_bits = NULL, *ptr; + UINT offset; + HENHMETAFILE emf = NULL; + + if (mf_size < sizeof(*mh)) return NULL; + + for (offset = mh->mtHeaderSize * 2; offset < mf_size; offset += (mr->rdSize * 2)) + { + mr = (METARECORD *)((char *)mh + offset); + chunk = (emf_in_wmf_comment *)(mr->rdParm + 2); + + if (mr->rdFunction != META_ESCAPE || mr->rdParm[0] != MFCOMMENT) goto done; + if (chunk->magic != WMFC_MAGIC) goto done; + + if (!emf_bits) + { + size = remaining = chunk->emf_size; + chunks = chunk->num_chunks; + emf_bits = ptr = HeapAlloc( GetProcessHeap(), 0, size ); + if (!emf_bits) goto done; + } + if (chunk->chunk_size > remaining) goto done; + remaining -= chunk->chunk_size; + if (chunk->remaining_size != remaining) goto done; + memcpy( ptr, chunk->emf_data, chunk->chunk_size ); + ptr += chunk->chunk_size; + if (--chunks == 0) break; + } + + for (offset = 0; offset < mf_size / 2; offset++) + checksum += *((WORD *)buf + offset); + if (checksum) goto done; + + emf = SetEnhMetaFileBits( size, emf_bits ); + +done: + HeapFree( GetProcessHeap(), 0, emf_bits ); + return emf; +} + typedef struct gdi_mf_comment { DWORD ident; @@ -2722,6 +2775,9 @@ HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer, const BYTE *lpbBuffer, HDC return NULL; } + ret = extract_emf_from_comment( lpbBuffer, cbBuffer ); + if (ret) return ret; + if(!hdcRef) hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL); diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index cde9867d087..08a5d3b6fb0 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -311,6 +311,27 @@ extern void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc) DECLSPEC_HIDDEN; extern HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh) DECLSPEC_HIDDEN; extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOOL unicode ) DECLSPEC_HIDDEN; +/* Format of comment record added by GetWinMetaFileBits */ +#include +typedef struct +{ + DWORD magic; /* WMFC */ + WORD unk04; /* 1 */ + WORD unk06; /* 0 */ + WORD unk08; /* 0 */ + WORD unk0a; /* 1 */ + WORD checksum; + DWORD unk0e; /* 0 */ + DWORD num_chunks; + DWORD chunk_size; + DWORD remaining_size; + DWORD emf_size; + BYTE emf_data[1]; +} emf_in_wmf_comment; +#include + +#define WMFC_MAGIC 0x43464d57 + /* path.c */ extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/metafile.c b/dlls/gdi32/metafile.c index 925d6481337..c7e25a7fa8e 100644 --- a/dlls/gdi32/metafile.c +++ b/dlls/gdi32/metafile.c @@ -1114,26 +1114,6 @@ UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf ) return mfSize; } -#include -typedef struct -{ - DWORD magic; /* WMFC */ - WORD unk04; /* 1 */ - WORD unk06; /* 0 */ - WORD unk08; /* 0 */ - WORD unk0a; /* 1 */ - WORD checksum; - DWORD unk0e; /* 0 */ - DWORD num_chunks; - DWORD chunk_size; - DWORD remaining_size; - DWORD emf_size; - BYTE emf_data[1]; -} emf_in_wmf_comment; -#include - -static const DWORD wmfc_magic = 0x43464d57; - /****************************************************************** * add_mf_comment * @@ -1158,7 +1138,7 @@ static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf) chunk = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment, emf_data[max_chunk_size])); if(!chunk) goto end; - chunk->magic = wmfc_magic; + chunk->magic = WMFC_MAGIC; chunk->unk04 = 1; chunk->unk06 = 0; chunk->unk08 = 0; diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c index 9a5c1a58d02..79f072b9cca 100644 --- a/dlls/gdi32/tests/metafile.c +++ b/dlls/gdi32/tests/metafile.c @@ -3249,16 +3249,17 @@ static BOOL near_match(int x, int y) static void getwinmetafilebits(UINT mode, int scale, RECT *rc) { - HENHMETAFILE emf; + HENHMETAFILE emf, emf2; HDC display_dc, emf_dc; - ENHMETAHEADER *enh_header; - UINT size, emf_size, i; + ENHMETAHEADER *enh_header, *enh2_header; + UINT size, emf_size, i, emf2_size; WORD check = 0; DWORD rec_num = 0; METAHEADER *mh = NULL; METARECORD *rec; INT horz_res, vert_res, horz_size, vert_size; INT curve_caps, line_caps, poly_caps; + METAFILEPICT mfp; display_dc = GetDC(NULL); ok(display_dc != NULL, "display_dc is NULL\n"); @@ -3401,6 +3402,21 @@ static void getwinmetafilebits(UINT mode, int scale, RECT *rc) rec = (METARECORD*)((WORD*)rec + rec->rdSize); } + /* Show that we get the original back when we do the reverse conversion. + mfp is ignored in this case. */ + mfp.mm = MM_ISOTROPIC; + mfp.xExt = 0xcafe; + mfp.yExt = 0xbeef; + emf2 = SetWinMetaFileBits( size, (BYTE*)mh, NULL, &mfp ); + ok( !!emf2, "got NULL\n" ); + emf2_size = GetEnhMetaFileBits( emf2, 0, NULL ); + enh2_header = HeapAlloc( GetProcessHeap(), 0, emf2_size ); + emf2_size = GetEnhMetaFileBits( emf2, emf2_size, (BYTE*)enh2_header ); + ok( emf_size == emf2_size, "%d %d\n", emf_size, emf2_size ); + ok( !memcmp( enh_header, enh2_header, emf_size ), "mismatch\n" ); + HeapFree( GetProcessHeap(), 0, enh2_header ); + DeleteEnhMetaFile( emf2 ); + end: HeapFree(GetProcessHeap(), 0, mh); HeapFree(GetProcessHeap(), 0, enh_header);