Commit 587ba291 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

ole32: Implement saving of the data cache.

Document a few of the unknown fields in the presentation data header.
parent e5c82d3a
......@@ -73,12 +73,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
typedef struct PresentationDataHeader
{
DWORD unknown1; /* -1 */
DWORD unknown2; /* 3, possibly CF_METAFILEPICT */
DWORD clipformat;
DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
DVASPECT dvAspect;
DWORD unknown5; /* -1 */
DWORD unknown6;
DWORD lindex;
DWORD tymed;
DWORD unknown7; /* 0 */
DWORD dwObjectExtentX;
DWORD dwObjectExtentY;
......@@ -102,6 +101,8 @@ typedef struct DataCacheEntry
DWORD id;
/* dirty flag */
BOOL dirty;
/* stream number (-1 if not set ) */
unsigned short stream_number;
} DataCacheEntry;
/****************************************************************************
......@@ -186,6 +187,12 @@ static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCacheControl));
}
static void dump_FORMATETC(const FORMATETC *formatetc)
{
TRACE("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
formatetc->lindex, formatetc->tymed);
}
/*
* Prototypes for the methods of the DataCache class.
......@@ -259,6 +266,7 @@ static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc
(*cache_entry)->storage = NULL;
(*cache_entry)->id = This->last_cache_id++;
(*cache_entry)->dirty = TRUE;
(*cache_entry)->stream_number = -1;
list_add_tail(&This->cache_list, &(*cache_entry)->entry);
return S_OK;
}
......@@ -517,6 +525,117 @@ static HRESULT DataCacheEntry_LoadData(DataCacheEntry *This)
return hres;
}
static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This,
IStorage *storage, IStream **stream)
{
HRESULT hr;
WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
'0' + (This->stream_number / 100) % 10,
'0' + (This->stream_number / 10) % 10,
'0' + This->stream_number % 10, 0};
/* FIXME: cache the created stream in This? */
hr = IStorage_CreateStream(storage, wszName,
STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
0, 0, stream);
return hr;
}
static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
BOOL same_as_load)
{
PresentationDataHeader header;
HRESULT hr;
IStream *pres_stream;
void *data = NULL;
TRACE("stream_number = %d, fmtetc = ", This->stream_number); dump_FORMATETC(&This->fmtetc); TRACE("\n");
hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
if (FAILED(hr))
return hr;
/* custom clipformat */
if (This->fmtetc.cfFormat > 0xc000)
FIXME("custom clipboard format not serialized properly\n");
header.unknown1 = -1;
header.clipformat = This->fmtetc.cfFormat;
if (This->fmtetc.ptd)
FIXME("ptd not serialized\n");
header.unknown3 = 4;
header.dvAspect = This->fmtetc.dwAspect;
header.lindex = This->fmtetc.lindex;
header.tymed = This->fmtetc.tymed;
header.unknown7 = 0;
header.dwObjectExtentX = 0;
header.dwObjectExtentY = 0;
header.dwSize = 0;
/* size the data */
switch (This->fmtetc.cfFormat)
{
case CF_METAFILEPICT:
{
if (This->stgmedium.tymed != TYMED_NULL)
{
const METAFILEPICT *mfpict = GlobalLock(This->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(This->stgmedium.u.hMetaFilePict);
}
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 (This->fmtetc.cfFormat)
{
case CF_METAFILEPICT:
{
if (This->stgmedium.tymed != TYMED_NULL)
{
const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
if (!mfpict)
{
IStream_Release(pres_stream);
return DV_E_STGMEDIUM;
}
data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
GlobalUnlock(This->stgmedium.u.hMetaFilePict);
}
break;
}
default:
break;
}
if (data)
hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
IStream_Release(pres_stream);
return hr;
}
/* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
* does no checking of whether src_stgm has a supported tymed, so this should be
* done in the caller */
......@@ -1153,11 +1272,13 @@ static HRESULT WINAPI DataCache_Load(
DataCacheEntry *cache_entry;
FORMATETC fmtetc;
fmtetc.cfFormat = header.unknown2;
fmtetc.cfFormat = header.clipformat;
fmtetc.ptd = NULL; /* FIXME */
fmtetc.dwAspect = header.dvAspect;
fmtetc.lindex = header.unknown5;
fmtetc.tymed = header.unknown6;
fmtetc.lindex = header.lindex;
fmtetc.tymed = header.tymed;
TRACE("loading entry with formatetc: "); dump_FORMATETC(&fmtetc); TRACE("\n");
cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
if (!cache_entry)
......@@ -1205,6 +1326,8 @@ static HRESULT WINAPI DataCache_Save(
DataCache *This = impl_from_IPersistStorage(iface);
DataCacheEntry *cache_entry;
BOOL dirty = FALSE;
HRESULT hr = S_OK;
unsigned short stream_number = 0;
TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
......@@ -1225,14 +1348,32 @@ static HRESULT WINAPI DataCache_Save(
return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
}
/* assign stream numbers to the cache entries */
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
if (cache_entry->stream_number != stream_number)
{
cache_entry->dirty = TRUE; /* needs to be written out again */
cache_entry->stream_number = stream_number;
}
stream_number++;
}
/* write out the cache entries */
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
/* FIXME: actually do the save here */
cache_entry->dirty = FALSE;
if (!fSameAsLoad || cache_entry->dirty)
{
hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
if (FAILED(hr))
break;
cache_entry->dirty = FALSE;
}
}
This->dirty = FALSE;
return S_OK;
return hr;
}
/************************************************************************
......@@ -1737,6 +1878,7 @@ static HRESULT WINAPI DataCache_Cache(
HRESULT hr;
TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
TRACE("pformatetc = "); dump_FORMATETC(pformatetc); TRACE("\n");
*pdwConnection = 0;
......
......@@ -1205,9 +1205,7 @@ static void test_data_cache(void)
fmtetc.ptd = NULL;
fmtetc.tymed = TYMED_MFPICT;
hr = IOleCache_Cache(pOleCache, &fmtetc, 0, &dwConnection);
todo_wine {
ok(hr == CACHE_S_SAMECACHE, "IOleCache_Cache with already loaded data format type should return CACHE_S_SAMECACHE instead of 0x%x\n", hr);
}
rcBounds.left = 0;
rcBounds.top = 0;
......@@ -1216,9 +1214,7 @@ static void test_data_cache(void)
hdcMem = CreateCompatibleDC(NULL);
hr = IViewObject_Draw(pViewObject, DVASPECT_ICON, -1, NULL, NULL, NULL, hdcMem, &rcBounds, NULL, draw_continue, 0xdeadbeef);
todo_wine {
ok_ole_success(hr, "IViewObject_Draw");
}
hr = IViewObject_Draw(pViewObject, DVASPECT_CONTENT, -1, NULL, NULL, NULL, hdcMem, &rcBounds, NULL, draw_continue, 0xdeadbeef);
ok(hr == OLE_E_BLANK, "IViewObject_Draw with uncached aspect should have returned OLE_E_BLANK instead of 0x%08x\n", hr);
......@@ -1227,21 +1223,21 @@ static void test_data_cache(void)
hr = IOleCache2_DiscardCache(pOleCache, DISCARDCACHE_NOSAVE);
todo_wine {
ok_ole_success(hr, "IOleCache2_DiscardCache");
}
hr = IViewObject_Draw(pViewObject, DVASPECT_ICON, -1, NULL, NULL, NULL, hdcMem, &rcBounds, NULL, draw_continue, 0xdeadbeef);
ok_ole_success(hr, "IViewObject_Draw");
}
/* unload the cached storage object, but don't allow it to be reloaded */
hr = IPersistStorage_HandsOffStorage(pPS);
ok_ole_success(hr, "IPersistStorage_HandsOffStorage");
todo_wine {
hr = IViewObject_Draw(pViewObject, DVASPECT_ICON, -1, NULL, NULL, NULL, hdcMem, &rcBounds, NULL, draw_continue, 0xdeadbeef);
ok_ole_success(hr, "IViewObject_Draw");
todo_wine {
hr = IOleCache2_DiscardCache(pOleCache, DISCARDCACHE_NOSAVE);
ok_ole_success(hr, "IOleCache2_DiscardCache");
}
hr = IViewObject_Draw(pViewObject, DVASPECT_ICON, -1, NULL, NULL, NULL, hdcMem, &rcBounds, NULL, draw_continue, 0xdeadbeef);
ok(hr == OLE_E_BLANK, "IViewObject_Draw with uncached aspect should have returned OLE_E_BLANK instead of 0x%08x\n", hr);
}
DeleteDC(hdcMem);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment