ole32: InitNew() should fail if there is a current storage.
[wine.git] / dlls / ole32 / datacache.c
blobecae89d284f3b1aabe0cda9fe884a0d6705841e9
1 /*
2 * OLE 2 Data cache
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2000 Abey George
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * NOTES:
22 * The OLE2 data cache supports a whole whack of
23 * interfaces including:
24 * IDataObject, IPersistStorage, IViewObject2,
25 * IOleCache2 and IOleCacheControl.
27 * Most of the implementation details are taken from: Inside OLE
28 * second edition by Kraig Brockschmidt,
30 * NOTES
31 * - This implementation of the datacache will let your application
32 * load documents that have embedded OLE objects in them and it will
33 * also retrieve the metafile representation of those objects.
34 * - This implementation of the datacache will also allow your
35 * application to save new documents with OLE objects in them.
36 * - The main thing that it doesn't do is allow you to activate
37 * or modify the OLE objects in any way.
38 * - I haven't found any good documentation on the real usage of
39 * the streams created by the data cache. In particular, How to
40 * determine what the XXX stands for in the stream name
41 * "\002OlePresXXX". It appears to just be a counter.
42 * - Also, I don't know the real content of the presentation stream
43 * header. I was able to figure-out where the extent of the object
44 * was stored and the aspect, but that's about it.
47 #include <stdarg.h>
48 #include <string.h>
50 #define COBJMACROS
51 #define NONAMELESSUNION
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "winerror.h"
58 #include "ole2.h"
59 #include "compobj_private.h"
60 #include "wine/unicode.h"
61 #include "wine/list.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
66 /****************************************************************************
67 * PresentationDataHeader
69 * This structure represents the header of the \002OlePresXXX stream in
70 * the OLE object storage.
72 typedef struct PresentationDataHeader
74 /* clipformat:
75 * - standard clipformat:
76 * DWORD length = 0xffffffff;
77 * DWORD cfFormat;
78 * - or custom clipformat:
79 * DWORD length;
80 * CHAR format_name[length]; (null-terminated)
82 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
83 DVASPECT dvAspect;
84 DWORD lindex;
85 DWORD advf;
86 DWORD unknown7; /* 0 */
87 DWORD dwObjectExtentX;
88 DWORD dwObjectExtentY;
89 DWORD dwSize;
90 } PresentationDataHeader;
92 enum stream_type
94 no_stream,
95 pres_stream,
96 contents_stream
99 typedef struct DataCacheEntry
101 struct list entry;
102 /* format of this entry */
103 FORMATETC fmtetc;
104 /* the clipboard format of the data */
105 CLIPFORMAT data_cf;
106 /* cached data */
107 STGMEDIUM stgmedium;
109 * This stream pointer is set through a call to
110 * IPersistStorage_Load. This is where the visual
111 * representation of the object is stored.
113 IStream *stream;
114 enum stream_type stream_type;
115 /* connection ID */
116 DWORD id;
117 /* dirty flag */
118 BOOL dirty;
119 /* stream number (-1 if not set ) */
120 unsigned short stream_number;
121 /* sink id set when object is running */
122 DWORD sink_id;
123 /* Advise sink flags */
124 DWORD advise_flags;
125 } DataCacheEntry;
127 /****************************************************************************
128 * DataCache
130 struct DataCache
133 * List all interface here
135 IUnknown IUnknown_inner;
136 IDataObject IDataObject_iface;
137 IPersistStorage IPersistStorage_iface;
138 IViewObject2 IViewObject2_iface;
139 IOleCache2 IOleCache2_iface;
140 IOleCacheControl IOleCacheControl_iface;
142 /* The sink that is connected to a remote object.
143 The other interfaces are not available by QI'ing the sink and vice-versa */
144 IAdviseSink IAdviseSink_iface;
147 * Reference count of this object
149 LONG ref;
152 * IUnknown implementation of the outer object.
154 IUnknown *outer_unk;
157 * The user of this object can setup ONE advise sink
158 * connection with the object. These parameters describe
159 * that connection.
161 DWORD sinkAspects;
162 DWORD sinkAdviseFlag;
163 IAdviseSink *sinkInterface;
165 CLSID clsid;
166 IStorage *presentationStorage;
168 /* list of cache entries */
169 struct list cache_list;
170 /* last id assigned to an entry */
171 DWORD last_cache_id;
172 /* dirty flag */
173 BOOL dirty;
174 /* running object set by OnRun */
175 IDataObject *running_object;
178 typedef struct DataCache DataCache;
181 * Here, I define utility macros to help with the casting of the
182 * "this" parameter.
183 * There is a version to accommodate all of the VTables implemented
184 * by this object.
187 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
189 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
192 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
194 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
197 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
199 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
202 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
204 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
207 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
209 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
212 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
214 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
217 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
219 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
222 const char *debugstr_formatetc(const FORMATETC *formatetc)
224 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
225 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
226 formatetc->lindex, formatetc->tymed);
229 /***********************************************************************
230 * bitmap_info_size
232 * Return the size of the bitmap info structure including color table.
234 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
236 unsigned int colors, size, masks = 0;
238 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
240 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
241 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
242 return sizeof(BITMAPCOREHEADER) + colors *
243 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
245 else /* assume BITMAPINFOHEADER */
247 colors = info->bmiHeader.biClrUsed;
248 if (colors > 256) /* buffer overflow otherwise */
249 colors = 256;
250 if (!colors && (info->bmiHeader.biBitCount <= 8))
251 colors = 1 << info->bmiHeader.biBitCount;
252 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
253 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
254 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
258 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
260 list_remove(&cache_entry->entry);
261 if (cache_entry->stream)
262 IStream_Release(cache_entry->stream);
263 CoTaskMemFree(cache_entry->fmtetc.ptd);
264 ReleaseStgMedium(&cache_entry->stgmedium);
265 if(cache_entry->sink_id)
266 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
268 HeapFree(GetProcessHeap(), 0, cache_entry);
271 static void DataCache_Destroy(
272 DataCache* ptrToDestroy)
274 DataCacheEntry *cache_entry, *next_cache_entry;
276 TRACE("()\n");
278 if (ptrToDestroy->sinkInterface != NULL)
280 IAdviseSink_Release(ptrToDestroy->sinkInterface);
281 ptrToDestroy->sinkInterface = NULL;
284 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
285 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
287 if (ptrToDestroy->presentationStorage != NULL)
289 IStorage_Release(ptrToDestroy->presentationStorage);
290 ptrToDestroy->presentationStorage = NULL;
294 * Free the datacache pointer.
296 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
299 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
301 DataCacheEntry *cache_entry;
302 FORMATETC fmt = *formatetc;
304 if (fmt.cfFormat == CF_BITMAP)
306 fmt.cfFormat = CF_DIB;
307 fmt.tymed = TYMED_HGLOBAL;
310 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
312 /* FIXME: also compare DVTARGETDEVICEs */
313 if ((!cache_entry->fmtetc.cfFormat || !fmt.cfFormat || (fmt.cfFormat == cache_entry->fmtetc.cfFormat)) &&
314 (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
315 (fmt.lindex == cache_entry->fmtetc.lindex) &&
316 (!cache_entry->fmtetc.tymed || !fmt.tymed || (fmt.tymed == cache_entry->fmtetc.tymed)))
317 return cache_entry;
319 return NULL;
322 /* checks that the clipformat and tymed are valid and returns an error if they
323 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
324 * DataCache_Draw */
325 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
327 if (!cfFormat || !tymed ||
328 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
329 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
330 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
331 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
332 return S_OK;
333 else if (tymed == TYMED_HGLOBAL)
334 return CACHE_S_FORMATETC_NOTSUPPORTED;
335 else
337 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
338 return DV_E_TYMED;
342 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf,
343 DWORD id)
345 HRESULT hr;
347 hr = copy_formatetc(&entry->fmtetc, fmt);
348 if (FAILED(hr)) return FALSE;
350 entry->data_cf = 0;
351 entry->stgmedium.tymed = TYMED_NULL;
352 entry->stgmedium.pUnkForRelease = NULL;
353 entry->stream = NULL;
354 entry->stream_type = no_stream;
355 entry->id = id;
356 entry->dirty = TRUE;
357 entry->stream_number = -1;
358 entry->sink_id = 0;
359 entry->advise_flags = advf;
361 return TRUE;
364 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf,
365 BOOL automatic, DataCacheEntry **cache_entry)
367 HRESULT hr;
368 DWORD id = automatic ? 1 : This->last_cache_id;
369 DataCacheEntry *entry;
371 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
372 if (FAILED(hr))
373 return hr;
374 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
375 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
377 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
378 if (!entry)
379 return E_OUTOFMEMORY;
381 if (!init_cache_entry(entry, formatetc, advf, id))
382 goto fail;
384 if (automatic)
385 list_add_head(&This->cache_list, &entry->entry);
386 else
388 list_add_tail(&This->cache_list, &entry->entry);
389 This->last_cache_id++;
392 if (cache_entry) *cache_entry = entry;
393 return hr;
395 fail:
396 HeapFree(GetProcessHeap(), 0, entry);
397 return E_OUTOFMEMORY;
400 /************************************************************************
401 * DataCache_FireOnViewChange
403 * This method will fire an OnViewChange notification to the advise
404 * sink registered with the datacache.
406 * See IAdviseSink::OnViewChange for more details.
408 static void DataCache_FireOnViewChange(
409 DataCache* this,
410 DWORD aspect,
411 LONG lindex)
413 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
416 * The sink supplies a filter when it registers
417 * we make sure we only send the notifications when that
418 * filter matches.
420 if ((this->sinkAspects & aspect) != 0)
422 if (this->sinkInterface != NULL)
424 IAdviseSink_OnViewChange(this->sinkInterface,
425 aspect,
426 lindex);
429 * Some sinks want to be unregistered automatically when
430 * the first notification goes out.
432 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
434 IAdviseSink_Release(this->sinkInterface);
436 this->sinkInterface = NULL;
437 this->sinkAspects = 0;
438 this->sinkAdviseFlag = 0;
444 /* Helper for DataCacheEntry_OpenPresStream */
445 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
447 /* The presentation streams have names of the form "\002OlePresXXX",
448 * where XXX goes from 000 to 999. */
449 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
451 LPCWSTR name = elem->pwcsName;
453 return (elem->type == STGTY_STREAM)
454 && (strlenW(name) == 11)
455 && (strncmpW(name, OlePres, 8) == 0)
456 && (name[8] >= '0') && (name[8] <= '9')
457 && (name[9] >= '0') && (name[9] <= '9')
458 && (name[10] >= '0') && (name[10] <= '9');
461 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
463 DWORD length;
464 HRESULT hr;
465 ULONG read;
467 *clipformat = 0;
469 hr = IStream_Read(stream, &length, sizeof(length), &read);
470 if (hr != S_OK || read != sizeof(length))
471 return DV_E_CLIPFORMAT;
472 if (length == -1)
474 DWORD cf;
475 hr = IStream_Read(stream, &cf, sizeof(cf), &read);
476 if (hr != S_OK || read != sizeof(cf))
477 return DV_E_CLIPFORMAT;
478 *clipformat = cf;
480 else
482 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
483 if (!format_name)
484 return E_OUTOFMEMORY;
485 hr = IStream_Read(stream, format_name, length, &read);
486 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
488 HeapFree(GetProcessHeap(), 0, format_name);
489 return DV_E_CLIPFORMAT;
491 *clipformat = RegisterClipboardFormatA(format_name);
492 HeapFree(GetProcessHeap(), 0, format_name);
494 return S_OK;
497 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
499 DWORD length;
500 HRESULT hr;
502 if (clipformat < 0xc000)
503 length = -1;
504 else
505 length = GetClipboardFormatNameA(clipformat, NULL, 0);
506 hr = IStream_Write(stream, &length, sizeof(length), NULL);
507 if (FAILED(hr))
508 return hr;
509 if (clipformat < 0xc000)
511 DWORD cf = clipformat;
512 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
514 else
516 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
517 if (!format_name)
518 return E_OUTOFMEMORY;
519 GetClipboardFormatNameA(clipformat, format_name, length);
520 hr = IStream_Write(stream, format_name, length, NULL);
521 HeapFree(GetProcessHeap(), 0, format_name);
523 return hr;
526 /************************************************************************
527 * DataCacheEntry_OpenPresStream
529 * This method will find the stream for the given presentation. It makes
530 * no attempt at fallback.
532 * Param:
533 * this - Pointer to the DataCache object
534 * drawAspect - The aspect of the object that we wish to draw.
535 * pStm - A returned stream. It points to the beginning of the
536 * - presentation data, including the header.
538 * Errors:
539 * S_OK The requested stream has been opened.
540 * OLE_E_BLANK The requested stream could not be found.
541 * Quite a few others I'm too lazy to map correctly.
543 * Notes:
544 * Algorithm: Scan the elements of the presentation storage, looking
545 * for presentation streams. For each presentation stream,
546 * load the header and check to see if the aspect matches.
548 * If a fallback is desired, just opening the first presentation stream
549 * is a possibility.
551 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
553 HRESULT hr;
554 LARGE_INTEGER offset;
556 if (cache_entry->stream)
558 /* Rewind the stream before returning it. */
559 offset.QuadPart = 0;
561 hr = IStream_Seek( cache_entry->stream, offset, STREAM_SEEK_SET, NULL );
562 if (SUCCEEDED( hr ))
564 *ppStm = cache_entry->stream;
565 IStream_AddRef( cache_entry->stream );
568 else
569 hr = OLE_E_BLANK;
571 return hr;
575 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
577 HRESULT hr;
578 STATSTG stat;
579 ULARGE_INTEGER current_pos;
580 void *bits;
581 METAFILEPICT *mfpict;
582 HGLOBAL hmfpict;
583 PresentationDataHeader header;
584 CLIPFORMAT clipformat;
585 static const LARGE_INTEGER offset_zero;
586 ULONG read;
588 if (cache_entry->stream_type != pres_stream)
590 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
591 return E_FAIL;
594 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
595 if (FAILED( hr )) return hr;
597 hr = read_clipformat( stm, &clipformat );
598 if (FAILED( hr )) return hr;
600 hr = IStream_Read( stm, &header, sizeof(header), &read );
601 if (hr != S_OK || read != sizeof(header)) return E_FAIL;
603 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
604 if (FAILED( hr )) return hr;
606 stat.cbSize.QuadPart -= current_pos.QuadPart;
608 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
609 if (!hmfpict) return E_OUTOFMEMORY;
610 mfpict = GlobalLock( hmfpict );
612 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
613 if (!bits)
615 GlobalFree( hmfpict );
616 return E_OUTOFMEMORY;
619 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
620 if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL;
622 if (SUCCEEDED( hr ))
624 /* FIXME: get this from the stream */
625 mfpict->mm = MM_ANISOTROPIC;
626 mfpict->xExt = header.dwObjectExtentX;
627 mfpict->yExt = header.dwObjectExtentY;
628 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
629 if (!mfpict->hMF)
630 hr = E_FAIL;
633 GlobalUnlock( hmfpict );
634 if (SUCCEEDED( hr ))
636 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
637 cache_entry->stgmedium.tymed = TYMED_MFPICT;
638 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
640 else
641 GlobalFree( hmfpict );
643 HeapFree( GetProcessHeap(), 0, bits );
645 return hr;
648 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
650 HRESULT hr;
651 STATSTG stat;
652 void *dib;
653 HGLOBAL hglobal;
654 ULONG read, info_size, bi_size;
655 BITMAPFILEHEADER file;
656 BITMAPINFOHEADER *info;
658 if (cache_entry->stream_type != contents_stream)
660 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
661 return E_FAIL;
664 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
665 if (FAILED( hr )) return hr;
667 if (stat.cbSize.QuadPart < sizeof(file) + sizeof(DWORD)) return E_FAIL;
668 hr = IStream_Read( stm, &file, sizeof(file), &read );
669 if (hr != S_OK || read != sizeof(file)) return E_FAIL;
670 stat.cbSize.QuadPart -= sizeof(file);
672 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
673 if (!hglobal) return E_OUTOFMEMORY;
674 dib = GlobalLock( hglobal );
676 hr = IStream_Read( stm, dib, sizeof(DWORD), &read );
677 if (hr != S_OK || read != sizeof(DWORD)) goto fail;
678 bi_size = *(DWORD *)dib;
679 if (stat.cbSize.QuadPart < bi_size) goto fail;
681 hr = IStream_Read( stm, (char *)dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read );
682 if (hr != S_OK || read != bi_size - sizeof(DWORD)) goto fail;
684 info_size = bitmap_info_size( dib, DIB_RGB_COLORS );
685 if (stat.cbSize.QuadPart < info_size) goto fail;
686 if (info_size > bi_size)
688 hr = IStream_Read( stm, (char *)dib + bi_size, info_size - bi_size, &read );
689 if (hr != S_OK || read != info_size - bi_size) goto fail;
691 stat.cbSize.QuadPart -= info_size;
693 if (file.bfOffBits)
695 LARGE_INTEGER skip;
697 skip.QuadPart = file.bfOffBits - sizeof(file) - info_size;
698 if (stat.cbSize.QuadPart < skip.QuadPart) goto fail;
699 hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL );
700 if (hr != S_OK) goto fail;
701 stat.cbSize.QuadPart -= skip.QuadPart;
704 hr = IStream_Read( stm, (char *)dib + info_size, stat.cbSize.u.LowPart, &read );
705 if (hr != S_OK || read != stat.cbSize.QuadPart) goto fail;
707 if (bi_size >= sizeof(*info))
709 info = (BITMAPINFOHEADER *)dib;
710 if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0)
712 HDC hdc = GetDC( 0 );
713 info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 );
714 info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 );
715 ReleaseDC( 0, hdc );
719 GlobalUnlock( hglobal );
721 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
722 cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
723 cache_entry->stgmedium.u.hGlobal = hglobal;
725 return S_OK;
727 fail:
728 GlobalUnlock( hglobal );
729 GlobalFree( hglobal );
730 return E_FAIL;
734 /************************************************************************
735 * DataCacheEntry_LoadData
737 * This method will read information for the requested presentation
738 * into the given structure.
740 * Param:
741 * This - The entry to load the data from.
743 * Returns:
744 * This method returns a metafile handle if it is successful.
745 * it will return 0 if not.
747 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
749 HRESULT hr;
750 IStream *stm;
752 hr = DataCacheEntry_OpenPresStream( cache_entry, &stm );
753 if (FAILED(hr)) return hr;
755 switch (cache_entry->fmtetc.cfFormat)
757 case CF_METAFILEPICT:
758 hr = load_mf_pict( cache_entry, stm );
759 break;
761 case CF_DIB:
762 hr = load_dib( cache_entry, stm );
763 break;
765 default:
766 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
767 hr = E_NOTIMPL;
770 IStream_Release( stm );
771 return hr;
774 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
775 IStorage *storage, IStream **stream)
777 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
778 '0' + (cache_entry->stream_number / 100) % 10,
779 '0' + (cache_entry->stream_number / 10) % 10,
780 '0' + cache_entry->stream_number % 10, 0};
782 /* FIXME: cache the created stream in This? */
783 return IStorage_CreateStream(storage, wszName,
784 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
785 0, 0, stream);
788 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
789 BOOL same_as_load)
791 PresentationDataHeader header;
792 HRESULT hr;
793 IStream *pres_stream;
794 void *data = NULL;
796 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
798 hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
799 if (FAILED(hr))
800 return hr;
802 hr = write_clipformat(pres_stream, cache_entry->data_cf);
803 if (FAILED(hr))
804 return hr;
806 if (cache_entry->fmtetc.ptd)
807 FIXME("ptd not serialized\n");
808 header.unknown3 = 4;
809 header.dvAspect = cache_entry->fmtetc.dwAspect;
810 header.lindex = cache_entry->fmtetc.lindex;
811 header.advf = cache_entry->advise_flags;
812 header.unknown7 = 0;
813 header.dwObjectExtentX = 0;
814 header.dwObjectExtentY = 0;
815 header.dwSize = 0;
817 /* size the data */
818 switch (cache_entry->data_cf)
820 case CF_METAFILEPICT:
822 if (cache_entry->stgmedium.tymed != TYMED_NULL)
824 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
825 if (!mfpict)
827 IStream_Release(pres_stream);
828 return DV_E_STGMEDIUM;
830 header.dwObjectExtentX = mfpict->xExt;
831 header.dwObjectExtentY = mfpict->yExt;
832 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
833 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
835 break;
837 default:
838 break;
842 * Write the header.
844 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
845 NULL);
846 if (FAILED(hr))
848 IStream_Release(pres_stream);
849 return hr;
852 /* get the data */
853 switch (cache_entry->data_cf)
855 case CF_METAFILEPICT:
857 if (cache_entry->stgmedium.tymed != TYMED_NULL)
859 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
860 if (!mfpict)
862 IStream_Release(pres_stream);
863 return DV_E_STGMEDIUM;
865 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
866 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
867 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
869 break;
871 default:
872 break;
875 if (data)
876 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
877 HeapFree(GetProcessHeap(), 0, data);
879 IStream_Release(pres_stream);
880 return hr;
883 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
884 * does no checking of whether src_stgm has a supported tymed, so this should be
885 * done in the caller */
886 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
887 const STGMEDIUM *src_stgm)
889 if (src_stgm->tymed == TYMED_MFPICT)
891 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
892 METAFILEPICT *dest_mfpict;
894 if (!src_mfpict)
895 return DV_E_STGMEDIUM;
896 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
897 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
898 if (!dest_mfpict)
900 GlobalUnlock(src_stgm->u.hMetaFilePict);
901 return E_OUTOFMEMORY;
903 *dest_mfpict = *src_mfpict;
904 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
905 GlobalUnlock(src_stgm->u.hMetaFilePict);
906 GlobalUnlock(dest_stgm->u.hMetaFilePict);
908 else if (src_stgm->tymed != TYMED_NULL)
910 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
911 GMEM_MOVEABLE);
912 if (!dest_stgm->u.hGlobal)
913 return E_OUTOFMEMORY;
915 dest_stgm->tymed = src_stgm->tymed;
916 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
917 if (dest_stgm->pUnkForRelease)
918 IUnknown_AddRef(dest_stgm->pUnkForRelease);
919 return S_OK;
922 static HGLOBAL synthesize_dib( HBITMAP bm )
924 HDC hdc = GetDC( 0 );
925 BITMAPINFOHEADER header;
926 BITMAPINFO *bmi;
927 HGLOBAL ret = 0;
928 DWORD header_size;
930 memset( &header, 0, sizeof(header) );
931 header.biSize = sizeof(header);
932 if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
934 header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
935 if (!(ret = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
936 bmi = GlobalLock( ret );
937 memset( bmi, 0, header_size );
938 memcpy( bmi, &header, header.biSize );
939 GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
940 GlobalUnlock( ret );
942 done:
943 ReleaseDC( 0, hdc );
944 return ret;
947 static HBITMAP synthesize_bitmap( HGLOBAL dib )
949 HBITMAP ret = 0;
950 BITMAPINFO *bmi;
951 HDC hdc = GetDC( 0 );
953 if ((bmi = GlobalLock( dib )))
955 /* FIXME: validate data size */
956 ret = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
957 (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
958 bmi, DIB_RGB_COLORS );
959 GlobalUnlock( dib );
961 ReleaseDC( 0, hdc );
962 return ret;
965 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
966 const FORMATETC *formatetc,
967 STGMEDIUM *stgmedium,
968 BOOL fRelease)
970 STGMEDIUM dib_copy;
972 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
973 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
974 stgmedium->tymed == TYMED_NULL)
976 WARN("invalid formatetc\n");
977 return DV_E_FORMATETC;
980 cache_entry->dirty = TRUE;
981 ReleaseStgMedium(&cache_entry->stgmedium);
982 cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
984 if (formatetc->cfFormat == CF_BITMAP)
986 dib_copy.tymed = TYMED_HGLOBAL;
987 dib_copy.u.hGlobal = synthesize_dib( stgmedium->u.hBitmap );
988 dib_copy.pUnkForRelease = NULL;
989 if (fRelease) ReleaseStgMedium(stgmedium);
990 stgmedium = &dib_copy;
991 fRelease = TRUE;
994 if (fRelease)
996 cache_entry->stgmedium = *stgmedium;
997 return S_OK;
999 else
1000 return copy_stg_medium(cache_entry->data_cf,
1001 &cache_entry->stgmedium, stgmedium);
1004 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, FORMATETC *fmt, STGMEDIUM *stgmedium)
1006 if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->stream)
1008 HRESULT hr = DataCacheEntry_LoadData(cache_entry);
1009 if (FAILED(hr))
1010 return hr;
1012 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1013 return OLE_E_BLANK;
1015 if (fmt->cfFormat == CF_BITMAP)
1017 stgmedium->tymed = TYMED_GDI;
1018 stgmedium->u.hBitmap = synthesize_bitmap( cache_entry->stgmedium.u.hGlobal );
1019 stgmedium->pUnkForRelease = NULL;
1020 return S_OK;
1022 return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
1025 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
1027 ReleaseStgMedium(&cache_entry->stgmedium);
1028 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
1029 return S_OK;
1032 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
1034 if (cache_entry->stream)
1036 IStream_Release(cache_entry->stream);
1037 cache_entry->stream = NULL;
1041 static inline DWORD tymed_from_cf( DWORD cf )
1043 switch( cf )
1045 case CF_BITMAP: return TYMED_GDI;
1046 case CF_METAFILEPICT: return TYMED_MFPICT;
1047 case CF_ENHMETAFILE: return TYMED_ENHMF;
1048 case CF_DIB:
1049 default: return TYMED_HGLOBAL;
1053 /****************************************************************
1054 * create_automatic_entry
1056 * Creates an appropriate cache entry for one of the CLSID_Picture_
1057 * classes. The connection id of the entry is one. Any pre-existing
1058 * automatic entry is re-assigned a new connection id, and moved to
1059 * the end of the list.
1061 static HRESULT create_automatic_entry(DataCache *cache, const CLSID *clsid)
1063 static const struct data
1065 const CLSID *clsid;
1066 FORMATETC fmt;
1067 } data[] =
1069 { &CLSID_Picture_Dib, { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
1070 { &CLSID_Picture_Metafile, { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
1071 { &CLSID_Picture_EnhMetafile, { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
1072 { NULL }
1074 const struct data *ptr = data;
1075 struct list *head;
1076 DataCacheEntry *entry;
1078 if (IsEqualCLSID( &cache->clsid, clsid )) return S_OK;
1080 /* move and reassign any pre-existing automatic entry */
1081 if ((head = list_head( &cache->cache_list )))
1083 entry = LIST_ENTRY( head, DataCacheEntry, entry );
1084 if (entry->id == 1)
1086 list_remove( &entry->entry );
1087 entry->id = cache->last_cache_id++;
1088 list_add_tail( &cache->cache_list, &entry->entry );
1092 while (ptr->clsid)
1094 if (IsEqualCLSID( clsid, ptr->clsid ))
1095 return DataCache_CreateEntry( cache, &ptr->fmt, 0, TRUE, NULL );
1096 ptr++;
1098 return S_OK;
1101 /*********************************************************
1102 * Method implementation for the non delegating IUnknown
1103 * part of the DataCache class.
1106 /************************************************************************
1107 * DataCache_NDIUnknown_QueryInterface (IUnknown)
1109 * This version of QueryInterface will not delegate its implementation
1110 * to the outer unknown.
1112 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
1113 IUnknown* iface,
1114 REFIID riid,
1115 void** ppvObject)
1117 DataCache *this = impl_from_IUnknown(iface);
1119 if ( ppvObject==0 )
1120 return E_INVALIDARG;
1122 *ppvObject = 0;
1124 if (IsEqualIID(&IID_IUnknown, riid))
1126 *ppvObject = iface;
1128 else if (IsEqualIID(&IID_IDataObject, riid))
1130 *ppvObject = &this->IDataObject_iface;
1132 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
1133 IsEqualIID(&IID_IPersist, riid) )
1135 *ppvObject = &this->IPersistStorage_iface;
1137 else if ( IsEqualIID(&IID_IViewObject, riid) ||
1138 IsEqualIID(&IID_IViewObject2, riid) )
1140 *ppvObject = &this->IViewObject2_iface;
1142 else if ( IsEqualIID(&IID_IOleCache, riid) ||
1143 IsEqualIID(&IID_IOleCache2, riid) )
1145 *ppvObject = &this->IOleCache2_iface;
1147 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1149 *ppvObject = &this->IOleCacheControl_iface;
1152 if ((*ppvObject)==0)
1154 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1155 return E_NOINTERFACE;
1158 IUnknown_AddRef((IUnknown*)*ppvObject);
1160 return S_OK;
1163 /************************************************************************
1164 * DataCache_NDIUnknown_AddRef (IUnknown)
1166 * This version of QueryInterface will not delegate its implementation
1167 * to the outer unknown.
1169 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1170 IUnknown* iface)
1172 DataCache *this = impl_from_IUnknown(iface);
1173 return InterlockedIncrement(&this->ref);
1176 /************************************************************************
1177 * DataCache_NDIUnknown_Release (IUnknown)
1179 * This version of QueryInterface will not delegate its implementation
1180 * to the outer unknown.
1182 static ULONG WINAPI DataCache_NDIUnknown_Release(
1183 IUnknown* iface)
1185 DataCache *this = impl_from_IUnknown(iface);
1186 ULONG ref;
1188 ref = InterlockedDecrement(&this->ref);
1190 if (ref == 0) DataCache_Destroy(this);
1192 return ref;
1195 /*********************************************************
1196 * Method implementation for the IDataObject
1197 * part of the DataCache class.
1200 /************************************************************************
1201 * DataCache_IDataObject_QueryInterface (IUnknown)
1203 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1204 IDataObject* iface,
1205 REFIID riid,
1206 void** ppvObject)
1208 DataCache *this = impl_from_IDataObject(iface);
1210 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1213 /************************************************************************
1214 * DataCache_IDataObject_AddRef (IUnknown)
1216 static ULONG WINAPI DataCache_IDataObject_AddRef(
1217 IDataObject* iface)
1219 DataCache *this = impl_from_IDataObject(iface);
1221 return IUnknown_AddRef(this->outer_unk);
1224 /************************************************************************
1225 * DataCache_IDataObject_Release (IUnknown)
1227 static ULONG WINAPI DataCache_IDataObject_Release(
1228 IDataObject* iface)
1230 DataCache *this = impl_from_IDataObject(iface);
1232 return IUnknown_Release(this->outer_unk);
1235 /************************************************************************
1236 * DataCache_GetData
1238 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1240 static HRESULT WINAPI DataCache_GetData(
1241 IDataObject* iface,
1242 LPFORMATETC pformatetcIn,
1243 STGMEDIUM* pmedium)
1245 DataCache *This = impl_from_IDataObject(iface);
1246 DataCacheEntry *cache_entry;
1248 memset(pmedium, 0, sizeof(*pmedium));
1250 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1251 if (!cache_entry)
1252 return OLE_E_BLANK;
1254 return DataCacheEntry_GetData(cache_entry, pformatetcIn, pmedium);
1257 static HRESULT WINAPI DataCache_GetDataHere(
1258 IDataObject* iface,
1259 LPFORMATETC pformatetc,
1260 STGMEDIUM* pmedium)
1262 FIXME("stub\n");
1263 return E_NOTIMPL;
1266 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1268 DataCache *This = impl_from_IDataObject( iface );
1269 DataCacheEntry *cache_entry;
1271 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1272 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1274 return cache_entry ? S_OK : S_FALSE;
1277 /************************************************************************
1278 * DataCache_EnumFormatEtc (IDataObject)
1280 * The data cache doesn't implement this method.
1282 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1283 IDataObject* iface,
1284 LPFORMATETC pformatectIn,
1285 LPFORMATETC pformatetcOut)
1287 TRACE("()\n");
1288 return E_NOTIMPL;
1291 /************************************************************************
1292 * DataCache_IDataObject_SetData (IDataObject)
1294 * This method is delegated to the IOleCache2 implementation.
1296 static HRESULT WINAPI DataCache_IDataObject_SetData(
1297 IDataObject* iface,
1298 LPFORMATETC pformatetc,
1299 STGMEDIUM* pmedium,
1300 BOOL fRelease)
1302 IOleCache2* oleCache = NULL;
1303 HRESULT hres;
1305 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1307 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1309 if (FAILED(hres))
1310 return E_UNEXPECTED;
1312 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1314 IOleCache2_Release(oleCache);
1316 return hres;
1319 /************************************************************************
1320 * DataCache_EnumFormatEtc (IDataObject)
1322 * The data cache doesn't implement this method.
1324 static HRESULT WINAPI DataCache_EnumFormatEtc(
1325 IDataObject* iface,
1326 DWORD dwDirection,
1327 IEnumFORMATETC** ppenumFormatEtc)
1329 TRACE("()\n");
1330 return E_NOTIMPL;
1333 /************************************************************************
1334 * DataCache_DAdvise (IDataObject)
1336 * The data cache doesn't support connections.
1338 static HRESULT WINAPI DataCache_DAdvise(
1339 IDataObject* iface,
1340 FORMATETC* pformatetc,
1341 DWORD advf,
1342 IAdviseSink* pAdvSink,
1343 DWORD* pdwConnection)
1345 TRACE("()\n");
1346 return OLE_E_ADVISENOTSUPPORTED;
1349 /************************************************************************
1350 * DataCache_DUnadvise (IDataObject)
1352 * The data cache doesn't support connections.
1354 static HRESULT WINAPI DataCache_DUnadvise(
1355 IDataObject* iface,
1356 DWORD dwConnection)
1358 TRACE("()\n");
1359 return OLE_E_NOCONNECTION;
1362 /************************************************************************
1363 * DataCache_EnumDAdvise (IDataObject)
1365 * The data cache doesn't support connections.
1367 static HRESULT WINAPI DataCache_EnumDAdvise(
1368 IDataObject* iface,
1369 IEnumSTATDATA** ppenumAdvise)
1371 TRACE("()\n");
1372 return OLE_E_ADVISENOTSUPPORTED;
1375 /*********************************************************
1376 * Method implementation for the IDataObject
1377 * part of the DataCache class.
1380 /************************************************************************
1381 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1383 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1384 IPersistStorage* iface,
1385 REFIID riid,
1386 void** ppvObject)
1388 DataCache *this = impl_from_IPersistStorage(iface);
1390 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1393 /************************************************************************
1394 * DataCache_IPersistStorage_AddRef (IUnknown)
1396 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1397 IPersistStorage* iface)
1399 DataCache *this = impl_from_IPersistStorage(iface);
1401 return IUnknown_AddRef(this->outer_unk);
1404 /************************************************************************
1405 * DataCache_IPersistStorage_Release (IUnknown)
1407 static ULONG WINAPI DataCache_IPersistStorage_Release(
1408 IPersistStorage* iface)
1410 DataCache *this = impl_from_IPersistStorage(iface);
1412 return IUnknown_Release(this->outer_unk);
1415 /************************************************************************
1416 * DataCache_GetClassID (IPersistStorage)
1419 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1421 DataCache *This = impl_from_IPersistStorage( iface );
1423 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1424 *clsid = This->clsid;
1426 return S_OK;
1429 /************************************************************************
1430 * DataCache_IsDirty (IPersistStorage)
1432 static HRESULT WINAPI DataCache_IsDirty(
1433 IPersistStorage* iface)
1435 DataCache *This = impl_from_IPersistStorage(iface);
1436 DataCacheEntry *cache_entry;
1438 TRACE("(%p)\n", iface);
1440 if (This->dirty)
1441 return S_OK;
1443 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1444 if (cache_entry->dirty)
1445 return S_OK;
1447 return S_FALSE;
1450 /************************************************************************
1451 * DataCache_InitNew (IPersistStorage)
1453 * The data cache implementation of IPersistStorage_InitNew simply stores
1454 * the storage pointer.
1456 static HRESULT WINAPI DataCache_InitNew(
1457 IPersistStorage* iface,
1458 IStorage* pStg)
1460 DataCache *This = impl_from_IPersistStorage(iface);
1461 CLSID clsid;
1462 HRESULT hr;
1464 TRACE("(%p, %p)\n", iface, pStg);
1466 if (This->presentationStorage != NULL)
1467 return CO_E_ALREADYINITIALIZED;
1469 This->presentationStorage = pStg;
1471 IStorage_AddRef(This->presentationStorage);
1472 This->dirty = TRUE;
1473 ReadClassStg( pStg, &clsid );
1474 hr = create_automatic_entry( This, &clsid );
1475 if (FAILED(hr))
1477 IStorage_Release( pStg );
1478 This->presentationStorage = NULL;
1479 return hr;
1481 This->clsid = clsid;
1483 return S_OK;
1487 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, IStream *stm,
1488 enum stream_type type )
1490 DataCacheEntry *cache_entry;
1491 HRESULT hr = S_OK;
1493 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1495 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1496 if (!cache_entry)
1497 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1498 if (SUCCEEDED( hr ))
1500 DataCacheEntry_DiscardData( cache_entry );
1501 if (cache_entry->stream) IStream_Release( cache_entry->stream );
1502 cache_entry->stream = stm;
1503 IStream_AddRef( stm );
1504 cache_entry->stream_type = type;
1505 cache_entry->dirty = FALSE;
1507 return hr;
1510 static HRESULT parse_pres_streams( DataCache *This, IStorage *stg )
1512 HRESULT hr;
1513 IEnumSTATSTG *stat_enum;
1514 STATSTG stat;
1515 IStream *stm;
1516 PresentationDataHeader header;
1517 ULONG actual_read;
1518 CLIPFORMAT clipformat;
1519 FORMATETC fmtetc;
1521 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stat_enum );
1522 if (FAILED( hr )) return hr;
1524 while ((hr = IEnumSTATSTG_Next( stat_enum, 1, &stat, NULL )) == S_OK)
1526 if (DataCache_IsPresentationStream( &stat ))
1528 hr = IStorage_OpenStream( stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1529 0, &stm );
1530 if (SUCCEEDED( hr ))
1532 hr = read_clipformat( stm, &clipformat );
1534 if (hr == S_OK)
1535 hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1537 if (hr == S_OK && actual_read == sizeof(header))
1539 fmtetc.cfFormat = clipformat;
1540 fmtetc.ptd = NULL; /* FIXME */
1541 fmtetc.dwAspect = header.dvAspect;
1542 fmtetc.lindex = header.lindex;
1543 fmtetc.tymed = tymed_from_cf( clipformat );
1545 add_cache_entry( This, &fmtetc, header.advf, stm, pres_stream );
1547 IStream_Release( stm );
1550 CoTaskMemFree( stat.pwcsName );
1552 IEnumSTATSTG_Release( stat_enum );
1554 return S_OK;
1557 static const FORMATETC static_dib_fmt = { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
1559 static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *stm )
1561 HRESULT hr;
1562 STATSTG stat;
1563 const FORMATETC *fmt;
1565 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
1566 if (FAILED( hr )) return hr;
1568 if (IsEqualCLSID( &stat.clsid, &CLSID_Picture_Dib ))
1569 fmt = &static_dib_fmt;
1570 else
1572 FIXME("unsupported format %s\n", debugstr_guid( &stat.clsid ));
1573 return E_FAIL;
1576 return add_cache_entry( This, fmt, 0, stm, contents_stream );
1579 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1581 /************************************************************************
1582 * DataCache_Load (IPersistStorage)
1584 * The data cache implementation of IPersistStorage_Load doesn't
1585 * actually load anything. Instead, it holds on to the storage pointer
1586 * and it will load the presentation information when the
1587 * IDataObject_GetData or IViewObject2_Draw methods are called.
1589 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1591 DataCache *This = impl_from_IPersistStorage(iface);
1592 HRESULT hr;
1593 IStream *stm;
1594 CLSID clsid;
1595 DataCacheEntry *entry, *cursor2;
1597 TRACE("(%p, %p)\n", iface, pStg);
1599 IPersistStorage_HandsOffStorage( iface );
1601 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1602 DataCacheEntry_Destroy( This, entry );
1604 ReadClassStg( pStg, &clsid );
1605 hr = create_automatic_entry( This, &clsid );
1606 if (FAILED( hr )) return hr;
1608 This->clsid = clsid;
1610 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1611 0, &stm );
1612 if (SUCCEEDED( hr ))
1614 hr = parse_contents_stream( This, pStg, stm );
1615 IStream_Release( stm );
1618 if (FAILED(hr))
1619 hr = parse_pres_streams( This, pStg );
1621 if (SUCCEEDED( hr ))
1623 This->dirty = FALSE;
1624 This->presentationStorage = pStg;
1625 IStorage_AddRef( This->presentationStorage );
1628 return hr;
1631 /************************************************************************
1632 * DataCache_Save (IPersistStorage)
1634 * Until we actually connect to a running object and retrieve new
1635 * information to it, we never have to save anything. However, it is
1636 * our responsibility to copy the information when saving to a new
1637 * storage.
1639 static HRESULT WINAPI DataCache_Save(
1640 IPersistStorage* iface,
1641 IStorage* pStg,
1642 BOOL fSameAsLoad)
1644 DataCache *This = impl_from_IPersistStorage(iface);
1645 DataCacheEntry *cache_entry;
1646 BOOL dirty = FALSE;
1647 HRESULT hr = S_OK;
1648 unsigned short stream_number = 0;
1650 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1652 dirty = This->dirty;
1653 if (!dirty)
1655 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1657 dirty = cache_entry->dirty;
1658 if (dirty)
1659 break;
1663 /* this is a shortcut if nothing changed */
1664 if (!dirty && !fSameAsLoad && This->presentationStorage)
1666 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1669 /* assign stream numbers to the cache entries */
1670 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1672 if (cache_entry->stream_number != stream_number)
1674 cache_entry->dirty = TRUE; /* needs to be written out again */
1675 cache_entry->stream_number = stream_number;
1677 stream_number++;
1680 /* write out the cache entries */
1681 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1683 if (!fSameAsLoad || cache_entry->dirty)
1685 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1686 if (FAILED(hr))
1687 break;
1689 cache_entry->dirty = FALSE;
1693 This->dirty = FALSE;
1694 return hr;
1697 /************************************************************************
1698 * DataCache_SaveCompleted (IPersistStorage)
1700 * This method is called to tell the cache to release the storage
1701 * pointer it's currently holding.
1703 static HRESULT WINAPI DataCache_SaveCompleted(
1704 IPersistStorage* iface,
1705 IStorage* pStgNew)
1707 TRACE("(%p, %p)\n", iface, pStgNew);
1709 if (pStgNew)
1711 IPersistStorage_HandsOffStorage(iface);
1713 DataCache_Load(iface, pStgNew);
1716 return S_OK;
1719 /************************************************************************
1720 * DataCache_HandsOffStorage (IPersistStorage)
1722 * This method is called to tell the cache to release the storage
1723 * pointer it's currently holding.
1725 static HRESULT WINAPI DataCache_HandsOffStorage(
1726 IPersistStorage* iface)
1728 DataCache *this = impl_from_IPersistStorage(iface);
1729 DataCacheEntry *cache_entry;
1731 TRACE("(%p)\n", iface);
1733 if (this->presentationStorage != NULL)
1735 IStorage_Release(this->presentationStorage);
1736 this->presentationStorage = NULL;
1739 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1740 DataCacheEntry_HandsOffStorage(cache_entry);
1742 return S_OK;
1745 /*********************************************************
1746 * Method implementation for the IViewObject2
1747 * part of the DataCache class.
1750 /************************************************************************
1751 * DataCache_IViewObject2_QueryInterface (IUnknown)
1753 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1754 IViewObject2* iface,
1755 REFIID riid,
1756 void** ppvObject)
1758 DataCache *this = impl_from_IViewObject2(iface);
1760 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1763 /************************************************************************
1764 * DataCache_IViewObject2_AddRef (IUnknown)
1766 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1767 IViewObject2* iface)
1769 DataCache *this = impl_from_IViewObject2(iface);
1771 return IUnknown_AddRef(this->outer_unk);
1774 /************************************************************************
1775 * DataCache_IViewObject2_Release (IUnknown)
1777 static ULONG WINAPI DataCache_IViewObject2_Release(
1778 IViewObject2* iface)
1780 DataCache *this = impl_from_IViewObject2(iface);
1782 return IUnknown_Release(this->outer_unk);
1785 /************************************************************************
1786 * DataCache_Draw (IViewObject2)
1788 * This method will draw the cached representation of the object
1789 * to the given device context.
1791 static HRESULT WINAPI DataCache_Draw(
1792 IViewObject2* iface,
1793 DWORD dwDrawAspect,
1794 LONG lindex,
1795 void* pvAspect,
1796 DVTARGETDEVICE* ptd,
1797 HDC hdcTargetDev,
1798 HDC hdcDraw,
1799 LPCRECTL lprcBounds,
1800 LPCRECTL lprcWBounds,
1801 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1802 ULONG_PTR dwContinue)
1804 DataCache *This = impl_from_IViewObject2(iface);
1805 HRESULT hres;
1806 DataCacheEntry *cache_entry;
1808 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1809 iface,
1810 dwDrawAspect,
1811 lindex,
1812 pvAspect,
1813 hdcTargetDev,
1814 hdcDraw,
1815 lprcBounds,
1816 lprcWBounds,
1817 pfnContinue,
1818 dwContinue);
1820 if (lprcBounds==NULL)
1821 return E_INVALIDARG;
1823 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1825 /* FIXME: compare ptd too */
1826 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1827 (cache_entry->fmtetc.lindex != lindex))
1828 continue;
1830 /* if the data hasn't been loaded yet, do it now */
1831 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1833 hres = DataCacheEntry_LoadData(cache_entry);
1834 if (FAILED(hres))
1835 continue;
1838 /* no data */
1839 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1840 continue;
1842 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1844 switch (cache_entry->data_cf)
1846 case CF_METAFILEPICT:
1849 * We have to be careful not to modify the state of the
1850 * DC.
1852 INT prevMapMode;
1853 SIZE oldWindowExt;
1854 SIZE oldViewportExt;
1855 POINT oldViewportOrg;
1856 METAFILEPICT *mfpict;
1858 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1859 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1860 continue;
1862 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1864 SetWindowExtEx(hdcDraw,
1865 mfpict->xExt,
1866 mfpict->yExt,
1867 &oldWindowExt);
1869 SetViewportExtEx(hdcDraw,
1870 lprcBounds->right - lprcBounds->left,
1871 lprcBounds->bottom - lprcBounds->top,
1872 &oldViewportExt);
1874 SetViewportOrgEx(hdcDraw,
1875 lprcBounds->left,
1876 lprcBounds->top,
1877 &oldViewportOrg);
1879 PlayMetaFile(hdcDraw, mfpict->hMF);
1881 SetWindowExtEx(hdcDraw,
1882 oldWindowExt.cx,
1883 oldWindowExt.cy,
1884 NULL);
1886 SetViewportExtEx(hdcDraw,
1887 oldViewportExt.cx,
1888 oldViewportExt.cy,
1889 NULL);
1891 SetViewportOrgEx(hdcDraw,
1892 oldViewportOrg.x,
1893 oldViewportOrg.y,
1894 NULL);
1896 SetMapMode(hdcDraw, prevMapMode);
1898 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1900 return S_OK;
1902 case CF_DIB:
1904 BITMAPINFO *info;
1905 BYTE *bits;
1907 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1908 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1909 continue;
1911 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
1912 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1913 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1914 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1915 bits, info, DIB_RGB_COLORS, SRCCOPY );
1917 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1918 return S_OK;
1923 WARN("no data could be found to be drawn\n");
1925 return OLE_E_BLANK;
1928 static HRESULT WINAPI DataCache_GetColorSet(
1929 IViewObject2* iface,
1930 DWORD dwDrawAspect,
1931 LONG lindex,
1932 void* pvAspect,
1933 DVTARGETDEVICE* ptd,
1934 HDC hicTargetDevice,
1935 LOGPALETTE** ppColorSet)
1937 FIXME("stub\n");
1938 return E_NOTIMPL;
1941 static HRESULT WINAPI DataCache_Freeze(
1942 IViewObject2* iface,
1943 DWORD dwDrawAspect,
1944 LONG lindex,
1945 void* pvAspect,
1946 DWORD* pdwFreeze)
1948 FIXME("stub\n");
1949 return E_NOTIMPL;
1952 static HRESULT WINAPI DataCache_Unfreeze(
1953 IViewObject2* iface,
1954 DWORD dwFreeze)
1956 FIXME("stub\n");
1957 return E_NOTIMPL;
1960 /************************************************************************
1961 * DataCache_SetAdvise (IViewObject2)
1963 * This sets-up an advisory sink with the data cache. When the object's
1964 * view changes, this sink is called.
1966 static HRESULT WINAPI DataCache_SetAdvise(
1967 IViewObject2* iface,
1968 DWORD aspects,
1969 DWORD advf,
1970 IAdviseSink* pAdvSink)
1972 DataCache *this = impl_from_IViewObject2(iface);
1974 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1977 * A call to this function removes the previous sink
1979 if (this->sinkInterface != NULL)
1981 IAdviseSink_Release(this->sinkInterface);
1982 this->sinkInterface = NULL;
1983 this->sinkAspects = 0;
1984 this->sinkAdviseFlag = 0;
1988 * Now, setup the new one.
1990 if (pAdvSink!=NULL)
1992 this->sinkInterface = pAdvSink;
1993 this->sinkAspects = aspects;
1994 this->sinkAdviseFlag = advf;
1996 IAdviseSink_AddRef(this->sinkInterface);
2000 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2001 * sink immediately.
2003 if (advf & ADVF_PRIMEFIRST)
2005 DataCache_FireOnViewChange(this, aspects, -1);
2008 return S_OK;
2011 /************************************************************************
2012 * DataCache_GetAdvise (IViewObject2)
2014 * This method queries the current state of the advise sink
2015 * installed on the data cache.
2017 static HRESULT WINAPI DataCache_GetAdvise(
2018 IViewObject2* iface,
2019 DWORD* pAspects,
2020 DWORD* pAdvf,
2021 IAdviseSink** ppAdvSink)
2023 DataCache *this = impl_from_IViewObject2(iface);
2025 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2028 * Just copy all the requested values.
2030 if (pAspects!=NULL)
2031 *pAspects = this->sinkAspects;
2033 if (pAdvf!=NULL)
2034 *pAdvf = this->sinkAdviseFlag;
2036 if (ppAdvSink!=NULL)
2038 if (this->sinkInterface != NULL)
2039 IAdviseSink_QueryInterface(this->sinkInterface,
2040 &IID_IAdviseSink,
2041 (void**)ppAdvSink);
2042 else *ppAdvSink = NULL;
2045 return S_OK;
2048 /************************************************************************
2049 * DataCache_GetExtent (IViewObject2)
2051 * This method retrieves the "natural" size of this cached object.
2053 static HRESULT WINAPI DataCache_GetExtent(
2054 IViewObject2* iface,
2055 DWORD dwDrawAspect,
2056 LONG lindex,
2057 DVTARGETDEVICE* ptd,
2058 LPSIZEL lpsizel)
2060 DataCache *This = impl_from_IViewObject2(iface);
2061 HRESULT hres = E_FAIL;
2062 DataCacheEntry *cache_entry;
2064 TRACE("(%p, %x, %d, %p, %p)\n",
2065 iface, dwDrawAspect, lindex, ptd, lpsizel);
2067 if (lpsizel==NULL)
2068 return E_POINTER;
2070 lpsizel->cx = 0;
2071 lpsizel->cy = 0;
2073 if (lindex!=-1)
2074 FIXME("Unimplemented flag lindex = %d\n", lindex);
2077 * Right now, we support only the callback from
2078 * the default handler.
2080 if (ptd!=NULL)
2081 FIXME("Unimplemented ptd = %p\n", ptd);
2083 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2085 /* FIXME: compare ptd too */
2086 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2087 (cache_entry->fmtetc.lindex != lindex))
2088 continue;
2090 /* if the data hasn't been loaded yet, do it now */
2091 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
2093 hres = DataCacheEntry_LoadData(cache_entry);
2094 if (FAILED(hres))
2095 continue;
2098 /* no data */
2099 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2100 continue;
2103 switch (cache_entry->data_cf)
2105 case CF_METAFILEPICT:
2107 METAFILEPICT *mfpict;
2109 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2110 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2111 continue;
2113 lpsizel->cx = mfpict->xExt;
2114 lpsizel->cy = mfpict->yExt;
2116 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2118 return S_OK;
2120 case CF_DIB:
2122 BITMAPINFOHEADER *info;
2123 LONG x_pels_m, y_pels_m;
2126 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2127 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2128 continue;
2130 x_pels_m = info->biXPelsPerMeter;
2131 y_pels_m = info->biYPelsPerMeter;
2133 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2134 if (x_pels_m != 0 && y_pels_m != 0)
2136 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
2137 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2139 else
2141 HDC hdc = GetDC( 0 );
2142 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2143 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2145 ReleaseDC( 0, hdc );
2148 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2150 return S_OK;
2155 WARN("no data could be found to get the extents from\n");
2158 * This method returns OLE_E_BLANK when it fails.
2160 return OLE_E_BLANK;
2164 /*********************************************************
2165 * Method implementation for the IOleCache2
2166 * part of the DataCache class.
2169 /************************************************************************
2170 * DataCache_IOleCache2_QueryInterface (IUnknown)
2172 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2173 IOleCache2* iface,
2174 REFIID riid,
2175 void** ppvObject)
2177 DataCache *this = impl_from_IOleCache2(iface);
2179 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2182 /************************************************************************
2183 * DataCache_IOleCache2_AddRef (IUnknown)
2185 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2186 IOleCache2* iface)
2188 DataCache *this = impl_from_IOleCache2(iface);
2190 return IUnknown_AddRef(this->outer_unk);
2193 /************************************************************************
2194 * DataCache_IOleCache2_Release (IUnknown)
2196 static ULONG WINAPI DataCache_IOleCache2_Release(
2197 IOleCache2* iface)
2199 DataCache *this = impl_from_IOleCache2(iface);
2201 return IUnknown_Release(this->outer_unk);
2204 /*****************************************************************************
2205 * setup_sink
2207 * Set up the sink connection to the running object.
2209 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2211 HRESULT hr = S_FALSE;
2212 DWORD flags;
2214 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2215 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2217 if(This->running_object)
2218 if(!(flags & ADVF_NODATA))
2219 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2220 &This->IAdviseSink_iface, &cache_entry->sink_id);
2221 return hr;
2224 static HRESULT WINAPI DataCache_Cache(
2225 IOleCache2* iface,
2226 FORMATETC* pformatetc,
2227 DWORD advf,
2228 DWORD* pdwConnection)
2230 DataCache *This = impl_from_IOleCache2(iface);
2231 DataCacheEntry *cache_entry;
2232 HRESULT hr;
2233 FORMATETC fmt_cpy;
2235 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2237 if (!pformatetc || !pdwConnection)
2238 return E_INVALIDARG;
2240 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2242 fmt_cpy = *pformatetc; /* No need for a deep copy */
2243 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2245 fmt_cpy.cfFormat = CF_DIB;
2246 fmt_cpy.tymed = TYMED_HGLOBAL;
2249 *pdwConnection = 0;
2251 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2252 if (cache_entry)
2254 TRACE("found an existing cache entry\n");
2255 *pdwConnection = cache_entry->id;
2256 return CACHE_S_SAMECACHE;
2259 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2261 if (SUCCEEDED(hr))
2263 *pdwConnection = cache_entry->id;
2264 setup_sink(This, cache_entry);
2267 return hr;
2270 static HRESULT WINAPI DataCache_Uncache(
2271 IOleCache2* iface,
2272 DWORD dwConnection)
2274 DataCache *This = impl_from_IOleCache2(iface);
2275 DataCacheEntry *cache_entry;
2277 TRACE("(%d)\n", dwConnection);
2279 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2280 if (cache_entry->id == dwConnection)
2282 DataCacheEntry_Destroy(This, cache_entry);
2283 return S_OK;
2286 WARN("no connection found for %d\n", dwConnection);
2288 return OLE_E_NOCONNECTION;
2291 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2292 IEnumSTATDATA **enum_stat)
2294 DataCache *This = impl_from_IOleCache2( iface );
2295 DataCacheEntry *cache_entry;
2296 int i = 0, count = 0;
2297 STATDATA *data;
2298 HRESULT hr;
2300 TRACE( "(%p, %p)\n", This, enum_stat );
2302 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2304 count++;
2305 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2306 count++;
2309 data = CoTaskMemAlloc( count * sizeof(*data) );
2310 if (!data) return E_OUTOFMEMORY;
2312 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2314 if (i == count) goto fail;
2315 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2316 if (FAILED(hr)) goto fail;
2317 data[i].advf = cache_entry->advise_flags;
2318 data[i].pAdvSink = NULL;
2319 data[i].dwConnection = cache_entry->id;
2320 i++;
2322 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2324 if (i == count) goto fail;
2325 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2326 if (FAILED(hr)) goto fail;
2327 data[i].formatetc.cfFormat = CF_BITMAP;
2328 data[i].formatetc.tymed = TYMED_GDI;
2329 data[i].advf = cache_entry->advise_flags;
2330 data[i].pAdvSink = NULL;
2331 data[i].dwConnection = cache_entry->id;
2332 i++;
2336 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2337 if (SUCCEEDED(hr)) return hr;
2339 fail:
2340 while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2341 CoTaskMemFree( data );
2342 return hr;
2345 static HRESULT WINAPI DataCache_InitCache(
2346 IOleCache2* iface,
2347 IDataObject* pDataObject)
2349 FIXME("stub\n");
2350 return E_NOTIMPL;
2353 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2354 IOleCache2* iface,
2355 FORMATETC* pformatetc,
2356 STGMEDIUM* pmedium,
2357 BOOL fRelease)
2359 DataCache *This = impl_from_IOleCache2(iface);
2360 DataCacheEntry *cache_entry;
2361 HRESULT hr;
2363 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2364 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2366 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2367 if (cache_entry)
2369 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2371 if (SUCCEEDED(hr))
2372 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2373 cache_entry->fmtetc.lindex);
2375 return hr;
2377 WARN("cache entry not found\n");
2379 return OLE_E_BLANK;
2382 static HRESULT WINAPI DataCache_UpdateCache(
2383 IOleCache2* iface,
2384 LPDATAOBJECT pDataObject,
2385 DWORD grfUpdf,
2386 LPVOID pReserved)
2388 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2389 return E_NOTIMPL;
2392 static HRESULT WINAPI DataCache_DiscardCache(
2393 IOleCache2* iface,
2394 DWORD dwDiscardOptions)
2396 DataCache *This = impl_from_IOleCache2(iface);
2397 DataCacheEntry *cache_entry;
2398 HRESULT hr = S_OK;
2400 TRACE("(%d)\n", dwDiscardOptions);
2402 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2403 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2405 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2407 hr = DataCacheEntry_DiscardData(cache_entry);
2408 if (FAILED(hr))
2409 break;
2412 return hr;
2416 /*********************************************************
2417 * Method implementation for the IOleCacheControl
2418 * part of the DataCache class.
2421 /************************************************************************
2422 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2424 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2425 IOleCacheControl* iface,
2426 REFIID riid,
2427 void** ppvObject)
2429 DataCache *this = impl_from_IOleCacheControl(iface);
2431 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2434 /************************************************************************
2435 * DataCache_IOleCacheControl_AddRef (IUnknown)
2437 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2438 IOleCacheControl* iface)
2440 DataCache *this = impl_from_IOleCacheControl(iface);
2442 return IUnknown_AddRef(this->outer_unk);
2445 /************************************************************************
2446 * DataCache_IOleCacheControl_Release (IUnknown)
2448 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2449 IOleCacheControl* iface)
2451 DataCache *this = impl_from_IOleCacheControl(iface);
2453 return IUnknown_Release(this->outer_unk);
2456 /************************************************************************
2457 * DataCache_OnRun (IOleCacheControl)
2459 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2461 DataCache *This = impl_from_IOleCacheControl(iface);
2462 DataCacheEntry *cache_entry;
2464 TRACE("(%p)->(%p)\n", iface, data_obj);
2466 if(This->running_object) return S_OK;
2468 /* No reference is taken on the data object */
2469 This->running_object = data_obj;
2471 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2473 setup_sink(This, cache_entry);
2476 return S_OK;
2479 /************************************************************************
2480 * DataCache_OnStop (IOleCacheControl)
2482 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2484 DataCache *This = impl_from_IOleCacheControl(iface);
2485 DataCacheEntry *cache_entry;
2487 TRACE("(%p)\n", iface);
2489 if(!This->running_object) return S_OK;
2491 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2493 if(cache_entry->sink_id)
2495 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2496 cache_entry->sink_id = 0;
2500 /* No ref taken in OnRun, so no Release call here */
2501 This->running_object = NULL;
2502 return S_OK;
2505 /************************************************************************
2506 * IAdviseSink methods.
2507 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2508 * give access to the cache's other interfaces. We don't maintain a ref count,
2509 * the object exists as long as the cache is around.
2511 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2513 *obj = NULL;
2514 if (IsEqualIID(&IID_IUnknown, iid) ||
2515 IsEqualIID(&IID_IAdviseSink, iid))
2517 *obj = iface;
2520 if(*obj)
2522 IAdviseSink_AddRef(iface);
2523 return S_OK;
2525 return E_NOINTERFACE;
2528 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2530 return 2;
2533 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2535 return 1;
2538 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2540 DataCache *This = impl_from_IAdviseSink(iface);
2541 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2542 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2545 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2547 FIXME("stub\n");
2550 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2552 FIXME("stub\n");
2555 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2557 FIXME("stub\n");
2560 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2562 FIXME("stub\n");
2566 * Virtual function tables for the DataCache class.
2568 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2570 DataCache_NDIUnknown_QueryInterface,
2571 DataCache_NDIUnknown_AddRef,
2572 DataCache_NDIUnknown_Release
2575 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2577 DataCache_IDataObject_QueryInterface,
2578 DataCache_IDataObject_AddRef,
2579 DataCache_IDataObject_Release,
2580 DataCache_GetData,
2581 DataCache_GetDataHere,
2582 DataCache_QueryGetData,
2583 DataCache_GetCanonicalFormatEtc,
2584 DataCache_IDataObject_SetData,
2585 DataCache_EnumFormatEtc,
2586 DataCache_DAdvise,
2587 DataCache_DUnadvise,
2588 DataCache_EnumDAdvise
2591 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2593 DataCache_IPersistStorage_QueryInterface,
2594 DataCache_IPersistStorage_AddRef,
2595 DataCache_IPersistStorage_Release,
2596 DataCache_GetClassID,
2597 DataCache_IsDirty,
2598 DataCache_InitNew,
2599 DataCache_Load,
2600 DataCache_Save,
2601 DataCache_SaveCompleted,
2602 DataCache_HandsOffStorage
2605 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2607 DataCache_IViewObject2_QueryInterface,
2608 DataCache_IViewObject2_AddRef,
2609 DataCache_IViewObject2_Release,
2610 DataCache_Draw,
2611 DataCache_GetColorSet,
2612 DataCache_Freeze,
2613 DataCache_Unfreeze,
2614 DataCache_SetAdvise,
2615 DataCache_GetAdvise,
2616 DataCache_GetExtent
2619 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2621 DataCache_IOleCache2_QueryInterface,
2622 DataCache_IOleCache2_AddRef,
2623 DataCache_IOleCache2_Release,
2624 DataCache_Cache,
2625 DataCache_Uncache,
2626 DataCache_EnumCache,
2627 DataCache_InitCache,
2628 DataCache_IOleCache2_SetData,
2629 DataCache_UpdateCache,
2630 DataCache_DiscardCache
2633 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2635 DataCache_IOleCacheControl_QueryInterface,
2636 DataCache_IOleCacheControl_AddRef,
2637 DataCache_IOleCacheControl_Release,
2638 DataCache_OnRun,
2639 DataCache_OnStop
2642 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2644 DataCache_IAdviseSink_QueryInterface,
2645 DataCache_IAdviseSink_AddRef,
2646 DataCache_IAdviseSink_Release,
2647 DataCache_OnDataChange,
2648 DataCache_OnViewChange,
2649 DataCache_OnRename,
2650 DataCache_OnSave,
2651 DataCache_OnClose
2654 /*********************************************************
2655 * Method implementation for DataCache class.
2657 static DataCache* DataCache_Construct(
2658 REFCLSID clsid,
2659 LPUNKNOWN pUnkOuter)
2661 DataCache* newObject = 0;
2664 * Allocate space for the object.
2666 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2668 if (newObject==0)
2669 return newObject;
2672 * Initialize the virtual function table.
2674 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2675 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2676 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2677 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2678 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2679 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2680 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2681 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2682 newObject->ref = 1;
2685 * Initialize the other members of the structure.
2687 newObject->sinkAspects = 0;
2688 newObject->sinkAdviseFlag = 0;
2689 newObject->sinkInterface = 0;
2690 newObject->clsid = CLSID_NULL;
2691 newObject->presentationStorage = NULL;
2692 list_init(&newObject->cache_list);
2693 newObject->last_cache_id = 2;
2694 newObject->dirty = FALSE;
2695 newObject->running_object = NULL;
2697 create_automatic_entry( newObject, clsid );
2698 newObject->clsid = *clsid;
2700 return newObject;
2703 /******************************************************************************
2704 * CreateDataCache [OLE32.@]
2706 * Creates a data cache to allow an object to render one or more of its views,
2707 * whether running or not.
2709 * PARAMS
2710 * pUnkOuter [I] Outer unknown for the object.
2711 * rclsid [I]
2712 * riid [I] IID of interface to return.
2713 * ppvObj [O] Address where the data cache object will be stored on return.
2715 * RETURNS
2716 * Success: S_OK.
2717 * Failure: HRESULT code.
2719 * NOTES
2720 * The following interfaces are supported by the returned data cache object:
2721 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2722 * IViewObject and IViewObject2.
2724 HRESULT WINAPI CreateDataCache(
2725 LPUNKNOWN pUnkOuter,
2726 REFCLSID rclsid,
2727 REFIID riid,
2728 LPVOID* ppvObj)
2730 DataCache* newCache = NULL;
2731 HRESULT hr = S_OK;
2733 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2736 * Sanity check
2738 if (ppvObj==0)
2739 return E_POINTER;
2741 *ppvObj = 0;
2744 * If this cache is constructed for aggregation, make sure
2745 * the caller is requesting the IUnknown interface.
2746 * This is necessary because it's the only time the non-delegating
2747 * IUnknown pointer can be returned to the outside.
2749 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2750 return E_INVALIDARG;
2753 * Try to construct a new instance of the class.
2755 newCache = DataCache_Construct(rclsid,
2756 pUnkOuter);
2758 if (newCache == 0)
2759 return E_OUTOFMEMORY;
2761 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
2762 IUnknown_Release(&newCache->IUnknown_inner);
2764 return hr;