Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 106 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 24 deletions(-)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index 325a98b33b..ff42e4d34a 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -547,6 +547,30 @@ static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); }
+static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) +{ + METAFILEPICT *pict; + HRESULT hr = E_FAIL; + UINT size; + void *bits; + + if (!(pict = GlobalLock( data ))) return hr; + + size = GetMetaFileBitsEx( pict->hMF, 0, NULL ); + if ((bits = HeapAlloc( GetProcessHeap(), 0, size ))) + { + GetMetaFileBitsEx( pict->hMF, size, bits ); + med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict ); + HeapFree( GetProcessHeap(), 0, bits ); + med->tymed = TYMED_ENHMF; + med->pUnkForRelease = NULL; + hr = S_OK; + } + + GlobalUnlock( data ); + return hr; +} + static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) { HRESULT hr; @@ -704,6 +728,60 @@ fail:
}
+static HRESULT load_emf( DataCacheEntry *cache_entry, IStream *stm ) +{ + HRESULT hr; + + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + STGMEDIUM stgmed; + + hr = load_mf_pict( cache_entry, stm ); + if (SUCCEEDED( hr )) + { + hr = synthesize_emf( cache_entry->stgmedium.u.hMetaFilePict, &stgmed ); + ReleaseStgMedium( &cache_entry->stgmedium ); + } + if (SUCCEEDED( hr )) + cache_entry->stgmedium = stgmed; + } + else + { + STATSTG stat; + BYTE *data; + ULONG read, size_bits; + + hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + + if (SUCCEEDED( hr )) + { + data = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart ); + if (!data) return E_OUTOFMEMORY; + + hr = IStream_Read( stm, data, stat.cbSize.u.LowPart, &read ); + if (hr != S_OK) + { + HeapFree( GetProcessHeap(), 0, data ); + return hr; + } + + if (read <= sizeof(DWORD) + sizeof(ENHMETAHEADER)) + { + HeapFree( GetProcessHeap(), 0, data ); + return E_FAIL; + } + size_bits = read - sizeof(DWORD) - sizeof(ENHMETAHEADER); + cache_entry->stgmedium.u.hEnhMetaFile = SetEnhMetaFileBits( size_bits, data + (read - size_bits) ); + cache_entry->stgmedium.tymed = TYMED_ENHMF; + cache_entry->stgmedium.pUnkForRelease = NULL; + + HeapFree( GetProcessHeap(), 0, data ); + } + } + + return hr; +} + /************************************************************************ * DataCacheEntry_LoadData * @@ -736,6 +814,10 @@ static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *st hr = load_dib( cache_entry, stm ); break;
+ case CF_ENHMETAFILE: + hr = load_emf( cache_entry, stm ); + break; + default: FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat ); hr = E_NOTIMPL; @@ -1118,30 +1200,6 @@ static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med ) return hr; }
-static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) -{ - METAFILEPICT *pict; - HRESULT hr = E_FAIL; - UINT size; - void *bits; - - if (!(pict = GlobalLock( data ))) return hr; - - size = GetMetaFileBitsEx( pict->hMF, 0, NULL ); - if ((bits = HeapAlloc( GetProcessHeap(), 0, size ))) - { - GetMetaFileBitsEx( pict->hMF, size, bits ); - med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict ); - HeapFree( GetProcessHeap(), 0, bits ); - med->tymed = TYMED_ENHMF; - med->pUnkForRelease = NULL; - hr = S_OK; - } - - GlobalUnlock( data ); - return hr; -} - static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry, const FORMATETC *formatetc, STGMEDIUM *stgmedium,
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 57 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index ff42e4d34a..22b39cb9b4 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -647,48 +647,61 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) { HRESULT hr; STATSTG stat; - void *dib; + BYTE *dib; HGLOBAL hglobal; ULONG read, info_size, bi_size; BITMAPFILEHEADER file; BITMAPINFOHEADER *info; - - if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) - { - FIXME( "Unimplemented for presentation stream\n" ); - return E_FAIL; - } + CLIPFORMAT cf; + PresentationDataHeader pres; + ULARGE_INTEGER current_pos; + static const LARGE_INTEGER offset_zero;
hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); if (FAILED( hr )) return hr;
- if (stat.cbSize.QuadPart < sizeof(file) + sizeof(DWORD)) return E_FAIL; - hr = IStream_Read( stm, &file, sizeof(file), &read ); - if (hr != S_OK || read != sizeof(file)) return E_FAIL; - stat.cbSize.QuadPart -= sizeof(file); + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + hr = read_clipformat( stm, &cf ); + if (hr != S_OK) return hr; + hr = IStream_Read( stm, &pres, sizeof(pres), &read ); + if (hr != S_OK) return hr; + } + else + { + hr = IStream_Read( stm, &file, sizeof(BITMAPFILEHEADER), &read ); + if (hr != S_OK) return hr; + } + + hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, ¤t_pos ); + if (FAILED( hr )) return hr; + stat.cbSize.QuadPart -= current_pos.QuadPart;
hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart ); if (!hglobal) return E_OUTOFMEMORY; dib = GlobalLock( hglobal );
+ /* read first DWORD of BITMAPINFOHEADER */ hr = IStream_Read( stm, dib, sizeof(DWORD), &read ); - if (hr != S_OK || read != sizeof(DWORD)) goto fail; + if (hr != S_OK) goto fail; bi_size = *(DWORD *)dib; if (stat.cbSize.QuadPart < bi_size) goto fail;
- hr = IStream_Read( stm, (char *)dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read ); - if (hr != S_OK || read != bi_size - sizeof(DWORD)) goto fail; + /* read rest of BITMAPINFOHEADER */ + hr = IStream_Read( stm, dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read ); + if (hr != S_OK) goto fail;
- info_size = bitmap_info_size( dib, DIB_RGB_COLORS ); + info_size = bitmap_info_size( (BITMAPINFO *)dib, DIB_RGB_COLORS ); if (stat.cbSize.QuadPart < info_size) goto fail; if (info_size > bi_size) { - hr = IStream_Read( stm, (char *)dib + bi_size, info_size - bi_size, &read ); - if (hr != S_OK || read != info_size - bi_size) goto fail; + hr = IStream_Read( stm, dib + bi_size, info_size - bi_size, &read ); + if (hr != S_OK) goto fail; } stat.cbSize.QuadPart -= info_size;
- if (file.bfOffBits) + /* set Stream pointer to beginning of bitmap bits */ + if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS && file.bfOffBits) { LARGE_INTEGER skip;
@@ -699,8 +712,8 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) stat.cbSize.QuadPart -= skip.QuadPart; }
- hr = IStream_Read( stm, (char *)dib + info_size, stat.cbSize.u.LowPart, &read ); - if (hr != S_OK || read != stat.cbSize.QuadPart) goto fail; + hr = IStream_Read( stm, dib + info_size, stat.cbSize.u.LowPart, &read ); + if (hr != S_OK) goto fail;
if (bi_size >= sizeof(*info)) { @@ -719,12 +732,12 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) cache_entry->stgmedium.tymed = TYMED_HGLOBAL; cache_entry->stgmedium.u.hGlobal = hglobal;
- return S_OK; + return hr;
fail: GlobalUnlock( hglobal ); GlobalFree( hglobal ); - return E_FAIL; + 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 | 65 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 28 deletions(-)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index 22b39cb9b4..b98c44826d 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -570,6 +570,17 @@ static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) GlobalUnlock( data ); 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 load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) { @@ -583,25 +594,26 @@ static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) CLIPFORMAT clipformat; static const LARGE_INTEGER offset_zero; ULONG read; - - if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS) - { - FIXME( "Unimplemented for CONTENTS stream\n" ); - return E_FAIL; - } + struct meta_placeable mf_place;
hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); if (FAILED( hr )) return hr;
- hr = read_clipformat( stm, &clipformat ); - if (FAILED( hr )) return hr; - - hr = IStream_Read( stm, &header, sizeof(header), &read ); - if (hr != S_OK || read != sizeof(header)) return E_FAIL; + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + hr = read_clipformat( stm, &clipformat ); + if (hr != S_OK) return hr; + hr = IStream_Read( stm, &header, sizeof(header), &read ); + if (hr != S_OK) return hr; + } + else + { + hr = IStream_Read( stm, &mf_place, sizeof(mf_place), &read ); + if (hr != S_OK) return hr; + }
hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, ¤t_pos ); if (FAILED( hr )) return hr; - stat.cbSize.QuadPart -= current_pos.QuadPart;
hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) ); @@ -616,14 +628,23 @@ static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) }
hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read ); - if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL;
if (SUCCEEDED( hr )) { - /* FIXME: get this from the stream */ mfpict->mm = MM_ANISOTROPIC; - mfpict->xExt = header.dwObjectExtentX; - mfpict->yExt = header.dwObjectExtentY; + /* FIXME: get this from the stream */ + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + mfpict->xExt = header.dwObjectExtentX; + mfpict->yExt = header.dwObjectExtentY; + } + else + { + mfpict->xExt = ((mf_place.bounding_box[2] - mf_place.bounding_box[0]) + * 2540) / mf_place.inch; + mfpict->yExt = ((mf_place.bounding_box[3] - mf_place.bounding_box[1]) + * 2540) / mf_place.inch; + } mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits ); if (!mfpict->hMF) hr = E_FAIL; @@ -912,18 +933,6 @@ 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;
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/datacache.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/ole32/datacache.c b/dlls/ole32/datacache.c index b98c44826d..b72b8ff2ef 100644 --- a/dlls/ole32/datacache.c +++ b/dlls/ole32/datacache.c @@ -1843,6 +1843,7 @@ static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg )
LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry ) DataCacheEntry_Destroy( This, entry ); + This->clsid = CLSID_NULL;
ReadClassStg( stg, &clsid ); hr = create_automatic_entry( This, &clsid );
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/ole32/tests/ole2.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-)
diff --git a/dlls/ole32/tests/ole2.c b/dlls/ole32/tests/ole2.c index 3bd4acce92..74dadd4048 100644 --- a/dlls/ole32/tests/ole2.c +++ b/dlls/ole32/tests/ole2.c @@ -4078,6 +4078,83 @@ static void check_storage_contents(IStorage *stg, const struct storage_def *stg_ } }
+static HRESULT stgmedium_cmp(const STGMEDIUM *med1, STGMEDIUM *med2) +{ + BYTE *data1, *data2; + ULONG datasize1, datasize2; + + if (med1->tymed != med2->tymed) + return E_FAIL; + + if (med1->tymed == TYMED_MFPICT) + { + METAFILEPICT *mfpict1 = GlobalLock(U(med1)->hMetaFilePict); + METAFILEPICT *mfpict2 = GlobalLock(U(med2)->hMetaFilePict); + + datasize1 = GetMetaFileBitsEx(mfpict1->hMF, 0, NULL); + datasize2 = GetMetaFileBitsEx(mfpict2->hMF, 0, NULL); + if (datasize1 == datasize2) + { + data1 = HeapAlloc(GetProcessHeap(), 0, datasize1); + data2 = HeapAlloc(GetProcessHeap(), 0, datasize2); + GetMetaFileBitsEx(mfpict1->hMF, datasize1, data1); + GetMetaFileBitsEx(mfpict2->hMF, datasize2, data2); + } + else return E_FAIL; + } + else if (med1->tymed == TYMED_ENHMF) + { + datasize1 = GetEnhMetaFileBits(med1->hEnhMetaFile, 0, NULL); + datasize2 = GetEnhMetaFileBits(med2->hEnhMetaFile, 0, NULL); + if (datasize1 == datasize2) + { + data1 = HeapAlloc(GetProcessHeap(), 0, datasize1); + data2 = HeapAlloc(GetProcessHeap(), 0, datasize2); + GetEnhMetaFileBits(med1->hEnhMetaFile, datasize1, data1); + GetEnhMetaFileBits(med2->hEnhMetaFile, datasize2, data2); + } + else return E_FAIL; + } + else if (med1->tymed == TYMED_HGLOBAL) + { + datasize1 = GlobalSize(med1->hGlobal); + datasize2 = GlobalSize(med2->hGlobal); + + if (datasize1 == datasize2) + { + data1 = GlobalLock(med1->hGlobal); + data2 = GlobalLock(med2->hGlobal); + } + else + return E_FAIL; + } + else + return E_NOTIMPL; + + if (memcmp(data1, data2, datasize1) != 0) + return E_FAIL; + + if (med1->tymed == TYMED_HGLOBAL) + { + GlobalUnlock(U(med1)->hGlobal); + GlobalUnlock(U(med2)->hGlobal); + } + else if (med1->tymed == TYMED_MFPICT) + { + HeapFree(GetProcessHeap(), 0, data1); + HeapFree(GetProcessHeap(), 0, data2); + GlobalUnlock(U(med1)->hMetaFilePict); + GlobalUnlock(U(med2)->hMetaFilePict); + } + else + { + HeapFree(GetProcessHeap(), 0, data1); + HeapFree(GetProcessHeap(), 0, data2); + } + + return S_OK; +} + static IStorage *create_storage_from_def(const struct storage_def *stg_def) { HRESULT hr; @@ -4250,8 +4327,10 @@ static void test_data_cache_save_data(void) IStorage *doc; IOleCache2 *cache; IPersistStorage *persist; + IDataObject *odata; int enumerated_streams, matched_streams, i; DWORD dummy; + STGMEDIUM stgmeds[MAX_FMTS]; struct tests_data_cache { FORMATETC fmts[MAX_FMTS]; @@ -4366,9 +4445,9 @@ static void test_data_cache_save_data(void) ok(SUCCEEDED(hr), "unexpected %#x\n", hr); if (i < pdata->num_set) { - get_stgmedium(pdata->fmts[i].cfFormat, &stgmed); - get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat, &stgmed, i); - hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmed, TRUE); + get_stgmedium(pdata->fmts[i].cfFormat, &stgmeds[i]); + get_stgdef(&pdata->stg_def, pdata->fmts[i].cfFormat, &stgmeds[i], i); + hr = IOleCache2_SetData(cache, &pdata->fmts[i], &stgmeds[i], FALSE); ok(hr == S_OK, "unexpected %#x\n", hr); } } @@ -4399,12 +4478,41 @@ static void test_data_cache_save_data(void) ok(enumerated_streams == pdata->stg_def.stream_count, "created %d != def streams %d\n", enumerated_streams, pdata->stg_def.stream_count);
+ IPersistStorage_Release(persist); + IOleCache2_Release(cache); + + /* now test _Load/_GetData using the storage we used for _Save */ + hr = CreateDataCache(NULL, pdata->clsid, &IID_IOleCache2, (void **)&cache); + ok(hr == S_OK, "unexpected %#x\n", hr); + hr = IOleCache2_QueryInterface(cache, &IID_IPersistStorage, (void **)&persist); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IStorage_SetClass(doc, pdata->clsid); + ok(hr == S_OK, "unexpected %#x\n", hr); + trace("IPersistStorage_Load\n"); + hr = IPersistStorage_Load(persist, doc); + ok(hr == S_OK, "unexpected %#x\n", hr); + + hr = IOleCache2_QueryInterface(cache, &IID_IDataObject, (void **)&odata); + ok(hr == S_OK, "unexpected %#x\n", hr); for (i = 0; i < pdata->num_set; i++) - HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data); + { + hr = IDataObject_GetData(odata, &pdata->fmts[i], &stgmed); + ok(hr == S_OK, "unexpected %#x\n", hr);
+ hr = stgmedium_cmp(&stgmeds[i], &stgmed); + ok(hr == S_OK, "unexpected %#x\n", hr); + ReleaseStgMedium(&stgmed); + ReleaseStgMedium(&stgmeds[i]); + } + + IDataObject_Release(odata); IPersistStorage_Release(persist); IStorage_Release(doc); IOleCache2_Release(cache); + for (i = 0; i < pdata->num_set; i++) + HeapFree(GetProcessHeap(), 0, (void *)pdata->stg_def.stream[i].data); + } }
Signed-off-by: Huw Davies huw@codeweavers.com