ole32: Implement saving of the data cache.

Document a few of the unknown fields in the presentation data header.
This commit is contained in:
Rob Shearman 2006-12-01 15:04:04 +00:00 committed by Alexandre Julliard
parent e5c82d3aa4
commit 587ba29174
2 changed files with 155 additions and 17 deletions

View File

@ -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)
{
/* FIXME: actually do the save here */
cache_entry->dirty = FALSE;
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)
{
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;

View File

@ -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);