mshtml: Store event target as EventTarget in HTMLEventObj.
[wine.git] / dlls / ole32 / datacache.c
blob808c2dcb04946bd9a1c2dd2e65e819365b4b5522
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 if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */
1127 *ppvObject = &this->IOleCache2_iface;
1128 else
1129 *ppvObject = iface;
1131 else if (IsEqualIID(&IID_IDataObject, riid))
1133 *ppvObject = &this->IDataObject_iface;
1135 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
1136 IsEqualIID(&IID_IPersist, riid) )
1138 *ppvObject = &this->IPersistStorage_iface;
1140 else if ( IsEqualIID(&IID_IViewObject, riid) ||
1141 IsEqualIID(&IID_IViewObject2, riid) )
1143 *ppvObject = &this->IViewObject2_iface;
1145 else if ( IsEqualIID(&IID_IOleCache, riid) ||
1146 IsEqualIID(&IID_IOleCache2, riid) )
1148 *ppvObject = &this->IOleCache2_iface;
1150 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1152 *ppvObject = &this->IOleCacheControl_iface;
1155 if ((*ppvObject)==0)
1157 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1158 return E_NOINTERFACE;
1161 IUnknown_AddRef((IUnknown*)*ppvObject);
1163 return S_OK;
1166 /************************************************************************
1167 * DataCache_NDIUnknown_AddRef (IUnknown)
1169 * This version of QueryInterface will not delegate its implementation
1170 * to the outer unknown.
1172 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1173 IUnknown* iface)
1175 DataCache *this = impl_from_IUnknown(iface);
1176 return InterlockedIncrement(&this->ref);
1179 /************************************************************************
1180 * DataCache_NDIUnknown_Release (IUnknown)
1182 * This version of QueryInterface will not delegate its implementation
1183 * to the outer unknown.
1185 static ULONG WINAPI DataCache_NDIUnknown_Release(
1186 IUnknown* iface)
1188 DataCache *this = impl_from_IUnknown(iface);
1189 ULONG ref;
1191 ref = InterlockedDecrement(&this->ref);
1193 if (ref == 0) DataCache_Destroy(this);
1195 return ref;
1198 /*********************************************************
1199 * Method implementation for the IDataObject
1200 * part of the DataCache class.
1203 /************************************************************************
1204 * DataCache_IDataObject_QueryInterface (IUnknown)
1206 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1207 IDataObject* iface,
1208 REFIID riid,
1209 void** ppvObject)
1211 DataCache *this = impl_from_IDataObject(iface);
1213 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1216 /************************************************************************
1217 * DataCache_IDataObject_AddRef (IUnknown)
1219 static ULONG WINAPI DataCache_IDataObject_AddRef(
1220 IDataObject* iface)
1222 DataCache *this = impl_from_IDataObject(iface);
1224 return IUnknown_AddRef(this->outer_unk);
1227 /************************************************************************
1228 * DataCache_IDataObject_Release (IUnknown)
1230 static ULONG WINAPI DataCache_IDataObject_Release(
1231 IDataObject* iface)
1233 DataCache *this = impl_from_IDataObject(iface);
1235 return IUnknown_Release(this->outer_unk);
1238 /************************************************************************
1239 * DataCache_GetData
1241 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1243 static HRESULT WINAPI DataCache_GetData(
1244 IDataObject* iface,
1245 LPFORMATETC pformatetcIn,
1246 STGMEDIUM* pmedium)
1248 DataCache *This = impl_from_IDataObject(iface);
1249 DataCacheEntry *cache_entry;
1251 TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
1253 memset(pmedium, 0, sizeof(*pmedium));
1255 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1256 if (!cache_entry)
1257 return OLE_E_BLANK;
1259 return DataCacheEntry_GetData(cache_entry, pformatetcIn, pmedium);
1262 static HRESULT WINAPI DataCache_GetDataHere(
1263 IDataObject* iface,
1264 LPFORMATETC pformatetc,
1265 STGMEDIUM* pmedium)
1267 FIXME("stub\n");
1268 return E_NOTIMPL;
1271 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1273 DataCache *This = impl_from_IDataObject( iface );
1274 DataCacheEntry *cache_entry;
1276 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1277 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1279 return cache_entry ? S_OK : S_FALSE;
1282 /************************************************************************
1283 * DataCache_EnumFormatEtc (IDataObject)
1285 * The data cache doesn't implement this method.
1287 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1288 IDataObject* iface,
1289 LPFORMATETC pformatectIn,
1290 LPFORMATETC pformatetcOut)
1292 TRACE("()\n");
1293 return E_NOTIMPL;
1296 /************************************************************************
1297 * DataCache_IDataObject_SetData (IDataObject)
1299 * This method is delegated to the IOleCache2 implementation.
1301 static HRESULT WINAPI DataCache_IDataObject_SetData(
1302 IDataObject* iface,
1303 LPFORMATETC pformatetc,
1304 STGMEDIUM* pmedium,
1305 BOOL fRelease)
1307 IOleCache2* oleCache = NULL;
1308 HRESULT hres;
1310 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1312 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1314 if (FAILED(hres))
1315 return E_UNEXPECTED;
1317 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1319 IOleCache2_Release(oleCache);
1321 return hres;
1324 /************************************************************************
1325 * DataCache_EnumFormatEtc (IDataObject)
1327 * The data cache doesn't implement this method.
1329 static HRESULT WINAPI DataCache_EnumFormatEtc(
1330 IDataObject* iface,
1331 DWORD dwDirection,
1332 IEnumFORMATETC** ppenumFormatEtc)
1334 TRACE("()\n");
1335 return E_NOTIMPL;
1338 /************************************************************************
1339 * DataCache_DAdvise (IDataObject)
1341 * The data cache doesn't support connections.
1343 static HRESULT WINAPI DataCache_DAdvise(
1344 IDataObject* iface,
1345 FORMATETC* pformatetc,
1346 DWORD advf,
1347 IAdviseSink* pAdvSink,
1348 DWORD* pdwConnection)
1350 TRACE("()\n");
1351 return OLE_E_ADVISENOTSUPPORTED;
1354 /************************************************************************
1355 * DataCache_DUnadvise (IDataObject)
1357 * The data cache doesn't support connections.
1359 static HRESULT WINAPI DataCache_DUnadvise(
1360 IDataObject* iface,
1361 DWORD dwConnection)
1363 TRACE("()\n");
1364 return OLE_E_NOCONNECTION;
1367 /************************************************************************
1368 * DataCache_EnumDAdvise (IDataObject)
1370 * The data cache doesn't support connections.
1372 static HRESULT WINAPI DataCache_EnumDAdvise(
1373 IDataObject* iface,
1374 IEnumSTATDATA** ppenumAdvise)
1376 TRACE("()\n");
1377 return OLE_E_ADVISENOTSUPPORTED;
1380 /*********************************************************
1381 * Method implementation for the IDataObject
1382 * part of the DataCache class.
1385 /************************************************************************
1386 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1388 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1389 IPersistStorage* iface,
1390 REFIID riid,
1391 void** ppvObject)
1393 DataCache *this = impl_from_IPersistStorage(iface);
1395 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1398 /************************************************************************
1399 * DataCache_IPersistStorage_AddRef (IUnknown)
1401 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1402 IPersistStorage* iface)
1404 DataCache *this = impl_from_IPersistStorage(iface);
1406 return IUnknown_AddRef(this->outer_unk);
1409 /************************************************************************
1410 * DataCache_IPersistStorage_Release (IUnknown)
1412 static ULONG WINAPI DataCache_IPersistStorage_Release(
1413 IPersistStorage* iface)
1415 DataCache *this = impl_from_IPersistStorage(iface);
1417 return IUnknown_Release(this->outer_unk);
1420 /************************************************************************
1421 * DataCache_GetClassID (IPersistStorage)
1424 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1426 DataCache *This = impl_from_IPersistStorage( iface );
1428 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1429 *clsid = This->clsid;
1431 return S_OK;
1434 /************************************************************************
1435 * DataCache_IsDirty (IPersistStorage)
1437 static HRESULT WINAPI DataCache_IsDirty(
1438 IPersistStorage* iface)
1440 DataCache *This = impl_from_IPersistStorage(iface);
1441 DataCacheEntry *cache_entry;
1443 TRACE("(%p)\n", iface);
1445 if (This->dirty)
1446 return S_OK;
1448 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1449 if (cache_entry->dirty)
1450 return S_OK;
1452 return S_FALSE;
1455 /************************************************************************
1456 * DataCache_InitNew (IPersistStorage)
1458 * The data cache implementation of IPersistStorage_InitNew simply stores
1459 * the storage pointer.
1461 static HRESULT WINAPI DataCache_InitNew(
1462 IPersistStorage* iface,
1463 IStorage* pStg)
1465 DataCache *This = impl_from_IPersistStorage(iface);
1466 CLSID clsid;
1467 HRESULT hr;
1469 TRACE("(%p, %p)\n", iface, pStg);
1471 if (This->presentationStorage != NULL)
1472 return CO_E_ALREADYINITIALIZED;
1474 This->presentationStorage = pStg;
1476 IStorage_AddRef(This->presentationStorage);
1477 This->dirty = TRUE;
1478 ReadClassStg( pStg, &clsid );
1479 hr = create_automatic_entry( This, &clsid );
1480 if (FAILED(hr))
1482 IStorage_Release( pStg );
1483 This->presentationStorage = NULL;
1484 return hr;
1486 This->clsid = clsid;
1488 return S_OK;
1492 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, IStream *stm,
1493 enum stream_type type )
1495 DataCacheEntry *cache_entry;
1496 HRESULT hr = S_OK;
1498 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1500 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1501 if (!cache_entry)
1502 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1503 if (SUCCEEDED( hr ))
1505 DataCacheEntry_DiscardData( cache_entry );
1506 if (cache_entry->stream) IStream_Release( cache_entry->stream );
1507 cache_entry->stream = stm;
1508 IStream_AddRef( stm );
1509 cache_entry->stream_type = type;
1510 cache_entry->dirty = FALSE;
1512 return hr;
1515 static HRESULT parse_pres_streams( DataCache *This, IStorage *stg )
1517 HRESULT hr;
1518 IEnumSTATSTG *stat_enum;
1519 STATSTG stat;
1520 IStream *stm;
1521 PresentationDataHeader header;
1522 ULONG actual_read;
1523 CLIPFORMAT clipformat;
1524 FORMATETC fmtetc;
1526 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stat_enum );
1527 if (FAILED( hr )) return hr;
1529 while ((hr = IEnumSTATSTG_Next( stat_enum, 1, &stat, NULL )) == S_OK)
1531 if (DataCache_IsPresentationStream( &stat ))
1533 hr = IStorage_OpenStream( stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1534 0, &stm );
1535 if (SUCCEEDED( hr ))
1537 hr = read_clipformat( stm, &clipformat );
1539 if (hr == S_OK)
1540 hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1542 if (hr == S_OK && actual_read == sizeof(header))
1544 fmtetc.cfFormat = clipformat;
1545 fmtetc.ptd = NULL; /* FIXME */
1546 fmtetc.dwAspect = header.dvAspect;
1547 fmtetc.lindex = header.lindex;
1548 fmtetc.tymed = tymed_from_cf( clipformat );
1550 add_cache_entry( This, &fmtetc, header.advf, stm, pres_stream );
1552 IStream_Release( stm );
1555 CoTaskMemFree( stat.pwcsName );
1557 IEnumSTATSTG_Release( stat_enum );
1559 return S_OK;
1562 static const FORMATETC static_dib_fmt = { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
1564 static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *stm )
1566 HRESULT hr;
1567 STATSTG stat;
1568 const FORMATETC *fmt;
1570 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
1571 if (FAILED( hr )) return hr;
1573 if (IsEqualCLSID( &stat.clsid, &CLSID_Picture_Dib ))
1574 fmt = &static_dib_fmt;
1575 else
1577 FIXME("unsupported format %s\n", debugstr_guid( &stat.clsid ));
1578 return E_FAIL;
1581 return add_cache_entry( This, fmt, 0, stm, contents_stream );
1584 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1586 /************************************************************************
1587 * DataCache_Load (IPersistStorage)
1589 * The data cache implementation of IPersistStorage_Load doesn't
1590 * actually load anything. Instead, it holds on to the storage pointer
1591 * and it will load the presentation information when the
1592 * IDataObject_GetData or IViewObject2_Draw methods are called.
1594 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1596 DataCache *This = impl_from_IPersistStorage(iface);
1597 HRESULT hr;
1598 IStream *stm;
1599 CLSID clsid;
1600 DataCacheEntry *entry, *cursor2;
1602 TRACE("(%p, %p)\n", iface, pStg);
1604 IPersistStorage_HandsOffStorage( iface );
1606 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1607 DataCacheEntry_Destroy( This, entry );
1609 ReadClassStg( pStg, &clsid );
1610 hr = create_automatic_entry( This, &clsid );
1611 if (FAILED( hr )) return hr;
1613 This->clsid = clsid;
1615 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1616 0, &stm );
1617 if (SUCCEEDED( hr ))
1619 hr = parse_contents_stream( This, pStg, stm );
1620 IStream_Release( stm );
1623 if (FAILED(hr))
1624 hr = parse_pres_streams( This, pStg );
1626 if (SUCCEEDED( hr ))
1628 This->dirty = FALSE;
1629 This->presentationStorage = pStg;
1630 IStorage_AddRef( This->presentationStorage );
1633 return hr;
1636 /************************************************************************
1637 * DataCache_Save (IPersistStorage)
1639 * Until we actually connect to a running object and retrieve new
1640 * information to it, we never have to save anything. However, it is
1641 * our responsibility to copy the information when saving to a new
1642 * storage.
1644 static HRESULT WINAPI DataCache_Save(
1645 IPersistStorage* iface,
1646 IStorage* pStg,
1647 BOOL fSameAsLoad)
1649 DataCache *This = impl_from_IPersistStorage(iface);
1650 DataCacheEntry *cache_entry;
1651 BOOL dirty = FALSE;
1652 HRESULT hr = S_OK;
1653 unsigned short stream_number = 0;
1655 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1657 dirty = This->dirty;
1658 if (!dirty)
1660 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1662 dirty = cache_entry->dirty;
1663 if (dirty)
1664 break;
1668 /* this is a shortcut if nothing changed */
1669 if (!dirty && !fSameAsLoad && This->presentationStorage)
1671 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1674 /* assign stream numbers to the cache entries */
1675 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1677 if (cache_entry->stream_number != stream_number)
1679 cache_entry->dirty = TRUE; /* needs to be written out again */
1680 cache_entry->stream_number = stream_number;
1682 stream_number++;
1685 /* write out the cache entries */
1686 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1688 if (!fSameAsLoad || cache_entry->dirty)
1690 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1691 if (FAILED(hr))
1692 break;
1694 cache_entry->dirty = FALSE;
1698 This->dirty = FALSE;
1699 return hr;
1702 /************************************************************************
1703 * DataCache_SaveCompleted (IPersistStorage)
1705 * This method is called to tell the cache to release the storage
1706 * pointer it's currently holding.
1708 static HRESULT WINAPI DataCache_SaveCompleted(
1709 IPersistStorage* iface,
1710 IStorage* pStgNew)
1712 TRACE("(%p, %p)\n", iface, pStgNew);
1714 if (pStgNew)
1716 IPersistStorage_HandsOffStorage(iface);
1718 DataCache_Load(iface, pStgNew);
1721 return S_OK;
1724 /************************************************************************
1725 * DataCache_HandsOffStorage (IPersistStorage)
1727 * This method is called to tell the cache to release the storage
1728 * pointer it's currently holding.
1730 static HRESULT WINAPI DataCache_HandsOffStorage(
1731 IPersistStorage* iface)
1733 DataCache *this = impl_from_IPersistStorage(iface);
1734 DataCacheEntry *cache_entry;
1736 TRACE("(%p)\n", iface);
1738 if (this->presentationStorage != NULL)
1740 IStorage_Release(this->presentationStorage);
1741 this->presentationStorage = NULL;
1744 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1745 DataCacheEntry_HandsOffStorage(cache_entry);
1747 return S_OK;
1750 /*********************************************************
1751 * Method implementation for the IViewObject2
1752 * part of the DataCache class.
1755 /************************************************************************
1756 * DataCache_IViewObject2_QueryInterface (IUnknown)
1758 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1759 IViewObject2* iface,
1760 REFIID riid,
1761 void** ppvObject)
1763 DataCache *this = impl_from_IViewObject2(iface);
1765 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1768 /************************************************************************
1769 * DataCache_IViewObject2_AddRef (IUnknown)
1771 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1772 IViewObject2* iface)
1774 DataCache *this = impl_from_IViewObject2(iface);
1776 return IUnknown_AddRef(this->outer_unk);
1779 /************************************************************************
1780 * DataCache_IViewObject2_Release (IUnknown)
1782 static ULONG WINAPI DataCache_IViewObject2_Release(
1783 IViewObject2* iface)
1785 DataCache *this = impl_from_IViewObject2(iface);
1787 return IUnknown_Release(this->outer_unk);
1790 /************************************************************************
1791 * DataCache_Draw (IViewObject2)
1793 * This method will draw the cached representation of the object
1794 * to the given device context.
1796 static HRESULT WINAPI DataCache_Draw(
1797 IViewObject2* iface,
1798 DWORD dwDrawAspect,
1799 LONG lindex,
1800 void* pvAspect,
1801 DVTARGETDEVICE* ptd,
1802 HDC hdcTargetDev,
1803 HDC hdcDraw,
1804 LPCRECTL lprcBounds,
1805 LPCRECTL lprcWBounds,
1806 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1807 ULONG_PTR dwContinue)
1809 DataCache *This = impl_from_IViewObject2(iface);
1810 HRESULT hres;
1811 DataCacheEntry *cache_entry;
1813 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1814 iface,
1815 dwDrawAspect,
1816 lindex,
1817 pvAspect,
1818 hdcTargetDev,
1819 hdcDraw,
1820 lprcBounds,
1821 lprcWBounds,
1822 pfnContinue,
1823 dwContinue);
1825 if (lprcBounds==NULL)
1826 return E_INVALIDARG;
1828 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1830 /* FIXME: compare ptd too */
1831 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1832 (cache_entry->fmtetc.lindex != lindex))
1833 continue;
1835 /* if the data hasn't been loaded yet, do it now */
1836 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1838 hres = DataCacheEntry_LoadData(cache_entry);
1839 if (FAILED(hres))
1840 continue;
1843 /* no data */
1844 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1845 continue;
1847 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1849 switch (cache_entry->data_cf)
1851 case CF_METAFILEPICT:
1854 * We have to be careful not to modify the state of the
1855 * DC.
1857 INT prevMapMode;
1858 SIZE oldWindowExt;
1859 SIZE oldViewportExt;
1860 POINT oldViewportOrg;
1861 METAFILEPICT *mfpict;
1863 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1864 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1865 continue;
1867 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1869 SetWindowExtEx(hdcDraw,
1870 mfpict->xExt,
1871 mfpict->yExt,
1872 &oldWindowExt);
1874 SetViewportExtEx(hdcDraw,
1875 lprcBounds->right - lprcBounds->left,
1876 lprcBounds->bottom - lprcBounds->top,
1877 &oldViewportExt);
1879 SetViewportOrgEx(hdcDraw,
1880 lprcBounds->left,
1881 lprcBounds->top,
1882 &oldViewportOrg);
1884 PlayMetaFile(hdcDraw, mfpict->hMF);
1886 SetWindowExtEx(hdcDraw,
1887 oldWindowExt.cx,
1888 oldWindowExt.cy,
1889 NULL);
1891 SetViewportExtEx(hdcDraw,
1892 oldViewportExt.cx,
1893 oldViewportExt.cy,
1894 NULL);
1896 SetViewportOrgEx(hdcDraw,
1897 oldViewportOrg.x,
1898 oldViewportOrg.y,
1899 NULL);
1901 SetMapMode(hdcDraw, prevMapMode);
1903 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1905 return S_OK;
1907 case CF_DIB:
1909 BITMAPINFO *info;
1910 BYTE *bits;
1912 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1913 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1914 continue;
1916 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
1917 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1918 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1919 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1920 bits, info, DIB_RGB_COLORS, SRCCOPY );
1922 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1923 return S_OK;
1928 WARN("no data could be found to be drawn\n");
1930 return OLE_E_BLANK;
1933 static HRESULT WINAPI DataCache_GetColorSet(
1934 IViewObject2* iface,
1935 DWORD dwDrawAspect,
1936 LONG lindex,
1937 void* pvAspect,
1938 DVTARGETDEVICE* ptd,
1939 HDC hicTargetDevice,
1940 LOGPALETTE** ppColorSet)
1942 FIXME("stub\n");
1943 return E_NOTIMPL;
1946 static HRESULT WINAPI DataCache_Freeze(
1947 IViewObject2* iface,
1948 DWORD dwDrawAspect,
1949 LONG lindex,
1950 void* pvAspect,
1951 DWORD* pdwFreeze)
1953 FIXME("stub\n");
1954 return E_NOTIMPL;
1957 static HRESULT WINAPI DataCache_Unfreeze(
1958 IViewObject2* iface,
1959 DWORD dwFreeze)
1961 FIXME("stub\n");
1962 return E_NOTIMPL;
1965 /************************************************************************
1966 * DataCache_SetAdvise (IViewObject2)
1968 * This sets-up an advisory sink with the data cache. When the object's
1969 * view changes, this sink is called.
1971 static HRESULT WINAPI DataCache_SetAdvise(
1972 IViewObject2* iface,
1973 DWORD aspects,
1974 DWORD advf,
1975 IAdviseSink* pAdvSink)
1977 DataCache *this = impl_from_IViewObject2(iface);
1979 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1982 * A call to this function removes the previous sink
1984 if (this->sinkInterface != NULL)
1986 IAdviseSink_Release(this->sinkInterface);
1987 this->sinkInterface = NULL;
1988 this->sinkAspects = 0;
1989 this->sinkAdviseFlag = 0;
1993 * Now, setup the new one.
1995 if (pAdvSink!=NULL)
1997 this->sinkInterface = pAdvSink;
1998 this->sinkAspects = aspects;
1999 this->sinkAdviseFlag = advf;
2001 IAdviseSink_AddRef(this->sinkInterface);
2005 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2006 * sink immediately.
2008 if (advf & ADVF_PRIMEFIRST)
2010 DataCache_FireOnViewChange(this, aspects, -1);
2013 return S_OK;
2016 /************************************************************************
2017 * DataCache_GetAdvise (IViewObject2)
2019 * This method queries the current state of the advise sink
2020 * installed on the data cache.
2022 static HRESULT WINAPI DataCache_GetAdvise(
2023 IViewObject2* iface,
2024 DWORD* pAspects,
2025 DWORD* pAdvf,
2026 IAdviseSink** ppAdvSink)
2028 DataCache *this = impl_from_IViewObject2(iface);
2030 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2033 * Just copy all the requested values.
2035 if (pAspects!=NULL)
2036 *pAspects = this->sinkAspects;
2038 if (pAdvf!=NULL)
2039 *pAdvf = this->sinkAdviseFlag;
2041 if (ppAdvSink!=NULL)
2043 if (this->sinkInterface != NULL)
2044 IAdviseSink_QueryInterface(this->sinkInterface,
2045 &IID_IAdviseSink,
2046 (void**)ppAdvSink);
2047 else *ppAdvSink = NULL;
2050 return S_OK;
2053 /************************************************************************
2054 * DataCache_GetExtent (IViewObject2)
2056 * This method retrieves the "natural" size of this cached object.
2058 static HRESULT WINAPI DataCache_GetExtent(
2059 IViewObject2* iface,
2060 DWORD dwDrawAspect,
2061 LONG lindex,
2062 DVTARGETDEVICE* ptd,
2063 LPSIZEL lpsizel)
2065 DataCache *This = impl_from_IViewObject2(iface);
2066 HRESULT hres = E_FAIL;
2067 DataCacheEntry *cache_entry;
2069 TRACE("(%p, %x, %d, %p, %p)\n",
2070 iface, dwDrawAspect, lindex, ptd, lpsizel);
2072 if (lpsizel==NULL)
2073 return E_POINTER;
2075 lpsizel->cx = 0;
2076 lpsizel->cy = 0;
2078 if (lindex!=-1)
2079 FIXME("Unimplemented flag lindex = %d\n", lindex);
2082 * Right now, we support only the callback from
2083 * the default handler.
2085 if (ptd!=NULL)
2086 FIXME("Unimplemented ptd = %p\n", ptd);
2088 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2090 /* FIXME: compare ptd too */
2091 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2092 (cache_entry->fmtetc.lindex != lindex))
2093 continue;
2095 /* if the data hasn't been loaded yet, do it now */
2096 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
2098 hres = DataCacheEntry_LoadData(cache_entry);
2099 if (FAILED(hres))
2100 continue;
2103 /* no data */
2104 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2105 continue;
2108 switch (cache_entry->data_cf)
2110 case CF_METAFILEPICT:
2112 METAFILEPICT *mfpict;
2114 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2115 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2116 continue;
2118 lpsizel->cx = mfpict->xExt;
2119 lpsizel->cy = mfpict->yExt;
2121 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2123 return S_OK;
2125 case CF_DIB:
2127 BITMAPINFOHEADER *info;
2128 LONG x_pels_m, y_pels_m;
2131 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2132 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2133 continue;
2135 x_pels_m = info->biXPelsPerMeter;
2136 y_pels_m = info->biYPelsPerMeter;
2138 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2139 if (x_pels_m != 0 && y_pels_m != 0)
2141 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
2142 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2144 else
2146 HDC hdc = GetDC( 0 );
2147 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2148 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2150 ReleaseDC( 0, hdc );
2153 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2155 return S_OK;
2160 WARN("no data could be found to get the extents from\n");
2163 * This method returns OLE_E_BLANK when it fails.
2165 return OLE_E_BLANK;
2169 /*********************************************************
2170 * Method implementation for the IOleCache2
2171 * part of the DataCache class.
2174 /************************************************************************
2175 * DataCache_IOleCache2_QueryInterface (IUnknown)
2177 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2178 IOleCache2* iface,
2179 REFIID riid,
2180 void** ppvObject)
2182 DataCache *this = impl_from_IOleCache2(iface);
2184 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2187 /************************************************************************
2188 * DataCache_IOleCache2_AddRef (IUnknown)
2190 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2191 IOleCache2* iface)
2193 DataCache *this = impl_from_IOleCache2(iface);
2195 return IUnknown_AddRef(this->outer_unk);
2198 /************************************************************************
2199 * DataCache_IOleCache2_Release (IUnknown)
2201 static ULONG WINAPI DataCache_IOleCache2_Release(
2202 IOleCache2* iface)
2204 DataCache *this = impl_from_IOleCache2(iface);
2206 return IUnknown_Release(this->outer_unk);
2209 /*****************************************************************************
2210 * setup_sink
2212 * Set up the sink connection to the running object.
2214 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2216 HRESULT hr = S_FALSE;
2217 DWORD flags;
2219 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2220 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2222 if(This->running_object)
2223 if(!(flags & ADVF_NODATA))
2224 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2225 &This->IAdviseSink_iface, &cache_entry->sink_id);
2226 return hr;
2229 static HRESULT WINAPI DataCache_Cache(
2230 IOleCache2* iface,
2231 FORMATETC* pformatetc,
2232 DWORD advf,
2233 DWORD* pdwConnection)
2235 DataCache *This = impl_from_IOleCache2(iface);
2236 DataCacheEntry *cache_entry;
2237 HRESULT hr;
2238 FORMATETC fmt_cpy;
2240 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2242 if (!pformatetc || !pdwConnection)
2243 return E_INVALIDARG;
2245 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2247 fmt_cpy = *pformatetc; /* No need for a deep copy */
2248 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2250 fmt_cpy.cfFormat = CF_DIB;
2251 fmt_cpy.tymed = TYMED_HGLOBAL;
2254 *pdwConnection = 0;
2256 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2257 if (cache_entry)
2259 TRACE("found an existing cache entry\n");
2260 *pdwConnection = cache_entry->id;
2261 return CACHE_S_SAMECACHE;
2264 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2266 if (SUCCEEDED(hr))
2268 *pdwConnection = cache_entry->id;
2269 setup_sink(This, cache_entry);
2272 return hr;
2275 static HRESULT WINAPI DataCache_Uncache(
2276 IOleCache2* iface,
2277 DWORD dwConnection)
2279 DataCache *This = impl_from_IOleCache2(iface);
2280 DataCacheEntry *cache_entry;
2282 TRACE("(%d)\n", dwConnection);
2284 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2285 if (cache_entry->id == dwConnection)
2287 DataCacheEntry_Destroy(This, cache_entry);
2288 return S_OK;
2291 WARN("no connection found for %d\n", dwConnection);
2293 return OLE_E_NOCONNECTION;
2296 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2297 IEnumSTATDATA **enum_stat)
2299 DataCache *This = impl_from_IOleCache2( iface );
2300 DataCacheEntry *cache_entry;
2301 int i = 0, count = 0;
2302 STATDATA *data;
2303 HRESULT hr;
2305 TRACE( "(%p, %p)\n", This, enum_stat );
2307 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2309 count++;
2310 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2311 count++;
2314 data = CoTaskMemAlloc( count * sizeof(*data) );
2315 if (!data) return E_OUTOFMEMORY;
2317 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2319 if (i == count) goto fail;
2320 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2321 if (FAILED(hr)) goto fail;
2322 data[i].advf = cache_entry->advise_flags;
2323 data[i].pAdvSink = NULL;
2324 data[i].dwConnection = cache_entry->id;
2325 i++;
2327 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2329 if (i == count) goto fail;
2330 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2331 if (FAILED(hr)) goto fail;
2332 data[i].formatetc.cfFormat = CF_BITMAP;
2333 data[i].formatetc.tymed = TYMED_GDI;
2334 data[i].advf = cache_entry->advise_flags;
2335 data[i].pAdvSink = NULL;
2336 data[i].dwConnection = cache_entry->id;
2337 i++;
2341 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2342 if (SUCCEEDED(hr)) return hr;
2344 fail:
2345 while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2346 CoTaskMemFree( data );
2347 return hr;
2350 static HRESULT WINAPI DataCache_InitCache(
2351 IOleCache2* iface,
2352 IDataObject* pDataObject)
2354 FIXME("stub\n");
2355 return E_NOTIMPL;
2358 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2359 IOleCache2* iface,
2360 FORMATETC* pformatetc,
2361 STGMEDIUM* pmedium,
2362 BOOL fRelease)
2364 DataCache *This = impl_from_IOleCache2(iface);
2365 DataCacheEntry *cache_entry;
2366 HRESULT hr;
2368 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2369 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2371 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2372 if (cache_entry)
2374 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2376 if (SUCCEEDED(hr))
2377 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2378 cache_entry->fmtetc.lindex);
2380 return hr;
2382 WARN("cache entry not found\n");
2384 return OLE_E_BLANK;
2387 static HRESULT WINAPI DataCache_UpdateCache(
2388 IOleCache2* iface,
2389 LPDATAOBJECT pDataObject,
2390 DWORD grfUpdf,
2391 LPVOID pReserved)
2393 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2394 return E_NOTIMPL;
2397 static HRESULT WINAPI DataCache_DiscardCache(
2398 IOleCache2* iface,
2399 DWORD dwDiscardOptions)
2401 DataCache *This = impl_from_IOleCache2(iface);
2402 DataCacheEntry *cache_entry;
2403 HRESULT hr = S_OK;
2405 TRACE("(%d)\n", dwDiscardOptions);
2407 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2408 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2410 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2412 hr = DataCacheEntry_DiscardData(cache_entry);
2413 if (FAILED(hr))
2414 break;
2417 return hr;
2421 /*********************************************************
2422 * Method implementation for the IOleCacheControl
2423 * part of the DataCache class.
2426 /************************************************************************
2427 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2429 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2430 IOleCacheControl* iface,
2431 REFIID riid,
2432 void** ppvObject)
2434 DataCache *this = impl_from_IOleCacheControl(iface);
2436 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2439 /************************************************************************
2440 * DataCache_IOleCacheControl_AddRef (IUnknown)
2442 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2443 IOleCacheControl* iface)
2445 DataCache *this = impl_from_IOleCacheControl(iface);
2447 return IUnknown_AddRef(this->outer_unk);
2450 /************************************************************************
2451 * DataCache_IOleCacheControl_Release (IUnknown)
2453 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2454 IOleCacheControl* iface)
2456 DataCache *this = impl_from_IOleCacheControl(iface);
2458 return IUnknown_Release(this->outer_unk);
2461 /************************************************************************
2462 * DataCache_OnRun (IOleCacheControl)
2464 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2466 DataCache *This = impl_from_IOleCacheControl(iface);
2467 DataCacheEntry *cache_entry;
2469 TRACE("(%p)->(%p)\n", iface, data_obj);
2471 if(This->running_object) return S_OK;
2473 /* No reference is taken on the data object */
2474 This->running_object = data_obj;
2476 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2478 setup_sink(This, cache_entry);
2481 return S_OK;
2484 /************************************************************************
2485 * DataCache_OnStop (IOleCacheControl)
2487 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2489 DataCache *This = impl_from_IOleCacheControl(iface);
2490 DataCacheEntry *cache_entry;
2492 TRACE("(%p)\n", iface);
2494 if(!This->running_object) return S_OK;
2496 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2498 if(cache_entry->sink_id)
2500 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2501 cache_entry->sink_id = 0;
2505 /* No ref taken in OnRun, so no Release call here */
2506 This->running_object = NULL;
2507 return S_OK;
2510 /************************************************************************
2511 * IAdviseSink methods.
2512 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2513 * give access to the cache's other interfaces. We don't maintain a ref count,
2514 * the object exists as long as the cache is around.
2516 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2518 *obj = NULL;
2519 if (IsEqualIID(&IID_IUnknown, iid) ||
2520 IsEqualIID(&IID_IAdviseSink, iid))
2522 *obj = iface;
2525 if(*obj)
2527 IAdviseSink_AddRef(iface);
2528 return S_OK;
2530 return E_NOINTERFACE;
2533 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2535 return 2;
2538 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2540 return 1;
2543 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2545 DataCache *This = impl_from_IAdviseSink(iface);
2546 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2547 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2550 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2552 FIXME("stub\n");
2555 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2557 FIXME("stub\n");
2560 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2562 FIXME("stub\n");
2565 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2567 FIXME("stub\n");
2571 * Virtual function tables for the DataCache class.
2573 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2575 DataCache_NDIUnknown_QueryInterface,
2576 DataCache_NDIUnknown_AddRef,
2577 DataCache_NDIUnknown_Release
2580 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2582 DataCache_IDataObject_QueryInterface,
2583 DataCache_IDataObject_AddRef,
2584 DataCache_IDataObject_Release,
2585 DataCache_GetData,
2586 DataCache_GetDataHere,
2587 DataCache_QueryGetData,
2588 DataCache_GetCanonicalFormatEtc,
2589 DataCache_IDataObject_SetData,
2590 DataCache_EnumFormatEtc,
2591 DataCache_DAdvise,
2592 DataCache_DUnadvise,
2593 DataCache_EnumDAdvise
2596 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2598 DataCache_IPersistStorage_QueryInterface,
2599 DataCache_IPersistStorage_AddRef,
2600 DataCache_IPersistStorage_Release,
2601 DataCache_GetClassID,
2602 DataCache_IsDirty,
2603 DataCache_InitNew,
2604 DataCache_Load,
2605 DataCache_Save,
2606 DataCache_SaveCompleted,
2607 DataCache_HandsOffStorage
2610 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2612 DataCache_IViewObject2_QueryInterface,
2613 DataCache_IViewObject2_AddRef,
2614 DataCache_IViewObject2_Release,
2615 DataCache_Draw,
2616 DataCache_GetColorSet,
2617 DataCache_Freeze,
2618 DataCache_Unfreeze,
2619 DataCache_SetAdvise,
2620 DataCache_GetAdvise,
2621 DataCache_GetExtent
2624 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2626 DataCache_IOleCache2_QueryInterface,
2627 DataCache_IOleCache2_AddRef,
2628 DataCache_IOleCache2_Release,
2629 DataCache_Cache,
2630 DataCache_Uncache,
2631 DataCache_EnumCache,
2632 DataCache_InitCache,
2633 DataCache_IOleCache2_SetData,
2634 DataCache_UpdateCache,
2635 DataCache_DiscardCache
2638 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2640 DataCache_IOleCacheControl_QueryInterface,
2641 DataCache_IOleCacheControl_AddRef,
2642 DataCache_IOleCacheControl_Release,
2643 DataCache_OnRun,
2644 DataCache_OnStop
2647 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2649 DataCache_IAdviseSink_QueryInterface,
2650 DataCache_IAdviseSink_AddRef,
2651 DataCache_IAdviseSink_Release,
2652 DataCache_OnDataChange,
2653 DataCache_OnViewChange,
2654 DataCache_OnRename,
2655 DataCache_OnSave,
2656 DataCache_OnClose
2659 /*********************************************************
2660 * Method implementation for DataCache class.
2662 static DataCache* DataCache_Construct(
2663 REFCLSID clsid,
2664 LPUNKNOWN pUnkOuter)
2666 DataCache* newObject = 0;
2669 * Allocate space for the object.
2671 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2673 if (newObject==0)
2674 return newObject;
2677 * Initialize the virtual function table.
2679 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2680 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2681 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2682 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2683 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2684 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2685 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2686 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2687 newObject->ref = 1;
2690 * Initialize the other members of the structure.
2692 newObject->sinkAspects = 0;
2693 newObject->sinkAdviseFlag = 0;
2694 newObject->sinkInterface = 0;
2695 newObject->clsid = CLSID_NULL;
2696 newObject->presentationStorage = NULL;
2697 list_init(&newObject->cache_list);
2698 newObject->last_cache_id = 2;
2699 newObject->dirty = FALSE;
2700 newObject->running_object = NULL;
2702 create_automatic_entry( newObject, clsid );
2703 newObject->clsid = *clsid;
2705 return newObject;
2708 /******************************************************************************
2709 * CreateDataCache [OLE32.@]
2711 * Creates a data cache to allow an object to render one or more of its views,
2712 * whether running or not.
2714 * PARAMS
2715 * pUnkOuter [I] Outer unknown for the object.
2716 * rclsid [I]
2717 * riid [I] IID of interface to return.
2718 * ppvObj [O] Address where the data cache object will be stored on return.
2720 * RETURNS
2721 * Success: S_OK.
2722 * Failure: HRESULT code.
2724 * NOTES
2725 * The following interfaces are supported by the returned data cache object:
2726 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2727 * IViewObject and IViewObject2.
2729 HRESULT WINAPI CreateDataCache(
2730 LPUNKNOWN pUnkOuter,
2731 REFCLSID rclsid,
2732 REFIID riid,
2733 LPVOID* ppvObj)
2735 DataCache* newCache = NULL;
2736 HRESULT hr = S_OK;
2738 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2741 * Sanity check
2743 if (ppvObj==0)
2744 return E_POINTER;
2746 *ppvObj = 0;
2749 * If this cache is constructed for aggregation, make sure
2750 * the caller is requesting the IUnknown interface.
2751 * This is necessary because it's the only time the non-delegating
2752 * IUnknown pointer can be returned to the outside.
2754 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2755 return E_INVALIDARG;
2758 * Try to construct a new instance of the class.
2760 newCache = DataCache_Construct(rclsid,
2761 pUnkOuter);
2763 if (newCache == 0)
2764 return E_OUTOFMEMORY;
2766 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
2767 IUnknown_Release(&newCache->IUnknown_inner);
2769 return hr;