msado15: Semi-stub _Recordset get/put Filter.
[wine.git] / dlls / ole32 / datacache.c
blobb3216992af57002d3338475344a5c21779d87d9d
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/list.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65 /****************************************************************************
66 * PresentationDataHeader
68 * This structure represents the header of the \002OlePresXXX stream in
69 * the OLE object storage.
71 typedef struct PresentationDataHeader
73 /* clipformat:
74 * - standard clipformat:
75 * DWORD length = 0xffffffff;
76 * DWORD cfFormat;
77 * - or custom clipformat:
78 * DWORD length;
79 * CHAR format_name[length]; (null-terminated)
81 DWORD tdSize; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD)
82 then there are tdSize - sizeof(DWORD) more bytes before dvAspect */
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 #define STREAM_NUMBER_NOT_SET -2
93 #define STREAM_NUMBER_CONTENTS -1 /* CONTENTS stream */
95 typedef struct DataCacheEntry
97 struct list entry;
98 /* format of this entry */
99 FORMATETC fmtetc;
100 /* cached data */
101 STGMEDIUM stgmedium;
102 /* connection ID */
103 DWORD id;
104 /* dirty flag */
105 BOOL dirty;
106 /* stream number that the entry was loaded from.
107 This is used to defer loading until the data is actually needed. */
108 int load_stream_num;
109 /* stream number that the entry will be saved to.
110 This may differ from above if cache entries have been Uncache()d for example. */
111 int save_stream_num;
112 /* sink id set when object is running */
113 DWORD sink_id;
114 /* Advise sink flags */
115 DWORD advise_flags;
116 } DataCacheEntry;
118 /****************************************************************************
119 * DataCache
121 struct DataCache
124 * List all interface here
126 IUnknown IUnknown_inner;
127 IDataObject IDataObject_iface;
128 IPersistStorage IPersistStorage_iface;
129 IViewObject2 IViewObject2_iface;
130 IOleCache2 IOleCache2_iface;
131 IOleCacheControl IOleCacheControl_iface;
133 /* The sink that is connected to a remote object.
134 The other interfaces are not available by QI'ing the sink and vice-versa */
135 IAdviseSink IAdviseSink_iface;
138 * Reference count of this object
140 LONG ref;
143 * IUnknown implementation of the outer object.
145 IUnknown *outer_unk;
148 * The user of this object can setup ONE advise sink
149 * connection with the object. These parameters describe
150 * that connection.
152 DWORD sinkAspects;
153 DWORD sinkAdviseFlag;
154 IAdviseSink *sinkInterface;
156 CLSID clsid;
157 /* Is the clsid one of the CLSID_Picture classes */
158 BOOL clsid_static;
160 IStorage *presentationStorage;
162 /* list of cache entries */
163 struct list cache_list;
164 /* last id assigned to an entry */
165 DWORD last_cache_id;
166 /* dirty flag */
167 BOOL dirty;
168 /* running object set by OnRun */
169 IDataObject *running_object;
172 typedef struct DataCache DataCache;
175 * Here, I define utility macros to help with the casting of the
176 * "this" parameter.
177 * There is a version to accommodate all of the VTables implemented
178 * by this object.
181 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
183 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
186 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
188 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
191 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
193 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
196 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
198 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
201 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
203 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
206 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
208 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
211 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
213 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
216 const char *debugstr_formatetc(const FORMATETC *formatetc)
218 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %ld, lindex = %ld, tymed = %ld }",
219 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
220 formatetc->lindex, formatetc->tymed);
223 /***********************************************************************
224 * bitmap_info_size
226 * Return the size of the bitmap info structure including color table.
228 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
230 unsigned int colors, size, masks = 0;
232 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
234 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
235 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
236 return sizeof(BITMAPCOREHEADER) + colors *
237 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
239 else /* assume BITMAPINFOHEADER */
241 colors = info->bmiHeader.biClrUsed;
242 if (colors > 256) /* buffer overflow otherwise */
243 colors = 256;
244 if (!colors && (info->bmiHeader.biBitCount <= 8))
245 colors = 1 << info->bmiHeader.biBitCount;
246 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
247 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
248 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
252 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
254 list_remove(&cache_entry->entry);
255 CoTaskMemFree(cache_entry->fmtetc.ptd);
256 ReleaseStgMedium(&cache_entry->stgmedium);
257 if(cache_entry->sink_id)
258 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
260 HeapFree(GetProcessHeap(), 0, cache_entry);
263 static void DataCache_Destroy(
264 DataCache* ptrToDestroy)
266 DataCacheEntry *cache_entry, *next_cache_entry;
268 TRACE("()\n");
270 if (ptrToDestroy->sinkInterface != NULL)
272 IAdviseSink_Release(ptrToDestroy->sinkInterface);
273 ptrToDestroy->sinkInterface = NULL;
276 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
277 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
279 if (ptrToDestroy->presentationStorage != NULL)
281 IStorage_Release(ptrToDestroy->presentationStorage);
282 ptrToDestroy->presentationStorage = NULL;
286 * Free the datacache pointer.
288 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
291 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
293 DataCacheEntry *cache_entry;
294 FORMATETC fmt = *formatetc;
296 if (fmt.cfFormat == CF_BITMAP)
298 fmt.cfFormat = CF_DIB;
299 fmt.tymed = TYMED_HGLOBAL;
302 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
304 /* FIXME: also compare DVTARGETDEVICEs */
305 if ((fmt.cfFormat == cache_entry->fmtetc.cfFormat) &&
306 (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
307 (fmt.lindex == cache_entry->fmtetc.lindex) &&
308 ((fmt.tymed == cache_entry->fmtetc.tymed) || !cache_entry->fmtetc.cfFormat)) /* tymed is ignored for view caching */
309 return cache_entry;
311 return NULL;
314 /* Returns the cache entry associated with a static CLSID.
315 This will be first in the list with connection id == 1 */
316 static HRESULT get_static_entry( DataCache *cache, DataCacheEntry **cache_entry )
318 DataCacheEntry *entry;
319 struct list *head = list_head( &cache->cache_list );
320 HRESULT hr = E_FAIL;
322 *cache_entry = NULL;
324 if (head)
326 entry = LIST_ENTRY( head, DataCacheEntry, entry );
327 if (entry->id == 1)
329 *cache_entry = entry;
330 hr = S_OK;
334 return hr;
337 /* checks that the clipformat and tymed are valid and returns an error if they
338 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
339 * DataCache_Draw */
340 static HRESULT check_valid_formatetc( const FORMATETC *fmt )
342 /* DVASPECT_ICON must be CF_METAFILEPICT */
343 if (fmt->dwAspect == DVASPECT_ICON && fmt->cfFormat != CF_METAFILEPICT)
344 return DV_E_FORMATETC;
346 if (!fmt->cfFormat ||
347 (fmt->cfFormat == CF_METAFILEPICT && fmt->tymed == TYMED_MFPICT) ||
348 (fmt->cfFormat == CF_BITMAP && fmt->tymed == TYMED_GDI) ||
349 (fmt->cfFormat == CF_DIB && fmt->tymed == TYMED_HGLOBAL) ||
350 (fmt->cfFormat == CF_ENHMETAFILE && fmt->tymed == TYMED_ENHMF))
351 return S_OK;
352 else if (fmt->tymed == TYMED_HGLOBAL)
353 return CACHE_S_FORMATETC_NOTSUPPORTED;
354 else
356 WARN("invalid clipformat/tymed combination: %d/%ld\n", fmt->cfFormat, fmt->tymed);
357 return DV_E_TYMED;
361 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf,
362 DWORD id)
364 HRESULT hr;
366 hr = copy_formatetc(&entry->fmtetc, fmt);
367 if (FAILED(hr)) return FALSE;
369 entry->stgmedium.tymed = TYMED_NULL;
370 entry->stgmedium.pUnkForRelease = NULL;
371 entry->id = id;
372 entry->dirty = TRUE;
373 entry->load_stream_num = STREAM_NUMBER_NOT_SET;
374 entry->save_stream_num = STREAM_NUMBER_NOT_SET;
375 entry->sink_id = 0;
376 entry->advise_flags = advf;
378 return TRUE;
381 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf,
382 BOOL automatic, DataCacheEntry **cache_entry)
384 HRESULT hr;
385 DWORD id = automatic ? 1 : This->last_cache_id;
386 DataCacheEntry *entry;
388 hr = check_valid_formatetc( formatetc );
389 if (FAILED(hr))
390 return hr;
391 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
392 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
394 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
395 if (!entry)
396 return E_OUTOFMEMORY;
398 if (!init_cache_entry(entry, formatetc, advf, id))
399 goto fail;
401 if (automatic)
402 list_add_head(&This->cache_list, &entry->entry);
403 else
405 list_add_tail(&This->cache_list, &entry->entry);
406 This->last_cache_id++;
409 if (cache_entry) *cache_entry = entry;
410 return hr;
412 fail:
413 HeapFree(GetProcessHeap(), 0, entry);
414 return E_OUTOFMEMORY;
417 /************************************************************************
418 * DataCache_FireOnViewChange
420 * This method will fire an OnViewChange notification to the advise
421 * sink registered with the datacache.
423 * See IAdviseSink::OnViewChange for more details.
425 static void DataCache_FireOnViewChange(
426 DataCache* this,
427 DWORD aspect,
428 LONG lindex)
430 TRACE("%p, %lx, %ld.\n", this, aspect, lindex);
433 * The sink supplies a filter when it registers
434 * we make sure we only send the notifications when that
435 * filter matches.
437 if ((this->sinkAspects & aspect) != 0)
439 if (this->sinkInterface != NULL)
441 IAdviseSink_OnViewChange(this->sinkInterface,
442 aspect,
443 lindex);
446 * Some sinks want to be unregistered automatically when
447 * the first notification goes out.
449 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
451 IAdviseSink_Release(this->sinkInterface);
453 this->sinkInterface = NULL;
454 this->sinkAspects = 0;
455 this->sinkAdviseFlag = 0;
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) {
473 /* No clipboard format present */
474 return S_OK;
476 if (length == -1)
478 DWORD cf;
479 hr = IStream_Read(stream, &cf, sizeof(cf), &read);
480 if (hr != S_OK || read != sizeof(cf))
481 return DV_E_CLIPFORMAT;
482 *clipformat = cf;
484 else
486 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
487 if (!format_name)
488 return E_OUTOFMEMORY;
489 hr = IStream_Read(stream, format_name, length, &read);
490 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
492 HeapFree(GetProcessHeap(), 0, format_name);
493 return DV_E_CLIPFORMAT;
495 *clipformat = RegisterClipboardFormatA(format_name);
496 HeapFree(GetProcessHeap(), 0, format_name);
498 return S_OK;
501 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
503 DWORD length;
504 HRESULT hr;
505 char format_name[256];
507 if (clipformat == 0)
508 length = 0;
509 else if (clipformat < 0xc000)
510 length = -1;
511 else
513 length = GetClipboardFormatNameA(clipformat, format_name, sizeof(format_name));
514 /* If there is a clipboard format name, we need to include its terminating \0 */
515 if (length) length++;
517 hr = IStream_Write(stream, &length, sizeof(length), NULL);
518 if (FAILED(hr) || clipformat == 0)
519 return hr;
521 if (clipformat < 0xc000)
523 DWORD cf = clipformat;
524 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
526 else
528 hr = IStream_Write(stream, format_name, length, NULL);
530 return hr;
533 static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm )
535 WCHAR pres[] = {2,'O','l','e','P','r','e','s',
536 '0' + (stream_number / 100) % 10,
537 '0' + (stream_number / 10) % 10,
538 '0' + stream_number % 10, 0};
539 const WCHAR *name = pres;
541 if (stream_number == STREAM_NUMBER_NOT_SET) return E_FAIL;
542 if (stream_number == STREAM_NUMBER_CONTENTS) name = L"CONTENTS";
544 return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
547 static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med )
549 METAFILEPICT *pict;
550 HRESULT hr = E_FAIL;
551 UINT size;
552 void *bits;
554 if (!(pict = GlobalLock( data ))) return hr;
556 size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
557 if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
559 GetMetaFileBitsEx( pict->hMF, size, bits );
560 med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict );
561 HeapFree( GetProcessHeap(), 0, bits );
562 med->tymed = TYMED_ENHMF;
563 med->pUnkForRelease = NULL;
564 hr = S_OK;
567 GlobalUnlock( data );
568 return hr;
570 #include <pshpack2.h>
571 struct meta_placeable
573 DWORD key;
574 WORD hwmf;
575 WORD bounding_box[4];
576 WORD inch;
577 DWORD reserved;
578 WORD checksum;
580 #include <poppack.h>
582 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
584 HRESULT hr;
585 STATSTG stat;
586 ULARGE_INTEGER current_pos;
587 void *bits;
588 METAFILEPICT *mfpict;
589 HGLOBAL hmfpict;
590 PresentationDataHeader header;
591 CLIPFORMAT clipformat;
592 static const LARGE_INTEGER offset_zero;
593 ULONG read;
594 struct meta_placeable mf_place;
596 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
597 if (FAILED( hr )) return hr;
599 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
601 hr = read_clipformat( stm, &clipformat );
602 if (hr != S_OK) return hr;
603 hr = IStream_Read( stm, &header, sizeof(header), &read );
604 if (hr != S_OK) return hr;
606 else
608 hr = IStream_Read( stm, &mf_place, sizeof(mf_place), &read );
609 if (hr != S_OK) return hr;
612 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
613 if (FAILED( hr )) return hr;
614 stat.cbSize.QuadPart -= current_pos.QuadPart;
616 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
617 if (!hmfpict) return E_OUTOFMEMORY;
618 mfpict = GlobalLock( hmfpict );
620 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
621 if (!bits)
623 GlobalFree( hmfpict );
624 return E_OUTOFMEMORY;
627 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
629 if (SUCCEEDED( hr ))
631 mfpict->mm = MM_ANISOTROPIC;
632 /* FIXME: get this from the stream */
633 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
635 mfpict->xExt = header.dwObjectExtentX;
636 mfpict->yExt = header.dwObjectExtentY;
638 else
640 mfpict->xExt = ((mf_place.bounding_box[2] - mf_place.bounding_box[0])
641 * 2540) / mf_place.inch;
642 mfpict->yExt = ((mf_place.bounding_box[3] - mf_place.bounding_box[1])
643 * 2540) / mf_place.inch;
645 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
646 if (!mfpict->hMF)
647 hr = E_FAIL;
650 GlobalUnlock( hmfpict );
651 if (SUCCEEDED( hr ))
653 cache_entry->stgmedium.tymed = TYMED_MFPICT;
654 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
656 else
657 GlobalFree( hmfpict );
659 HeapFree( GetProcessHeap(), 0, bits );
661 return hr;
664 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
666 HRESULT hr;
667 STATSTG stat;
668 BYTE *dib;
669 HGLOBAL hglobal;
670 ULONG read, info_size, bi_size;
671 BITMAPFILEHEADER file;
672 BITMAPINFOHEADER *info;
673 CLIPFORMAT cf;
674 PresentationDataHeader pres;
675 ULARGE_INTEGER current_pos;
676 static const LARGE_INTEGER offset_zero;
678 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
679 if (FAILED( hr )) return hr;
681 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
683 hr = read_clipformat( stm, &cf );
684 if (hr != S_OK) return hr;
685 hr = IStream_Read( stm, &pres, sizeof(pres), &read );
686 if (hr != S_OK) return hr;
688 else
690 hr = IStream_Read( stm, &file, sizeof(BITMAPFILEHEADER), &read );
691 if (hr != S_OK) return hr;
694 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
695 if (FAILED( hr )) return hr;
696 stat.cbSize.QuadPart -= current_pos.QuadPart;
698 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
699 if (!hglobal) return E_OUTOFMEMORY;
700 dib = GlobalLock( hglobal );
702 /* read first DWORD of BITMAPINFOHEADER */
703 hr = IStream_Read( stm, dib, sizeof(DWORD), &read );
704 if (hr != S_OK) goto fail;
705 bi_size = *(DWORD *)dib;
706 if (stat.cbSize.QuadPart < bi_size) goto fail;
708 /* read rest of BITMAPINFOHEADER */
709 hr = IStream_Read( stm, dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read );
710 if (hr != S_OK) goto fail;
712 info_size = bitmap_info_size( (BITMAPINFO *)dib, DIB_RGB_COLORS );
713 if (stat.cbSize.QuadPart < info_size) goto fail;
714 if (info_size > bi_size)
716 hr = IStream_Read( stm, dib + bi_size, info_size - bi_size, &read );
717 if (hr != S_OK) goto fail;
719 stat.cbSize.QuadPart -= info_size;
721 /* set Stream pointer to beginning of bitmap bits */
722 if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS && file.bfOffBits)
724 LARGE_INTEGER skip;
726 skip.QuadPart = file.bfOffBits - sizeof(file) - info_size;
727 if (stat.cbSize.QuadPart < skip.QuadPart) goto fail;
728 hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL );
729 if (hr != S_OK) goto fail;
730 stat.cbSize.QuadPart -= skip.QuadPart;
733 hr = IStream_Read( stm, dib + info_size, stat.cbSize.u.LowPart, &read );
734 if (hr != S_OK) goto fail;
736 if (bi_size >= sizeof(*info))
738 info = (BITMAPINFOHEADER *)dib;
739 if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0)
741 HDC hdc = GetDC( 0 );
742 info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 );
743 info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 );
744 ReleaseDC( 0, hdc );
748 GlobalUnlock( hglobal );
750 cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
751 cache_entry->stgmedium.u.hGlobal = hglobal;
753 return hr;
755 fail:
756 GlobalUnlock( hglobal );
757 GlobalFree( hglobal );
758 return hr;
762 static HRESULT load_emf( DataCacheEntry *cache_entry, IStream *stm )
764 HRESULT hr;
766 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
768 STGMEDIUM stgmed;
770 hr = load_mf_pict( cache_entry, stm );
771 if (SUCCEEDED( hr ))
773 hr = synthesize_emf( cache_entry->stgmedium.u.hMetaFilePict, &stgmed );
774 ReleaseStgMedium( &cache_entry->stgmedium );
776 if (SUCCEEDED( hr ))
777 cache_entry->stgmedium = stgmed;
779 else
781 STATSTG stat;
782 BYTE *data;
783 ULONG read, size_bits;
785 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
787 if (SUCCEEDED( hr ))
789 data = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart );
790 if (!data) return E_OUTOFMEMORY;
792 hr = IStream_Read( stm, data, stat.cbSize.u.LowPart, &read );
793 if (hr != S_OK)
795 HeapFree( GetProcessHeap(), 0, data );
796 return hr;
799 if (read <= sizeof(DWORD) + sizeof(ENHMETAHEADER))
801 HeapFree( GetProcessHeap(), 0, data );
802 return E_FAIL;
804 size_bits = read - sizeof(DWORD) - sizeof(ENHMETAHEADER);
805 cache_entry->stgmedium.u.hEnhMetaFile = SetEnhMetaFileBits( size_bits, data + (read - size_bits) );
806 cache_entry->stgmedium.tymed = TYMED_ENHMF;
807 cache_entry->stgmedium.pUnkForRelease = NULL;
809 HeapFree( GetProcessHeap(), 0, data );
813 return hr;
816 /************************************************************************
817 * DataCacheEntry_LoadData
819 * This method will read information for the requested presentation
820 * into the given structure.
822 * Param:
823 * This - The entry to load the data from.
825 * Returns:
826 * This method returns a metafile handle if it is successful.
827 * it will return 0 if not.
829 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *stg)
831 HRESULT hr;
832 IStream *stm;
834 if (!stg) return OLE_E_BLANK;
835 hr = open_pres_stream( stg, cache_entry->load_stream_num, &stm );
836 if (FAILED(hr)) return hr;
838 switch (cache_entry->fmtetc.cfFormat)
840 case CF_METAFILEPICT:
841 hr = load_mf_pict( cache_entry, stm );
842 break;
844 case CF_DIB:
845 hr = load_dib( cache_entry, stm );
846 break;
848 case CF_ENHMETAFILE:
849 hr = load_emf( cache_entry, stm );
850 break;
852 default:
853 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
854 hr = E_NOTIMPL;
857 IStream_Release( stm );
858 return hr;
861 static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header)
863 if (entry->fmtetc.ptd)
864 FIXME("ptd not serialized\n");
865 header->tdSize = sizeof(header->tdSize);
866 header->dvAspect = entry->fmtetc.dwAspect;
867 header->lindex = entry->fmtetc.lindex;
868 header->advf = entry->advise_flags;
869 header->unknown7 = 0;
870 header->dwObjectExtentX = 0;
871 header->dwObjectExtentY = 0;
872 header->dwSize = 0;
875 static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream)
877 HRESULT hr = S_OK;
878 int data_size = 0;
879 BITMAPINFO *bmi = NULL;
881 if (entry->stgmedium.tymed != TYMED_NULL)
883 data_size = GlobalSize(entry->stgmedium.u.hGlobal);
884 bmi = GlobalLock(entry->stgmedium.u.hGlobal);
887 if (!contents)
889 PresentationDataHeader header;
891 init_stream_header(entry, &header);
892 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
893 if (FAILED(hr)) goto end;
894 if (data_size)
896 header.dwSize = data_size;
897 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
898 if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0)
900 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter);
901 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter);
903 else
905 HDC hdc = GetDC(0);
906 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
907 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
908 ReleaseDC(0, hdc);
911 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
912 if (hr == S_OK && data_size)
913 hr = IStream_Write(stream, bmi, data_size, NULL);
915 else if(data_size)
917 BITMAPFILEHEADER bmp_fhdr;
919 bmp_fhdr.bfType = 0x4d42;
920 bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER);
921 bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0;
922 bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER);
923 hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL);
924 if (hr == S_OK)
925 hr = IStream_Write(stream, bmi, data_size, NULL);
928 end:
929 if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal);
930 return hr;
933 static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream)
935 HRESULT hr = S_OK;
936 int data_size = 0;
937 void *data = NULL;
938 METAFILEPICT *mfpict = NULL;
940 if (!contents)
942 PresentationDataHeader header;
944 init_stream_header(entry, &header);
945 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
946 if (FAILED(hr)) return hr;
947 if (entry->stgmedium.tymed != TYMED_NULL)
949 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
950 if (!mfpict)
951 return DV_E_STGMEDIUM;
952 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
953 header.dwObjectExtentX = mfpict->xExt;
954 header.dwObjectExtentY = mfpict->yExt;
955 header.dwSize = data_size;
956 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
957 if (!data)
959 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
960 return E_OUTOFMEMORY;
962 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
963 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
965 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
966 if (hr == S_OK && data_size)
967 hr = IStream_Write(stream, data, data_size, NULL);
968 HeapFree(GetProcessHeap(), 0, data);
970 else if (entry->stgmedium.tymed != TYMED_NULL)
972 struct meta_placeable meta_place_rec;
973 WORD *check;
975 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
976 if (!mfpict)
977 return DV_E_STGMEDIUM;
978 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
979 data = HeapAlloc(GetProcessHeap(), 0, data_size);
980 if (!data)
982 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
983 return E_OUTOFMEMORY;
985 GetMetaFileBitsEx(mfpict->hMF, data_size, data);
987 /* units are in 1/8th of a point (1 point is 1/72th of an inch) */
988 meta_place_rec.key = 0x9ac6cdd7;
989 meta_place_rec.hwmf = 0;
990 meta_place_rec.inch = 576;
991 meta_place_rec.bounding_box[0] = 0;
992 meta_place_rec.bounding_box[1] = 0;
993 meta_place_rec.bounding_box[2] = 0;
994 meta_place_rec.bounding_box[3] = 0;
995 meta_place_rec.checksum = 0;
996 meta_place_rec.reserved = 0;
998 /* These values are rounded down so MulDiv won't do the right thing */
999 meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540;
1000 meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540;
1001 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
1003 for (check = (WORD *)&meta_place_rec; check != &meta_place_rec.checksum; check++)
1004 meta_place_rec.checksum ^= *check;
1005 hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL);
1006 if (hr == S_OK && data_size)
1007 hr = IStream_Write(stream, data, data_size, NULL);
1008 HeapFree(GetProcessHeap(), 0, data);
1011 return hr;
1014 static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream)
1016 HRESULT hr = S_OK;
1017 int data_size = 0;
1018 BYTE *data;
1020 if (!contents)
1022 PresentationDataHeader header;
1023 METAFILEPICT *mfpict;
1024 HDC hdc = GetDC(0);
1026 init_stream_header(entry, &header);
1027 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1028 if (FAILED(hr))
1030 ReleaseDC(0, hdc);
1031 return hr;
1033 data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc);
1034 header.dwSize = data_size;
1035 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
1036 if (!data)
1038 ReleaseDC(0, hdc);
1039 return E_OUTOFMEMORY;
1041 GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc);
1042 ReleaseDC(0, hdc);
1043 mfpict = (METAFILEPICT *)data;
1044 header.dwObjectExtentX = mfpict->xExt;
1045 header.dwObjectExtentY = mfpict->yExt;
1046 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
1047 if (hr == S_OK && data_size)
1048 hr = IStream_Write(stream, data, data_size, NULL);
1049 HeapFree(GetProcessHeap(), 0, data);
1051 else if (entry->stgmedium.tymed != TYMED_NULL)
1053 data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL);
1054 data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size);
1055 if (!data) return E_OUTOFMEMORY;
1056 *((DWORD *)data) = sizeof(ENHMETAHEADER);
1057 GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER));
1058 memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER));
1059 data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER);
1060 hr = IStream_Write(stream, data, data_size, NULL);
1061 HeapFree(GetProcessHeap(), 0, data);
1064 return hr;
1067 static HRESULT save_view_cache(DataCacheEntry *entry, IStream *stream)
1069 HRESULT hr;
1070 PresentationDataHeader header;
1072 init_stream_header(entry, &header);
1073 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1074 if (SUCCEEDED(hr))
1075 hr = IStream_Write(stream, &header, FIELD_OFFSET(PresentationDataHeader, unknown7), NULL);
1077 return hr;
1080 static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage,
1081 BOOL contents, IStream **stream)
1083 WCHAR pres[] = {2,'O','l','e','P','r','e','s',
1084 '0' + (cache_entry->save_stream_num / 100) % 10,
1085 '0' + (cache_entry->save_stream_num / 10) % 10,
1086 '0' + cache_entry->save_stream_num % 10, 0};
1087 const WCHAR *name;
1089 if (contents)
1090 name = L"CONTENTS";
1091 else
1092 name = pres;
1094 return IStorage_CreateStream(storage, name,
1095 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
1096 0, 0, stream);
1099 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
1100 BOOL same_as_load)
1102 HRESULT hr;
1103 IStream *stream;
1104 BOOL contents = (cache_entry->id == 1);
1106 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->save_stream_num, debugstr_formatetc(&cache_entry->fmtetc));
1108 hr = create_stream(cache_entry, storage, contents, &stream);
1109 if (FAILED(hr))
1110 return hr;
1112 switch (cache_entry->fmtetc.cfFormat)
1114 case CF_DIB:
1115 hr = save_dib(cache_entry, contents, stream);
1116 break;
1117 case CF_METAFILEPICT:
1118 hr = save_mfpict(cache_entry, contents, stream);
1119 break;
1120 case CF_ENHMETAFILE:
1121 hr = save_emf(cache_entry, contents, stream);
1122 break;
1123 case 0:
1124 hr = save_view_cache(cache_entry, stream);
1125 break;
1126 default:
1127 FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat);
1130 IStream_Release(stream);
1131 return hr;
1134 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
1135 * does no checking of whether src_stgm has a supported tymed, so this should be
1136 * done in the caller */
1137 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
1138 const STGMEDIUM *src_stgm)
1140 if (src_stgm->tymed == TYMED_MFPICT)
1142 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
1143 METAFILEPICT *dest_mfpict;
1145 if (!src_mfpict)
1146 return DV_E_STGMEDIUM;
1147 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
1148 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
1149 if (!dest_mfpict)
1151 GlobalUnlock(src_stgm->u.hMetaFilePict);
1152 return E_OUTOFMEMORY;
1154 *dest_mfpict = *src_mfpict;
1155 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
1156 GlobalUnlock(src_stgm->u.hMetaFilePict);
1157 GlobalUnlock(dest_stgm->u.hMetaFilePict);
1159 else if (src_stgm->tymed != TYMED_NULL)
1161 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
1162 GMEM_MOVEABLE);
1163 if (!dest_stgm->u.hGlobal)
1164 return E_OUTOFMEMORY;
1166 dest_stgm->tymed = src_stgm->tymed;
1167 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
1168 if (dest_stgm->pUnkForRelease)
1169 IUnknown_AddRef(dest_stgm->pUnkForRelease);
1170 return S_OK;
1173 static HRESULT synthesize_dib( HBITMAP bm, STGMEDIUM *med )
1175 HDC hdc = GetDC( 0 );
1176 BITMAPINFOHEADER header;
1177 BITMAPINFO *bmi;
1178 HRESULT hr = E_FAIL;
1179 DWORD header_size;
1181 memset( &header, 0, sizeof(header) );
1182 header.biSize = sizeof(header);
1183 if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
1185 header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
1186 if (!(med->u.hGlobal = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
1187 bmi = GlobalLock( med->u.hGlobal );
1188 memset( bmi, 0, header_size );
1189 memcpy( bmi, &header, header.biSize );
1190 GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
1191 GlobalUnlock( med->u.hGlobal );
1192 med->tymed = TYMED_HGLOBAL;
1193 med->pUnkForRelease = NULL;
1194 hr = S_OK;
1196 done:
1197 ReleaseDC( 0, hdc );
1198 return hr;
1201 static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med )
1203 HRESULT hr = E_FAIL;
1204 BITMAPINFO *bmi;
1205 HDC hdc = GetDC( 0 );
1207 if ((bmi = GlobalLock( dib )))
1209 /* FIXME: validate data size */
1210 med->u.hBitmap = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
1211 (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
1212 bmi, DIB_RGB_COLORS );
1213 GlobalUnlock( dib );
1214 med->tymed = TYMED_GDI;
1215 med->pUnkForRelease = NULL;
1216 hr = S_OK;
1218 ReleaseDC( 0, hdc );
1219 return hr;
1222 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
1223 const FORMATETC *formatetc,
1224 STGMEDIUM *stgmedium,
1225 BOOL fRelease)
1227 STGMEDIUM copy;
1228 HRESULT hr;
1230 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
1231 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
1232 stgmedium->tymed == TYMED_NULL)
1234 WARN("invalid formatetc\n");
1235 return DV_E_FORMATETC;
1238 cache_entry->dirty = TRUE;
1239 ReleaseStgMedium(&cache_entry->stgmedium);
1241 if (formatetc->cfFormat == CF_BITMAP)
1243 hr = synthesize_dib( stgmedium->u.hBitmap, &copy );
1244 if (FAILED(hr)) return hr;
1245 if (fRelease) ReleaseStgMedium(stgmedium);
1246 stgmedium = &copy;
1247 fRelease = TRUE;
1249 else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE)
1251 hr = synthesize_emf( stgmedium->u.hMetaFilePict, &copy );
1252 if (FAILED(hr)) return hr;
1253 if (fRelease) ReleaseStgMedium(stgmedium);
1254 stgmedium = &copy;
1255 fRelease = TRUE;
1258 if (fRelease)
1260 cache_entry->stgmedium = *stgmedium;
1261 return S_OK;
1263 else
1264 return copy_stg_medium(cache_entry->fmtetc.cfFormat, &cache_entry->stgmedium, stgmedium);
1267 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, IStorage *stg, FORMATETC *fmt, STGMEDIUM *stgmedium)
1269 if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET)
1271 HRESULT hr = DataCacheEntry_LoadData(cache_entry, stg);
1272 if (FAILED(hr))
1273 return hr;
1275 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1276 return OLE_E_BLANK;
1278 if (fmt->cfFormat == CF_BITMAP)
1279 return synthesize_bitmap( cache_entry->stgmedium.u.hGlobal, stgmedium );
1281 return copy_stg_medium(cache_entry->fmtetc.cfFormat, stgmedium, &cache_entry->stgmedium);
1284 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
1286 ReleaseStgMedium(&cache_entry->stgmedium);
1287 return S_OK;
1290 static inline DWORD tymed_from_cf( DWORD cf )
1292 switch( cf )
1294 case CF_BITMAP: return TYMED_GDI;
1295 case CF_METAFILEPICT: return TYMED_MFPICT;
1296 case CF_ENHMETAFILE: return TYMED_ENHMF;
1297 case CF_DIB:
1298 default: return TYMED_HGLOBAL;
1302 /****************************************************************
1303 * create_automatic_entry
1305 * Creates an appropriate cache entry for one of the CLSID_Picture_
1306 * classes. The connection id of the entry is one. Any pre-existing
1307 * automatic entry is re-assigned a new connection id, and moved to
1308 * the end of the list.
1310 static HRESULT create_automatic_entry(DataCache *cache, const CLSID *clsid)
1312 static const struct data
1314 const CLSID *clsid;
1315 FORMATETC fmt;
1316 } data[] =
1318 { &CLSID_Picture_Dib, { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
1319 { &CLSID_Picture_Metafile, { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
1320 { &CLSID_Picture_EnhMetafile, { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
1321 { NULL }
1323 const struct data *ptr = data;
1324 struct list *head;
1325 DataCacheEntry *entry;
1327 if (IsEqualCLSID( &cache->clsid, clsid )) return S_OK;
1329 /* move and reassign any pre-existing automatic entry */
1330 if ((head = list_head( &cache->cache_list )))
1332 entry = LIST_ENTRY( head, DataCacheEntry, entry );
1333 if (entry->id == 1)
1335 list_remove( &entry->entry );
1336 entry->id = cache->last_cache_id++;
1337 list_add_tail( &cache->cache_list, &entry->entry );
1341 while (ptr->clsid)
1343 if (IsEqualCLSID( clsid, ptr->clsid ))
1345 cache->clsid_static = TRUE;
1346 return DataCache_CreateEntry( cache, &ptr->fmt, 0, TRUE, NULL );
1348 ptr++;
1350 cache->clsid_static = FALSE;
1351 return S_OK;
1354 /*********************************************************
1355 * Method implementation for the non delegating IUnknown
1356 * part of the DataCache class.
1359 /************************************************************************
1360 * DataCache_NDIUnknown_QueryInterface (IUnknown)
1362 * This version of QueryInterface will not delegate its implementation
1363 * to the outer unknown.
1365 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
1366 IUnknown* iface,
1367 REFIID riid,
1368 void** ppvObject)
1370 DataCache *this = impl_from_IUnknown(iface);
1372 if ( ppvObject==0 )
1373 return E_INVALIDARG;
1375 *ppvObject = 0;
1377 if (IsEqualIID(&IID_IUnknown, riid))
1379 if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */
1380 *ppvObject = &this->IOleCache2_iface;
1381 else
1382 *ppvObject = iface;
1384 else if (IsEqualIID(&IID_IDataObject, riid))
1386 *ppvObject = &this->IDataObject_iface;
1388 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
1389 IsEqualIID(&IID_IPersist, riid) )
1391 *ppvObject = &this->IPersistStorage_iface;
1393 else if ( IsEqualIID(&IID_IViewObject, riid) ||
1394 IsEqualIID(&IID_IViewObject2, riid) )
1396 *ppvObject = &this->IViewObject2_iface;
1398 else if ( IsEqualIID(&IID_IOleCache, riid) ||
1399 IsEqualIID(&IID_IOleCache2, riid) )
1401 *ppvObject = &this->IOleCache2_iface;
1403 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1405 *ppvObject = &this->IOleCacheControl_iface;
1408 if ((*ppvObject)==0)
1410 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1411 return E_NOINTERFACE;
1414 IUnknown_AddRef((IUnknown*)*ppvObject);
1416 return S_OK;
1419 /************************************************************************
1420 * DataCache_NDIUnknown_AddRef (IUnknown)
1422 * This version of QueryInterface will not delegate its implementation
1423 * to the outer unknown.
1425 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1426 IUnknown* iface)
1428 DataCache *this = impl_from_IUnknown(iface);
1429 return InterlockedIncrement(&this->ref);
1432 /************************************************************************
1433 * DataCache_NDIUnknown_Release (IUnknown)
1435 * This version of QueryInterface will not delegate its implementation
1436 * to the outer unknown.
1438 static ULONG WINAPI DataCache_NDIUnknown_Release(
1439 IUnknown* iface)
1441 DataCache *this = impl_from_IUnknown(iface);
1442 ULONG ref;
1444 ref = InterlockedDecrement(&this->ref);
1446 if (ref == 0) DataCache_Destroy(this);
1448 return ref;
1451 /*********************************************************
1452 * Method implementation for the IDataObject
1453 * part of the DataCache class.
1456 /************************************************************************
1457 * DataCache_IDataObject_QueryInterface (IUnknown)
1459 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1460 IDataObject* iface,
1461 REFIID riid,
1462 void** ppvObject)
1464 DataCache *this = impl_from_IDataObject(iface);
1466 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1469 /************************************************************************
1470 * DataCache_IDataObject_AddRef (IUnknown)
1472 static ULONG WINAPI DataCache_IDataObject_AddRef(
1473 IDataObject* iface)
1475 DataCache *this = impl_from_IDataObject(iface);
1477 return IUnknown_AddRef(this->outer_unk);
1480 /************************************************************************
1481 * DataCache_IDataObject_Release (IUnknown)
1483 static ULONG WINAPI DataCache_IDataObject_Release(
1484 IDataObject* iface)
1486 DataCache *this = impl_from_IDataObject(iface);
1488 return IUnknown_Release(this->outer_unk);
1491 /************************************************************************
1492 * DataCache_GetData
1494 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1496 static HRESULT WINAPI DataCache_GetData(
1497 IDataObject* iface,
1498 LPFORMATETC pformatetcIn,
1499 STGMEDIUM* pmedium)
1501 DataCache *This = impl_from_IDataObject(iface);
1502 DataCacheEntry *cache_entry;
1504 TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
1506 memset(pmedium, 0, sizeof(*pmedium));
1508 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1509 if (!cache_entry)
1510 return OLE_E_BLANK;
1512 return DataCacheEntry_GetData(cache_entry, This->presentationStorage, pformatetcIn, pmedium);
1515 static HRESULT WINAPI DataCache_GetDataHere(
1516 IDataObject* iface,
1517 LPFORMATETC pformatetc,
1518 STGMEDIUM* pmedium)
1520 FIXME("stub\n");
1521 return E_NOTIMPL;
1524 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1526 DataCache *This = impl_from_IDataObject( iface );
1527 DataCacheEntry *cache_entry;
1529 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1530 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1532 return cache_entry ? S_OK : S_FALSE;
1535 /************************************************************************
1536 * DataCache_EnumFormatEtc (IDataObject)
1538 * The data cache doesn't implement this method.
1540 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1541 IDataObject* iface,
1542 LPFORMATETC pformatectIn,
1543 LPFORMATETC pformatetcOut)
1545 TRACE("()\n");
1546 return E_NOTIMPL;
1549 /************************************************************************
1550 * DataCache_IDataObject_SetData (IDataObject)
1552 * This method is delegated to the IOleCache2 implementation.
1554 static HRESULT WINAPI DataCache_IDataObject_SetData(
1555 IDataObject* iface,
1556 LPFORMATETC pformatetc,
1557 STGMEDIUM* pmedium,
1558 BOOL fRelease)
1560 IOleCache2* oleCache = NULL;
1561 HRESULT hres;
1563 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1565 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1567 if (FAILED(hres))
1568 return E_UNEXPECTED;
1570 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1572 IOleCache2_Release(oleCache);
1574 return hres;
1577 /************************************************************************
1578 * DataCache_EnumFormatEtc (IDataObject)
1580 * The data cache doesn't implement this method.
1582 static HRESULT WINAPI DataCache_EnumFormatEtc(
1583 IDataObject* iface,
1584 DWORD dwDirection,
1585 IEnumFORMATETC** ppenumFormatEtc)
1587 TRACE("()\n");
1588 return E_NOTIMPL;
1591 /************************************************************************
1592 * DataCache_DAdvise (IDataObject)
1594 * The data cache doesn't support connections.
1596 static HRESULT WINAPI DataCache_DAdvise(
1597 IDataObject* iface,
1598 FORMATETC* pformatetc,
1599 DWORD advf,
1600 IAdviseSink* pAdvSink,
1601 DWORD* pdwConnection)
1603 TRACE("()\n");
1604 return OLE_E_ADVISENOTSUPPORTED;
1607 /************************************************************************
1608 * DataCache_DUnadvise (IDataObject)
1610 * The data cache doesn't support connections.
1612 static HRESULT WINAPI DataCache_DUnadvise(
1613 IDataObject* iface,
1614 DWORD dwConnection)
1616 TRACE("()\n");
1617 return OLE_E_NOCONNECTION;
1620 /************************************************************************
1621 * DataCache_EnumDAdvise (IDataObject)
1623 * The data cache doesn't support connections.
1625 static HRESULT WINAPI DataCache_EnumDAdvise(
1626 IDataObject* iface,
1627 IEnumSTATDATA** ppenumAdvise)
1629 TRACE("()\n");
1630 return OLE_E_ADVISENOTSUPPORTED;
1633 /*********************************************************
1634 * Method implementation for the IDataObject
1635 * part of the DataCache class.
1638 /************************************************************************
1639 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1641 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1642 IPersistStorage* iface,
1643 REFIID riid,
1644 void** ppvObject)
1646 DataCache *this = impl_from_IPersistStorage(iface);
1648 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1651 /************************************************************************
1652 * DataCache_IPersistStorage_AddRef (IUnknown)
1654 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1655 IPersistStorage* iface)
1657 DataCache *this = impl_from_IPersistStorage(iface);
1659 return IUnknown_AddRef(this->outer_unk);
1662 /************************************************************************
1663 * DataCache_IPersistStorage_Release (IUnknown)
1665 static ULONG WINAPI DataCache_IPersistStorage_Release(
1666 IPersistStorage* iface)
1668 DataCache *this = impl_from_IPersistStorage(iface);
1670 return IUnknown_Release(this->outer_unk);
1673 /************************************************************************
1674 * DataCache_GetClassID (IPersistStorage)
1677 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1679 DataCache *This = impl_from_IPersistStorage( iface );
1681 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1682 *clsid = This->clsid;
1684 return S_OK;
1687 /************************************************************************
1688 * DataCache_IsDirty (IPersistStorage)
1690 static HRESULT WINAPI DataCache_IsDirty(
1691 IPersistStorage* iface)
1693 DataCache *This = impl_from_IPersistStorage(iface);
1694 DataCacheEntry *cache_entry;
1696 TRACE("(%p)\n", iface);
1698 if (This->dirty)
1699 return S_OK;
1701 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1702 if (cache_entry->dirty)
1703 return S_OK;
1705 return S_FALSE;
1708 /************************************************************************
1709 * DataCache_InitNew (IPersistStorage)
1711 * The data cache implementation of IPersistStorage_InitNew simply stores
1712 * the storage pointer.
1714 static HRESULT WINAPI DataCache_InitNew(
1715 IPersistStorage* iface,
1716 IStorage* pStg)
1718 DataCache *This = impl_from_IPersistStorage(iface);
1719 CLSID clsid;
1720 HRESULT hr;
1722 TRACE("(%p, %p)\n", iface, pStg);
1724 if (This->presentationStorage != NULL)
1725 return CO_E_ALREADYINITIALIZED;
1727 This->presentationStorage = pStg;
1729 IStorage_AddRef(This->presentationStorage);
1730 This->dirty = TRUE;
1731 ReadClassStg( pStg, &clsid );
1732 hr = create_automatic_entry( This, &clsid );
1733 if (FAILED(hr))
1735 IStorage_Release( pStg );
1736 This->presentationStorage = NULL;
1737 return hr;
1739 This->clsid = clsid;
1741 return S_OK;
1745 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, int stream_number )
1747 DataCacheEntry *cache_entry;
1748 HRESULT hr = S_OK;
1750 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1752 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1753 if (!cache_entry)
1754 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1755 if (SUCCEEDED( hr ))
1757 DataCacheEntry_DiscardData( cache_entry );
1758 cache_entry->load_stream_num = stream_number;
1759 cache_entry->save_stream_num = stream_number;
1760 cache_entry->dirty = FALSE;
1762 return hr;
1765 static HRESULT parse_pres_streams( DataCache *cache, IStorage *stg )
1767 HRESULT hr;
1768 IStream *stm;
1769 PresentationDataHeader header;
1770 ULONG actual_read;
1771 CLIPFORMAT clipformat;
1772 FORMATETC fmtetc;
1773 int stream_number = 0;
1777 hr = open_pres_stream( stg, stream_number, &stm );
1778 if (FAILED(hr)) break;
1780 hr = read_clipformat( stm, &clipformat );
1782 if (hr == S_OK) hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1784 if (hr == S_OK && actual_read == sizeof(header))
1786 fmtetc.cfFormat = clipformat;
1787 fmtetc.ptd = NULL; /* FIXME */
1788 fmtetc.dwAspect = header.dvAspect;
1789 fmtetc.lindex = header.lindex;
1790 fmtetc.tymed = tymed_from_cf( clipformat );
1792 add_cache_entry( cache, &fmtetc, header.advf, stream_number );
1794 IStream_Release( stm );
1795 stream_number++;
1796 } while (hr == S_OK);
1798 return S_OK;
1801 static HRESULT parse_contents_stream( DataCache *cache, IStorage *stg )
1803 HRESULT hr;
1804 IStream *stm;
1805 DataCacheEntry *cache_entry;
1807 hr = open_pres_stream( stg, STREAM_NUMBER_CONTENTS, &stm );
1808 if (FAILED( hr )) return hr;
1810 hr = get_static_entry( cache, &cache_entry );
1811 if (hr == S_OK)
1813 cache_entry->load_stream_num = STREAM_NUMBER_CONTENTS;
1814 cache_entry->save_stream_num = STREAM_NUMBER_CONTENTS;
1815 cache_entry->dirty = FALSE;
1818 IStream_Release( stm );
1819 return hr;
1822 /************************************************************************
1823 * DataCache_Load (IPersistStorage)
1825 * The data cache implementation of IPersistStorage_Load doesn't
1826 * actually load anything. Instead, it holds on to the storage pointer
1827 * and it will load the presentation information when the
1828 * IDataObject_GetData or IViewObject2_Draw methods are called.
1830 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg )
1832 DataCache *This = impl_from_IPersistStorage(iface);
1833 HRESULT hr;
1834 CLSID clsid;
1835 DataCacheEntry *entry, *cursor2;
1837 TRACE("(%p, %p)\n", iface, stg);
1839 IPersistStorage_HandsOffStorage( iface );
1841 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1842 DataCacheEntry_Destroy( This, entry );
1843 This->clsid = CLSID_NULL;
1845 ReadClassStg( stg, &clsid );
1846 hr = create_automatic_entry( This, &clsid );
1847 if (FAILED( hr )) return hr;
1849 This->clsid = clsid;
1851 if (This->clsid_static)
1853 hr = parse_contents_stream( This, stg );
1854 if (FAILED(hr)) hr = parse_pres_streams( This, stg );
1856 else
1857 hr = parse_pres_streams( This, stg );
1859 if (SUCCEEDED( hr ))
1861 This->dirty = FALSE;
1862 This->presentationStorage = stg;
1863 IStorage_AddRef( This->presentationStorage );
1866 return hr;
1869 /************************************************************************
1870 * DataCache_Save (IPersistStorage)
1872 * Until we actually connect to a running object and retrieve new
1873 * information to it, we never have to save anything. However, it is
1874 * our responsibility to copy the information when saving to a new
1875 * storage.
1877 static HRESULT WINAPI DataCache_Save(IPersistStorage* iface, IStorage *stg, BOOL same_as_load)
1879 DataCache *This = impl_from_IPersistStorage(iface);
1880 DataCacheEntry *cache_entry;
1881 HRESULT hr = S_OK;
1882 int stream_number = 0;
1884 TRACE("(%p, %p, %d)\n", iface, stg, same_as_load);
1886 /* assign stream numbers to the cache entries */
1887 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1889 if (cache_entry->save_stream_num != stream_number)
1891 cache_entry->dirty = TRUE; /* needs to be written out again */
1892 cache_entry->save_stream_num = stream_number;
1894 stream_number++;
1897 /* write out the cache entries */
1898 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1900 if (!same_as_load || cache_entry->dirty)
1902 hr = DataCacheEntry_Save(cache_entry, stg, same_as_load);
1903 if (FAILED(hr))
1904 break;
1906 if (same_as_load) cache_entry->dirty = FALSE;
1910 if (same_as_load) This->dirty = FALSE;
1911 return hr;
1914 /************************************************************************
1915 * DataCache_SaveCompleted (IPersistStorage)
1917 * This method is called to tell the cache to release the storage
1918 * pointer it's currently holding.
1920 static HRESULT WINAPI DataCache_SaveCompleted(
1921 IPersistStorage* iface,
1922 IStorage* pStgNew)
1924 TRACE("(%p, %p)\n", iface, pStgNew);
1926 if (pStgNew)
1928 IPersistStorage_HandsOffStorage(iface);
1930 DataCache_Load(iface, pStgNew);
1933 return S_OK;
1936 /************************************************************************
1937 * DataCache_HandsOffStorage (IPersistStorage)
1939 * This method is called to tell the cache to release the storage
1940 * pointer it's currently holding.
1942 static HRESULT WINAPI DataCache_HandsOffStorage(
1943 IPersistStorage* iface)
1945 DataCache *this = impl_from_IPersistStorage(iface);
1947 TRACE("(%p)\n", iface);
1949 if (this->presentationStorage != NULL)
1951 IStorage_Release(this->presentationStorage);
1952 this->presentationStorage = NULL;
1955 return S_OK;
1958 /*********************************************************
1959 * Method implementation for the IViewObject2
1960 * part of the DataCache class.
1963 /************************************************************************
1964 * DataCache_IViewObject2_QueryInterface (IUnknown)
1966 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1967 IViewObject2* iface,
1968 REFIID riid,
1969 void** ppvObject)
1971 DataCache *this = impl_from_IViewObject2(iface);
1973 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1976 /************************************************************************
1977 * DataCache_IViewObject2_AddRef (IUnknown)
1979 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1980 IViewObject2* iface)
1982 DataCache *this = impl_from_IViewObject2(iface);
1984 return IUnknown_AddRef(this->outer_unk);
1987 /************************************************************************
1988 * DataCache_IViewObject2_Release (IUnknown)
1990 static ULONG WINAPI DataCache_IViewObject2_Release(
1991 IViewObject2* iface)
1993 DataCache *this = impl_from_IViewObject2(iface);
1995 return IUnknown_Release(this->outer_unk);
1998 /************************************************************************
1999 * DataCache_Draw (IViewObject2)
2001 * This method will draw the cached representation of the object
2002 * to the given device context.
2004 static HRESULT WINAPI DataCache_Draw(
2005 IViewObject2* iface,
2006 DWORD dwDrawAspect,
2007 LONG lindex,
2008 void* pvAspect,
2009 DVTARGETDEVICE* ptd,
2010 HDC hdcTargetDev,
2011 HDC hdcDraw,
2012 LPCRECTL lprcBounds,
2013 LPCRECTL lprcWBounds,
2014 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
2015 ULONG_PTR dwContinue)
2017 DataCache *This = impl_from_IViewObject2(iface);
2018 HRESULT hres;
2019 DataCacheEntry *cache_entry;
2021 TRACE("%p, %lx, %ld, %p, %p, %p, %p, %p, %p, %Ix.\n",
2022 iface,
2023 dwDrawAspect,
2024 lindex,
2025 pvAspect,
2026 hdcTargetDev,
2027 hdcDraw,
2028 lprcBounds,
2029 lprcWBounds,
2030 pfnContinue,
2031 dwContinue);
2033 if (lprcBounds==NULL)
2034 return E_INVALIDARG;
2036 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2038 /* FIXME: compare ptd too */
2039 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2040 (cache_entry->fmtetc.lindex != lindex))
2041 continue;
2043 /* if the data hasn't been loaded yet, do it now */
2044 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2046 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2047 if (FAILED(hres))
2048 continue;
2051 /* no data */
2052 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2053 continue;
2055 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
2057 switch (cache_entry->fmtetc.cfFormat)
2059 case CF_METAFILEPICT:
2062 * We have to be careful not to modify the state of the
2063 * DC.
2065 INT prevMapMode;
2066 SIZE oldWindowExt;
2067 SIZE oldViewportExt;
2068 POINT oldViewportOrg;
2069 METAFILEPICT *mfpict;
2071 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2072 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2073 continue;
2075 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
2077 SetWindowExtEx(hdcDraw,
2078 mfpict->xExt,
2079 mfpict->yExt,
2080 &oldWindowExt);
2082 SetViewportExtEx(hdcDraw,
2083 lprcBounds->right - lprcBounds->left,
2084 lprcBounds->bottom - lprcBounds->top,
2085 &oldViewportExt);
2087 SetViewportOrgEx(hdcDraw,
2088 lprcBounds->left,
2089 lprcBounds->top,
2090 &oldViewportOrg);
2092 PlayMetaFile(hdcDraw, mfpict->hMF);
2094 SetWindowExtEx(hdcDraw,
2095 oldWindowExt.cx,
2096 oldWindowExt.cy,
2097 NULL);
2099 SetViewportExtEx(hdcDraw,
2100 oldViewportExt.cx,
2101 oldViewportExt.cy,
2102 NULL);
2104 SetViewportOrgEx(hdcDraw,
2105 oldViewportOrg.x,
2106 oldViewportOrg.y,
2107 NULL);
2109 SetMapMode(hdcDraw, prevMapMode);
2111 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2113 return S_OK;
2115 case CF_DIB:
2117 BITMAPINFO *info;
2118 BYTE *bits;
2120 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2121 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2122 continue;
2124 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
2125 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
2126 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
2127 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
2128 bits, info, DIB_RGB_COLORS, SRCCOPY );
2130 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2131 return S_OK;
2136 WARN("no data could be found to be drawn\n");
2138 return OLE_E_BLANK;
2141 static HRESULT WINAPI DataCache_GetColorSet(
2142 IViewObject2* iface,
2143 DWORD dwDrawAspect,
2144 LONG lindex,
2145 void* pvAspect,
2146 DVTARGETDEVICE* ptd,
2147 HDC hicTargetDevice,
2148 LOGPALETTE** ppColorSet)
2150 FIXME("stub\n");
2151 return E_NOTIMPL;
2154 static HRESULT WINAPI DataCache_Freeze(
2155 IViewObject2* iface,
2156 DWORD dwDrawAspect,
2157 LONG lindex,
2158 void* pvAspect,
2159 DWORD* pdwFreeze)
2161 FIXME("stub\n");
2162 return E_NOTIMPL;
2165 static HRESULT WINAPI DataCache_Unfreeze(
2166 IViewObject2* iface,
2167 DWORD dwFreeze)
2169 FIXME("stub\n");
2170 return E_NOTIMPL;
2173 /************************************************************************
2174 * DataCache_SetAdvise (IViewObject2)
2176 * This sets-up an advisory sink with the data cache. When the object's
2177 * view changes, this sink is called.
2179 static HRESULT WINAPI DataCache_SetAdvise(
2180 IViewObject2* iface,
2181 DWORD aspects,
2182 DWORD advf,
2183 IAdviseSink* pAdvSink)
2185 DataCache *this = impl_from_IViewObject2(iface);
2187 TRACE("%p, %lx, %lx, %p.\n", iface, aspects, advf, pAdvSink);
2190 * A call to this function removes the previous sink
2192 if (this->sinkInterface != NULL)
2194 IAdviseSink_Release(this->sinkInterface);
2195 this->sinkInterface = NULL;
2196 this->sinkAspects = 0;
2197 this->sinkAdviseFlag = 0;
2201 * Now, setup the new one.
2203 if (pAdvSink!=NULL)
2205 this->sinkInterface = pAdvSink;
2206 this->sinkAspects = aspects;
2207 this->sinkAdviseFlag = advf;
2209 IAdviseSink_AddRef(this->sinkInterface);
2213 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2214 * sink immediately.
2216 if (advf & ADVF_PRIMEFIRST)
2218 DataCache_FireOnViewChange(this, aspects, -1);
2221 return S_OK;
2224 /************************************************************************
2225 * DataCache_GetAdvise (IViewObject2)
2227 * This method queries the current state of the advise sink
2228 * installed on the data cache.
2230 static HRESULT WINAPI DataCache_GetAdvise(
2231 IViewObject2* iface,
2232 DWORD* pAspects,
2233 DWORD* pAdvf,
2234 IAdviseSink** ppAdvSink)
2236 DataCache *this = impl_from_IViewObject2(iface);
2238 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2241 * Just copy all the requested values.
2243 if (pAspects!=NULL)
2244 *pAspects = this->sinkAspects;
2246 if (pAdvf!=NULL)
2247 *pAdvf = this->sinkAdviseFlag;
2249 if (ppAdvSink!=NULL)
2251 if (this->sinkInterface != NULL)
2252 IAdviseSink_QueryInterface(this->sinkInterface,
2253 &IID_IAdviseSink,
2254 (void**)ppAdvSink);
2255 else *ppAdvSink = NULL;
2258 return S_OK;
2261 /************************************************************************
2262 * DataCache_GetExtent (IViewObject2)
2264 * This method retrieves the "natural" size of this cached object.
2266 static HRESULT WINAPI DataCache_GetExtent(
2267 IViewObject2* iface,
2268 DWORD dwDrawAspect,
2269 LONG lindex,
2270 DVTARGETDEVICE* ptd,
2271 LPSIZEL lpsizel)
2273 DataCache *This = impl_from_IViewObject2(iface);
2274 HRESULT hres = E_FAIL;
2275 DataCacheEntry *cache_entry;
2277 TRACE("%p, %lx, %ld, %p, %p.\n", iface, dwDrawAspect, lindex, ptd, lpsizel);
2279 if (lpsizel==NULL)
2280 return E_POINTER;
2282 lpsizel->cx = 0;
2283 lpsizel->cy = 0;
2285 if (lindex!=-1)
2286 FIXME("Unimplemented flag lindex = %ld\n", lindex);
2289 * Right now, we support only the callback from
2290 * the default handler.
2292 if (ptd!=NULL)
2293 FIXME("Unimplemented ptd = %p\n", ptd);
2295 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2297 /* FIXME: compare ptd too */
2298 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2299 (cache_entry->fmtetc.lindex != lindex))
2300 continue;
2302 /* if the data hasn't been loaded yet, do it now */
2303 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2305 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2306 if (FAILED(hres))
2307 continue;
2310 /* no data */
2311 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2312 continue;
2315 switch (cache_entry->fmtetc.cfFormat)
2317 case CF_METAFILEPICT:
2319 METAFILEPICT *mfpict;
2321 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2322 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2323 continue;
2325 lpsizel->cx = mfpict->xExt;
2326 lpsizel->cy = mfpict->yExt;
2328 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2330 return S_OK;
2332 case CF_DIB:
2334 BITMAPINFOHEADER *info;
2335 LONG x_pels_m, y_pels_m;
2338 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2339 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2340 continue;
2342 x_pels_m = info->biXPelsPerMeter;
2343 y_pels_m = info->biYPelsPerMeter;
2345 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2346 if (x_pels_m != 0 && y_pels_m != 0)
2348 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
2349 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2351 else
2353 HDC hdc = GetDC( 0 );
2354 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2355 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2357 ReleaseDC( 0, hdc );
2360 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2362 return S_OK;
2367 WARN("no data could be found to get the extents from\n");
2370 * This method returns OLE_E_BLANK when it fails.
2372 return OLE_E_BLANK;
2376 /*********************************************************
2377 * Method implementation for the IOleCache2
2378 * part of the DataCache class.
2381 /************************************************************************
2382 * DataCache_IOleCache2_QueryInterface (IUnknown)
2384 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2385 IOleCache2* iface,
2386 REFIID riid,
2387 void** ppvObject)
2389 DataCache *this = impl_from_IOleCache2(iface);
2391 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2394 /************************************************************************
2395 * DataCache_IOleCache2_AddRef (IUnknown)
2397 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2398 IOleCache2* iface)
2400 DataCache *this = impl_from_IOleCache2(iface);
2402 return IUnknown_AddRef(this->outer_unk);
2405 /************************************************************************
2406 * DataCache_IOleCache2_Release (IUnknown)
2408 static ULONG WINAPI DataCache_IOleCache2_Release(
2409 IOleCache2* iface)
2411 DataCache *this = impl_from_IOleCache2(iface);
2413 return IUnknown_Release(this->outer_unk);
2416 /*****************************************************************************
2417 * setup_sink
2419 * Set up the sink connection to the running object.
2421 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2423 HRESULT hr = S_FALSE;
2424 DWORD flags;
2426 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2427 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2429 if(This->running_object)
2430 if(!(flags & ADVF_NODATA))
2431 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2432 &This->IAdviseSink_iface, &cache_entry->sink_id);
2433 return hr;
2436 static HRESULT WINAPI DataCache_Cache(
2437 IOleCache2* iface,
2438 FORMATETC* pformatetc,
2439 DWORD advf,
2440 DWORD* pdwConnection)
2442 DataCache *This = impl_from_IOleCache2(iface);
2443 DataCacheEntry *cache_entry;
2444 HRESULT hr;
2445 FORMATETC fmt_cpy;
2447 TRACE("%p, %#lx, %p.\n", pformatetc, advf, pdwConnection);
2449 if (!pformatetc || !pdwConnection)
2450 return E_INVALIDARG;
2452 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2454 fmt_cpy = *pformatetc; /* No need for a deep copy */
2455 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2457 fmt_cpy.cfFormat = CF_DIB;
2458 fmt_cpy.tymed = TYMED_HGLOBAL;
2461 /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */
2462 if (fmt_cpy.dwAspect == DVASPECT_ICON && fmt_cpy.cfFormat == 0)
2464 fmt_cpy.cfFormat = CF_METAFILEPICT;
2465 fmt_cpy.tymed = TYMED_MFPICT;
2468 *pdwConnection = 0;
2470 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2471 if (cache_entry)
2473 TRACE("found an existing cache entry\n");
2474 *pdwConnection = cache_entry->id;
2475 return CACHE_S_SAMECACHE;
2478 if (This->clsid_static && fmt_cpy.dwAspect != DVASPECT_ICON) return DV_E_FORMATETC;
2480 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2482 if (SUCCEEDED(hr))
2484 *pdwConnection = cache_entry->id;
2485 setup_sink(This, cache_entry);
2488 return hr;
2491 static HRESULT WINAPI DataCache_Uncache(
2492 IOleCache2* iface,
2493 DWORD dwConnection)
2495 DataCache *This = impl_from_IOleCache2(iface);
2496 DataCacheEntry *cache_entry;
2498 TRACE("%ld\n", dwConnection);
2500 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2501 if (cache_entry->id == dwConnection)
2503 DataCacheEntry_Destroy(This, cache_entry);
2504 return S_OK;
2507 WARN("no connection found for %ld\n", dwConnection);
2509 return OLE_E_NOCONNECTION;
2512 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2513 IEnumSTATDATA **enum_stat)
2515 DataCache *This = impl_from_IOleCache2( iface );
2516 DataCacheEntry *cache_entry;
2517 int i = 0, count = 0;
2518 STATDATA *data;
2519 HRESULT hr;
2521 TRACE( "(%p, %p)\n", This, enum_stat );
2523 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2525 count++;
2526 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2527 count++;
2530 data = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*data) );
2531 if (!data) return E_OUTOFMEMORY;
2533 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2535 if (i == count) goto fail;
2536 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2537 if (FAILED(hr)) goto fail;
2538 data[i].advf = cache_entry->advise_flags;
2539 data[i].pAdvSink = NULL;
2540 data[i].dwConnection = cache_entry->id;
2541 i++;
2543 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2545 if (i == count) goto fail;
2546 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2547 if (FAILED(hr)) goto fail;
2548 data[i].formatetc.cfFormat = CF_BITMAP;
2549 data[i].formatetc.tymed = TYMED_GDI;
2550 data[i].advf = cache_entry->advise_flags;
2551 data[i].pAdvSink = NULL;
2552 data[i].dwConnection = cache_entry->id;
2553 i++;
2557 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2558 if (SUCCEEDED(hr)) return hr;
2560 fail:
2561 while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2562 HeapFree( GetProcessHeap(), 0, data );
2563 return hr;
2566 static HRESULT WINAPI DataCache_InitCache( IOleCache2 *iface, IDataObject *data )
2568 TRACE( "(%p %p)\n", iface, data );
2569 return IOleCache2_UpdateCache( iface, data, UPDFCACHE_ALLBUTNODATACACHE, NULL );
2572 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2573 IOleCache2* iface,
2574 FORMATETC* pformatetc,
2575 STGMEDIUM* pmedium,
2576 BOOL fRelease)
2578 DataCache *This = impl_from_IOleCache2(iface);
2579 DataCacheEntry *cache_entry;
2580 HRESULT hr;
2582 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2583 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2585 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2586 if (cache_entry)
2588 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2590 if (SUCCEEDED(hr))
2591 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2592 cache_entry->fmtetc.lindex);
2594 return hr;
2596 WARN("cache entry not found\n");
2598 return OLE_E_BLANK;
2601 static BOOL entry_updatable( DataCacheEntry *entry, DWORD mode )
2603 BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL;
2605 if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE;
2607 if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE;
2608 if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE;
2609 if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE;
2610 if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE;
2611 if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE;
2613 return FALSE;
2616 static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data,
2617 DWORD mode, void *reserved )
2619 DataCache *This = impl_from_IOleCache2(iface);
2620 DataCacheEntry *cache_entry;
2621 STGMEDIUM med;
2622 HRESULT hr = S_OK;
2623 CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP };
2624 FORMATETC fmt;
2625 int i, slots = 0;
2626 BOOL done_one = FALSE;
2628 TRACE("%p, %p, %#lx, %p.\n", iface, data, mode, reserved );
2630 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2632 slots++;
2634 if (!entry_updatable( cache_entry, mode ))
2636 done_one = TRUE;
2637 continue;
2640 fmt = cache_entry->fmtetc;
2642 if (fmt.cfFormat)
2644 hr = IDataObject_GetData( data, &fmt, &med );
2645 if (hr != S_OK && fmt.cfFormat == CF_DIB)
2647 fmt.cfFormat = CF_BITMAP;
2648 fmt.tymed = TYMED_GDI;
2649 hr = IDataObject_GetData( data, &fmt, &med );
2651 if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE)
2653 fmt.cfFormat = CF_METAFILEPICT;
2654 fmt.tymed = TYMED_MFPICT;
2655 hr = IDataObject_GetData( data, &fmt, &med );
2657 if (hr == S_OK)
2659 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2660 if (hr != S_OK) ReleaseStgMedium( &med );
2661 else done_one = TRUE;
2664 else
2666 for (i = 0; i < ARRAY_SIZE(view_list); i++)
2668 fmt.cfFormat = view_list[i];
2669 fmt.tymed = tymed_from_cf( fmt.cfFormat );
2670 hr = IDataObject_QueryGetData( data, &fmt );
2671 if (hr == S_OK)
2673 hr = IDataObject_GetData( data, &fmt, &med );
2674 if (hr == S_OK)
2676 if (fmt.cfFormat == CF_BITMAP)
2678 cache_entry->fmtetc.cfFormat = CF_DIB;
2679 cache_entry->fmtetc.tymed = TYMED_HGLOBAL;
2681 else
2683 cache_entry->fmtetc.cfFormat = fmt.cfFormat;
2684 cache_entry->fmtetc.tymed = fmt.tymed;
2686 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2687 if (hr != S_OK) ReleaseStgMedium( &med );
2688 else done_one = TRUE;
2689 break;
2696 return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED;
2699 static HRESULT WINAPI DataCache_DiscardCache(
2700 IOleCache2* iface,
2701 DWORD dwDiscardOptions)
2703 DataCache *This = impl_from_IOleCache2(iface);
2704 DataCacheEntry *cache_entry;
2705 HRESULT hr = S_OK;
2707 TRACE("%ld\n", dwDiscardOptions);
2709 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2710 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2712 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2714 hr = DataCacheEntry_DiscardData(cache_entry);
2715 if (FAILED(hr))
2716 break;
2719 return hr;
2723 /*********************************************************
2724 * Method implementation for the IOleCacheControl
2725 * part of the DataCache class.
2728 /************************************************************************
2729 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2731 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2732 IOleCacheControl* iface,
2733 REFIID riid,
2734 void** ppvObject)
2736 DataCache *this = impl_from_IOleCacheControl(iface);
2738 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2741 /************************************************************************
2742 * DataCache_IOleCacheControl_AddRef (IUnknown)
2744 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2745 IOleCacheControl* iface)
2747 DataCache *this = impl_from_IOleCacheControl(iface);
2749 return IUnknown_AddRef(this->outer_unk);
2752 /************************************************************************
2753 * DataCache_IOleCacheControl_Release (IUnknown)
2755 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2756 IOleCacheControl* iface)
2758 DataCache *this = impl_from_IOleCacheControl(iface);
2760 return IUnknown_Release(this->outer_unk);
2763 /************************************************************************
2764 * DataCache_OnRun (IOleCacheControl)
2766 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2768 DataCache *This = impl_from_IOleCacheControl(iface);
2769 DataCacheEntry *cache_entry;
2771 TRACE("(%p)->(%p)\n", iface, data_obj);
2773 if(This->running_object) return S_OK;
2775 /* No reference is taken on the data object */
2776 This->running_object = data_obj;
2778 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2780 setup_sink(This, cache_entry);
2783 return S_OK;
2786 /************************************************************************
2787 * DataCache_OnStop (IOleCacheControl)
2789 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2791 DataCache *This = impl_from_IOleCacheControl(iface);
2792 DataCacheEntry *cache_entry;
2794 TRACE("(%p)\n", iface);
2796 if(!This->running_object) return S_OK;
2798 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2800 if(cache_entry->sink_id)
2802 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2803 cache_entry->sink_id = 0;
2807 /* No ref taken in OnRun, so no Release call here */
2808 This->running_object = NULL;
2809 return S_OK;
2812 /************************************************************************
2813 * IAdviseSink methods.
2814 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2815 * give access to the cache's other interfaces. We don't maintain a ref count,
2816 * the object exists as long as the cache is around.
2818 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2820 *obj = NULL;
2821 if (IsEqualIID(&IID_IUnknown, iid) ||
2822 IsEqualIID(&IID_IAdviseSink, iid))
2824 *obj = iface;
2827 if(*obj)
2829 IAdviseSink_AddRef(iface);
2830 return S_OK;
2832 return E_NOINTERFACE;
2835 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2837 return 2;
2840 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2842 return 1;
2845 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2847 DataCache *This = impl_from_IAdviseSink(iface);
2848 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2849 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2852 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2854 FIXME("stub\n");
2857 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2859 FIXME("stub\n");
2862 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2864 FIXME("stub\n");
2867 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2869 FIXME("stub\n");
2873 * Virtual function tables for the DataCache class.
2875 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2877 DataCache_NDIUnknown_QueryInterface,
2878 DataCache_NDIUnknown_AddRef,
2879 DataCache_NDIUnknown_Release
2882 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2884 DataCache_IDataObject_QueryInterface,
2885 DataCache_IDataObject_AddRef,
2886 DataCache_IDataObject_Release,
2887 DataCache_GetData,
2888 DataCache_GetDataHere,
2889 DataCache_QueryGetData,
2890 DataCache_GetCanonicalFormatEtc,
2891 DataCache_IDataObject_SetData,
2892 DataCache_EnumFormatEtc,
2893 DataCache_DAdvise,
2894 DataCache_DUnadvise,
2895 DataCache_EnumDAdvise
2898 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2900 DataCache_IPersistStorage_QueryInterface,
2901 DataCache_IPersistStorage_AddRef,
2902 DataCache_IPersistStorage_Release,
2903 DataCache_GetClassID,
2904 DataCache_IsDirty,
2905 DataCache_InitNew,
2906 DataCache_Load,
2907 DataCache_Save,
2908 DataCache_SaveCompleted,
2909 DataCache_HandsOffStorage
2912 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2914 DataCache_IViewObject2_QueryInterface,
2915 DataCache_IViewObject2_AddRef,
2916 DataCache_IViewObject2_Release,
2917 DataCache_Draw,
2918 DataCache_GetColorSet,
2919 DataCache_Freeze,
2920 DataCache_Unfreeze,
2921 DataCache_SetAdvise,
2922 DataCache_GetAdvise,
2923 DataCache_GetExtent
2926 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2928 DataCache_IOleCache2_QueryInterface,
2929 DataCache_IOleCache2_AddRef,
2930 DataCache_IOleCache2_Release,
2931 DataCache_Cache,
2932 DataCache_Uncache,
2933 DataCache_EnumCache,
2934 DataCache_InitCache,
2935 DataCache_IOleCache2_SetData,
2936 DataCache_UpdateCache,
2937 DataCache_DiscardCache
2940 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2942 DataCache_IOleCacheControl_QueryInterface,
2943 DataCache_IOleCacheControl_AddRef,
2944 DataCache_IOleCacheControl_Release,
2945 DataCache_OnRun,
2946 DataCache_OnStop
2949 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2951 DataCache_IAdviseSink_QueryInterface,
2952 DataCache_IAdviseSink_AddRef,
2953 DataCache_IAdviseSink_Release,
2954 DataCache_OnDataChange,
2955 DataCache_OnViewChange,
2956 DataCache_OnRename,
2957 DataCache_OnSave,
2958 DataCache_OnClose
2961 /*********************************************************
2962 * Method implementation for DataCache class.
2964 static DataCache* DataCache_Construct(
2965 REFCLSID clsid,
2966 LPUNKNOWN pUnkOuter)
2968 DataCache* newObject = 0;
2971 * Allocate space for the object.
2973 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2975 if (newObject==0)
2976 return newObject;
2979 * Initialize the virtual function table.
2981 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2982 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2983 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2984 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2985 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2986 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2987 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2988 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2989 newObject->ref = 1;
2992 * Initialize the other members of the structure.
2994 newObject->sinkAspects = 0;
2995 newObject->sinkAdviseFlag = 0;
2996 newObject->sinkInterface = 0;
2997 newObject->clsid = CLSID_NULL;
2998 newObject->clsid_static = FALSE;
2999 newObject->presentationStorage = NULL;
3000 list_init(&newObject->cache_list);
3001 newObject->last_cache_id = 2;
3002 newObject->dirty = FALSE;
3003 newObject->running_object = NULL;
3005 create_automatic_entry( newObject, clsid );
3006 newObject->clsid = *clsid;
3008 return newObject;
3011 /******************************************************************************
3012 * CreateDataCache [OLE32.@]
3014 * Creates a data cache to allow an object to render one or more of its views,
3015 * whether running or not.
3017 * PARAMS
3018 * pUnkOuter [I] Outer unknown for the object.
3019 * rclsid [I]
3020 * riid [I] IID of interface to return.
3021 * ppvObj [O] Address where the data cache object will be stored on return.
3023 * RETURNS
3024 * Success: S_OK.
3025 * Failure: HRESULT code.
3027 * NOTES
3028 * The following interfaces are supported by the returned data cache object:
3029 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
3030 * IViewObject and IViewObject2.
3032 HRESULT WINAPI CreateDataCache(
3033 LPUNKNOWN pUnkOuter,
3034 REFCLSID rclsid,
3035 REFIID riid,
3036 LPVOID* ppvObj)
3038 DataCache* newCache = NULL;
3039 HRESULT hr = S_OK;
3041 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
3044 * Sanity check
3046 if (ppvObj==0)
3047 return E_POINTER;
3049 *ppvObj = 0;
3052 * If this cache is constructed for aggregation, make sure
3053 * the caller is requesting the IUnknown interface.
3054 * This is necessary because it's the only time the non-delegating
3055 * IUnknown pointer can be returned to the outside.
3057 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
3058 return E_INVALIDARG;
3061 * Try to construct a new instance of the class.
3063 newCache = DataCache_Construct(rclsid,
3064 pUnkOuter);
3066 if (newCache == 0)
3067 return E_OUTOFMEMORY;
3069 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
3070 IUnknown_Release(&newCache->IUnknown_inner);
3072 return hr;