Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 239 ++++++++++++++++++++++++------------------------- 1 file changed, 119 insertions(+), 120 deletions(-)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index c550c75cd3..f46f71215d 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -775,16 +775,118 @@ static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry) return hr; }
-static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry, - IStorage *storage, IStream **stream) +static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header) { - WCHAR wszName[] = {2,'O','l','e','P','r','e','s', + if (entry->fmtetc.ptd) + FIXME("ptd not serialized\n"); + header->tdSize = sizeof(header->tdSize); + header->dvAspect = entry->fmtetc.dwAspect; + header->lindex = entry->fmtetc.lindex; + header->advf = entry->advise_flags; + header->unknown7 = 0; + header->dwObjectExtentX = 0; + header->dwObjectExtentY = 0; + header->dwSize = 0; +} + +static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream) +{ + HRESULT hr = S_OK; + int data_size = GlobalSize(entry->stgmedium.u.hGlobal); + BITMAPINFO *bmi = GlobalLock(entry->stgmedium.u.hGlobal); + + if (!contents) + { + PresentationDataHeader header; + + init_stream_header(entry, &header); + hr = write_clipformat(stream, entry->fmtetc.cfFormat); + if (FAILED(hr)) goto end; + if (data_size) + { + header.dwSize = data_size; + /* Size in units of 0.01mm (ie. MM_HIMETRIC) */ + if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0) + { + header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter); + header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter); + } + else + { + HDC hdc = GetDC(0); + header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX)); + header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY)); + ReleaseDC(0, hdc); + } + } + hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, bmi, data_size, NULL); + } + +end: + if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal); + return hr; +} + +static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream) +{ + HRESULT hr = S_OK; + int data_size = 0; + void *data = NULL; + METAFILEPICT *mfpict = NULL; + + if (!contents) + { + PresentationDataHeader header; + + init_stream_header(entry, &header); + hr = write_clipformat(stream, entry->fmtetc.cfFormat); + if (FAILED(hr)) return hr; + if (entry->stgmedium.tymed != TYMED_NULL) + { + mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict); + if (!mfpict) + return DV_E_STGMEDIUM; + data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); + header.dwObjectExtentX = mfpict->xExt; + header.dwObjectExtentY = mfpict->yExt; + header.dwSize = data_size; + data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); + if (!data) + { + GlobalUnlock(entry->stgmedium.u.hMetaFilePict); + return E_OUTOFMEMORY; + } + GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data); + GlobalUnlock(entry->stgmedium.u.hMetaFilePict); + } + hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, data, data_size, NULL); + HeapFree(GetProcessHeap(), 0, data); + } + + return hr; +} + +static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0}; + +static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage, + BOOL contents, IStream **stream) +{ + WCHAR pres[] = {2,'O','l','e','P','r','e','s', '0' + (cache_entry->stream_number / 100) % 10, '0' + (cache_entry->stream_number / 10) % 10, '0' + cache_entry->stream_number % 10, 0}; + const WCHAR *name;
- /* FIXME: cache the created stream in This? */ - return IStorage_CreateStream(storage, wszName, + if (contents) + name = CONTENTS; + else + name = pres; + + return IStorage_CreateStream(storage, name, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0, 0, stream); } @@ -792,130 +894,29 @@ static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry, static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage, BOOL same_as_load) { - PresentationDataHeader header; HRESULT hr; - IStream *pres_stream; - void *data = NULL; + IStream *stream; + BOOL contents = (cache_entry->id == 1);
TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
- hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream); + hr = create_stream(cache_entry, storage, contents, &stream); if (FAILED(hr)) return hr;
- hr = write_clipformat(pres_stream, cache_entry->fmtetc.cfFormat); - if (FAILED(hr)) - return hr; - - if (cache_entry->fmtetc.ptd) - FIXME("ptd not serialized\n"); - header.tdSize = sizeof(header.tdSize); - header.dvAspect = cache_entry->fmtetc.dwAspect; - header.lindex = cache_entry->fmtetc.lindex; - header.advf = cache_entry->advise_flags; - header.unknown7 = 0; - header.dwObjectExtentX = 0; - header.dwObjectExtentY = 0; - header.dwSize = 0; - - /* size the data */ - switch (cache_entry->fmtetc.cfFormat) - { - case CF_METAFILEPICT: - { - if (cache_entry->stgmedium.tymed != TYMED_NULL) - { - const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict); - if (!mfpict) - { - IStream_Release(pres_stream); - return DV_E_STGMEDIUM; - } - header.dwObjectExtentX = mfpict->xExt; - header.dwObjectExtentY = mfpict->yExt; - header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); - GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); - } - break; - } - case CF_DIB: - { - header.dwSize = GlobalSize(cache_entry->stgmedium.u.hGlobal); - if (header.dwSize) - { - const BITMAPINFO *bmi = GlobalLock(cache_entry->stgmedium.u.hGlobal); - /* Size in units of 0.01mm (ie. MM_HIMETRIC) */ - if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0) - { - header.dwObjectExtentX = MulDiv( bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter ); - header.dwObjectExtentY = MulDiv( bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter ); - } - else - { - HDC hdc = GetDC(0); - header.dwObjectExtentX = MulDiv( bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX) ); - header.dwObjectExtentY = MulDiv( bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY) ); - ReleaseDC(0, hdc); - } - GlobalUnlock(cache_entry->stgmedium.u.hGlobal); - } - break; - } - default: - break; - } - - /* - * Write the header. - */ - hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader), - NULL); - if (FAILED(hr)) - { - IStream_Release(pres_stream); - return hr; - } - - /* get the data */ switch (cache_entry->fmtetc.cfFormat) { - case CF_METAFILEPICT: - { - if (cache_entry->stgmedium.tymed != TYMED_NULL) - { - const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict); - if (!mfpict) - { - IStream_Release(pres_stream); - return DV_E_STGMEDIUM; - } - if (header.dwSize) - { - data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); - GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data); - GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); - if (data) - { - hr = IStream_Write(pres_stream, data, header.dwSize, NULL); - HeapFree(GetProcessHeap(), 0, data); - } - } - } - break; - } - case CF_DIB: - { - data = GlobalLock(cache_entry->stgmedium.u.hGlobal); - if (header.dwSize) - hr = IStream_Write(pres_stream, data, header.dwSize, NULL); - GlobalUnlock(cache_entry->stgmedium.u.hGlobal); - break; - } - default: - break; + case CF_DIB: + hr = save_dib(cache_entry, contents, stream); + break; + case CF_METAFILEPICT: + hr = save_mfpict(cache_entry, contents, stream); + break; + default: + FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat); }
- IStream_Release(pres_stream); + IStream_Release(stream); return hr; }
@@ -1651,8 +1652,6 @@ static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *s return add_cache_entry( This, fmt, 0, stm, contents_stream ); }
-static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0}; - /************************************************************************ * DataCache_Load (IPersistStorage) *
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index f46f71215d..945d2fea95 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -823,6 +823,19 @@ static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream) if (hr == S_OK && data_size) hr = IStream_Write(stream, bmi, data_size, NULL); } + else + { + BITMAPFILEHEADER bmp_fhdr; + + bmp_fhdr.bfType = 0x4d42; + bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER); + bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0; + if (data_size) + bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER); + hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, bmi, data_size, NULL); + }
end: if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal);
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index 945d2fea95..869f122a38 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -842,6 +842,18 @@ end: return hr; }
+#include <pshpack2.h> +struct meta_placeable +{ + DWORD key; + WORD hwmf; + WORD bounding_box[4]; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#include <poppack.h> + static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream) { HRESULT hr = S_OK; @@ -879,6 +891,50 @@ static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream hr = IStream_Write(stream, data, data_size, NULL); HeapFree(GetProcessHeap(), 0, data); } + else + { + struct meta_placeable meta_place_rec; + WORD *check; + + if (entry->stgmedium.tymed != TYMED_NULL) + { + mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict); + if (!mfpict) + return DV_E_STGMEDIUM; + data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); + data = HeapAlloc(GetProcessHeap(), 0, data_size); + if (!data) + { + GlobalUnlock(entry->stgmedium.u.hMetaFilePict); + return E_OUTOFMEMORY; + } + GetMetaFileBitsEx(mfpict->hMF, data_size, data); + } + + /* units are in 1/8th of a point (1 point is 1/72th of an inch) */ + meta_place_rec.key = 0x9ac6cdd7; + meta_place_rec.hwmf = 0; + meta_place_rec.inch = 576; + meta_place_rec.bounding_box[0] = 0; + meta_place_rec.bounding_box[1] = 0; + meta_place_rec.bounding_box[2] = 0; + meta_place_rec.bounding_box[3] = 0; + meta_place_rec.checksum = 0; + meta_place_rec.reserved = 0; + if (mfpict) + { + /* These values are rounded down so MulDiv won't do the right thing */ + meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540; + meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540; + GlobalUnlock(entry->stgmedium.u.hMetaFilePict); + } + for (check = (WORD *)&meta_place_rec; check != (WORD *)&meta_place_rec.checksum; check++) + meta_place_rec.checksum ^= *check; + hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, data, data_size, NULL); + HeapFree(GetProcessHeap(), 0, data); + }
return hr; }
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index 869f122a38..b418301276 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -939,8 +939,61 @@ static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream return hr; }
+static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream) +{ + HRESULT hr = S_OK; + int data_size = 0; + BYTE *data; + + if (!contents) + { + PresentationDataHeader header; + METAFILEPICT *mfpict; + HDC hdc = GetDC(0); + + init_stream_header(entry, &header); + hr = write_clipformat(stream, entry->fmtetc.cfFormat); + if (FAILED(hr)) + { + ReleaseDC(0, hdc); + return hr; + } + data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc); + header.dwSize = data_size; + data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); + if (!data) + { + ReleaseDC(0, hdc); + return E_OUTOFMEMORY; + } + GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc); + ReleaseDC(0, hdc); + mfpict = (METAFILEPICT *)data; + header.dwObjectExtentX = mfpict->xExt; + header.dwObjectExtentY = mfpict->yExt; + hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, data, data_size, NULL); + HeapFree(GetProcessHeap(), 0, data); + } + else + { + data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL); + data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size); + if (!data) return E_OUTOFMEMORY; + *((DWORD *)data) = sizeof(ENHMETAHEADER); + GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER)); + memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER)); + data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER); + if (hr == S_OK && data_size) + hr = IStream_Write(stream, data, data_size, NULL); + HeapFree(GetProcessHeap(), 0, data); + } + + return hr; +} + static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0}; - static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage, BOOL contents, IStream **stream) { @@ -981,6 +1034,9 @@ static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storag case CF_METAFILEPICT: hr = save_mfpict(cache_entry, contents, stream); break; + case CF_ENHMETAFILE: + hr = save_emf(cache_entry, contents, stream); + break; default: FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat); }
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/tests/ole2.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)
diff --git a/dlls/ole32/tests/ole2.c b/dlls/ole32/tests/ole2.c index ca6756a6e5..a8cbcdeb1e 100644 --- a/dlls/ole32/tests/ole2.c +++ b/dlls/ole32/tests/ole2.c @@ -229,6 +229,16 @@ static void create_bitmap( STGMEDIUM *med ) med->pUnkForRelease = NULL; }
+static void create_emf(STGMEDIUM *med) +{ + HDC hdc = CreateEnhMetaFileW(NULL, NULL, NULL, NULL); + + Rectangle(hdc, 0, 0, 150, 300); + med->tymed = TYMED_ENHMF; + U(med)->hEnhMetaFile = CloseEnhMetaFile(hdc); + med->pUnkForRelease = NULL; +} + static void create_mfpict(STGMEDIUM *med) { METAFILEPICT *mf; @@ -4110,6 +4120,7 @@ static void get_stgdef(struct storage_def *stg_def, CLIPFORMAT cf, STGMEDIUM *st BYTE *data; int data_size; METAFILEPICT *mfpict; + HDC hdc;
switch (cf) { @@ -4149,6 +4160,27 @@ static void get_stgdef(struct storage_def *stg_def, CLIPFORMAT cf, STGMEDIUM *st stg_def->stream[stm_idx].data_size = data_size; stg_def->stream[stm_idx].data = data; break; + case CF_ENHMETAFILE: + if (!strcmp(stg_def->stream[stm_idx].name, "CONTENTS")) + { + data_size = GetEnhMetaFileBits(U(stg_med)->hEnhMetaFile, 0, NULL); + data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size); + *((DWORD *)data) = sizeof(ENHMETAHEADER); + GetEnhMetaFileBits(U(stg_med)->hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER)); + memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER)); + data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER); + } + else + { + hdc = GetDC(NULL); + data_size = GetWinMetaFileBits(U(stg_med)->hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc); + data = HeapAlloc(GetProcessHeap(), 0, data_size); + GetWinMetaFileBits(U(stg_med)->hEnhMetaFile, data_size, data, MM_ANISOTROPIC, hdc); + ReleaseDC(NULL, hdc); + } + stg_def->stream[stm_idx].data_size = data_size; + stg_def->stream[stm_idx].data = data; + break; } }
@@ -4162,6 +4194,9 @@ static void get_stgmedium(CLIPFORMAT cfFormat, STGMEDIUM *stgmedium) case CF_METAFILEPICT: create_mfpict(stgmedium); break; + case CF_ENHMETAFILE: + create_emf(stgmedium); + break; default: ok(0, "cf %x not implemented\n", cfFormat); } @@ -4206,6 +4241,42 @@ static void test_data_cache_save_data(void) &CLSID_WineTestOld, 1, { { "\2OlePres000", CF_METAFILEPICT, DVASPECT_CONTENT, 0, NULL, 0 } } } }, + { + { + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 1, 1, &CLSID_WineTest, + { + &CLSID_WineTestOld, 1, { { "\2OlePres000", CF_ENHMETAFILE, DVASPECT_CONTENT, 0, NULL, 0 } } + } + }, + { + { + { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, + }, + 1, 1, &CLSID_Picture_Dib, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT }, + }, + 1, 1, &CLSID_Picture_Metafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, + { + { + { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF }, + }, + 1, 1, &CLSID_Picture_EnhMetafile, + { + &CLSID_WineTestOld, 1, { { "CONTENTS", -1, 0, 0, NULL, 0 } } + } + }, { { { 0 }
Signed-off-by: Huw Davies huw@codeweavers.com