ole32: Add a trace to IDataObject::GetData.
[wine.git] / dlls / ole32 / datacache.c
bloba95d0fbc0b095b10a99065f063e27b58e1deda60
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 TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
1250 memset(pmedium, 0, sizeof(*pmedium));
1252 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1253 if (!cache_entry)
1254 return OLE_E_BLANK;
1256 return DataCacheEntry_GetData(cache_entry, pformatetcIn, pmedium);
1259 static HRESULT WINAPI DataCache_GetDataHere(
1260 IDataObject* iface,
1261 LPFORMATETC pformatetc,
1262 STGMEDIUM* pmedium)
1264 FIXME("stub\n");
1265 return E_NOTIMPL;
1268 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1270 DataCache *This = impl_from_IDataObject( iface );
1271 DataCacheEntry *cache_entry;
1273 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1274 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1276 return cache_entry ? S_OK : S_FALSE;
1279 /************************************************************************
1280 * DataCache_EnumFormatEtc (IDataObject)
1282 * The data cache doesn't implement this method.
1284 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1285 IDataObject* iface,
1286 LPFORMATETC pformatectIn,
1287 LPFORMATETC pformatetcOut)
1289 TRACE("()\n");
1290 return E_NOTIMPL;
1293 /************************************************************************
1294 * DataCache_IDataObject_SetData (IDataObject)
1296 * This method is delegated to the IOleCache2 implementation.
1298 static HRESULT WINAPI DataCache_IDataObject_SetData(
1299 IDataObject* iface,
1300 LPFORMATETC pformatetc,
1301 STGMEDIUM* pmedium,
1302 BOOL fRelease)
1304 IOleCache2* oleCache = NULL;
1305 HRESULT hres;
1307 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1309 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1311 if (FAILED(hres))
1312 return E_UNEXPECTED;
1314 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1316 IOleCache2_Release(oleCache);
1318 return hres;
1321 /************************************************************************
1322 * DataCache_EnumFormatEtc (IDataObject)
1324 * The data cache doesn't implement this method.
1326 static HRESULT WINAPI DataCache_EnumFormatEtc(
1327 IDataObject* iface,
1328 DWORD dwDirection,
1329 IEnumFORMATETC** ppenumFormatEtc)
1331 TRACE("()\n");
1332 return E_NOTIMPL;
1335 /************************************************************************
1336 * DataCache_DAdvise (IDataObject)
1338 * The data cache doesn't support connections.
1340 static HRESULT WINAPI DataCache_DAdvise(
1341 IDataObject* iface,
1342 FORMATETC* pformatetc,
1343 DWORD advf,
1344 IAdviseSink* pAdvSink,
1345 DWORD* pdwConnection)
1347 TRACE("()\n");
1348 return OLE_E_ADVISENOTSUPPORTED;
1351 /************************************************************************
1352 * DataCache_DUnadvise (IDataObject)
1354 * The data cache doesn't support connections.
1356 static HRESULT WINAPI DataCache_DUnadvise(
1357 IDataObject* iface,
1358 DWORD dwConnection)
1360 TRACE("()\n");
1361 return OLE_E_NOCONNECTION;
1364 /************************************************************************
1365 * DataCache_EnumDAdvise (IDataObject)
1367 * The data cache doesn't support connections.
1369 static HRESULT WINAPI DataCache_EnumDAdvise(
1370 IDataObject* iface,
1371 IEnumSTATDATA** ppenumAdvise)
1373 TRACE("()\n");
1374 return OLE_E_ADVISENOTSUPPORTED;
1377 /*********************************************************
1378 * Method implementation for the IDataObject
1379 * part of the DataCache class.
1382 /************************************************************************
1383 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1385 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1386 IPersistStorage* iface,
1387 REFIID riid,
1388 void** ppvObject)
1390 DataCache *this = impl_from_IPersistStorage(iface);
1392 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1395 /************************************************************************
1396 * DataCache_IPersistStorage_AddRef (IUnknown)
1398 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1399 IPersistStorage* iface)
1401 DataCache *this = impl_from_IPersistStorage(iface);
1403 return IUnknown_AddRef(this->outer_unk);
1406 /************************************************************************
1407 * DataCache_IPersistStorage_Release (IUnknown)
1409 static ULONG WINAPI DataCache_IPersistStorage_Release(
1410 IPersistStorage* iface)
1412 DataCache *this = impl_from_IPersistStorage(iface);
1414 return IUnknown_Release(this->outer_unk);
1417 /************************************************************************
1418 * DataCache_GetClassID (IPersistStorage)
1421 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1423 DataCache *This = impl_from_IPersistStorage( iface );
1425 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1426 *clsid = This->clsid;
1428 return S_OK;
1431 /************************************************************************
1432 * DataCache_IsDirty (IPersistStorage)
1434 static HRESULT WINAPI DataCache_IsDirty(
1435 IPersistStorage* iface)
1437 DataCache *This = impl_from_IPersistStorage(iface);
1438 DataCacheEntry *cache_entry;
1440 TRACE("(%p)\n", iface);
1442 if (This->dirty)
1443 return S_OK;
1445 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1446 if (cache_entry->dirty)
1447 return S_OK;
1449 return S_FALSE;
1452 /************************************************************************
1453 * DataCache_InitNew (IPersistStorage)
1455 * The data cache implementation of IPersistStorage_InitNew simply stores
1456 * the storage pointer.
1458 static HRESULT WINAPI DataCache_InitNew(
1459 IPersistStorage* iface,
1460 IStorage* pStg)
1462 DataCache *This = impl_from_IPersistStorage(iface);
1463 CLSID clsid;
1464 HRESULT hr;
1466 TRACE("(%p, %p)\n", iface, pStg);
1468 if (This->presentationStorage != NULL)
1469 return CO_E_ALREADYINITIALIZED;
1471 This->presentationStorage = pStg;
1473 IStorage_AddRef(This->presentationStorage);
1474 This->dirty = TRUE;
1475 ReadClassStg( pStg, &clsid );
1476 hr = create_automatic_entry( This, &clsid );
1477 if (FAILED(hr))
1479 IStorage_Release( pStg );
1480 This->presentationStorage = NULL;
1481 return hr;
1483 This->clsid = clsid;
1485 return S_OK;
1489 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, IStream *stm,
1490 enum stream_type type )
1492 DataCacheEntry *cache_entry;
1493 HRESULT hr = S_OK;
1495 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1497 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1498 if (!cache_entry)
1499 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1500 if (SUCCEEDED( hr ))
1502 DataCacheEntry_DiscardData( cache_entry );
1503 if (cache_entry->stream) IStream_Release( cache_entry->stream );
1504 cache_entry->stream = stm;
1505 IStream_AddRef( stm );
1506 cache_entry->stream_type = type;
1507 cache_entry->dirty = FALSE;
1509 return hr;
1512 static HRESULT parse_pres_streams( DataCache *This, IStorage *stg )
1514 HRESULT hr;
1515 IEnumSTATSTG *stat_enum;
1516 STATSTG stat;
1517 IStream *stm;
1518 PresentationDataHeader header;
1519 ULONG actual_read;
1520 CLIPFORMAT clipformat;
1521 FORMATETC fmtetc;
1523 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stat_enum );
1524 if (FAILED( hr )) return hr;
1526 while ((hr = IEnumSTATSTG_Next( stat_enum, 1, &stat, NULL )) == S_OK)
1528 if (DataCache_IsPresentationStream( &stat ))
1530 hr = IStorage_OpenStream( stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1531 0, &stm );
1532 if (SUCCEEDED( hr ))
1534 hr = read_clipformat( stm, &clipformat );
1536 if (hr == S_OK)
1537 hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1539 if (hr == S_OK && actual_read == sizeof(header))
1541 fmtetc.cfFormat = clipformat;
1542 fmtetc.ptd = NULL; /* FIXME */
1543 fmtetc.dwAspect = header.dvAspect;
1544 fmtetc.lindex = header.lindex;
1545 fmtetc.tymed = tymed_from_cf( clipformat );
1547 add_cache_entry( This, &fmtetc, header.advf, stm, pres_stream );
1549 IStream_Release( stm );
1552 CoTaskMemFree( stat.pwcsName );
1554 IEnumSTATSTG_Release( stat_enum );
1556 return S_OK;
1559 static const FORMATETC static_dib_fmt = { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
1561 static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *stm )
1563 HRESULT hr;
1564 STATSTG stat;
1565 const FORMATETC *fmt;
1567 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
1568 if (FAILED( hr )) return hr;
1570 if (IsEqualCLSID( &stat.clsid, &CLSID_Picture_Dib ))
1571 fmt = &static_dib_fmt;
1572 else
1574 FIXME("unsupported format %s\n", debugstr_guid( &stat.clsid ));
1575 return E_FAIL;
1578 return add_cache_entry( This, fmt, 0, stm, contents_stream );
1581 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1583 /************************************************************************
1584 * DataCache_Load (IPersistStorage)
1586 * The data cache implementation of IPersistStorage_Load doesn't
1587 * actually load anything. Instead, it holds on to the storage pointer
1588 * and it will load the presentation information when the
1589 * IDataObject_GetData or IViewObject2_Draw methods are called.
1591 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1593 DataCache *This = impl_from_IPersistStorage(iface);
1594 HRESULT hr;
1595 IStream *stm;
1596 CLSID clsid;
1597 DataCacheEntry *entry, *cursor2;
1599 TRACE("(%p, %p)\n", iface, pStg);
1601 IPersistStorage_HandsOffStorage( iface );
1603 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1604 DataCacheEntry_Destroy( This, entry );
1606 ReadClassStg( pStg, &clsid );
1607 hr = create_automatic_entry( This, &clsid );
1608 if (FAILED( hr )) return hr;
1610 This->clsid = clsid;
1612 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1613 0, &stm );
1614 if (SUCCEEDED( hr ))
1616 hr = parse_contents_stream( This, pStg, stm );
1617 IStream_Release( stm );
1620 if (FAILED(hr))
1621 hr = parse_pres_streams( This, pStg );
1623 if (SUCCEEDED( hr ))
1625 This->dirty = FALSE;
1626 This->presentationStorage = pStg;
1627 IStorage_AddRef( This->presentationStorage );
1630 return hr;
1633 /************************************************************************
1634 * DataCache_Save (IPersistStorage)
1636 * Until we actually connect to a running object and retrieve new
1637 * information to it, we never have to save anything. However, it is
1638 * our responsibility to copy the information when saving to a new
1639 * storage.
1641 static HRESULT WINAPI DataCache_Save(
1642 IPersistStorage* iface,
1643 IStorage* pStg,
1644 BOOL fSameAsLoad)
1646 DataCache *This = impl_from_IPersistStorage(iface);
1647 DataCacheEntry *cache_entry;
1648 BOOL dirty = FALSE;
1649 HRESULT hr = S_OK;
1650 unsigned short stream_number = 0;
1652 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1654 dirty = This->dirty;
1655 if (!dirty)
1657 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1659 dirty = cache_entry->dirty;
1660 if (dirty)
1661 break;
1665 /* this is a shortcut if nothing changed */
1666 if (!dirty && !fSameAsLoad && This->presentationStorage)
1668 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1671 /* assign stream numbers to the cache entries */
1672 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1674 if (cache_entry->stream_number != stream_number)
1676 cache_entry->dirty = TRUE; /* needs to be written out again */
1677 cache_entry->stream_number = stream_number;
1679 stream_number++;
1682 /* write out the cache entries */
1683 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1685 if (!fSameAsLoad || cache_entry->dirty)
1687 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1688 if (FAILED(hr))
1689 break;
1691 cache_entry->dirty = FALSE;
1695 This->dirty = FALSE;
1696 return hr;
1699 /************************************************************************
1700 * DataCache_SaveCompleted (IPersistStorage)
1702 * This method is called to tell the cache to release the storage
1703 * pointer it's currently holding.
1705 static HRESULT WINAPI DataCache_SaveCompleted(
1706 IPersistStorage* iface,
1707 IStorage* pStgNew)
1709 TRACE("(%p, %p)\n", iface, pStgNew);
1711 if (pStgNew)
1713 IPersistStorage_HandsOffStorage(iface);
1715 DataCache_Load(iface, pStgNew);
1718 return S_OK;
1721 /************************************************************************
1722 * DataCache_HandsOffStorage (IPersistStorage)
1724 * This method is called to tell the cache to release the storage
1725 * pointer it's currently holding.
1727 static HRESULT WINAPI DataCache_HandsOffStorage(
1728 IPersistStorage* iface)
1730 DataCache *this = impl_from_IPersistStorage(iface);
1731 DataCacheEntry *cache_entry;
1733 TRACE("(%p)\n", iface);
1735 if (this->presentationStorage != NULL)
1737 IStorage_Release(this->presentationStorage);
1738 this->presentationStorage = NULL;
1741 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1742 DataCacheEntry_HandsOffStorage(cache_entry);
1744 return S_OK;
1747 /*********************************************************
1748 * Method implementation for the IViewObject2
1749 * part of the DataCache class.
1752 /************************************************************************
1753 * DataCache_IViewObject2_QueryInterface (IUnknown)
1755 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1756 IViewObject2* iface,
1757 REFIID riid,
1758 void** ppvObject)
1760 DataCache *this = impl_from_IViewObject2(iface);
1762 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1765 /************************************************************************
1766 * DataCache_IViewObject2_AddRef (IUnknown)
1768 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1769 IViewObject2* iface)
1771 DataCache *this = impl_from_IViewObject2(iface);
1773 return IUnknown_AddRef(this->outer_unk);
1776 /************************************************************************
1777 * DataCache_IViewObject2_Release (IUnknown)
1779 static ULONG WINAPI DataCache_IViewObject2_Release(
1780 IViewObject2* iface)
1782 DataCache *this = impl_from_IViewObject2(iface);
1784 return IUnknown_Release(this->outer_unk);
1787 /************************************************************************
1788 * DataCache_Draw (IViewObject2)
1790 * This method will draw the cached representation of the object
1791 * to the given device context.
1793 static HRESULT WINAPI DataCache_Draw(
1794 IViewObject2* iface,
1795 DWORD dwDrawAspect,
1796 LONG lindex,
1797 void* pvAspect,
1798 DVTARGETDEVICE* ptd,
1799 HDC hdcTargetDev,
1800 HDC hdcDraw,
1801 LPCRECTL lprcBounds,
1802 LPCRECTL lprcWBounds,
1803 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1804 ULONG_PTR dwContinue)
1806 DataCache *This = impl_from_IViewObject2(iface);
1807 HRESULT hres;
1808 DataCacheEntry *cache_entry;
1810 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1811 iface,
1812 dwDrawAspect,
1813 lindex,
1814 pvAspect,
1815 hdcTargetDev,
1816 hdcDraw,
1817 lprcBounds,
1818 lprcWBounds,
1819 pfnContinue,
1820 dwContinue);
1822 if (lprcBounds==NULL)
1823 return E_INVALIDARG;
1825 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1827 /* FIXME: compare ptd too */
1828 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1829 (cache_entry->fmtetc.lindex != lindex))
1830 continue;
1832 /* if the data hasn't been loaded yet, do it now */
1833 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1835 hres = DataCacheEntry_LoadData(cache_entry);
1836 if (FAILED(hres))
1837 continue;
1840 /* no data */
1841 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1842 continue;
1844 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1846 switch (cache_entry->data_cf)
1848 case CF_METAFILEPICT:
1851 * We have to be careful not to modify the state of the
1852 * DC.
1854 INT prevMapMode;
1855 SIZE oldWindowExt;
1856 SIZE oldViewportExt;
1857 POINT oldViewportOrg;
1858 METAFILEPICT *mfpict;
1860 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1861 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1862 continue;
1864 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1866 SetWindowExtEx(hdcDraw,
1867 mfpict->xExt,
1868 mfpict->yExt,
1869 &oldWindowExt);
1871 SetViewportExtEx(hdcDraw,
1872 lprcBounds->right - lprcBounds->left,
1873 lprcBounds->bottom - lprcBounds->top,
1874 &oldViewportExt);
1876 SetViewportOrgEx(hdcDraw,
1877 lprcBounds->left,
1878 lprcBounds->top,
1879 &oldViewportOrg);
1881 PlayMetaFile(hdcDraw, mfpict->hMF);
1883 SetWindowExtEx(hdcDraw,
1884 oldWindowExt.cx,
1885 oldWindowExt.cy,
1886 NULL);
1888 SetViewportExtEx(hdcDraw,
1889 oldViewportExt.cx,
1890 oldViewportExt.cy,
1891 NULL);
1893 SetViewportOrgEx(hdcDraw,
1894 oldViewportOrg.x,
1895 oldViewportOrg.y,
1896 NULL);
1898 SetMapMode(hdcDraw, prevMapMode);
1900 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1902 return S_OK;
1904 case CF_DIB:
1906 BITMAPINFO *info;
1907 BYTE *bits;
1909 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1910 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1911 continue;
1913 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
1914 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1915 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1916 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1917 bits, info, DIB_RGB_COLORS, SRCCOPY );
1919 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1920 return S_OK;
1925 WARN("no data could be found to be drawn\n");
1927 return OLE_E_BLANK;
1930 static HRESULT WINAPI DataCache_GetColorSet(
1931 IViewObject2* iface,
1932 DWORD dwDrawAspect,
1933 LONG lindex,
1934 void* pvAspect,
1935 DVTARGETDEVICE* ptd,
1936 HDC hicTargetDevice,
1937 LOGPALETTE** ppColorSet)
1939 FIXME("stub\n");
1940 return E_NOTIMPL;
1943 static HRESULT WINAPI DataCache_Freeze(
1944 IViewObject2* iface,
1945 DWORD dwDrawAspect,
1946 LONG lindex,
1947 void* pvAspect,
1948 DWORD* pdwFreeze)
1950 FIXME("stub\n");
1951 return E_NOTIMPL;
1954 static HRESULT WINAPI DataCache_Unfreeze(
1955 IViewObject2* iface,
1956 DWORD dwFreeze)
1958 FIXME("stub\n");
1959 return E_NOTIMPL;
1962 /************************************************************************
1963 * DataCache_SetAdvise (IViewObject2)
1965 * This sets-up an advisory sink with the data cache. When the object's
1966 * view changes, this sink is called.
1968 static HRESULT WINAPI DataCache_SetAdvise(
1969 IViewObject2* iface,
1970 DWORD aspects,
1971 DWORD advf,
1972 IAdviseSink* pAdvSink)
1974 DataCache *this = impl_from_IViewObject2(iface);
1976 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1979 * A call to this function removes the previous sink
1981 if (this->sinkInterface != NULL)
1983 IAdviseSink_Release(this->sinkInterface);
1984 this->sinkInterface = NULL;
1985 this->sinkAspects = 0;
1986 this->sinkAdviseFlag = 0;
1990 * Now, setup the new one.
1992 if (pAdvSink!=NULL)
1994 this->sinkInterface = pAdvSink;
1995 this->sinkAspects = aspects;
1996 this->sinkAdviseFlag = advf;
1998 IAdviseSink_AddRef(this->sinkInterface);
2002 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2003 * sink immediately.
2005 if (advf & ADVF_PRIMEFIRST)
2007 DataCache_FireOnViewChange(this, aspects, -1);
2010 return S_OK;
2013 /************************************************************************
2014 * DataCache_GetAdvise (IViewObject2)
2016 * This method queries the current state of the advise sink
2017 * installed on the data cache.
2019 static HRESULT WINAPI DataCache_GetAdvise(
2020 IViewObject2* iface,
2021 DWORD* pAspects,
2022 DWORD* pAdvf,
2023 IAdviseSink** ppAdvSink)
2025 DataCache *this = impl_from_IViewObject2(iface);
2027 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2030 * Just copy all the requested values.
2032 if (pAspects!=NULL)
2033 *pAspects = this->sinkAspects;
2035 if (pAdvf!=NULL)
2036 *pAdvf = this->sinkAdviseFlag;
2038 if (ppAdvSink!=NULL)
2040 if (this->sinkInterface != NULL)
2041 IAdviseSink_QueryInterface(this->sinkInterface,
2042 &IID_IAdviseSink,
2043 (void**)ppAdvSink);
2044 else *ppAdvSink = NULL;
2047 return S_OK;
2050 /************************************************************************
2051 * DataCache_GetExtent (IViewObject2)
2053 * This method retrieves the "natural" size of this cached object.
2055 static HRESULT WINAPI DataCache_GetExtent(
2056 IViewObject2* iface,
2057 DWORD dwDrawAspect,
2058 LONG lindex,
2059 DVTARGETDEVICE* ptd,
2060 LPSIZEL lpsizel)
2062 DataCache *This = impl_from_IViewObject2(iface);
2063 HRESULT hres = E_FAIL;
2064 DataCacheEntry *cache_entry;
2066 TRACE("(%p, %x, %d, %p, %p)\n",
2067 iface, dwDrawAspect, lindex, ptd, lpsizel);
2069 if (lpsizel==NULL)
2070 return E_POINTER;
2072 lpsizel->cx = 0;
2073 lpsizel->cy = 0;
2075 if (lindex!=-1)
2076 FIXME("Unimplemented flag lindex = %d\n", lindex);
2079 * Right now, we support only the callback from
2080 * the default handler.
2082 if (ptd!=NULL)
2083 FIXME("Unimplemented ptd = %p\n", ptd);
2085 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2087 /* FIXME: compare ptd too */
2088 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2089 (cache_entry->fmtetc.lindex != lindex))
2090 continue;
2092 /* if the data hasn't been loaded yet, do it now */
2093 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
2095 hres = DataCacheEntry_LoadData(cache_entry);
2096 if (FAILED(hres))
2097 continue;
2100 /* no data */
2101 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2102 continue;
2105 switch (cache_entry->data_cf)
2107 case CF_METAFILEPICT:
2109 METAFILEPICT *mfpict;
2111 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2112 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2113 continue;
2115 lpsizel->cx = mfpict->xExt;
2116 lpsizel->cy = mfpict->yExt;
2118 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2120 return S_OK;
2122 case CF_DIB:
2124 BITMAPINFOHEADER *info;
2125 LONG x_pels_m, y_pels_m;
2128 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2129 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2130 continue;
2132 x_pels_m = info->biXPelsPerMeter;
2133 y_pels_m = info->biYPelsPerMeter;
2135 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2136 if (x_pels_m != 0 && y_pels_m != 0)
2138 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
2139 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2141 else
2143 HDC hdc = GetDC( 0 );
2144 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2145 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2147 ReleaseDC( 0, hdc );
2150 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2152 return S_OK;
2157 WARN("no data could be found to get the extents from\n");
2160 * This method returns OLE_E_BLANK when it fails.
2162 return OLE_E_BLANK;
2166 /*********************************************************
2167 * Method implementation for the IOleCache2
2168 * part of the DataCache class.
2171 /************************************************************************
2172 * DataCache_IOleCache2_QueryInterface (IUnknown)
2174 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2175 IOleCache2* iface,
2176 REFIID riid,
2177 void** ppvObject)
2179 DataCache *this = impl_from_IOleCache2(iface);
2181 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2184 /************************************************************************
2185 * DataCache_IOleCache2_AddRef (IUnknown)
2187 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2188 IOleCache2* iface)
2190 DataCache *this = impl_from_IOleCache2(iface);
2192 return IUnknown_AddRef(this->outer_unk);
2195 /************************************************************************
2196 * DataCache_IOleCache2_Release (IUnknown)
2198 static ULONG WINAPI DataCache_IOleCache2_Release(
2199 IOleCache2* iface)
2201 DataCache *this = impl_from_IOleCache2(iface);
2203 return IUnknown_Release(this->outer_unk);
2206 /*****************************************************************************
2207 * setup_sink
2209 * Set up the sink connection to the running object.
2211 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2213 HRESULT hr = S_FALSE;
2214 DWORD flags;
2216 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2217 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2219 if(This->running_object)
2220 if(!(flags & ADVF_NODATA))
2221 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2222 &This->IAdviseSink_iface, &cache_entry->sink_id);
2223 return hr;
2226 static HRESULT WINAPI DataCache_Cache(
2227 IOleCache2* iface,
2228 FORMATETC* pformatetc,
2229 DWORD advf,
2230 DWORD* pdwConnection)
2232 DataCache *This = impl_from_IOleCache2(iface);
2233 DataCacheEntry *cache_entry;
2234 HRESULT hr;
2235 FORMATETC fmt_cpy;
2237 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2239 if (!pformatetc || !pdwConnection)
2240 return E_INVALIDARG;
2242 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2244 fmt_cpy = *pformatetc; /* No need for a deep copy */
2245 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2247 fmt_cpy.cfFormat = CF_DIB;
2248 fmt_cpy.tymed = TYMED_HGLOBAL;
2251 *pdwConnection = 0;
2253 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2254 if (cache_entry)
2256 TRACE("found an existing cache entry\n");
2257 *pdwConnection = cache_entry->id;
2258 return CACHE_S_SAMECACHE;
2261 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2263 if (SUCCEEDED(hr))
2265 *pdwConnection = cache_entry->id;
2266 setup_sink(This, cache_entry);
2269 return hr;
2272 static HRESULT WINAPI DataCache_Uncache(
2273 IOleCache2* iface,
2274 DWORD dwConnection)
2276 DataCache *This = impl_from_IOleCache2(iface);
2277 DataCacheEntry *cache_entry;
2279 TRACE("(%d)\n", dwConnection);
2281 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2282 if (cache_entry->id == dwConnection)
2284 DataCacheEntry_Destroy(This, cache_entry);
2285 return S_OK;
2288 WARN("no connection found for %d\n", dwConnection);
2290 return OLE_E_NOCONNECTION;
2293 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2294 IEnumSTATDATA **enum_stat)
2296 DataCache *This = impl_from_IOleCache2( iface );
2297 DataCacheEntry *cache_entry;
2298 int i = 0, count = 0;
2299 STATDATA *data;
2300 HRESULT hr;
2302 TRACE( "(%p, %p)\n", This, enum_stat );
2304 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2306 count++;
2307 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2308 count++;
2311 data = CoTaskMemAlloc( count * sizeof(*data) );
2312 if (!data) return E_OUTOFMEMORY;
2314 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2316 if (i == count) goto fail;
2317 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2318 if (FAILED(hr)) goto fail;
2319 data[i].advf = cache_entry->advise_flags;
2320 data[i].pAdvSink = NULL;
2321 data[i].dwConnection = cache_entry->id;
2322 i++;
2324 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2326 if (i == count) goto fail;
2327 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2328 if (FAILED(hr)) goto fail;
2329 data[i].formatetc.cfFormat = CF_BITMAP;
2330 data[i].formatetc.tymed = TYMED_GDI;
2331 data[i].advf = cache_entry->advise_flags;
2332 data[i].pAdvSink = NULL;
2333 data[i].dwConnection = cache_entry->id;
2334 i++;
2338 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2339 if (SUCCEEDED(hr)) return hr;
2341 fail:
2342 while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2343 CoTaskMemFree( data );
2344 return hr;
2347 static HRESULT WINAPI DataCache_InitCache(
2348 IOleCache2* iface,
2349 IDataObject* pDataObject)
2351 FIXME("stub\n");
2352 return E_NOTIMPL;
2355 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2356 IOleCache2* iface,
2357 FORMATETC* pformatetc,
2358 STGMEDIUM* pmedium,
2359 BOOL fRelease)
2361 DataCache *This = impl_from_IOleCache2(iface);
2362 DataCacheEntry *cache_entry;
2363 HRESULT hr;
2365 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2366 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2368 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2369 if (cache_entry)
2371 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2373 if (SUCCEEDED(hr))
2374 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2375 cache_entry->fmtetc.lindex);
2377 return hr;
2379 WARN("cache entry not found\n");
2381 return OLE_E_BLANK;
2384 static HRESULT WINAPI DataCache_UpdateCache(
2385 IOleCache2* iface,
2386 LPDATAOBJECT pDataObject,
2387 DWORD grfUpdf,
2388 LPVOID pReserved)
2390 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2391 return E_NOTIMPL;
2394 static HRESULT WINAPI DataCache_DiscardCache(
2395 IOleCache2* iface,
2396 DWORD dwDiscardOptions)
2398 DataCache *This = impl_from_IOleCache2(iface);
2399 DataCacheEntry *cache_entry;
2400 HRESULT hr = S_OK;
2402 TRACE("(%d)\n", dwDiscardOptions);
2404 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2405 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2407 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2409 hr = DataCacheEntry_DiscardData(cache_entry);
2410 if (FAILED(hr))
2411 break;
2414 return hr;
2418 /*********************************************************
2419 * Method implementation for the IOleCacheControl
2420 * part of the DataCache class.
2423 /************************************************************************
2424 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2426 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2427 IOleCacheControl* iface,
2428 REFIID riid,
2429 void** ppvObject)
2431 DataCache *this = impl_from_IOleCacheControl(iface);
2433 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2436 /************************************************************************
2437 * DataCache_IOleCacheControl_AddRef (IUnknown)
2439 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2440 IOleCacheControl* iface)
2442 DataCache *this = impl_from_IOleCacheControl(iface);
2444 return IUnknown_AddRef(this->outer_unk);
2447 /************************************************************************
2448 * DataCache_IOleCacheControl_Release (IUnknown)
2450 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2451 IOleCacheControl* iface)
2453 DataCache *this = impl_from_IOleCacheControl(iface);
2455 return IUnknown_Release(this->outer_unk);
2458 /************************************************************************
2459 * DataCache_OnRun (IOleCacheControl)
2461 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2463 DataCache *This = impl_from_IOleCacheControl(iface);
2464 DataCacheEntry *cache_entry;
2466 TRACE("(%p)->(%p)\n", iface, data_obj);
2468 if(This->running_object) return S_OK;
2470 /* No reference is taken on the data object */
2471 This->running_object = data_obj;
2473 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2475 setup_sink(This, cache_entry);
2478 return S_OK;
2481 /************************************************************************
2482 * DataCache_OnStop (IOleCacheControl)
2484 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2486 DataCache *This = impl_from_IOleCacheControl(iface);
2487 DataCacheEntry *cache_entry;
2489 TRACE("(%p)\n", iface);
2491 if(!This->running_object) return S_OK;
2493 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2495 if(cache_entry->sink_id)
2497 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2498 cache_entry->sink_id = 0;
2502 /* No ref taken in OnRun, so no Release call here */
2503 This->running_object = NULL;
2504 return S_OK;
2507 /************************************************************************
2508 * IAdviseSink methods.
2509 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2510 * give access to the cache's other interfaces. We don't maintain a ref count,
2511 * the object exists as long as the cache is around.
2513 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2515 *obj = NULL;
2516 if (IsEqualIID(&IID_IUnknown, iid) ||
2517 IsEqualIID(&IID_IAdviseSink, iid))
2519 *obj = iface;
2522 if(*obj)
2524 IAdviseSink_AddRef(iface);
2525 return S_OK;
2527 return E_NOINTERFACE;
2530 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2532 return 2;
2535 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2537 return 1;
2540 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2542 DataCache *This = impl_from_IAdviseSink(iface);
2543 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2544 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2547 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2549 FIXME("stub\n");
2552 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2554 FIXME("stub\n");
2557 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2559 FIXME("stub\n");
2562 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2564 FIXME("stub\n");
2568 * Virtual function tables for the DataCache class.
2570 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2572 DataCache_NDIUnknown_QueryInterface,
2573 DataCache_NDIUnknown_AddRef,
2574 DataCache_NDIUnknown_Release
2577 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2579 DataCache_IDataObject_QueryInterface,
2580 DataCache_IDataObject_AddRef,
2581 DataCache_IDataObject_Release,
2582 DataCache_GetData,
2583 DataCache_GetDataHere,
2584 DataCache_QueryGetData,
2585 DataCache_GetCanonicalFormatEtc,
2586 DataCache_IDataObject_SetData,
2587 DataCache_EnumFormatEtc,
2588 DataCache_DAdvise,
2589 DataCache_DUnadvise,
2590 DataCache_EnumDAdvise
2593 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2595 DataCache_IPersistStorage_QueryInterface,
2596 DataCache_IPersistStorage_AddRef,
2597 DataCache_IPersistStorage_Release,
2598 DataCache_GetClassID,
2599 DataCache_IsDirty,
2600 DataCache_InitNew,
2601 DataCache_Load,
2602 DataCache_Save,
2603 DataCache_SaveCompleted,
2604 DataCache_HandsOffStorage
2607 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2609 DataCache_IViewObject2_QueryInterface,
2610 DataCache_IViewObject2_AddRef,
2611 DataCache_IViewObject2_Release,
2612 DataCache_Draw,
2613 DataCache_GetColorSet,
2614 DataCache_Freeze,
2615 DataCache_Unfreeze,
2616 DataCache_SetAdvise,
2617 DataCache_GetAdvise,
2618 DataCache_GetExtent
2621 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2623 DataCache_IOleCache2_QueryInterface,
2624 DataCache_IOleCache2_AddRef,
2625 DataCache_IOleCache2_Release,
2626 DataCache_Cache,
2627 DataCache_Uncache,
2628 DataCache_EnumCache,
2629 DataCache_InitCache,
2630 DataCache_IOleCache2_SetData,
2631 DataCache_UpdateCache,
2632 DataCache_DiscardCache
2635 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2637 DataCache_IOleCacheControl_QueryInterface,
2638 DataCache_IOleCacheControl_AddRef,
2639 DataCache_IOleCacheControl_Release,
2640 DataCache_OnRun,
2641 DataCache_OnStop
2644 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2646 DataCache_IAdviseSink_QueryInterface,
2647 DataCache_IAdviseSink_AddRef,
2648 DataCache_IAdviseSink_Release,
2649 DataCache_OnDataChange,
2650 DataCache_OnViewChange,
2651 DataCache_OnRename,
2652 DataCache_OnSave,
2653 DataCache_OnClose
2656 /*********************************************************
2657 * Method implementation for DataCache class.
2659 static DataCache* DataCache_Construct(
2660 REFCLSID clsid,
2661 LPUNKNOWN pUnkOuter)
2663 DataCache* newObject = 0;
2666 * Allocate space for the object.
2668 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2670 if (newObject==0)
2671 return newObject;
2674 * Initialize the virtual function table.
2676 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2677 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2678 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2679 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2680 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2681 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2682 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2683 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2684 newObject->ref = 1;
2687 * Initialize the other members of the structure.
2689 newObject->sinkAspects = 0;
2690 newObject->sinkAdviseFlag = 0;
2691 newObject->sinkInterface = 0;
2692 newObject->clsid = CLSID_NULL;
2693 newObject->presentationStorage = NULL;
2694 list_init(&newObject->cache_list);
2695 newObject->last_cache_id = 2;
2696 newObject->dirty = FALSE;
2697 newObject->running_object = NULL;
2699 create_automatic_entry( newObject, clsid );
2700 newObject->clsid = *clsid;
2702 return newObject;
2705 /******************************************************************************
2706 * CreateDataCache [OLE32.@]
2708 * Creates a data cache to allow an object to render one or more of its views,
2709 * whether running or not.
2711 * PARAMS
2712 * pUnkOuter [I] Outer unknown for the object.
2713 * rclsid [I]
2714 * riid [I] IID of interface to return.
2715 * ppvObj [O] Address where the data cache object will be stored on return.
2717 * RETURNS
2718 * Success: S_OK.
2719 * Failure: HRESULT code.
2721 * NOTES
2722 * The following interfaces are supported by the returned data cache object:
2723 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2724 * IViewObject and IViewObject2.
2726 HRESULT WINAPI CreateDataCache(
2727 LPUNKNOWN pUnkOuter,
2728 REFCLSID rclsid,
2729 REFIID riid,
2730 LPVOID* ppvObj)
2732 DataCache* newCache = NULL;
2733 HRESULT hr = S_OK;
2735 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2738 * Sanity check
2740 if (ppvObj==0)
2741 return E_POINTER;
2743 *ppvObj = 0;
2746 * If this cache is constructed for aggregation, make sure
2747 * the caller is requesting the IUnknown interface.
2748 * This is necessary because it's the only time the non-delegating
2749 * IUnknown pointer can be returned to the outside.
2751 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2752 return E_INVALIDARG;
2755 * Try to construct a new instance of the class.
2757 newCache = DataCache_Construct(rclsid,
2758 pUnkOuter);
2760 if (newCache == 0)
2761 return E_OUTOFMEMORY;
2763 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
2764 IUnknown_Release(&newCache->IUnknown_inner);
2766 return hr;