mstask: Implement ITask::DeleteTrigger().
[wine.git] / dlls / ole32 / datacache.c
blobb72b8ff2efe1ae0fc9f6c0b5c1fa91a344508b42
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 tdSize; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD)
83 then there are tdSize - sizeof(DWORD) more bytes before dvAspect */
84 DVASPECT dvAspect;
85 DWORD lindex;
86 DWORD advf;
87 DWORD unknown7; /* 0 */
88 DWORD dwObjectExtentX;
89 DWORD dwObjectExtentY;
90 DWORD dwSize;
91 } PresentationDataHeader;
93 #define STREAM_NUMBER_NOT_SET -2
94 #define STREAM_NUMBER_CONTENTS -1 /* CONTENTS stream */
96 typedef struct DataCacheEntry
98 struct list entry;
99 /* format of this entry */
100 FORMATETC fmtetc;
101 /* cached data */
102 STGMEDIUM stgmedium;
103 /* connection ID */
104 DWORD id;
105 /* dirty flag */
106 BOOL dirty;
107 /* stream number that the entry was loaded from.
108 This is used to defer loading until the data is actually needed. */
109 int load_stream_num;
110 /* stream number that the entry will be saved to.
111 This may differ from above if cache entries have been Uncache()d for example. */
112 int save_stream_num;
113 /* sink id set when object is running */
114 DWORD sink_id;
115 /* Advise sink flags */
116 DWORD advise_flags;
117 } DataCacheEntry;
119 /****************************************************************************
120 * DataCache
122 struct DataCache
125 * List all interface here
127 IUnknown IUnknown_inner;
128 IDataObject IDataObject_iface;
129 IPersistStorage IPersistStorage_iface;
130 IViewObject2 IViewObject2_iface;
131 IOleCache2 IOleCache2_iface;
132 IOleCacheControl IOleCacheControl_iface;
134 /* The sink that is connected to a remote object.
135 The other interfaces are not available by QI'ing the sink and vice-versa */
136 IAdviseSink IAdviseSink_iface;
139 * Reference count of this object
141 LONG ref;
144 * IUnknown implementation of the outer object.
146 IUnknown *outer_unk;
149 * The user of this object can setup ONE advise sink
150 * connection with the object. These parameters describe
151 * that connection.
153 DWORD sinkAspects;
154 DWORD sinkAdviseFlag;
155 IAdviseSink *sinkInterface;
157 CLSID clsid;
158 /* Is the clsid one of the CLSID_Picture classes */
159 BOOL clsid_static;
161 IStorage *presentationStorage;
163 /* list of cache entries */
164 struct list cache_list;
165 /* last id assigned to an entry */
166 DWORD last_cache_id;
167 /* dirty flag */
168 BOOL dirty;
169 /* running object set by OnRun */
170 IDataObject *running_object;
173 typedef struct DataCache DataCache;
176 * Here, I define utility macros to help with the casting of the
177 * "this" parameter.
178 * There is a version to accommodate all of the VTables implemented
179 * by this object.
182 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
184 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
187 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
189 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
192 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
194 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
197 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
199 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
202 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
204 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
207 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
209 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
212 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
214 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
217 const char *debugstr_formatetc(const FORMATETC *formatetc)
219 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
220 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
221 formatetc->lindex, formatetc->tymed);
224 /***********************************************************************
225 * bitmap_info_size
227 * Return the size of the bitmap info structure including color table.
229 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
231 unsigned int colors, size, masks = 0;
233 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
235 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
236 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
237 return sizeof(BITMAPCOREHEADER) + colors *
238 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
240 else /* assume BITMAPINFOHEADER */
242 colors = info->bmiHeader.biClrUsed;
243 if (colors > 256) /* buffer overflow otherwise */
244 colors = 256;
245 if (!colors && (info->bmiHeader.biBitCount <= 8))
246 colors = 1 << info->bmiHeader.biBitCount;
247 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
248 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
249 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
253 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
255 list_remove(&cache_entry->entry);
256 CoTaskMemFree(cache_entry->fmtetc.ptd);
257 ReleaseStgMedium(&cache_entry->stgmedium);
258 if(cache_entry->sink_id)
259 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
261 HeapFree(GetProcessHeap(), 0, cache_entry);
264 static void DataCache_Destroy(
265 DataCache* ptrToDestroy)
267 DataCacheEntry *cache_entry, *next_cache_entry;
269 TRACE("()\n");
271 if (ptrToDestroy->sinkInterface != NULL)
273 IAdviseSink_Release(ptrToDestroy->sinkInterface);
274 ptrToDestroy->sinkInterface = NULL;
277 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
278 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
280 if (ptrToDestroy->presentationStorage != NULL)
282 IStorage_Release(ptrToDestroy->presentationStorage);
283 ptrToDestroy->presentationStorage = NULL;
287 * Free the datacache pointer.
289 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
292 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
294 DataCacheEntry *cache_entry;
295 FORMATETC fmt = *formatetc;
297 if (fmt.cfFormat == CF_BITMAP)
299 fmt.cfFormat = CF_DIB;
300 fmt.tymed = TYMED_HGLOBAL;
303 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
305 /* FIXME: also compare DVTARGETDEVICEs */
306 if ((fmt.cfFormat == cache_entry->fmtetc.cfFormat) &&
307 (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
308 (fmt.lindex == cache_entry->fmtetc.lindex) &&
309 ((fmt.tymed == cache_entry->fmtetc.tymed) || !cache_entry->fmtetc.cfFormat)) /* tymed is ignored for view caching */
310 return cache_entry;
312 return NULL;
315 /* Returns the cache entry associated with a static CLSID.
316 This will be first in the list with connection id == 1 */
317 static HRESULT get_static_entry( DataCache *cache, DataCacheEntry **cache_entry )
319 DataCacheEntry *entry;
320 struct list *head = list_head( &cache->cache_list );
321 HRESULT hr = E_FAIL;
323 *cache_entry = NULL;
325 if (head)
327 entry = LIST_ENTRY( head, DataCacheEntry, entry );
328 if (entry->id == 1)
330 *cache_entry = entry;
331 hr = S_OK;
335 return hr;
338 /* checks that the clipformat and tymed are valid and returns an error if they
339 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
340 * DataCache_Draw */
341 static HRESULT check_valid_formatetc( const FORMATETC *fmt )
343 /* DVASPECT_ICON must be CF_METAFILEPICT */
344 if (fmt->dwAspect == DVASPECT_ICON && fmt->cfFormat != CF_METAFILEPICT)
345 return DV_E_FORMATETC;
347 if (!fmt->cfFormat ||
348 (fmt->cfFormat == CF_METAFILEPICT && fmt->tymed == TYMED_MFPICT) ||
349 (fmt->cfFormat == CF_BITMAP && fmt->tymed == TYMED_GDI) ||
350 (fmt->cfFormat == CF_DIB && fmt->tymed == TYMED_HGLOBAL) ||
351 (fmt->cfFormat == CF_ENHMETAFILE && fmt->tymed == TYMED_ENHMF))
352 return S_OK;
353 else if (fmt->tymed == TYMED_HGLOBAL)
354 return CACHE_S_FORMATETC_NOTSUPPORTED;
355 else
357 WARN("invalid clipformat/tymed combination: %d/%d\n", fmt->cfFormat, fmt->tymed);
358 return DV_E_TYMED;
362 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf,
363 DWORD id)
365 HRESULT hr;
367 hr = copy_formatetc(&entry->fmtetc, fmt);
368 if (FAILED(hr)) return FALSE;
370 entry->stgmedium.tymed = TYMED_NULL;
371 entry->stgmedium.pUnkForRelease = NULL;
372 entry->id = id;
373 entry->dirty = TRUE;
374 entry->load_stream_num = STREAM_NUMBER_NOT_SET;
375 entry->save_stream_num = STREAM_NUMBER_NOT_SET;
376 entry->sink_id = 0;
377 entry->advise_flags = advf;
379 return TRUE;
382 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf,
383 BOOL automatic, DataCacheEntry **cache_entry)
385 HRESULT hr;
386 DWORD id = automatic ? 1 : This->last_cache_id;
387 DataCacheEntry *entry;
389 hr = check_valid_formatetc( formatetc );
390 if (FAILED(hr))
391 return hr;
392 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
393 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
395 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
396 if (!entry)
397 return E_OUTOFMEMORY;
399 if (!init_cache_entry(entry, formatetc, advf, id))
400 goto fail;
402 if (automatic)
403 list_add_head(&This->cache_list, &entry->entry);
404 else
406 list_add_tail(&This->cache_list, &entry->entry);
407 This->last_cache_id++;
410 if (cache_entry) *cache_entry = entry;
411 return hr;
413 fail:
414 HeapFree(GetProcessHeap(), 0, entry);
415 return E_OUTOFMEMORY;
418 /************************************************************************
419 * DataCache_FireOnViewChange
421 * This method will fire an OnViewChange notification to the advise
422 * sink registered with the datacache.
424 * See IAdviseSink::OnViewChange for more details.
426 static void DataCache_FireOnViewChange(
427 DataCache* this,
428 DWORD aspect,
429 LONG lindex)
431 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
434 * The sink supplies a filter when it registers
435 * we make sure we only send the notifications when that
436 * filter matches.
438 if ((this->sinkAspects & aspect) != 0)
440 if (this->sinkInterface != NULL)
442 IAdviseSink_OnViewChange(this->sinkInterface,
443 aspect,
444 lindex);
447 * Some sinks want to be unregistered automatically when
448 * the first notification goes out.
450 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
452 IAdviseSink_Release(this->sinkInterface);
454 this->sinkInterface = NULL;
455 this->sinkAspects = 0;
456 this->sinkAdviseFlag = 0;
462 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
464 DWORD length;
465 HRESULT hr;
466 ULONG read;
468 *clipformat = 0;
470 hr = IStream_Read(stream, &length, sizeof(length), &read);
471 if (hr != S_OK || read != sizeof(length))
472 return DV_E_CLIPFORMAT;
473 if (!length) {
474 /* No clipboard format present */
475 return S_OK;
477 if (length == -1)
479 DWORD cf;
480 hr = IStream_Read(stream, &cf, sizeof(cf), &read);
481 if (hr != S_OK || read != sizeof(cf))
482 return DV_E_CLIPFORMAT;
483 *clipformat = cf;
485 else
487 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
488 if (!format_name)
489 return E_OUTOFMEMORY;
490 hr = IStream_Read(stream, format_name, length, &read);
491 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
493 HeapFree(GetProcessHeap(), 0, format_name);
494 return DV_E_CLIPFORMAT;
496 *clipformat = RegisterClipboardFormatA(format_name);
497 HeapFree(GetProcessHeap(), 0, format_name);
499 return S_OK;
502 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
504 DWORD length;
505 HRESULT hr;
506 char format_name[256];
508 if (clipformat == 0)
509 length = 0;
510 else if (clipformat < 0xc000)
511 length = -1;
512 else
514 length = GetClipboardFormatNameA(clipformat, format_name, sizeof(format_name));
515 /* If there is a clipboard format name, we need to include its terminating \0 */
516 if (length) length++;
518 hr = IStream_Write(stream, &length, sizeof(length), NULL);
519 if (FAILED(hr) || clipformat == 0)
520 return hr;
522 if (clipformat < 0xc000)
524 DWORD cf = clipformat;
525 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
527 else
529 hr = IStream_Write(stream, format_name, length, NULL);
531 return hr;
534 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
536 static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm )
538 WCHAR pres[] = {2,'O','l','e','P','r','e','s',
539 '0' + (stream_number / 100) % 10,
540 '0' + (stream_number / 10) % 10,
541 '0' + stream_number % 10, 0};
542 const WCHAR *name = pres;
544 if (stream_number == STREAM_NUMBER_NOT_SET) return E_FAIL;
545 if (stream_number == STREAM_NUMBER_CONTENTS) name = CONTENTS;
547 return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
550 static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med )
552 METAFILEPICT *pict;
553 HRESULT hr = E_FAIL;
554 UINT size;
555 void *bits;
557 if (!(pict = GlobalLock( data ))) return hr;
559 size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
560 if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
562 GetMetaFileBitsEx( pict->hMF, size, bits );
563 med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict );
564 HeapFree( GetProcessHeap(), 0, bits );
565 med->tymed = TYMED_ENHMF;
566 med->pUnkForRelease = NULL;
567 hr = S_OK;
570 GlobalUnlock( data );
571 return hr;
573 #include <pshpack2.h>
574 struct meta_placeable
576 DWORD key;
577 WORD hwmf;
578 WORD bounding_box[4];
579 WORD inch;
580 DWORD reserved;
581 WORD checksum;
583 #include <poppack.h>
585 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
587 HRESULT hr;
588 STATSTG stat;
589 ULARGE_INTEGER current_pos;
590 void *bits;
591 METAFILEPICT *mfpict;
592 HGLOBAL hmfpict;
593 PresentationDataHeader header;
594 CLIPFORMAT clipformat;
595 static const LARGE_INTEGER offset_zero;
596 ULONG read;
597 struct meta_placeable mf_place;
599 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
600 if (FAILED( hr )) return hr;
602 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
604 hr = read_clipformat( stm, &clipformat );
605 if (hr != S_OK) return hr;
606 hr = IStream_Read( stm, &header, sizeof(header), &read );
607 if (hr != S_OK) return hr;
609 else
611 hr = IStream_Read( stm, &mf_place, sizeof(mf_place), &read );
612 if (hr != S_OK) return hr;
615 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
616 if (FAILED( hr )) return hr;
617 stat.cbSize.QuadPart -= current_pos.QuadPart;
619 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
620 if (!hmfpict) return E_OUTOFMEMORY;
621 mfpict = GlobalLock( hmfpict );
623 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
624 if (!bits)
626 GlobalFree( hmfpict );
627 return E_OUTOFMEMORY;
630 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
632 if (SUCCEEDED( hr ))
634 mfpict->mm = MM_ANISOTROPIC;
635 /* FIXME: get this from the stream */
636 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
638 mfpict->xExt = header.dwObjectExtentX;
639 mfpict->yExt = header.dwObjectExtentY;
641 else
643 mfpict->xExt = ((mf_place.bounding_box[2] - mf_place.bounding_box[0])
644 * 2540) / mf_place.inch;
645 mfpict->yExt = ((mf_place.bounding_box[3] - mf_place.bounding_box[1])
646 * 2540) / mf_place.inch;
648 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
649 if (!mfpict->hMF)
650 hr = E_FAIL;
653 GlobalUnlock( hmfpict );
654 if (SUCCEEDED( hr ))
656 cache_entry->stgmedium.tymed = TYMED_MFPICT;
657 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
659 else
660 GlobalFree( hmfpict );
662 HeapFree( GetProcessHeap(), 0, bits );
664 return hr;
667 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
669 HRESULT hr;
670 STATSTG stat;
671 BYTE *dib;
672 HGLOBAL hglobal;
673 ULONG read, info_size, bi_size;
674 BITMAPFILEHEADER file;
675 BITMAPINFOHEADER *info;
676 CLIPFORMAT cf;
677 PresentationDataHeader pres;
678 ULARGE_INTEGER current_pos;
679 static const LARGE_INTEGER offset_zero;
681 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
682 if (FAILED( hr )) return hr;
684 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
686 hr = read_clipformat( stm, &cf );
687 if (hr != S_OK) return hr;
688 hr = IStream_Read( stm, &pres, sizeof(pres), &read );
689 if (hr != S_OK) return hr;
691 else
693 hr = IStream_Read( stm, &file, sizeof(BITMAPFILEHEADER), &read );
694 if (hr != S_OK) return hr;
697 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
698 if (FAILED( hr )) return hr;
699 stat.cbSize.QuadPart -= current_pos.QuadPart;
701 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
702 if (!hglobal) return E_OUTOFMEMORY;
703 dib = GlobalLock( hglobal );
705 /* read first DWORD of BITMAPINFOHEADER */
706 hr = IStream_Read( stm, dib, sizeof(DWORD), &read );
707 if (hr != S_OK) goto fail;
708 bi_size = *(DWORD *)dib;
709 if (stat.cbSize.QuadPart < bi_size) goto fail;
711 /* read rest of BITMAPINFOHEADER */
712 hr = IStream_Read( stm, dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read );
713 if (hr != S_OK) goto fail;
715 info_size = bitmap_info_size( (BITMAPINFO *)dib, DIB_RGB_COLORS );
716 if (stat.cbSize.QuadPart < info_size) goto fail;
717 if (info_size > bi_size)
719 hr = IStream_Read( stm, dib + bi_size, info_size - bi_size, &read );
720 if (hr != S_OK) goto fail;
722 stat.cbSize.QuadPart -= info_size;
724 /* set Stream pointer to beginning of bitmap bits */
725 if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS && file.bfOffBits)
727 LARGE_INTEGER skip;
729 skip.QuadPart = file.bfOffBits - sizeof(file) - info_size;
730 if (stat.cbSize.QuadPart < skip.QuadPart) goto fail;
731 hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL );
732 if (hr != S_OK) goto fail;
733 stat.cbSize.QuadPart -= skip.QuadPart;
736 hr = IStream_Read( stm, dib + info_size, stat.cbSize.u.LowPart, &read );
737 if (hr != S_OK) goto fail;
739 if (bi_size >= sizeof(*info))
741 info = (BITMAPINFOHEADER *)dib;
742 if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0)
744 HDC hdc = GetDC( 0 );
745 info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 );
746 info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 );
747 ReleaseDC( 0, hdc );
751 GlobalUnlock( hglobal );
753 cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
754 cache_entry->stgmedium.u.hGlobal = hglobal;
756 return hr;
758 fail:
759 GlobalUnlock( hglobal );
760 GlobalFree( hglobal );
761 return hr;
765 static HRESULT load_emf( DataCacheEntry *cache_entry, IStream *stm )
767 HRESULT hr;
769 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
771 STGMEDIUM stgmed;
773 hr = load_mf_pict( cache_entry, stm );
774 if (SUCCEEDED( hr ))
776 hr = synthesize_emf( cache_entry->stgmedium.u.hMetaFilePict, &stgmed );
777 ReleaseStgMedium( &cache_entry->stgmedium );
779 if (SUCCEEDED( hr ))
780 cache_entry->stgmedium = stgmed;
782 else
784 STATSTG stat;
785 BYTE *data;
786 ULONG read, size_bits;
788 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
790 if (SUCCEEDED( hr ))
792 data = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart );
793 if (!data) return E_OUTOFMEMORY;
795 hr = IStream_Read( stm, data, stat.cbSize.u.LowPart, &read );
796 if (hr != S_OK)
798 HeapFree( GetProcessHeap(), 0, data );
799 return hr;
802 if (read <= sizeof(DWORD) + sizeof(ENHMETAHEADER))
804 HeapFree( GetProcessHeap(), 0, data );
805 return E_FAIL;
807 size_bits = read - sizeof(DWORD) - sizeof(ENHMETAHEADER);
808 cache_entry->stgmedium.u.hEnhMetaFile = SetEnhMetaFileBits( size_bits, data + (read - size_bits) );
809 cache_entry->stgmedium.tymed = TYMED_ENHMF;
810 cache_entry->stgmedium.pUnkForRelease = NULL;
812 HeapFree( GetProcessHeap(), 0, data );
816 return hr;
819 /************************************************************************
820 * DataCacheEntry_LoadData
822 * This method will read information for the requested presentation
823 * into the given structure.
825 * Param:
826 * This - The entry to load the data from.
828 * Returns:
829 * This method returns a metafile handle if it is successful.
830 * it will return 0 if not.
832 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *stg)
834 HRESULT hr;
835 IStream *stm;
837 if (!stg) return OLE_E_BLANK;
838 hr = open_pres_stream( stg, cache_entry->load_stream_num, &stm );
839 if (FAILED(hr)) return hr;
841 switch (cache_entry->fmtetc.cfFormat)
843 case CF_METAFILEPICT:
844 hr = load_mf_pict( cache_entry, stm );
845 break;
847 case CF_DIB:
848 hr = load_dib( cache_entry, stm );
849 break;
851 case CF_ENHMETAFILE:
852 hr = load_emf( cache_entry, stm );
853 break;
855 default:
856 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
857 hr = E_NOTIMPL;
860 IStream_Release( stm );
861 return hr;
864 static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header)
866 if (entry->fmtetc.ptd)
867 FIXME("ptd not serialized\n");
868 header->tdSize = sizeof(header->tdSize);
869 header->dvAspect = entry->fmtetc.dwAspect;
870 header->lindex = entry->fmtetc.lindex;
871 header->advf = entry->advise_flags;
872 header->unknown7 = 0;
873 header->dwObjectExtentX = 0;
874 header->dwObjectExtentY = 0;
875 header->dwSize = 0;
878 static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream)
880 HRESULT hr = S_OK;
881 int data_size = 0;
882 BITMAPINFO *bmi = NULL;
884 if (entry->stgmedium.tymed != TYMED_NULL)
886 data_size = GlobalSize(entry->stgmedium.u.hGlobal);
887 bmi = GlobalLock(entry->stgmedium.u.hGlobal);
890 if (!contents)
892 PresentationDataHeader header;
894 init_stream_header(entry, &header);
895 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
896 if (FAILED(hr)) goto end;
897 if (data_size)
899 header.dwSize = data_size;
900 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
901 if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0)
903 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter);
904 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter);
906 else
908 HDC hdc = GetDC(0);
909 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
910 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
911 ReleaseDC(0, hdc);
914 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
915 if (hr == S_OK && data_size)
916 hr = IStream_Write(stream, bmi, data_size, NULL);
918 else if(data_size)
920 BITMAPFILEHEADER bmp_fhdr;
922 bmp_fhdr.bfType = 0x4d42;
923 bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER);
924 bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0;
925 bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER);
926 hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL);
927 if (hr == S_OK)
928 hr = IStream_Write(stream, bmi, data_size, NULL);
931 end:
932 if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal);
933 return hr;
936 static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream)
938 HRESULT hr = S_OK;
939 int data_size = 0;
940 void *data = NULL;
941 METAFILEPICT *mfpict = NULL;
943 if (!contents)
945 PresentationDataHeader header;
947 init_stream_header(entry, &header);
948 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
949 if (FAILED(hr)) return hr;
950 if (entry->stgmedium.tymed != TYMED_NULL)
952 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
953 if (!mfpict)
954 return DV_E_STGMEDIUM;
955 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
956 header.dwObjectExtentX = mfpict->xExt;
957 header.dwObjectExtentY = mfpict->yExt;
958 header.dwSize = data_size;
959 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
960 if (!data)
962 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
963 return E_OUTOFMEMORY;
965 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
966 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
968 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
969 if (hr == S_OK && data_size)
970 hr = IStream_Write(stream, data, data_size, NULL);
971 HeapFree(GetProcessHeap(), 0, data);
973 else if (entry->stgmedium.tymed != TYMED_NULL)
975 struct meta_placeable meta_place_rec;
976 WORD *check;
978 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
979 if (!mfpict)
980 return DV_E_STGMEDIUM;
981 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
982 data = HeapAlloc(GetProcessHeap(), 0, data_size);
983 if (!data)
985 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
986 return E_OUTOFMEMORY;
988 GetMetaFileBitsEx(mfpict->hMF, data_size, data);
990 /* units are in 1/8th of a point (1 point is 1/72th of an inch) */
991 meta_place_rec.key = 0x9ac6cdd7;
992 meta_place_rec.hwmf = 0;
993 meta_place_rec.inch = 576;
994 meta_place_rec.bounding_box[0] = 0;
995 meta_place_rec.bounding_box[1] = 0;
996 meta_place_rec.bounding_box[2] = 0;
997 meta_place_rec.bounding_box[3] = 0;
998 meta_place_rec.checksum = 0;
999 meta_place_rec.reserved = 0;
1001 /* These values are rounded down so MulDiv won't do the right thing */
1002 meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540;
1003 meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540;
1004 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
1006 for (check = (WORD *)&meta_place_rec; check != (WORD *)&meta_place_rec.checksum; check++)
1007 meta_place_rec.checksum ^= *check;
1008 hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL);
1009 if (hr == S_OK && data_size)
1010 hr = IStream_Write(stream, data, data_size, NULL);
1011 HeapFree(GetProcessHeap(), 0, data);
1014 return hr;
1017 static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream)
1019 HRESULT hr = S_OK;
1020 int data_size = 0;
1021 BYTE *data;
1023 if (!contents)
1025 PresentationDataHeader header;
1026 METAFILEPICT *mfpict;
1027 HDC hdc = GetDC(0);
1029 init_stream_header(entry, &header);
1030 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1031 if (FAILED(hr))
1033 ReleaseDC(0, hdc);
1034 return hr;
1036 data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc);
1037 header.dwSize = data_size;
1038 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
1039 if (!data)
1041 ReleaseDC(0, hdc);
1042 return E_OUTOFMEMORY;
1044 GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc);
1045 ReleaseDC(0, hdc);
1046 mfpict = (METAFILEPICT *)data;
1047 header.dwObjectExtentX = mfpict->xExt;
1048 header.dwObjectExtentY = mfpict->yExt;
1049 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
1050 if (hr == S_OK && data_size)
1051 hr = IStream_Write(stream, data, data_size, NULL);
1052 HeapFree(GetProcessHeap(), 0, data);
1054 else if (entry->stgmedium.tymed != TYMED_NULL)
1056 data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL);
1057 data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size);
1058 if (!data) return E_OUTOFMEMORY;
1059 *((DWORD *)data) = sizeof(ENHMETAHEADER);
1060 GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER));
1061 memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER));
1062 data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER);
1063 hr = IStream_Write(stream, data, data_size, NULL);
1064 HeapFree(GetProcessHeap(), 0, data);
1067 return hr;
1070 static HRESULT save_view_cache(DataCacheEntry *entry, IStream *stream)
1072 HRESULT hr;
1073 PresentationDataHeader header;
1075 init_stream_header(entry, &header);
1076 hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1077 if (SUCCEEDED(hr))
1078 hr = IStream_Write(stream, &header, FIELD_OFFSET(PresentationDataHeader, unknown7), NULL);
1080 return hr;
1083 static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage,
1084 BOOL contents, IStream **stream)
1086 WCHAR pres[] = {2,'O','l','e','P','r','e','s',
1087 '0' + (cache_entry->save_stream_num / 100) % 10,
1088 '0' + (cache_entry->save_stream_num / 10) % 10,
1089 '0' + cache_entry->save_stream_num % 10, 0};
1090 const WCHAR *name;
1092 if (contents)
1093 name = CONTENTS;
1094 else
1095 name = pres;
1097 return IStorage_CreateStream(storage, name,
1098 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
1099 0, 0, stream);
1102 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
1103 BOOL same_as_load)
1105 HRESULT hr;
1106 IStream *stream;
1107 BOOL contents = (cache_entry->id == 1);
1109 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->save_stream_num, debugstr_formatetc(&cache_entry->fmtetc));
1111 hr = create_stream(cache_entry, storage, contents, &stream);
1112 if (FAILED(hr))
1113 return hr;
1115 switch (cache_entry->fmtetc.cfFormat)
1117 case CF_DIB:
1118 hr = save_dib(cache_entry, contents, stream);
1119 break;
1120 case CF_METAFILEPICT:
1121 hr = save_mfpict(cache_entry, contents, stream);
1122 break;
1123 case CF_ENHMETAFILE:
1124 hr = save_emf(cache_entry, contents, stream);
1125 break;
1126 case 0:
1127 hr = save_view_cache(cache_entry, stream);
1128 break;
1129 default:
1130 FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat);
1133 IStream_Release(stream);
1134 return hr;
1137 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
1138 * does no checking of whether src_stgm has a supported tymed, so this should be
1139 * done in the caller */
1140 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
1141 const STGMEDIUM *src_stgm)
1143 if (src_stgm->tymed == TYMED_MFPICT)
1145 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
1146 METAFILEPICT *dest_mfpict;
1148 if (!src_mfpict)
1149 return DV_E_STGMEDIUM;
1150 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
1151 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
1152 if (!dest_mfpict)
1154 GlobalUnlock(src_stgm->u.hMetaFilePict);
1155 return E_OUTOFMEMORY;
1157 *dest_mfpict = *src_mfpict;
1158 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
1159 GlobalUnlock(src_stgm->u.hMetaFilePict);
1160 GlobalUnlock(dest_stgm->u.hMetaFilePict);
1162 else if (src_stgm->tymed != TYMED_NULL)
1164 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
1165 GMEM_MOVEABLE);
1166 if (!dest_stgm->u.hGlobal)
1167 return E_OUTOFMEMORY;
1169 dest_stgm->tymed = src_stgm->tymed;
1170 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
1171 if (dest_stgm->pUnkForRelease)
1172 IUnknown_AddRef(dest_stgm->pUnkForRelease);
1173 return S_OK;
1176 static HRESULT synthesize_dib( HBITMAP bm, STGMEDIUM *med )
1178 HDC hdc = GetDC( 0 );
1179 BITMAPINFOHEADER header;
1180 BITMAPINFO *bmi;
1181 HRESULT hr = E_FAIL;
1182 DWORD header_size;
1184 memset( &header, 0, sizeof(header) );
1185 header.biSize = sizeof(header);
1186 if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
1188 header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
1189 if (!(med->u.hGlobal = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
1190 bmi = GlobalLock( med->u.hGlobal );
1191 memset( bmi, 0, header_size );
1192 memcpy( bmi, &header, header.biSize );
1193 GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
1194 GlobalUnlock( med->u.hGlobal );
1195 med->tymed = TYMED_HGLOBAL;
1196 med->pUnkForRelease = NULL;
1197 hr = S_OK;
1199 done:
1200 ReleaseDC( 0, hdc );
1201 return hr;
1204 static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med )
1206 HRESULT hr = E_FAIL;
1207 BITMAPINFO *bmi;
1208 HDC hdc = GetDC( 0 );
1210 if ((bmi = GlobalLock( dib )))
1212 /* FIXME: validate data size */
1213 med->u.hBitmap = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
1214 (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
1215 bmi, DIB_RGB_COLORS );
1216 GlobalUnlock( dib );
1217 med->tymed = TYMED_GDI;
1218 med->pUnkForRelease = NULL;
1219 hr = S_OK;
1221 ReleaseDC( 0, hdc );
1222 return hr;
1225 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
1226 const FORMATETC *formatetc,
1227 STGMEDIUM *stgmedium,
1228 BOOL fRelease)
1230 STGMEDIUM copy;
1231 HRESULT hr;
1233 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
1234 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
1235 stgmedium->tymed == TYMED_NULL)
1237 WARN("invalid formatetc\n");
1238 return DV_E_FORMATETC;
1241 cache_entry->dirty = TRUE;
1242 ReleaseStgMedium(&cache_entry->stgmedium);
1244 if (formatetc->cfFormat == CF_BITMAP)
1246 hr = synthesize_dib( stgmedium->u.hBitmap, &copy );
1247 if (FAILED(hr)) return hr;
1248 if (fRelease) ReleaseStgMedium(stgmedium);
1249 stgmedium = &copy;
1250 fRelease = TRUE;
1252 else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE)
1254 hr = synthesize_emf( stgmedium->u.hMetaFilePict, &copy );
1255 if (FAILED(hr)) return hr;
1256 if (fRelease) ReleaseStgMedium(stgmedium);
1257 stgmedium = &copy;
1258 fRelease = TRUE;
1261 if (fRelease)
1263 cache_entry->stgmedium = *stgmedium;
1264 return S_OK;
1266 else
1267 return copy_stg_medium(cache_entry->fmtetc.cfFormat, &cache_entry->stgmedium, stgmedium);
1270 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, IStorage *stg, FORMATETC *fmt, STGMEDIUM *stgmedium)
1272 if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET)
1274 HRESULT hr = DataCacheEntry_LoadData(cache_entry, stg);
1275 if (FAILED(hr))
1276 return hr;
1278 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1279 return OLE_E_BLANK;
1281 if (fmt->cfFormat == CF_BITMAP)
1282 return synthesize_bitmap( cache_entry->stgmedium.u.hGlobal, stgmedium );
1284 return copy_stg_medium(cache_entry->fmtetc.cfFormat, stgmedium, &cache_entry->stgmedium);
1287 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
1289 ReleaseStgMedium(&cache_entry->stgmedium);
1290 return S_OK;
1293 static inline DWORD tymed_from_cf( DWORD cf )
1295 switch( cf )
1297 case CF_BITMAP: return TYMED_GDI;
1298 case CF_METAFILEPICT: return TYMED_MFPICT;
1299 case CF_ENHMETAFILE: return TYMED_ENHMF;
1300 case CF_DIB:
1301 default: return TYMED_HGLOBAL;
1305 /****************************************************************
1306 * create_automatic_entry
1308 * Creates an appropriate cache entry for one of the CLSID_Picture_
1309 * classes. The connection id of the entry is one. Any pre-existing
1310 * automatic entry is re-assigned a new connection id, and moved to
1311 * the end of the list.
1313 static HRESULT create_automatic_entry(DataCache *cache, const CLSID *clsid)
1315 static const struct data
1317 const CLSID *clsid;
1318 FORMATETC fmt;
1319 } data[] =
1321 { &CLSID_Picture_Dib, { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
1322 { &CLSID_Picture_Metafile, { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
1323 { &CLSID_Picture_EnhMetafile, { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
1324 { NULL }
1326 const struct data *ptr = data;
1327 struct list *head;
1328 DataCacheEntry *entry;
1330 if (IsEqualCLSID( &cache->clsid, clsid )) return S_OK;
1332 /* move and reassign any pre-existing automatic entry */
1333 if ((head = list_head( &cache->cache_list )))
1335 entry = LIST_ENTRY( head, DataCacheEntry, entry );
1336 if (entry->id == 1)
1338 list_remove( &entry->entry );
1339 entry->id = cache->last_cache_id++;
1340 list_add_tail( &cache->cache_list, &entry->entry );
1344 while (ptr->clsid)
1346 if (IsEqualCLSID( clsid, ptr->clsid ))
1348 cache->clsid_static = TRUE;
1349 return DataCache_CreateEntry( cache, &ptr->fmt, 0, TRUE, NULL );
1351 ptr++;
1353 cache->clsid_static = FALSE;
1354 return S_OK;
1357 /*********************************************************
1358 * Method implementation for the non delegating IUnknown
1359 * part of the DataCache class.
1362 /************************************************************************
1363 * DataCache_NDIUnknown_QueryInterface (IUnknown)
1365 * This version of QueryInterface will not delegate its implementation
1366 * to the outer unknown.
1368 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
1369 IUnknown* iface,
1370 REFIID riid,
1371 void** ppvObject)
1373 DataCache *this = impl_from_IUnknown(iface);
1375 if ( ppvObject==0 )
1376 return E_INVALIDARG;
1378 *ppvObject = 0;
1380 if (IsEqualIID(&IID_IUnknown, riid))
1382 if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */
1383 *ppvObject = &this->IOleCache2_iface;
1384 else
1385 *ppvObject = iface;
1387 else if (IsEqualIID(&IID_IDataObject, riid))
1389 *ppvObject = &this->IDataObject_iface;
1391 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
1392 IsEqualIID(&IID_IPersist, riid) )
1394 *ppvObject = &this->IPersistStorage_iface;
1396 else if ( IsEqualIID(&IID_IViewObject, riid) ||
1397 IsEqualIID(&IID_IViewObject2, riid) )
1399 *ppvObject = &this->IViewObject2_iface;
1401 else if ( IsEqualIID(&IID_IOleCache, riid) ||
1402 IsEqualIID(&IID_IOleCache2, riid) )
1404 *ppvObject = &this->IOleCache2_iface;
1406 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1408 *ppvObject = &this->IOleCacheControl_iface;
1411 if ((*ppvObject)==0)
1413 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1414 return E_NOINTERFACE;
1417 IUnknown_AddRef((IUnknown*)*ppvObject);
1419 return S_OK;
1422 /************************************************************************
1423 * DataCache_NDIUnknown_AddRef (IUnknown)
1425 * This version of QueryInterface will not delegate its implementation
1426 * to the outer unknown.
1428 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1429 IUnknown* iface)
1431 DataCache *this = impl_from_IUnknown(iface);
1432 return InterlockedIncrement(&this->ref);
1435 /************************************************************************
1436 * DataCache_NDIUnknown_Release (IUnknown)
1438 * This version of QueryInterface will not delegate its implementation
1439 * to the outer unknown.
1441 static ULONG WINAPI DataCache_NDIUnknown_Release(
1442 IUnknown* iface)
1444 DataCache *this = impl_from_IUnknown(iface);
1445 ULONG ref;
1447 ref = InterlockedDecrement(&this->ref);
1449 if (ref == 0) DataCache_Destroy(this);
1451 return ref;
1454 /*********************************************************
1455 * Method implementation for the IDataObject
1456 * part of the DataCache class.
1459 /************************************************************************
1460 * DataCache_IDataObject_QueryInterface (IUnknown)
1462 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1463 IDataObject* iface,
1464 REFIID riid,
1465 void** ppvObject)
1467 DataCache *this = impl_from_IDataObject(iface);
1469 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1472 /************************************************************************
1473 * DataCache_IDataObject_AddRef (IUnknown)
1475 static ULONG WINAPI DataCache_IDataObject_AddRef(
1476 IDataObject* iface)
1478 DataCache *this = impl_from_IDataObject(iface);
1480 return IUnknown_AddRef(this->outer_unk);
1483 /************************************************************************
1484 * DataCache_IDataObject_Release (IUnknown)
1486 static ULONG WINAPI DataCache_IDataObject_Release(
1487 IDataObject* iface)
1489 DataCache *this = impl_from_IDataObject(iface);
1491 return IUnknown_Release(this->outer_unk);
1494 /************************************************************************
1495 * DataCache_GetData
1497 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1499 static HRESULT WINAPI DataCache_GetData(
1500 IDataObject* iface,
1501 LPFORMATETC pformatetcIn,
1502 STGMEDIUM* pmedium)
1504 DataCache *This = impl_from_IDataObject(iface);
1505 DataCacheEntry *cache_entry;
1507 TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
1509 memset(pmedium, 0, sizeof(*pmedium));
1511 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1512 if (!cache_entry)
1513 return OLE_E_BLANK;
1515 return DataCacheEntry_GetData(cache_entry, This->presentationStorage, pformatetcIn, pmedium);
1518 static HRESULT WINAPI DataCache_GetDataHere(
1519 IDataObject* iface,
1520 LPFORMATETC pformatetc,
1521 STGMEDIUM* pmedium)
1523 FIXME("stub\n");
1524 return E_NOTIMPL;
1527 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1529 DataCache *This = impl_from_IDataObject( iface );
1530 DataCacheEntry *cache_entry;
1532 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1533 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1535 return cache_entry ? S_OK : S_FALSE;
1538 /************************************************************************
1539 * DataCache_EnumFormatEtc (IDataObject)
1541 * The data cache doesn't implement this method.
1543 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1544 IDataObject* iface,
1545 LPFORMATETC pformatectIn,
1546 LPFORMATETC pformatetcOut)
1548 TRACE("()\n");
1549 return E_NOTIMPL;
1552 /************************************************************************
1553 * DataCache_IDataObject_SetData (IDataObject)
1555 * This method is delegated to the IOleCache2 implementation.
1557 static HRESULT WINAPI DataCache_IDataObject_SetData(
1558 IDataObject* iface,
1559 LPFORMATETC pformatetc,
1560 STGMEDIUM* pmedium,
1561 BOOL fRelease)
1563 IOleCache2* oleCache = NULL;
1564 HRESULT hres;
1566 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1568 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1570 if (FAILED(hres))
1571 return E_UNEXPECTED;
1573 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1575 IOleCache2_Release(oleCache);
1577 return hres;
1580 /************************************************************************
1581 * DataCache_EnumFormatEtc (IDataObject)
1583 * The data cache doesn't implement this method.
1585 static HRESULT WINAPI DataCache_EnumFormatEtc(
1586 IDataObject* iface,
1587 DWORD dwDirection,
1588 IEnumFORMATETC** ppenumFormatEtc)
1590 TRACE("()\n");
1591 return E_NOTIMPL;
1594 /************************************************************************
1595 * DataCache_DAdvise (IDataObject)
1597 * The data cache doesn't support connections.
1599 static HRESULT WINAPI DataCache_DAdvise(
1600 IDataObject* iface,
1601 FORMATETC* pformatetc,
1602 DWORD advf,
1603 IAdviseSink* pAdvSink,
1604 DWORD* pdwConnection)
1606 TRACE("()\n");
1607 return OLE_E_ADVISENOTSUPPORTED;
1610 /************************************************************************
1611 * DataCache_DUnadvise (IDataObject)
1613 * The data cache doesn't support connections.
1615 static HRESULT WINAPI DataCache_DUnadvise(
1616 IDataObject* iface,
1617 DWORD dwConnection)
1619 TRACE("()\n");
1620 return OLE_E_NOCONNECTION;
1623 /************************************************************************
1624 * DataCache_EnumDAdvise (IDataObject)
1626 * The data cache doesn't support connections.
1628 static HRESULT WINAPI DataCache_EnumDAdvise(
1629 IDataObject* iface,
1630 IEnumSTATDATA** ppenumAdvise)
1632 TRACE("()\n");
1633 return OLE_E_ADVISENOTSUPPORTED;
1636 /*********************************************************
1637 * Method implementation for the IDataObject
1638 * part of the DataCache class.
1641 /************************************************************************
1642 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1644 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1645 IPersistStorage* iface,
1646 REFIID riid,
1647 void** ppvObject)
1649 DataCache *this = impl_from_IPersistStorage(iface);
1651 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1654 /************************************************************************
1655 * DataCache_IPersistStorage_AddRef (IUnknown)
1657 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1658 IPersistStorage* iface)
1660 DataCache *this = impl_from_IPersistStorage(iface);
1662 return IUnknown_AddRef(this->outer_unk);
1665 /************************************************************************
1666 * DataCache_IPersistStorage_Release (IUnknown)
1668 static ULONG WINAPI DataCache_IPersistStorage_Release(
1669 IPersistStorage* iface)
1671 DataCache *this = impl_from_IPersistStorage(iface);
1673 return IUnknown_Release(this->outer_unk);
1676 /************************************************************************
1677 * DataCache_GetClassID (IPersistStorage)
1680 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1682 DataCache *This = impl_from_IPersistStorage( iface );
1684 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1685 *clsid = This->clsid;
1687 return S_OK;
1690 /************************************************************************
1691 * DataCache_IsDirty (IPersistStorage)
1693 static HRESULT WINAPI DataCache_IsDirty(
1694 IPersistStorage* iface)
1696 DataCache *This = impl_from_IPersistStorage(iface);
1697 DataCacheEntry *cache_entry;
1699 TRACE("(%p)\n", iface);
1701 if (This->dirty)
1702 return S_OK;
1704 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1705 if (cache_entry->dirty)
1706 return S_OK;
1708 return S_FALSE;
1711 /************************************************************************
1712 * DataCache_InitNew (IPersistStorage)
1714 * The data cache implementation of IPersistStorage_InitNew simply stores
1715 * the storage pointer.
1717 static HRESULT WINAPI DataCache_InitNew(
1718 IPersistStorage* iface,
1719 IStorage* pStg)
1721 DataCache *This = impl_from_IPersistStorage(iface);
1722 CLSID clsid;
1723 HRESULT hr;
1725 TRACE("(%p, %p)\n", iface, pStg);
1727 if (This->presentationStorage != NULL)
1728 return CO_E_ALREADYINITIALIZED;
1730 This->presentationStorage = pStg;
1732 IStorage_AddRef(This->presentationStorage);
1733 This->dirty = TRUE;
1734 ReadClassStg( pStg, &clsid );
1735 hr = create_automatic_entry( This, &clsid );
1736 if (FAILED(hr))
1738 IStorage_Release( pStg );
1739 This->presentationStorage = NULL;
1740 return hr;
1742 This->clsid = clsid;
1744 return S_OK;
1748 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, int stream_number )
1750 DataCacheEntry *cache_entry;
1751 HRESULT hr = S_OK;
1753 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1755 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1756 if (!cache_entry)
1757 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1758 if (SUCCEEDED( hr ))
1760 DataCacheEntry_DiscardData( cache_entry );
1761 cache_entry->load_stream_num = stream_number;
1762 cache_entry->save_stream_num = stream_number;
1763 cache_entry->dirty = FALSE;
1765 return hr;
1768 static HRESULT parse_pres_streams( DataCache *cache, IStorage *stg )
1770 HRESULT hr;
1771 IStream *stm;
1772 PresentationDataHeader header;
1773 ULONG actual_read;
1774 CLIPFORMAT clipformat;
1775 FORMATETC fmtetc;
1776 int stream_number = 0;
1780 hr = open_pres_stream( stg, stream_number, &stm );
1781 if (FAILED(hr)) break;
1783 hr = read_clipformat( stm, &clipformat );
1785 if (hr == S_OK) hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1787 if (hr == S_OK && actual_read == sizeof(header))
1789 fmtetc.cfFormat = clipformat;
1790 fmtetc.ptd = NULL; /* FIXME */
1791 fmtetc.dwAspect = header.dvAspect;
1792 fmtetc.lindex = header.lindex;
1793 fmtetc.tymed = tymed_from_cf( clipformat );
1795 add_cache_entry( cache, &fmtetc, header.advf, stream_number );
1797 IStream_Release( stm );
1798 stream_number++;
1799 } while (hr == S_OK);
1801 return S_OK;
1804 static HRESULT parse_contents_stream( DataCache *cache, IStorage *stg )
1806 HRESULT hr;
1807 IStream *stm;
1808 DataCacheEntry *cache_entry;
1810 hr = open_pres_stream( stg, STREAM_NUMBER_CONTENTS, &stm );
1811 if (FAILED( hr )) return hr;
1813 hr = get_static_entry( cache, &cache_entry );
1814 if (hr == S_OK)
1816 cache_entry->load_stream_num = STREAM_NUMBER_CONTENTS;
1817 cache_entry->save_stream_num = STREAM_NUMBER_CONTENTS;
1818 cache_entry->dirty = FALSE;
1821 IStream_Release( stm );
1822 return hr;
1825 /************************************************************************
1826 * DataCache_Load (IPersistStorage)
1828 * The data cache implementation of IPersistStorage_Load doesn't
1829 * actually load anything. Instead, it holds on to the storage pointer
1830 * and it will load the presentation information when the
1831 * IDataObject_GetData or IViewObject2_Draw methods are called.
1833 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg )
1835 DataCache *This = impl_from_IPersistStorage(iface);
1836 HRESULT hr;
1837 CLSID clsid;
1838 DataCacheEntry *entry, *cursor2;
1840 TRACE("(%p, %p)\n", iface, stg);
1842 IPersistStorage_HandsOffStorage( iface );
1844 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1845 DataCacheEntry_Destroy( This, entry );
1846 This->clsid = CLSID_NULL;
1848 ReadClassStg( stg, &clsid );
1849 hr = create_automatic_entry( This, &clsid );
1850 if (FAILED( hr )) return hr;
1852 This->clsid = clsid;
1854 if (This->clsid_static)
1856 hr = parse_contents_stream( This, stg );
1857 if (FAILED(hr)) hr = parse_pres_streams( This, stg );
1859 else
1860 hr = parse_pres_streams( This, stg );
1862 if (SUCCEEDED( hr ))
1864 This->dirty = FALSE;
1865 This->presentationStorage = stg;
1866 IStorage_AddRef( This->presentationStorage );
1869 return hr;
1872 /************************************************************************
1873 * DataCache_Save (IPersistStorage)
1875 * Until we actually connect to a running object and retrieve new
1876 * information to it, we never have to save anything. However, it is
1877 * our responsibility to copy the information when saving to a new
1878 * storage.
1880 static HRESULT WINAPI DataCache_Save(IPersistStorage* iface, IStorage *stg, BOOL same_as_load)
1882 DataCache *This = impl_from_IPersistStorage(iface);
1883 DataCacheEntry *cache_entry;
1884 HRESULT hr = S_OK;
1885 int stream_number = 0;
1887 TRACE("(%p, %p, %d)\n", iface, stg, same_as_load);
1889 /* assign stream numbers to the cache entries */
1890 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1892 if (cache_entry->save_stream_num != stream_number)
1894 cache_entry->dirty = TRUE; /* needs to be written out again */
1895 cache_entry->save_stream_num = stream_number;
1897 stream_number++;
1900 /* write out the cache entries */
1901 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1903 if (!same_as_load || cache_entry->dirty)
1905 hr = DataCacheEntry_Save(cache_entry, stg, same_as_load);
1906 if (FAILED(hr))
1907 break;
1909 if (same_as_load) cache_entry->dirty = FALSE;
1913 if (same_as_load) This->dirty = FALSE;
1914 return hr;
1917 /************************************************************************
1918 * DataCache_SaveCompleted (IPersistStorage)
1920 * This method is called to tell the cache to release the storage
1921 * pointer it's currently holding.
1923 static HRESULT WINAPI DataCache_SaveCompleted(
1924 IPersistStorage* iface,
1925 IStorage* pStgNew)
1927 TRACE("(%p, %p)\n", iface, pStgNew);
1929 if (pStgNew)
1931 IPersistStorage_HandsOffStorage(iface);
1933 DataCache_Load(iface, pStgNew);
1936 return S_OK;
1939 /************************************************************************
1940 * DataCache_HandsOffStorage (IPersistStorage)
1942 * This method is called to tell the cache to release the storage
1943 * pointer it's currently holding.
1945 static HRESULT WINAPI DataCache_HandsOffStorage(
1946 IPersistStorage* iface)
1948 DataCache *this = impl_from_IPersistStorage(iface);
1950 TRACE("(%p)\n", iface);
1952 if (this->presentationStorage != NULL)
1954 IStorage_Release(this->presentationStorage);
1955 this->presentationStorage = NULL;
1958 return S_OK;
1961 /*********************************************************
1962 * Method implementation for the IViewObject2
1963 * part of the DataCache class.
1966 /************************************************************************
1967 * DataCache_IViewObject2_QueryInterface (IUnknown)
1969 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1970 IViewObject2* iface,
1971 REFIID riid,
1972 void** ppvObject)
1974 DataCache *this = impl_from_IViewObject2(iface);
1976 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1979 /************************************************************************
1980 * DataCache_IViewObject2_AddRef (IUnknown)
1982 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1983 IViewObject2* iface)
1985 DataCache *this = impl_from_IViewObject2(iface);
1987 return IUnknown_AddRef(this->outer_unk);
1990 /************************************************************************
1991 * DataCache_IViewObject2_Release (IUnknown)
1993 static ULONG WINAPI DataCache_IViewObject2_Release(
1994 IViewObject2* iface)
1996 DataCache *this = impl_from_IViewObject2(iface);
1998 return IUnknown_Release(this->outer_unk);
2001 /************************************************************************
2002 * DataCache_Draw (IViewObject2)
2004 * This method will draw the cached representation of the object
2005 * to the given device context.
2007 static HRESULT WINAPI DataCache_Draw(
2008 IViewObject2* iface,
2009 DWORD dwDrawAspect,
2010 LONG lindex,
2011 void* pvAspect,
2012 DVTARGETDEVICE* ptd,
2013 HDC hdcTargetDev,
2014 HDC hdcDraw,
2015 LPCRECTL lprcBounds,
2016 LPCRECTL lprcWBounds,
2017 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
2018 ULONG_PTR dwContinue)
2020 DataCache *This = impl_from_IViewObject2(iface);
2021 HRESULT hres;
2022 DataCacheEntry *cache_entry;
2024 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
2025 iface,
2026 dwDrawAspect,
2027 lindex,
2028 pvAspect,
2029 hdcTargetDev,
2030 hdcDraw,
2031 lprcBounds,
2032 lprcWBounds,
2033 pfnContinue,
2034 dwContinue);
2036 if (lprcBounds==NULL)
2037 return E_INVALIDARG;
2039 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2041 /* FIXME: compare ptd too */
2042 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2043 (cache_entry->fmtetc.lindex != lindex))
2044 continue;
2046 /* if the data hasn't been loaded yet, do it now */
2047 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2049 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2050 if (FAILED(hres))
2051 continue;
2054 /* no data */
2055 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2056 continue;
2058 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
2060 switch (cache_entry->fmtetc.cfFormat)
2062 case CF_METAFILEPICT:
2065 * We have to be careful not to modify the state of the
2066 * DC.
2068 INT prevMapMode;
2069 SIZE oldWindowExt;
2070 SIZE oldViewportExt;
2071 POINT oldViewportOrg;
2072 METAFILEPICT *mfpict;
2074 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2075 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2076 continue;
2078 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
2080 SetWindowExtEx(hdcDraw,
2081 mfpict->xExt,
2082 mfpict->yExt,
2083 &oldWindowExt);
2085 SetViewportExtEx(hdcDraw,
2086 lprcBounds->right - lprcBounds->left,
2087 lprcBounds->bottom - lprcBounds->top,
2088 &oldViewportExt);
2090 SetViewportOrgEx(hdcDraw,
2091 lprcBounds->left,
2092 lprcBounds->top,
2093 &oldViewportOrg);
2095 PlayMetaFile(hdcDraw, mfpict->hMF);
2097 SetWindowExtEx(hdcDraw,
2098 oldWindowExt.cx,
2099 oldWindowExt.cy,
2100 NULL);
2102 SetViewportExtEx(hdcDraw,
2103 oldViewportExt.cx,
2104 oldViewportExt.cy,
2105 NULL);
2107 SetViewportOrgEx(hdcDraw,
2108 oldViewportOrg.x,
2109 oldViewportOrg.y,
2110 NULL);
2112 SetMapMode(hdcDraw, prevMapMode);
2114 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2116 return S_OK;
2118 case CF_DIB:
2120 BITMAPINFO *info;
2121 BYTE *bits;
2123 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2124 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2125 continue;
2127 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
2128 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
2129 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
2130 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
2131 bits, info, DIB_RGB_COLORS, SRCCOPY );
2133 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2134 return S_OK;
2139 WARN("no data could be found to be drawn\n");
2141 return OLE_E_BLANK;
2144 static HRESULT WINAPI DataCache_GetColorSet(
2145 IViewObject2* iface,
2146 DWORD dwDrawAspect,
2147 LONG lindex,
2148 void* pvAspect,
2149 DVTARGETDEVICE* ptd,
2150 HDC hicTargetDevice,
2151 LOGPALETTE** ppColorSet)
2153 FIXME("stub\n");
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI DataCache_Freeze(
2158 IViewObject2* iface,
2159 DWORD dwDrawAspect,
2160 LONG lindex,
2161 void* pvAspect,
2162 DWORD* pdwFreeze)
2164 FIXME("stub\n");
2165 return E_NOTIMPL;
2168 static HRESULT WINAPI DataCache_Unfreeze(
2169 IViewObject2* iface,
2170 DWORD dwFreeze)
2172 FIXME("stub\n");
2173 return E_NOTIMPL;
2176 /************************************************************************
2177 * DataCache_SetAdvise (IViewObject2)
2179 * This sets-up an advisory sink with the data cache. When the object's
2180 * view changes, this sink is called.
2182 static HRESULT WINAPI DataCache_SetAdvise(
2183 IViewObject2* iface,
2184 DWORD aspects,
2185 DWORD advf,
2186 IAdviseSink* pAdvSink)
2188 DataCache *this = impl_from_IViewObject2(iface);
2190 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
2193 * A call to this function removes the previous sink
2195 if (this->sinkInterface != NULL)
2197 IAdviseSink_Release(this->sinkInterface);
2198 this->sinkInterface = NULL;
2199 this->sinkAspects = 0;
2200 this->sinkAdviseFlag = 0;
2204 * Now, setup the new one.
2206 if (pAdvSink!=NULL)
2208 this->sinkInterface = pAdvSink;
2209 this->sinkAspects = aspects;
2210 this->sinkAdviseFlag = advf;
2212 IAdviseSink_AddRef(this->sinkInterface);
2216 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2217 * sink immediately.
2219 if (advf & ADVF_PRIMEFIRST)
2221 DataCache_FireOnViewChange(this, aspects, -1);
2224 return S_OK;
2227 /************************************************************************
2228 * DataCache_GetAdvise (IViewObject2)
2230 * This method queries the current state of the advise sink
2231 * installed on the data cache.
2233 static HRESULT WINAPI DataCache_GetAdvise(
2234 IViewObject2* iface,
2235 DWORD* pAspects,
2236 DWORD* pAdvf,
2237 IAdviseSink** ppAdvSink)
2239 DataCache *this = impl_from_IViewObject2(iface);
2241 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2244 * Just copy all the requested values.
2246 if (pAspects!=NULL)
2247 *pAspects = this->sinkAspects;
2249 if (pAdvf!=NULL)
2250 *pAdvf = this->sinkAdviseFlag;
2252 if (ppAdvSink!=NULL)
2254 if (this->sinkInterface != NULL)
2255 IAdviseSink_QueryInterface(this->sinkInterface,
2256 &IID_IAdviseSink,
2257 (void**)ppAdvSink);
2258 else *ppAdvSink = NULL;
2261 return S_OK;
2264 /************************************************************************
2265 * DataCache_GetExtent (IViewObject2)
2267 * This method retrieves the "natural" size of this cached object.
2269 static HRESULT WINAPI DataCache_GetExtent(
2270 IViewObject2* iface,
2271 DWORD dwDrawAspect,
2272 LONG lindex,
2273 DVTARGETDEVICE* ptd,
2274 LPSIZEL lpsizel)
2276 DataCache *This = impl_from_IViewObject2(iface);
2277 HRESULT hres = E_FAIL;
2278 DataCacheEntry *cache_entry;
2280 TRACE("(%p, %x, %d, %p, %p)\n",
2281 iface, dwDrawAspect, lindex, ptd, lpsizel);
2283 if (lpsizel==NULL)
2284 return E_POINTER;
2286 lpsizel->cx = 0;
2287 lpsizel->cy = 0;
2289 if (lindex!=-1)
2290 FIXME("Unimplemented flag lindex = %d\n", lindex);
2293 * Right now, we support only the callback from
2294 * the default handler.
2296 if (ptd!=NULL)
2297 FIXME("Unimplemented ptd = %p\n", ptd);
2299 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2301 /* FIXME: compare ptd too */
2302 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2303 (cache_entry->fmtetc.lindex != lindex))
2304 continue;
2306 /* if the data hasn't been loaded yet, do it now */
2307 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2309 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2310 if (FAILED(hres))
2311 continue;
2314 /* no data */
2315 if (cache_entry->stgmedium.tymed == TYMED_NULL)
2316 continue;
2319 switch (cache_entry->fmtetc.cfFormat)
2321 case CF_METAFILEPICT:
2323 METAFILEPICT *mfpict;
2325 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2326 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2327 continue;
2329 lpsizel->cx = mfpict->xExt;
2330 lpsizel->cy = mfpict->yExt;
2332 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2334 return S_OK;
2336 case CF_DIB:
2338 BITMAPINFOHEADER *info;
2339 LONG x_pels_m, y_pels_m;
2342 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2343 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2344 continue;
2346 x_pels_m = info->biXPelsPerMeter;
2347 y_pels_m = info->biYPelsPerMeter;
2349 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2350 if (x_pels_m != 0 && y_pels_m != 0)
2352 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
2353 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2355 else
2357 HDC hdc = GetDC( 0 );
2358 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2359 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2361 ReleaseDC( 0, hdc );
2364 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2366 return S_OK;
2371 WARN("no data could be found to get the extents from\n");
2374 * This method returns OLE_E_BLANK when it fails.
2376 return OLE_E_BLANK;
2380 /*********************************************************
2381 * Method implementation for the IOleCache2
2382 * part of the DataCache class.
2385 /************************************************************************
2386 * DataCache_IOleCache2_QueryInterface (IUnknown)
2388 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2389 IOleCache2* iface,
2390 REFIID riid,
2391 void** ppvObject)
2393 DataCache *this = impl_from_IOleCache2(iface);
2395 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2398 /************************************************************************
2399 * DataCache_IOleCache2_AddRef (IUnknown)
2401 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2402 IOleCache2* iface)
2404 DataCache *this = impl_from_IOleCache2(iface);
2406 return IUnknown_AddRef(this->outer_unk);
2409 /************************************************************************
2410 * DataCache_IOleCache2_Release (IUnknown)
2412 static ULONG WINAPI DataCache_IOleCache2_Release(
2413 IOleCache2* iface)
2415 DataCache *this = impl_from_IOleCache2(iface);
2417 return IUnknown_Release(this->outer_unk);
2420 /*****************************************************************************
2421 * setup_sink
2423 * Set up the sink connection to the running object.
2425 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2427 HRESULT hr = S_FALSE;
2428 DWORD flags;
2430 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2431 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2433 if(This->running_object)
2434 if(!(flags & ADVF_NODATA))
2435 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2436 &This->IAdviseSink_iface, &cache_entry->sink_id);
2437 return hr;
2440 static HRESULT WINAPI DataCache_Cache(
2441 IOleCache2* iface,
2442 FORMATETC* pformatetc,
2443 DWORD advf,
2444 DWORD* pdwConnection)
2446 DataCache *This = impl_from_IOleCache2(iface);
2447 DataCacheEntry *cache_entry;
2448 HRESULT hr;
2449 FORMATETC fmt_cpy;
2451 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2453 if (!pformatetc || !pdwConnection)
2454 return E_INVALIDARG;
2456 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2458 fmt_cpy = *pformatetc; /* No need for a deep copy */
2459 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2461 fmt_cpy.cfFormat = CF_DIB;
2462 fmt_cpy.tymed = TYMED_HGLOBAL;
2465 /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */
2466 if (fmt_cpy.dwAspect == DVASPECT_ICON && fmt_cpy.cfFormat == 0)
2468 fmt_cpy.cfFormat = CF_METAFILEPICT;
2469 fmt_cpy.tymed = TYMED_MFPICT;
2472 *pdwConnection = 0;
2474 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2475 if (cache_entry)
2477 TRACE("found an existing cache entry\n");
2478 *pdwConnection = cache_entry->id;
2479 return CACHE_S_SAMECACHE;
2482 if (This->clsid_static && fmt_cpy.dwAspect != DVASPECT_ICON) return DV_E_FORMATETC;
2484 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2486 if (SUCCEEDED(hr))
2488 *pdwConnection = cache_entry->id;
2489 setup_sink(This, cache_entry);
2492 return hr;
2495 static HRESULT WINAPI DataCache_Uncache(
2496 IOleCache2* iface,
2497 DWORD dwConnection)
2499 DataCache *This = impl_from_IOleCache2(iface);
2500 DataCacheEntry *cache_entry;
2502 TRACE("(%d)\n", dwConnection);
2504 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2505 if (cache_entry->id == dwConnection)
2507 DataCacheEntry_Destroy(This, cache_entry);
2508 return S_OK;
2511 WARN("no connection found for %d\n", dwConnection);
2513 return OLE_E_NOCONNECTION;
2516 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2517 IEnumSTATDATA **enum_stat)
2519 DataCache *This = impl_from_IOleCache2( iface );
2520 DataCacheEntry *cache_entry;
2521 int i = 0, count = 0;
2522 STATDATA *data;
2523 HRESULT hr;
2525 TRACE( "(%p, %p)\n", This, enum_stat );
2527 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2529 count++;
2530 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2531 count++;
2534 data = CoTaskMemAlloc( count * sizeof(*data) );
2535 if (!data) return E_OUTOFMEMORY;
2537 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2539 if (i == count) goto fail;
2540 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2541 if (FAILED(hr)) goto fail;
2542 data[i].advf = cache_entry->advise_flags;
2543 data[i].pAdvSink = NULL;
2544 data[i].dwConnection = cache_entry->id;
2545 i++;
2547 if (cache_entry->fmtetc.cfFormat == CF_DIB)
2549 if (i == count) goto fail;
2550 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2551 if (FAILED(hr)) goto fail;
2552 data[i].formatetc.cfFormat = CF_BITMAP;
2553 data[i].formatetc.tymed = TYMED_GDI;
2554 data[i].advf = cache_entry->advise_flags;
2555 data[i].pAdvSink = NULL;
2556 data[i].dwConnection = cache_entry->id;
2557 i++;
2561 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2562 if (SUCCEEDED(hr)) return hr;
2564 fail:
2565 while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2566 CoTaskMemFree( data );
2567 return hr;
2570 static HRESULT WINAPI DataCache_InitCache( IOleCache2 *iface, IDataObject *data )
2572 TRACE( "(%p %p)\n", iface, data );
2573 return IOleCache2_UpdateCache( iface, data, UPDFCACHE_ALLBUTNODATACACHE, NULL );
2576 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2577 IOleCache2* iface,
2578 FORMATETC* pformatetc,
2579 STGMEDIUM* pmedium,
2580 BOOL fRelease)
2582 DataCache *This = impl_from_IOleCache2(iface);
2583 DataCacheEntry *cache_entry;
2584 HRESULT hr;
2586 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2587 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2589 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2590 if (cache_entry)
2592 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2594 if (SUCCEEDED(hr))
2595 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2596 cache_entry->fmtetc.lindex);
2598 return hr;
2600 WARN("cache entry not found\n");
2602 return OLE_E_BLANK;
2605 static BOOL entry_updatable( DataCacheEntry *entry, DWORD mode )
2607 BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL;
2609 if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE;
2611 if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE;
2612 if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE;
2613 if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE;
2614 if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE;
2615 if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE;
2617 return FALSE;
2620 static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data,
2621 DWORD mode, void *reserved )
2623 DataCache *This = impl_from_IOleCache2(iface);
2624 DataCacheEntry *cache_entry;
2625 STGMEDIUM med;
2626 HRESULT hr = S_OK;
2627 CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP };
2628 FORMATETC fmt;
2629 int i, slots = 0;
2630 BOOL done_one = FALSE;
2632 TRACE( "(%p %p %08x %p)\n", iface, data, mode, reserved );
2634 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2636 slots++;
2638 if (!entry_updatable( cache_entry, mode ))
2640 done_one = TRUE;
2641 continue;
2644 fmt = cache_entry->fmtetc;
2646 if (fmt.cfFormat)
2648 hr = IDataObject_GetData( data, &fmt, &med );
2649 if (hr != S_OK && fmt.cfFormat == CF_DIB)
2651 fmt.cfFormat = CF_BITMAP;
2652 fmt.tymed = TYMED_GDI;
2653 hr = IDataObject_GetData( data, &fmt, &med );
2655 if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE)
2657 fmt.cfFormat = CF_METAFILEPICT;
2658 fmt.tymed = TYMED_MFPICT;
2659 hr = IDataObject_GetData( data, &fmt, &med );
2661 if (hr == S_OK)
2663 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2664 if (hr != S_OK) ReleaseStgMedium( &med );
2665 else done_one = TRUE;
2668 else
2670 for (i = 0; i < sizeof(view_list) / sizeof(view_list[0]); i++)
2672 fmt.cfFormat = view_list[i];
2673 fmt.tymed = tymed_from_cf( fmt.cfFormat );
2674 hr = IDataObject_QueryGetData( data, &fmt );
2675 if (hr == S_OK)
2677 hr = IDataObject_GetData( data, &fmt, &med );
2678 if (hr == S_OK)
2680 if (fmt.cfFormat == CF_BITMAP)
2682 cache_entry->fmtetc.cfFormat = CF_DIB;
2683 cache_entry->fmtetc.tymed = TYMED_HGLOBAL;
2685 else
2687 cache_entry->fmtetc.cfFormat = fmt.cfFormat;
2688 cache_entry->fmtetc.tymed = fmt.tymed;
2690 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2691 if (hr != S_OK) ReleaseStgMedium( &med );
2692 else done_one = TRUE;
2693 break;
2700 return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED;
2703 static HRESULT WINAPI DataCache_DiscardCache(
2704 IOleCache2* iface,
2705 DWORD dwDiscardOptions)
2707 DataCache *This = impl_from_IOleCache2(iface);
2708 DataCacheEntry *cache_entry;
2709 HRESULT hr = S_OK;
2711 TRACE("(%d)\n", dwDiscardOptions);
2713 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2714 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2716 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2718 hr = DataCacheEntry_DiscardData(cache_entry);
2719 if (FAILED(hr))
2720 break;
2723 return hr;
2727 /*********************************************************
2728 * Method implementation for the IOleCacheControl
2729 * part of the DataCache class.
2732 /************************************************************************
2733 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2735 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2736 IOleCacheControl* iface,
2737 REFIID riid,
2738 void** ppvObject)
2740 DataCache *this = impl_from_IOleCacheControl(iface);
2742 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2745 /************************************************************************
2746 * DataCache_IOleCacheControl_AddRef (IUnknown)
2748 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2749 IOleCacheControl* iface)
2751 DataCache *this = impl_from_IOleCacheControl(iface);
2753 return IUnknown_AddRef(this->outer_unk);
2756 /************************************************************************
2757 * DataCache_IOleCacheControl_Release (IUnknown)
2759 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2760 IOleCacheControl* iface)
2762 DataCache *this = impl_from_IOleCacheControl(iface);
2764 return IUnknown_Release(this->outer_unk);
2767 /************************************************************************
2768 * DataCache_OnRun (IOleCacheControl)
2770 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2772 DataCache *This = impl_from_IOleCacheControl(iface);
2773 DataCacheEntry *cache_entry;
2775 TRACE("(%p)->(%p)\n", iface, data_obj);
2777 if(This->running_object) return S_OK;
2779 /* No reference is taken on the data object */
2780 This->running_object = data_obj;
2782 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2784 setup_sink(This, cache_entry);
2787 return S_OK;
2790 /************************************************************************
2791 * DataCache_OnStop (IOleCacheControl)
2793 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2795 DataCache *This = impl_from_IOleCacheControl(iface);
2796 DataCacheEntry *cache_entry;
2798 TRACE("(%p)\n", iface);
2800 if(!This->running_object) return S_OK;
2802 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2804 if(cache_entry->sink_id)
2806 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2807 cache_entry->sink_id = 0;
2811 /* No ref taken in OnRun, so no Release call here */
2812 This->running_object = NULL;
2813 return S_OK;
2816 /************************************************************************
2817 * IAdviseSink methods.
2818 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2819 * give access to the cache's other interfaces. We don't maintain a ref count,
2820 * the object exists as long as the cache is around.
2822 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2824 *obj = NULL;
2825 if (IsEqualIID(&IID_IUnknown, iid) ||
2826 IsEqualIID(&IID_IAdviseSink, iid))
2828 *obj = iface;
2831 if(*obj)
2833 IAdviseSink_AddRef(iface);
2834 return S_OK;
2836 return E_NOINTERFACE;
2839 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2841 return 2;
2844 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2846 return 1;
2849 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2851 DataCache *This = impl_from_IAdviseSink(iface);
2852 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2853 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2856 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2858 FIXME("stub\n");
2861 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2863 FIXME("stub\n");
2866 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2868 FIXME("stub\n");
2871 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2873 FIXME("stub\n");
2877 * Virtual function tables for the DataCache class.
2879 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2881 DataCache_NDIUnknown_QueryInterface,
2882 DataCache_NDIUnknown_AddRef,
2883 DataCache_NDIUnknown_Release
2886 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2888 DataCache_IDataObject_QueryInterface,
2889 DataCache_IDataObject_AddRef,
2890 DataCache_IDataObject_Release,
2891 DataCache_GetData,
2892 DataCache_GetDataHere,
2893 DataCache_QueryGetData,
2894 DataCache_GetCanonicalFormatEtc,
2895 DataCache_IDataObject_SetData,
2896 DataCache_EnumFormatEtc,
2897 DataCache_DAdvise,
2898 DataCache_DUnadvise,
2899 DataCache_EnumDAdvise
2902 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2904 DataCache_IPersistStorage_QueryInterface,
2905 DataCache_IPersistStorage_AddRef,
2906 DataCache_IPersistStorage_Release,
2907 DataCache_GetClassID,
2908 DataCache_IsDirty,
2909 DataCache_InitNew,
2910 DataCache_Load,
2911 DataCache_Save,
2912 DataCache_SaveCompleted,
2913 DataCache_HandsOffStorage
2916 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2918 DataCache_IViewObject2_QueryInterface,
2919 DataCache_IViewObject2_AddRef,
2920 DataCache_IViewObject2_Release,
2921 DataCache_Draw,
2922 DataCache_GetColorSet,
2923 DataCache_Freeze,
2924 DataCache_Unfreeze,
2925 DataCache_SetAdvise,
2926 DataCache_GetAdvise,
2927 DataCache_GetExtent
2930 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2932 DataCache_IOleCache2_QueryInterface,
2933 DataCache_IOleCache2_AddRef,
2934 DataCache_IOleCache2_Release,
2935 DataCache_Cache,
2936 DataCache_Uncache,
2937 DataCache_EnumCache,
2938 DataCache_InitCache,
2939 DataCache_IOleCache2_SetData,
2940 DataCache_UpdateCache,
2941 DataCache_DiscardCache
2944 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2946 DataCache_IOleCacheControl_QueryInterface,
2947 DataCache_IOleCacheControl_AddRef,
2948 DataCache_IOleCacheControl_Release,
2949 DataCache_OnRun,
2950 DataCache_OnStop
2953 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2955 DataCache_IAdviseSink_QueryInterface,
2956 DataCache_IAdviseSink_AddRef,
2957 DataCache_IAdviseSink_Release,
2958 DataCache_OnDataChange,
2959 DataCache_OnViewChange,
2960 DataCache_OnRename,
2961 DataCache_OnSave,
2962 DataCache_OnClose
2965 /*********************************************************
2966 * Method implementation for DataCache class.
2968 static DataCache* DataCache_Construct(
2969 REFCLSID clsid,
2970 LPUNKNOWN pUnkOuter)
2972 DataCache* newObject = 0;
2975 * Allocate space for the object.
2977 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2979 if (newObject==0)
2980 return newObject;
2983 * Initialize the virtual function table.
2985 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2986 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2987 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2988 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2989 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2990 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2991 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2992 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2993 newObject->ref = 1;
2996 * Initialize the other members of the structure.
2998 newObject->sinkAspects = 0;
2999 newObject->sinkAdviseFlag = 0;
3000 newObject->sinkInterface = 0;
3001 newObject->clsid = CLSID_NULL;
3002 newObject->clsid_static = FALSE;
3003 newObject->presentationStorage = NULL;
3004 list_init(&newObject->cache_list);
3005 newObject->last_cache_id = 2;
3006 newObject->dirty = FALSE;
3007 newObject->running_object = NULL;
3009 create_automatic_entry( newObject, clsid );
3010 newObject->clsid = *clsid;
3012 return newObject;
3015 /******************************************************************************
3016 * CreateDataCache [OLE32.@]
3018 * Creates a data cache to allow an object to render one or more of its views,
3019 * whether running or not.
3021 * PARAMS
3022 * pUnkOuter [I] Outer unknown for the object.
3023 * rclsid [I]
3024 * riid [I] IID of interface to return.
3025 * ppvObj [O] Address where the data cache object will be stored on return.
3027 * RETURNS
3028 * Success: S_OK.
3029 * Failure: HRESULT code.
3031 * NOTES
3032 * The following interfaces are supported by the returned data cache object:
3033 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
3034 * IViewObject and IViewObject2.
3036 HRESULT WINAPI CreateDataCache(
3037 LPUNKNOWN pUnkOuter,
3038 REFCLSID rclsid,
3039 REFIID riid,
3040 LPVOID* ppvObj)
3042 DataCache* newCache = NULL;
3043 HRESULT hr = S_OK;
3045 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
3048 * Sanity check
3050 if (ppvObj==0)
3051 return E_POINTER;
3053 *ppvObj = 0;
3056 * If this cache is constructed for aggregation, make sure
3057 * the caller is requesting the IUnknown interface.
3058 * This is necessary because it's the only time the non-delegating
3059 * IUnknown pointer can be returned to the outside.
3061 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
3062 return E_INVALIDARG;
3065 * Try to construct a new instance of the class.
3067 newCache = DataCache_Construct(rclsid,
3068 pUnkOuter);
3070 if (newCache == 0)
3071 return E_OUTOFMEMORY;
3073 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
3074 IUnknown_Release(&newCache->IUnknown_inner);
3076 return hr;