53a312cbc062e77e733e4adbc0b6f6ddb1370967
[reactos.git] / reactos / dll / win32 / ole32 / datacache.c
1 /*
2 * OLE 2 Data cache
3 *
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2000 Abey George
6 *
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.
11 *
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.
16 *
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
20 *
21 * NOTES:
22 * The OLE2 data cache supports a whole whack of
23 * interfaces including:
24 * IDataObject, IPersistStorage, IViewObject2,
25 * IOleCache2 and IOleCacheControl.
26 *
27 * Most of the implementation details are taken from: Inside OLE
28 * second edition by Kraig Brockschmidt,
29 *
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.
45 */
46 #define WIN32_NO_STATUS
47 #define _INC_WINDOWS
48
49 #include <stdarg.h>
50 //#include <string.h>
51
52 #define COBJMACROS
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
55
56 #include <windef.h>
57 #include <winbase.h>
58 #include <wingdi.h>
59 //#include "winuser.h"
60 //#include "winerror.h"
61 #include <wine/unicode.h>
62 #include <ole2.h>
63 #include <wine/list.h>
64 #include <wine/debug.h>
65
66 WINE_DEFAULT_DEBUG_CHANNEL(ole);
67
68 /****************************************************************************
69 * PresentationDataHeader
70 *
71 * This structure represents the header of the \002OlePresXXX stream in
72 * the OLE object storage.
73 */
74 typedef struct PresentationDataHeader
75 {
76 /* clipformat:
77 * - standard clipformat:
78 * DWORD length = 0xffffffff;
79 * DWORD cfFormat;
80 * - or custom clipformat:
81 * DWORD length;
82 * CHAR format_name[length]; (null-terminated)
83 */
84 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
85 DVASPECT dvAspect;
86 DWORD lindex;
87 DWORD tymed;
88 DWORD unknown7; /* 0 */
89 DWORD dwObjectExtentX;
90 DWORD dwObjectExtentY;
91 DWORD dwSize;
92 } PresentationDataHeader;
93
94 typedef struct DataCacheEntry
95 {
96 struct list entry;
97 /* format of this entry */
98 FORMATETC fmtetc;
99 /* the clipboard format of the data */
100 CLIPFORMAT data_cf;
101 /* cached data */
102 STGMEDIUM stgmedium;
103 /*
104 * This storage pointer is set through a call to
105 * IPersistStorage_Load. This is where the visual
106 * representation of the object is stored.
107 */
108 IStorage *storage;
109 /* connection ID */
110 DWORD id;
111 /* dirty flag */
112 BOOL dirty;
113 /* stream number (-1 if not set ) */
114 unsigned short stream_number;
115 /* sink id set when object is running */
116 DWORD sink_id;
117 /* Advise sink flags */
118 DWORD advise_flags;
119 } DataCacheEntry;
120
121 /****************************************************************************
122 * DataCache
123 */
124 struct DataCache
125 {
126 /*
127 * List all interface here
128 */
129 IDataObject IDataObject_iface;
130 IUnknown IUnknown_iface;
131 IPersistStorage IPersistStorage_iface;
132 IViewObject2 IViewObject2_iface;
133 IOleCache2 IOleCache2_iface;
134 IOleCacheControl IOleCacheControl_iface;
135
136 /* The sink that is connected to a remote object.
137 The other interfaces are not available by QI'ing the sink and vice-versa */
138 IAdviseSink IAdviseSink_iface;
139
140 /*
141 * Reference count of this object
142 */
143 LONG ref;
144
145 /*
146 * IUnknown implementation of the outer object.
147 */
148 IUnknown* outerUnknown;
149
150 /*
151 * The user of this object can setup ONE advise sink
152 * connection with the object. These parameters describe
153 * that connection.
154 */
155 DWORD sinkAspects;
156 DWORD sinkAdviseFlag;
157 IAdviseSink* sinkInterface;
158 IStorage *presentationStorage;
159
160 /* list of cache entries */
161 struct list cache_list;
162 /* last id assigned to an entry */
163 DWORD last_cache_id;
164 /* dirty flag */
165 BOOL dirty;
166 /* running object set by OnRun */
167 IDataObject *running_object;
168 };
169
170 typedef struct DataCache DataCache;
171
172 /*
173 * Here, I define utility macros to help with the casting of the
174 * "this" parameter.
175 * There is a version to accommodate all of the VTables implemented
176 * by this object.
177 */
178
179 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
180 {
181 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
182 }
183
184 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
185 {
186 return CONTAINING_RECORD(iface, DataCache, IUnknown_iface);
187 }
188
189 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
190 {
191 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
192 }
193
194 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
195 {
196 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
197 }
198
199 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
200 {
201 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
202 }
203
204 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
205 {
206 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
207 }
208
209 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
210 {
211 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
212 }
213
214 static const char * debugstr_formatetc(const FORMATETC *formatetc)
215 {
216 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
217 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
218 formatetc->lindex, formatetc->tymed);
219 }
220
221 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
222 {
223 list_remove(&cache_entry->entry);
224 if (cache_entry->storage)
225 IStorage_Release(cache_entry->storage);
226 HeapFree(GetProcessHeap(), 0, cache_entry->fmtetc.ptd);
227 ReleaseStgMedium(&cache_entry->stgmedium);
228 if(cache_entry->sink_id)
229 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
230
231 HeapFree(GetProcessHeap(), 0, cache_entry);
232 }
233
234 static void DataCache_Destroy(
235 DataCache* ptrToDestroy)
236 {
237 DataCacheEntry *cache_entry, *next_cache_entry;
238
239 TRACE("()\n");
240
241 if (ptrToDestroy->sinkInterface != NULL)
242 {
243 IAdviseSink_Release(ptrToDestroy->sinkInterface);
244 ptrToDestroy->sinkInterface = NULL;
245 }
246
247 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
248 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
249
250 if (ptrToDestroy->presentationStorage != NULL)
251 {
252 IStorage_Release(ptrToDestroy->presentationStorage);
253 ptrToDestroy->presentationStorage = NULL;
254 }
255
256 /*
257 * Free the datacache pointer.
258 */
259 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
260 }
261
262 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
263 {
264 DataCacheEntry *cache_entry;
265 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
266 {
267 /* FIXME: also compare DVTARGETDEVICEs */
268 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
269 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
270 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
271 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
272 return cache_entry;
273 }
274 return NULL;
275 }
276
277 /* checks that the clipformat and tymed are valid and returns an error if they
278 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
279 * DataCache_Draw */
280 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
281 {
282 if (!cfFormat || !tymed ||
283 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
284 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
285 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
286 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
287 return S_OK;
288 else if (tymed == TYMED_HGLOBAL)
289 return CACHE_S_FORMATETC_NOTSUPPORTED;
290 else
291 {
292 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
293 return DV_E_TYMED;
294 }
295 }
296
297 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
298 {
299 HRESULT hr;
300
301 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
302 if (FAILED(hr))
303 return hr;
304 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
305 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
306
307 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
308 if (!*cache_entry)
309 return E_OUTOFMEMORY;
310
311 (*cache_entry)->fmtetc = *formatetc;
312 if (formatetc->ptd)
313 {
314 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
315 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
316 }
317 (*cache_entry)->data_cf = 0;
318 (*cache_entry)->stgmedium.tymed = TYMED_NULL;
319 (*cache_entry)->stgmedium.pUnkForRelease = NULL;
320 (*cache_entry)->storage = NULL;
321 (*cache_entry)->id = This->last_cache_id++;
322 (*cache_entry)->dirty = TRUE;
323 (*cache_entry)->stream_number = -1;
324 (*cache_entry)->sink_id = 0;
325 (*cache_entry)->advise_flags = 0;
326 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
327 return hr;
328 }
329
330 /************************************************************************
331 * DataCache_FireOnViewChange
332 *
333 * This method will fire an OnViewChange notification to the advise
334 * sink registered with the datacache.
335 *
336 * See IAdviseSink::OnViewChange for more details.
337 */
338 static void DataCache_FireOnViewChange(
339 DataCache* this,
340 DWORD aspect,
341 LONG lindex)
342 {
343 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
344
345 /*
346 * The sink supplies a filter when it registers
347 * we make sure we only send the notifications when that
348 * filter matches.
349 */
350 if ((this->sinkAspects & aspect) != 0)
351 {
352 if (this->sinkInterface != NULL)
353 {
354 IAdviseSink_OnViewChange(this->sinkInterface,
355 aspect,
356 lindex);
357
358 /*
359 * Some sinks want to be unregistered automatically when
360 * the first notification goes out.
361 */
362 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
363 {
364 IAdviseSink_Release(this->sinkInterface);
365
366 this->sinkInterface = NULL;
367 this->sinkAspects = 0;
368 this->sinkAdviseFlag = 0;
369 }
370 }
371 }
372 }
373
374 /* Helper for DataCacheEntry_OpenPresStream */
375 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
376 {
377 /* The presentation streams have names of the form "\002OlePresXXX",
378 * where XXX goes from 000 to 999. */
379 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
380
381 LPCWSTR name = elem->pwcsName;
382
383 return (elem->type == STGTY_STREAM)
384 && (strlenW(name) == 11)
385 && (strncmpW(name, OlePres, 8) == 0)
386 && (name[8] >= '0') && (name[8] <= '9')
387 && (name[9] >= '0') && (name[9] <= '9')
388 && (name[10] >= '0') && (name[10] <= '9');
389 }
390
391 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
392 {
393 DWORD length;
394 HRESULT hr;
395 ULONG read;
396
397 *clipformat = 0;
398
399 hr = IStream_Read(stream, &length, sizeof(length), &read);
400 if (hr != S_OK || read != sizeof(length))
401 return DV_E_CLIPFORMAT;
402 if (length == -1)
403 {
404 DWORD cf;
405 hr = IStream_Read(stream, &cf, sizeof(cf), 0);
406 if (hr != S_OK || read != sizeof(cf))
407 return DV_E_CLIPFORMAT;
408 *clipformat = cf;
409 }
410 else
411 {
412 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
413 if (!format_name)
414 return E_OUTOFMEMORY;
415 hr = IStream_Read(stream, format_name, length, &read);
416 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
417 {
418 HeapFree(GetProcessHeap(), 0, format_name);
419 return DV_E_CLIPFORMAT;
420 }
421 *clipformat = RegisterClipboardFormatA(format_name);
422 HeapFree(GetProcessHeap(), 0, format_name);
423 }
424 return S_OK;
425 }
426
427 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
428 {
429 DWORD length;
430 HRESULT hr;
431
432 if (clipformat < 0xc000)
433 length = -1;
434 else
435 length = GetClipboardFormatNameA(clipformat, NULL, 0);
436 hr = IStream_Write(stream, &length, sizeof(length), NULL);
437 if (FAILED(hr))
438 return hr;
439 if (clipformat < 0xc000)
440 {
441 DWORD cf = clipformat;
442 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
443 }
444 else
445 {
446 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
447 if (!format_name)
448 return E_OUTOFMEMORY;
449 GetClipboardFormatNameA(clipformat, format_name, length);
450 hr = IStream_Write(stream, format_name, length, NULL);
451 HeapFree(GetProcessHeap(), 0, format_name);
452 }
453 return hr;
454 }
455
456 /************************************************************************
457 * DataCacheEntry_OpenPresStream
458 *
459 * This method will find the stream for the given presentation. It makes
460 * no attempt at fallback.
461 *
462 * Param:
463 * this - Pointer to the DataCache object
464 * drawAspect - The aspect of the object that we wish to draw.
465 * pStm - A returned stream. It points to the beginning of the
466 * - presentation data, including the header.
467 *
468 * Errors:
469 * S_OK The requested stream has been opened.
470 * OLE_E_BLANK The requested stream could not be found.
471 * Quite a few others I'm too lazy to map correctly.
472 *
473 * Notes:
474 * Algorithm: Scan the elements of the presentation storage, looking
475 * for presentation streams. For each presentation stream,
476 * load the header and check to see if the aspect matches.
477 *
478 * If a fallback is desired, just opening the first presentation stream
479 * is a possibility.
480 */
481 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
482 {
483 STATSTG elem;
484 IEnumSTATSTG *pEnum;
485 HRESULT hr;
486
487 if (!ppStm) return E_POINTER;
488
489 hr = IStorage_EnumElements(cache_entry->storage, 0, NULL, 0, &pEnum);
490 if (FAILED(hr)) return hr;
491
492 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
493 {
494 if (DataCache_IsPresentationStream(&elem))
495 {
496 IStream *pStm;
497
498 hr = IStorage_OpenStream(cache_entry->storage, elem.pwcsName,
499 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
500 &pStm);
501 if (SUCCEEDED(hr))
502 {
503 PresentationDataHeader header;
504 ULONG actual_read;
505 CLIPFORMAT clipformat;
506
507 hr = read_clipformat(pStm, &clipformat);
508
509 if (hr == S_OK)
510 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
511
512 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
513 if (hr == S_OK && actual_read == sizeof(header)
514 && header.dvAspect == cache_entry->fmtetc.dwAspect)
515 {
516 /* Rewind the stream before returning it. */
517 LARGE_INTEGER offset;
518 offset.u.LowPart = 0;
519 offset.u.HighPart = 0;
520 IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
521
522 *ppStm = pStm;
523
524 CoTaskMemFree(elem.pwcsName);
525 IEnumSTATSTG_Release(pEnum);
526
527 return S_OK;
528 }
529
530 IStream_Release(pStm);
531 }
532 }
533
534 CoTaskMemFree(elem.pwcsName);
535 }
536
537 IEnumSTATSTG_Release(pEnum);
538
539 return (hr == S_FALSE ? OLE_E_BLANK : hr);
540 }
541
542 /************************************************************************
543 * DataCacheEntry_LoadData
544 *
545 * This method will read information for the requested presentation
546 * into the given structure.
547 *
548 * Param:
549 * This - The entry to load the data from.
550 *
551 * Returns:
552 * This method returns a metafile handle if it is successful.
553 * it will return 0 if not.
554 */
555 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
556 {
557 IStream* presStream = NULL;
558 HRESULT hres;
559 ULARGE_INTEGER current_pos;
560 STATSTG streamInfo;
561 void* metafileBits;
562 METAFILEPICT *mfpict;
563 HGLOBAL hmfpict;
564 PresentationDataHeader header;
565 CLIPFORMAT clipformat;
566 static const LARGE_INTEGER offset_zero;
567
568 /*
569 * Open the presentation stream.
570 */
571 hres = DataCacheEntry_OpenPresStream(cache_entry, &presStream);
572
573 if (FAILED(hres))
574 return hres;
575
576 /*
577 * Get the size of the stream.
578 */
579 hres = IStream_Stat(presStream,
580 &streamInfo,
581 STATFLAG_NONAME);
582
583 /*
584 * Read the header.
585 */
586
587 hres = read_clipformat(presStream, &clipformat);
588 if (FAILED(hres))
589 {
590 IStream_Release(presStream);
591 return hres;
592 }
593
594 hres = IStream_Read(
595 presStream,
596 &header,
597 sizeof(PresentationDataHeader),
598 NULL);
599 if (hres != S_OK)
600 {
601 IStream_Release(presStream);
602 return E_FAIL;
603 }
604
605 hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, &current_pos);
606
607 streamInfo.cbSize.QuadPart -= current_pos.QuadPart;
608
609 hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
610 if (!hmfpict)
611 {
612 IStream_Release(presStream);
613 return E_OUTOFMEMORY;
614 }
615 mfpict = GlobalLock(hmfpict);
616
617 /*
618 * Allocate a buffer for the metafile bits.
619 */
620 metafileBits = HeapAlloc(GetProcessHeap(),
621 0,
622 streamInfo.cbSize.u.LowPart);
623
624 /*
625 * Read the metafile bits.
626 */
627 hres = IStream_Read(
628 presStream,
629 metafileBits,
630 streamInfo.cbSize.u.LowPart,
631 NULL);
632
633 /*
634 * Create a metafile with those bits.
635 */
636 if (SUCCEEDED(hres))
637 {
638 /* FIXME: get this from the stream */
639 mfpict->mm = MM_ANISOTROPIC;
640 mfpict->xExt = header.dwObjectExtentX;
641 mfpict->yExt = header.dwObjectExtentY;
642 mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
643 if (!mfpict->hMF)
644 hres = E_FAIL;
645 }
646
647 GlobalUnlock(hmfpict);
648 if (SUCCEEDED(hres))
649 {
650 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
651 cache_entry->stgmedium.tymed = TYMED_MFPICT;
652 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
653 }
654 else
655 GlobalFree(hmfpict);
656
657 /*
658 * Cleanup.
659 */
660 HeapFree(GetProcessHeap(), 0, metafileBits);
661 IStream_Release(presStream);
662
663 return hres;
664 }
665
666 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
667 IStorage *storage, IStream **stream)
668 {
669 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
670 '0' + (cache_entry->stream_number / 100) % 10,
671 '0' + (cache_entry->stream_number / 10) % 10,
672 '0' + cache_entry->stream_number % 10, 0};
673
674 /* FIXME: cache the created stream in This? */
675 return IStorage_CreateStream(storage, wszName,
676 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
677 0, 0, stream);
678 }
679
680 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
681 BOOL same_as_load)
682 {
683 PresentationDataHeader header;
684 HRESULT hr;
685 IStream *pres_stream;
686 void *data = NULL;
687
688 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
689
690 hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
691 if (FAILED(hr))
692 return hr;
693
694 hr = write_clipformat(pres_stream, cache_entry->data_cf);
695 if (FAILED(hr))
696 return hr;
697
698 if (cache_entry->fmtetc.ptd)
699 FIXME("ptd not serialized\n");
700 header.unknown3 = 4;
701 header.dvAspect = cache_entry->fmtetc.dwAspect;
702 header.lindex = cache_entry->fmtetc.lindex;
703 header.tymed = cache_entry->stgmedium.tymed;
704 header.unknown7 = 0;
705 header.dwObjectExtentX = 0;
706 header.dwObjectExtentY = 0;
707 header.dwSize = 0;
708
709 /* size the data */
710 switch (cache_entry->data_cf)
711 {
712 case CF_METAFILEPICT:
713 {
714 if (cache_entry->stgmedium.tymed != TYMED_NULL)
715 {
716 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
717 if (!mfpict)
718 {
719 IStream_Release(pres_stream);
720 return DV_E_STGMEDIUM;
721 }
722 header.dwObjectExtentX = mfpict->xExt;
723 header.dwObjectExtentY = mfpict->yExt;
724 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
725 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
726 }
727 break;
728 }
729 default:
730 break;
731 }
732
733 /*
734 * Write the header.
735 */
736 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
737 NULL);
738 if (FAILED(hr))
739 {
740 IStream_Release(pres_stream);
741 return hr;
742 }
743
744 /* get the data */
745 switch (cache_entry->data_cf)
746 {
747 case CF_METAFILEPICT:
748 {
749 if (cache_entry->stgmedium.tymed != TYMED_NULL)
750 {
751 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
752 if (!mfpict)
753 {
754 IStream_Release(pres_stream);
755 return DV_E_STGMEDIUM;
756 }
757 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
758 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
759 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
760 }
761 break;
762 }
763 default:
764 break;
765 }
766
767 if (data)
768 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
769 HeapFree(GetProcessHeap(), 0, data);
770
771 IStream_Release(pres_stream);
772 return hr;
773 }
774
775 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
776 * does no checking of whether src_stgm has a supported tymed, so this should be
777 * done in the caller */
778 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
779 const STGMEDIUM *src_stgm)
780 {
781 if (src_stgm->tymed == TYMED_MFPICT)
782 {
783 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
784 METAFILEPICT *dest_mfpict;
785
786 if (!src_mfpict)
787 return DV_E_STGMEDIUM;
788 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
789 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
790 if (!dest_mfpict)
791 {
792 GlobalUnlock(src_stgm->u.hMetaFilePict);
793 return E_OUTOFMEMORY;
794 }
795 *dest_mfpict = *src_mfpict;
796 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
797 GlobalUnlock(src_stgm->u.hMetaFilePict);
798 GlobalUnlock(dest_stgm->u.hMetaFilePict);
799 }
800 else if (src_stgm->tymed != TYMED_NULL)
801 {
802 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
803 GMEM_MOVEABLE);
804 if (!dest_stgm->u.hGlobal)
805 return E_OUTOFMEMORY;
806 }
807 dest_stgm->tymed = src_stgm->tymed;
808 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
809 if (dest_stgm->pUnkForRelease)
810 IUnknown_AddRef(dest_stgm->pUnkForRelease);
811 return S_OK;
812 }
813
814 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
815 const FORMATETC *formatetc,
816 const STGMEDIUM *stgmedium,
817 BOOL fRelease)
818 {
819 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
820 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
821 stgmedium->tymed == TYMED_NULL)
822 {
823 WARN("invalid formatetc\n");
824 return DV_E_FORMATETC;
825 }
826
827 cache_entry->dirty = TRUE;
828 ReleaseStgMedium(&cache_entry->stgmedium);
829 cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
830 if (fRelease)
831 {
832 cache_entry->stgmedium = *stgmedium;
833 return S_OK;
834 }
835 else
836 return copy_stg_medium(cache_entry->data_cf,
837 &cache_entry->stgmedium, stgmedium);
838 }
839
840 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
841 {
842 if (stgmedium->tymed == TYMED_NULL && cache_entry->storage)
843 {
844 HRESULT hr = DataCacheEntry_LoadData(cache_entry);
845 if (FAILED(hr))
846 return hr;
847 }
848 if (cache_entry->stgmedium.tymed == TYMED_NULL)
849 return OLE_E_BLANK;
850 return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
851 }
852
853 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
854 {
855 ReleaseStgMedium(&cache_entry->stgmedium);
856 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
857 return S_OK;
858 }
859
860 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
861 {
862 if (cache_entry->storage)
863 {
864 IStorage_Release(cache_entry->storage);
865 cache_entry->storage = NULL;
866 }
867 }
868
869 /*********************************************************
870 * Method implementation for the non delegating IUnknown
871 * part of the DataCache class.
872 */
873
874 /************************************************************************
875 * DataCache_NDIUnknown_QueryInterface (IUnknown)
876 *
877 * This version of QueryInterface will not delegate its implementation
878 * to the outer unknown.
879 */
880 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
881 IUnknown* iface,
882 REFIID riid,
883 void** ppvObject)
884 {
885 DataCache *this = impl_from_IUnknown(iface);
886
887 if ( ppvObject==0 )
888 return E_INVALIDARG;
889
890 *ppvObject = 0;
891
892 if (IsEqualIID(&IID_IUnknown, riid))
893 {
894 *ppvObject = iface;
895 }
896 else if (IsEqualIID(&IID_IDataObject, riid))
897 {
898 *ppvObject = &this->IDataObject_iface;
899 }
900 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
901 IsEqualIID(&IID_IPersist, riid) )
902 {
903 *ppvObject = &this->IPersistStorage_iface;
904 }
905 else if ( IsEqualIID(&IID_IViewObject, riid) ||
906 IsEqualIID(&IID_IViewObject2, riid) )
907 {
908 *ppvObject = &this->IViewObject2_iface;
909 }
910 else if ( IsEqualIID(&IID_IOleCache, riid) ||
911 IsEqualIID(&IID_IOleCache2, riid) )
912 {
913 *ppvObject = &this->IOleCache2_iface;
914 }
915 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
916 {
917 *ppvObject = &this->IOleCacheControl_iface;
918 }
919
920 if ((*ppvObject)==0)
921 {
922 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
923 return E_NOINTERFACE;
924 }
925
926 IUnknown_AddRef((IUnknown*)*ppvObject);
927
928 return S_OK;
929 }
930
931 /************************************************************************
932 * DataCache_NDIUnknown_AddRef (IUnknown)
933 *
934 * This version of QueryInterface will not delegate its implementation
935 * to the outer unknown.
936 */
937 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
938 IUnknown* iface)
939 {
940 DataCache *this = impl_from_IUnknown(iface);
941 return InterlockedIncrement(&this->ref);
942 }
943
944 /************************************************************************
945 * DataCache_NDIUnknown_Release (IUnknown)
946 *
947 * This version of QueryInterface will not delegate its implementation
948 * to the outer unknown.
949 */
950 static ULONG WINAPI DataCache_NDIUnknown_Release(
951 IUnknown* iface)
952 {
953 DataCache *this = impl_from_IUnknown(iface);
954 ULONG ref;
955
956 ref = InterlockedDecrement(&this->ref);
957
958 if (ref == 0) DataCache_Destroy(this);
959
960 return ref;
961 }
962
963 /*********************************************************
964 * Method implementation for the IDataObject
965 * part of the DataCache class.
966 */
967
968 /************************************************************************
969 * DataCache_IDataObject_QueryInterface (IUnknown)
970 */
971 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
972 IDataObject* iface,
973 REFIID riid,
974 void** ppvObject)
975 {
976 DataCache *this = impl_from_IDataObject(iface);
977
978 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
979 }
980
981 /************************************************************************
982 * DataCache_IDataObject_AddRef (IUnknown)
983 */
984 static ULONG WINAPI DataCache_IDataObject_AddRef(
985 IDataObject* iface)
986 {
987 DataCache *this = impl_from_IDataObject(iface);
988
989 return IUnknown_AddRef(this->outerUnknown);
990 }
991
992 /************************************************************************
993 * DataCache_IDataObject_Release (IUnknown)
994 */
995 static ULONG WINAPI DataCache_IDataObject_Release(
996 IDataObject* iface)
997 {
998 DataCache *this = impl_from_IDataObject(iface);
999
1000 return IUnknown_Release(this->outerUnknown);
1001 }
1002
1003 /************************************************************************
1004 * DataCache_GetData
1005 *
1006 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1007 */
1008 static HRESULT WINAPI DataCache_GetData(
1009 IDataObject* iface,
1010 LPFORMATETC pformatetcIn,
1011 STGMEDIUM* pmedium)
1012 {
1013 DataCache *This = impl_from_IDataObject(iface);
1014 DataCacheEntry *cache_entry;
1015
1016 memset(pmedium, 0, sizeof(*pmedium));
1017
1018 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1019 if (!cache_entry)
1020 return OLE_E_BLANK;
1021
1022 return DataCacheEntry_GetData(cache_entry, pmedium);
1023 }
1024
1025 static HRESULT WINAPI DataCache_GetDataHere(
1026 IDataObject* iface,
1027 LPFORMATETC pformatetc,
1028 STGMEDIUM* pmedium)
1029 {
1030 FIXME("stub\n");
1031 return E_NOTIMPL;
1032 }
1033
1034 static HRESULT WINAPI DataCache_QueryGetData(
1035 IDataObject* iface,
1036 LPFORMATETC pformatetc)
1037 {
1038 FIXME("stub\n");
1039 return E_NOTIMPL;
1040 }
1041
1042 /************************************************************************
1043 * DataCache_EnumFormatEtc (IDataObject)
1044 *
1045 * The data cache doesn't implement this method.
1046 */
1047 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1048 IDataObject* iface,
1049 LPFORMATETC pformatectIn,
1050 LPFORMATETC pformatetcOut)
1051 {
1052 TRACE("()\n");
1053 return E_NOTIMPL;
1054 }
1055
1056 /************************************************************************
1057 * DataCache_IDataObject_SetData (IDataObject)
1058 *
1059 * This method is delegated to the IOleCache2 implementation.
1060 */
1061 static HRESULT WINAPI DataCache_IDataObject_SetData(
1062 IDataObject* iface,
1063 LPFORMATETC pformatetc,
1064 STGMEDIUM* pmedium,
1065 BOOL fRelease)
1066 {
1067 IOleCache2* oleCache = NULL;
1068 HRESULT hres;
1069
1070 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1071
1072 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1073
1074 if (FAILED(hres))
1075 return E_UNEXPECTED;
1076
1077 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1078
1079 IOleCache2_Release(oleCache);
1080
1081 return hres;
1082 }
1083
1084 /************************************************************************
1085 * DataCache_EnumFormatEtc (IDataObject)
1086 *
1087 * The data cache doesn't implement this method.
1088 */
1089 static HRESULT WINAPI DataCache_EnumFormatEtc(
1090 IDataObject* iface,
1091 DWORD dwDirection,
1092 IEnumFORMATETC** ppenumFormatEtc)
1093 {
1094 TRACE("()\n");
1095 return E_NOTIMPL;
1096 }
1097
1098 /************************************************************************
1099 * DataCache_DAdvise (IDataObject)
1100 *
1101 * The data cache doesn't support connections.
1102 */
1103 static HRESULT WINAPI DataCache_DAdvise(
1104 IDataObject* iface,
1105 FORMATETC* pformatetc,
1106 DWORD advf,
1107 IAdviseSink* pAdvSink,
1108 DWORD* pdwConnection)
1109 {
1110 TRACE("()\n");
1111 return OLE_E_ADVISENOTSUPPORTED;
1112 }
1113
1114 /************************************************************************
1115 * DataCache_DUnadvise (IDataObject)
1116 *
1117 * The data cache doesn't support connections.
1118 */
1119 static HRESULT WINAPI DataCache_DUnadvise(
1120 IDataObject* iface,
1121 DWORD dwConnection)
1122 {
1123 TRACE("()\n");
1124 return OLE_E_NOCONNECTION;
1125 }
1126
1127 /************************************************************************
1128 * DataCache_EnumDAdvise (IDataObject)
1129 *
1130 * The data cache doesn't support connections.
1131 */
1132 static HRESULT WINAPI DataCache_EnumDAdvise(
1133 IDataObject* iface,
1134 IEnumSTATDATA** ppenumAdvise)
1135 {
1136 TRACE("()\n");
1137 return OLE_E_ADVISENOTSUPPORTED;
1138 }
1139
1140 /*********************************************************
1141 * Method implementation for the IDataObject
1142 * part of the DataCache class.
1143 */
1144
1145 /************************************************************************
1146 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1147 */
1148 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1149 IPersistStorage* iface,
1150 REFIID riid,
1151 void** ppvObject)
1152 {
1153 DataCache *this = impl_from_IPersistStorage(iface);
1154
1155 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1156 }
1157
1158 /************************************************************************
1159 * DataCache_IPersistStorage_AddRef (IUnknown)
1160 */
1161 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1162 IPersistStorage* iface)
1163 {
1164 DataCache *this = impl_from_IPersistStorage(iface);
1165
1166 return IUnknown_AddRef(this->outerUnknown);
1167 }
1168
1169 /************************************************************************
1170 * DataCache_IPersistStorage_Release (IUnknown)
1171 */
1172 static ULONG WINAPI DataCache_IPersistStorage_Release(
1173 IPersistStorage* iface)
1174 {
1175 DataCache *this = impl_from_IPersistStorage(iface);
1176
1177 return IUnknown_Release(this->outerUnknown);
1178 }
1179
1180 /************************************************************************
1181 * DataCache_GetClassID (IPersistStorage)
1182 *
1183 * The data cache doesn't implement this method.
1184 */
1185 static HRESULT WINAPI DataCache_GetClassID(
1186 IPersistStorage* iface,
1187 CLSID* pClassID)
1188 {
1189 DataCache *This = impl_from_IPersistStorage(iface);
1190 DataCacheEntry *cache_entry;
1191
1192 TRACE("(%p, %p)\n", iface, pClassID);
1193
1194 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1195 {
1196 if (cache_entry->storage != NULL)
1197 {
1198 STATSTG statstg;
1199 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1200 if (SUCCEEDED(hr))
1201 {
1202 *pClassID = statstg.clsid;
1203 return S_OK;
1204 }
1205 }
1206 }
1207
1208 *pClassID = CLSID_NULL;
1209
1210 return S_OK;
1211 }
1212
1213 /************************************************************************
1214 * DataCache_IsDirty (IPersistStorage)
1215 */
1216 static HRESULT WINAPI DataCache_IsDirty(
1217 IPersistStorage* iface)
1218 {
1219 DataCache *This = impl_from_IPersistStorage(iface);
1220 DataCacheEntry *cache_entry;
1221
1222 TRACE("(%p)\n", iface);
1223
1224 if (This->dirty)
1225 return S_OK;
1226
1227 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1228 if (cache_entry->dirty)
1229 return S_OK;
1230
1231 return S_FALSE;
1232 }
1233
1234 /************************************************************************
1235 * DataCache_InitNew (IPersistStorage)
1236 *
1237 * The data cache implementation of IPersistStorage_InitNew simply stores
1238 * the storage pointer.
1239 */
1240 static HRESULT WINAPI DataCache_InitNew(
1241 IPersistStorage* iface,
1242 IStorage* pStg)
1243 {
1244 DataCache *This = impl_from_IPersistStorage(iface);
1245
1246 TRACE("(%p, %p)\n", iface, pStg);
1247
1248 if (This->presentationStorage != NULL)
1249 IStorage_Release(This->presentationStorage);
1250
1251 This->presentationStorage = pStg;
1252
1253 IStorage_AddRef(This->presentationStorage);
1254 This->dirty = TRUE;
1255
1256 return S_OK;
1257 }
1258
1259 /************************************************************************
1260 * DataCache_Load (IPersistStorage)
1261 *
1262 * The data cache implementation of IPersistStorage_Load doesn't
1263 * actually load anything. Instead, it holds on to the storage pointer
1264 * and it will load the presentation information when the
1265 * IDataObject_GetData or IViewObject2_Draw methods are called.
1266 */
1267 static HRESULT WINAPI DataCache_Load(
1268 IPersistStorage* iface,
1269 IStorage* pStg)
1270 {
1271 DataCache *This = impl_from_IPersistStorage(iface);
1272 STATSTG elem;
1273 IEnumSTATSTG *pEnum;
1274 HRESULT hr;
1275
1276 TRACE("(%p, %p)\n", iface, pStg);
1277
1278 if (This->presentationStorage != NULL)
1279 IStorage_Release(This->presentationStorage);
1280
1281 This->presentationStorage = pStg;
1282
1283 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1284 if (FAILED(hr)) return hr;
1285
1286 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1287 {
1288 if (DataCache_IsPresentationStream(&elem))
1289 {
1290 IStream *pStm;
1291
1292 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1293 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1294 &pStm);
1295 if (SUCCEEDED(hr))
1296 {
1297 PresentationDataHeader header;
1298 ULONG actual_read;
1299 CLIPFORMAT clipformat;
1300
1301 hr = read_clipformat(pStm, &clipformat);
1302
1303 if (hr == S_OK)
1304 hr = IStream_Read(pStm, &header, sizeof(header),
1305 &actual_read);
1306
1307 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1308 if (hr == S_OK && actual_read == sizeof(header))
1309 {
1310 DataCacheEntry *cache_entry;
1311 FORMATETC fmtetc;
1312
1313 fmtetc.cfFormat = clipformat;
1314 fmtetc.ptd = NULL; /* FIXME */
1315 fmtetc.dwAspect = header.dvAspect;
1316 fmtetc.lindex = header.lindex;
1317 fmtetc.tymed = header.tymed;
1318
1319 TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1320
1321 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1322 if (!cache_entry)
1323 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1324 if (SUCCEEDED(hr))
1325 {
1326 DataCacheEntry_DiscardData(cache_entry);
1327 if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1328 cache_entry->storage = pStg;
1329 IStorage_AddRef(pStg);
1330 cache_entry->dirty = FALSE;
1331 }
1332 }
1333
1334 IStream_Release(pStm);
1335 }
1336 }
1337
1338 CoTaskMemFree(elem.pwcsName);
1339 }
1340
1341 This->dirty = FALSE;
1342
1343 IEnumSTATSTG_Release(pEnum);
1344
1345 IStorage_AddRef(This->presentationStorage);
1346 return S_OK;
1347 }
1348
1349 /************************************************************************
1350 * DataCache_Save (IPersistStorage)
1351 *
1352 * Until we actually connect to a running object and retrieve new
1353 * information to it, we never have to save anything. However, it is
1354 * our responsibility to copy the information when saving to a new
1355 * storage.
1356 */
1357 static HRESULT WINAPI DataCache_Save(
1358 IPersistStorage* iface,
1359 IStorage* pStg,
1360 BOOL fSameAsLoad)
1361 {
1362 DataCache *This = impl_from_IPersistStorage(iface);
1363 DataCacheEntry *cache_entry;
1364 BOOL dirty = FALSE;
1365 HRESULT hr = S_OK;
1366 unsigned short stream_number = 0;
1367
1368 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1369
1370 dirty = This->dirty;
1371 if (!dirty)
1372 {
1373 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1374 {
1375 dirty = cache_entry->dirty;
1376 if (dirty)
1377 break;
1378 }
1379 }
1380
1381 /* this is a shortcut if nothing changed */
1382 if (!dirty && !fSameAsLoad && This->presentationStorage)
1383 {
1384 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1385 }
1386
1387 /* assign stream numbers to the cache entries */
1388 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1389 {
1390 if (cache_entry->stream_number != stream_number)
1391 {
1392 cache_entry->dirty = TRUE; /* needs to be written out again */
1393 cache_entry->stream_number = stream_number;
1394 }
1395 stream_number++;
1396 }
1397
1398 /* write out the cache entries */
1399 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1400 {
1401 if (!fSameAsLoad || cache_entry->dirty)
1402 {
1403 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1404 if (FAILED(hr))
1405 break;
1406
1407 cache_entry->dirty = FALSE;
1408 }
1409 }
1410
1411 This->dirty = FALSE;
1412 return hr;
1413 }
1414
1415 /************************************************************************
1416 * DataCache_SaveCompleted (IPersistStorage)
1417 *
1418 * This method is called to tell the cache to release the storage
1419 * pointer it's currently holding.
1420 */
1421 static HRESULT WINAPI DataCache_SaveCompleted(
1422 IPersistStorage* iface,
1423 IStorage* pStgNew)
1424 {
1425 TRACE("(%p, %p)\n", iface, pStgNew);
1426
1427 if (pStgNew)
1428 {
1429 IPersistStorage_HandsOffStorage(iface);
1430
1431 DataCache_Load(iface, pStgNew);
1432 }
1433
1434 return S_OK;
1435 }
1436
1437 /************************************************************************
1438 * DataCache_HandsOffStorage (IPersistStorage)
1439 *
1440 * This method is called to tell the cache to release the storage
1441 * pointer it's currently holding.
1442 */
1443 static HRESULT WINAPI DataCache_HandsOffStorage(
1444 IPersistStorage* iface)
1445 {
1446 DataCache *this = impl_from_IPersistStorage(iface);
1447 DataCacheEntry *cache_entry;
1448
1449 TRACE("(%p)\n", iface);
1450
1451 if (this->presentationStorage != NULL)
1452 {
1453 IStorage_Release(this->presentationStorage);
1454 this->presentationStorage = NULL;
1455 }
1456
1457 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1458 DataCacheEntry_HandsOffStorage(cache_entry);
1459
1460 return S_OK;
1461 }
1462
1463 /*********************************************************
1464 * Method implementation for the IViewObject2
1465 * part of the DataCache class.
1466 */
1467
1468 /************************************************************************
1469 * DataCache_IViewObject2_QueryInterface (IUnknown)
1470 */
1471 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1472 IViewObject2* iface,
1473 REFIID riid,
1474 void** ppvObject)
1475 {
1476 DataCache *this = impl_from_IViewObject2(iface);
1477
1478 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1479 }
1480
1481 /************************************************************************
1482 * DataCache_IViewObject2_AddRef (IUnknown)
1483 */
1484 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1485 IViewObject2* iface)
1486 {
1487 DataCache *this = impl_from_IViewObject2(iface);
1488
1489 return IUnknown_AddRef(this->outerUnknown);
1490 }
1491
1492 /************************************************************************
1493 * DataCache_IViewObject2_Release (IUnknown)
1494 */
1495 static ULONG WINAPI DataCache_IViewObject2_Release(
1496 IViewObject2* iface)
1497 {
1498 DataCache *this = impl_from_IViewObject2(iface);
1499
1500 return IUnknown_Release(this->outerUnknown);
1501 }
1502
1503 /************************************************************************
1504 * DataCache_Draw (IViewObject2)
1505 *
1506 * This method will draw the cached representation of the object
1507 * to the given device context.
1508 */
1509 static HRESULT WINAPI DataCache_Draw(
1510 IViewObject2* iface,
1511 DWORD dwDrawAspect,
1512 LONG lindex,
1513 void* pvAspect,
1514 DVTARGETDEVICE* ptd,
1515 HDC hdcTargetDev,
1516 HDC hdcDraw,
1517 LPCRECTL lprcBounds,
1518 LPCRECTL lprcWBounds,
1519 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1520 ULONG_PTR dwContinue)
1521 {
1522 DataCache *This = impl_from_IViewObject2(iface);
1523 HRESULT hres;
1524 DataCacheEntry *cache_entry;
1525
1526 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1527 iface,
1528 dwDrawAspect,
1529 lindex,
1530 pvAspect,
1531 hdcTargetDev,
1532 hdcDraw,
1533 lprcBounds,
1534 lprcWBounds,
1535 pfnContinue,
1536 dwContinue);
1537
1538 if (lprcBounds==NULL)
1539 return E_INVALIDARG;
1540
1541 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1542 {
1543 /* FIXME: compare ptd too */
1544 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1545 (cache_entry->fmtetc.lindex != lindex))
1546 continue;
1547
1548 /* if the data hasn't been loaded yet, do it now */
1549 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1550 {
1551 hres = DataCacheEntry_LoadData(cache_entry);
1552 if (FAILED(hres))
1553 continue;
1554 }
1555
1556 /* no data */
1557 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1558 continue;
1559
1560 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1561
1562 switch (cache_entry->data_cf)
1563 {
1564 case CF_METAFILEPICT:
1565 {
1566 /*
1567 * We have to be careful not to modify the state of the
1568 * DC.
1569 */
1570 INT prevMapMode;
1571 SIZE oldWindowExt;
1572 SIZE oldViewportExt;
1573 POINT oldViewportOrg;
1574 METAFILEPICT *mfpict;
1575
1576 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1577 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1578 continue;
1579
1580 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1581
1582 SetWindowExtEx(hdcDraw,
1583 mfpict->xExt,
1584 mfpict->yExt,
1585 &oldWindowExt);
1586
1587 SetViewportExtEx(hdcDraw,
1588 lprcBounds->right - lprcBounds->left,
1589 lprcBounds->bottom - lprcBounds->top,
1590 &oldViewportExt);
1591
1592 SetViewportOrgEx(hdcDraw,
1593 lprcBounds->left,
1594 lprcBounds->top,
1595 &oldViewportOrg);
1596
1597 PlayMetaFile(hdcDraw, mfpict->hMF);
1598
1599 SetWindowExtEx(hdcDraw,
1600 oldWindowExt.cx,
1601 oldWindowExt.cy,
1602 NULL);
1603
1604 SetViewportExtEx(hdcDraw,
1605 oldViewportExt.cx,
1606 oldViewportExt.cy,
1607 NULL);
1608
1609 SetViewportOrgEx(hdcDraw,
1610 oldViewportOrg.x,
1611 oldViewportOrg.y,
1612 NULL);
1613
1614 SetMapMode(hdcDraw, prevMapMode);
1615
1616 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1617
1618 return S_OK;
1619 }
1620 }
1621 }
1622
1623 WARN("no data could be found to be drawn\n");
1624
1625 return OLE_E_BLANK;
1626 }
1627
1628 static HRESULT WINAPI DataCache_GetColorSet(
1629 IViewObject2* iface,
1630 DWORD dwDrawAspect,
1631 LONG lindex,
1632 void* pvAspect,
1633 DVTARGETDEVICE* ptd,
1634 HDC hicTargetDevice,
1635 LOGPALETTE** ppColorSet)
1636 {
1637 FIXME("stub\n");
1638 return E_NOTIMPL;
1639 }
1640
1641 static HRESULT WINAPI DataCache_Freeze(
1642 IViewObject2* iface,
1643 DWORD dwDrawAspect,
1644 LONG lindex,
1645 void* pvAspect,
1646 DWORD* pdwFreeze)
1647 {
1648 FIXME("stub\n");
1649 return E_NOTIMPL;
1650 }
1651
1652 static HRESULT WINAPI DataCache_Unfreeze(
1653 IViewObject2* iface,
1654 DWORD dwFreeze)
1655 {
1656 FIXME("stub\n");
1657 return E_NOTIMPL;
1658 }
1659
1660 /************************************************************************
1661 * DataCache_SetAdvise (IViewObject2)
1662 *
1663 * This sets-up an advisory sink with the data cache. When the object's
1664 * view changes, this sink is called.
1665 */
1666 static HRESULT WINAPI DataCache_SetAdvise(
1667 IViewObject2* iface,
1668 DWORD aspects,
1669 DWORD advf,
1670 IAdviseSink* pAdvSink)
1671 {
1672 DataCache *this = impl_from_IViewObject2(iface);
1673
1674 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1675
1676 /*
1677 * A call to this function removes the previous sink
1678 */
1679 if (this->sinkInterface != NULL)
1680 {
1681 IAdviseSink_Release(this->sinkInterface);
1682 this->sinkInterface = NULL;
1683 this->sinkAspects = 0;
1684 this->sinkAdviseFlag = 0;
1685 }
1686
1687 /*
1688 * Now, setup the new one.
1689 */
1690 if (pAdvSink!=NULL)
1691 {
1692 this->sinkInterface = pAdvSink;
1693 this->sinkAspects = aspects;
1694 this->sinkAdviseFlag = advf;
1695
1696 IAdviseSink_AddRef(this->sinkInterface);
1697 }
1698
1699 /*
1700 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1701 * sink immediately.
1702 */
1703 if (advf & ADVF_PRIMEFIRST)
1704 {
1705 DataCache_FireOnViewChange(this, aspects, -1);
1706 }
1707
1708 return S_OK;
1709 }
1710
1711 /************************************************************************
1712 * DataCache_GetAdvise (IViewObject2)
1713 *
1714 * This method queries the current state of the advise sink
1715 * installed on the data cache.
1716 */
1717 static HRESULT WINAPI DataCache_GetAdvise(
1718 IViewObject2* iface,
1719 DWORD* pAspects,
1720 DWORD* pAdvf,
1721 IAdviseSink** ppAdvSink)
1722 {
1723 DataCache *this = impl_from_IViewObject2(iface);
1724
1725 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1726
1727 /*
1728 * Just copy all the requested values.
1729 */
1730 if (pAspects!=NULL)
1731 *pAspects = this->sinkAspects;
1732
1733 if (pAdvf!=NULL)
1734 *pAdvf = this->sinkAdviseFlag;
1735
1736 if (ppAdvSink!=NULL)
1737 {
1738 if (this->sinkInterface != NULL)
1739 IAdviseSink_QueryInterface(this->sinkInterface,
1740 &IID_IAdviseSink,
1741 (void**)ppAdvSink);
1742 else *ppAdvSink = NULL;
1743 }
1744
1745 return S_OK;
1746 }
1747
1748 /************************************************************************
1749 * DataCache_GetExtent (IViewObject2)
1750 *
1751 * This method retrieves the "natural" size of this cached object.
1752 */
1753 static HRESULT WINAPI DataCache_GetExtent(
1754 IViewObject2* iface,
1755 DWORD dwDrawAspect,
1756 LONG lindex,
1757 DVTARGETDEVICE* ptd,
1758 LPSIZEL lpsizel)
1759 {
1760 DataCache *This = impl_from_IViewObject2(iface);
1761 HRESULT hres = E_FAIL;
1762 DataCacheEntry *cache_entry;
1763
1764 TRACE("(%p, %x, %d, %p, %p)\n",
1765 iface, dwDrawAspect, lindex, ptd, lpsizel);
1766
1767 if (lpsizel==NULL)
1768 return E_POINTER;
1769
1770 lpsizel->cx = 0;
1771 lpsizel->cy = 0;
1772
1773 if (lindex!=-1)
1774 FIXME("Unimplemented flag lindex = %d\n", lindex);
1775
1776 /*
1777 * Right now, we support only the callback from
1778 * the default handler.
1779 */
1780 if (ptd!=NULL)
1781 FIXME("Unimplemented ptd = %p\n", ptd);
1782
1783 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1784 {
1785 /* FIXME: compare ptd too */
1786 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1787 (cache_entry->fmtetc.lindex != lindex))
1788 continue;
1789
1790 /* if the data hasn't been loaded yet, do it now */
1791 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1792 {
1793 hres = DataCacheEntry_LoadData(cache_entry);
1794 if (FAILED(hres))
1795 continue;
1796 }
1797
1798 /* no data */
1799 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1800 continue;
1801
1802
1803 switch (cache_entry->data_cf)
1804 {
1805 case CF_METAFILEPICT:
1806 {
1807 METAFILEPICT *mfpict;
1808
1809 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1810 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1811 continue;
1812
1813 lpsizel->cx = mfpict->xExt;
1814 lpsizel->cy = mfpict->yExt;
1815
1816 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1817
1818 return S_OK;
1819 }
1820 }
1821 }
1822
1823 WARN("no data could be found to get the extents from\n");
1824
1825 /*
1826 * This method returns OLE_E_BLANK when it fails.
1827 */
1828 return OLE_E_BLANK;
1829 }
1830
1831
1832 /*********************************************************
1833 * Method implementation for the IOleCache2
1834 * part of the DataCache class.
1835 */
1836
1837 /************************************************************************
1838 * DataCache_IOleCache2_QueryInterface (IUnknown)
1839 */
1840 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1841 IOleCache2* iface,
1842 REFIID riid,
1843 void** ppvObject)
1844 {
1845 DataCache *this = impl_from_IOleCache2(iface);
1846
1847 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1848 }
1849
1850 /************************************************************************
1851 * DataCache_IOleCache2_AddRef (IUnknown)
1852 */
1853 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1854 IOleCache2* iface)
1855 {
1856 DataCache *this = impl_from_IOleCache2(iface);
1857
1858 return IUnknown_AddRef(this->outerUnknown);
1859 }
1860
1861 /************************************************************************
1862 * DataCache_IOleCache2_Release (IUnknown)
1863 */
1864 static ULONG WINAPI DataCache_IOleCache2_Release(
1865 IOleCache2* iface)
1866 {
1867 DataCache *this = impl_from_IOleCache2(iface);
1868
1869 return IUnknown_Release(this->outerUnknown);
1870 }
1871
1872 /*****************************************************************************
1873 * setup_sink
1874 *
1875 * Set up the sink connection to the running object.
1876 */
1877 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
1878 {
1879 HRESULT hr = S_FALSE;
1880 DWORD flags;
1881
1882 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
1883 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
1884
1885 if(This->running_object)
1886 if(!(flags & ADVF_NODATA))
1887 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
1888 &This->IAdviseSink_iface, &cache_entry->sink_id);
1889 return hr;
1890 }
1891
1892 static HRESULT WINAPI DataCache_Cache(
1893 IOleCache2* iface,
1894 FORMATETC* pformatetc,
1895 DWORD advf,
1896 DWORD* pdwConnection)
1897 {
1898 DataCache *This = impl_from_IOleCache2(iface);
1899 DataCacheEntry *cache_entry;
1900 HRESULT hr;
1901
1902 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1903
1904 if (!pformatetc || !pdwConnection)
1905 return E_INVALIDARG;
1906
1907 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1908
1909 *pdwConnection = 0;
1910
1911 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1912 if (cache_entry)
1913 {
1914 TRACE("found an existing cache entry\n");
1915 *pdwConnection = cache_entry->id;
1916 return CACHE_S_SAMECACHE;
1917 }
1918
1919 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1920
1921 if (SUCCEEDED(hr))
1922 {
1923 *pdwConnection = cache_entry->id;
1924 cache_entry->advise_flags = advf;
1925 setup_sink(This, cache_entry);
1926 }
1927
1928 return hr;
1929 }
1930
1931 static HRESULT WINAPI DataCache_Uncache(
1932 IOleCache2* iface,
1933 DWORD dwConnection)
1934 {
1935 DataCache *This = impl_from_IOleCache2(iface);
1936 DataCacheEntry *cache_entry;
1937
1938 TRACE("(%d)\n", dwConnection);
1939
1940 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1941 if (cache_entry->id == dwConnection)
1942 {
1943 DataCacheEntry_Destroy(This, cache_entry);
1944 return S_OK;
1945 }
1946
1947 WARN("no connection found for %d\n", dwConnection);
1948
1949 return OLE_E_NOCONNECTION;
1950 }
1951
1952 static HRESULT WINAPI DataCache_EnumCache(
1953 IOleCache2* iface,
1954 IEnumSTATDATA** ppenumSTATDATA)
1955 {
1956 FIXME("stub\n");
1957 return E_NOTIMPL;
1958 }
1959
1960 static HRESULT WINAPI DataCache_InitCache(
1961 IOleCache2* iface,
1962 IDataObject* pDataObject)
1963 {
1964 FIXME("stub\n");
1965 return E_NOTIMPL;
1966 }
1967
1968 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1969 IOleCache2* iface,
1970 FORMATETC* pformatetc,
1971 STGMEDIUM* pmedium,
1972 BOOL fRelease)
1973 {
1974 DataCache *This = impl_from_IOleCache2(iface);
1975 DataCacheEntry *cache_entry;
1976 HRESULT hr;
1977
1978 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
1979 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
1980
1981 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1982 if (cache_entry)
1983 {
1984 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
1985
1986 if (SUCCEEDED(hr))
1987 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
1988 cache_entry->fmtetc.lindex);
1989
1990 return hr;
1991 }
1992 WARN("cache entry not found\n");
1993
1994 return OLE_E_BLANK;
1995 }
1996
1997 static HRESULT WINAPI DataCache_UpdateCache(
1998 IOleCache2* iface,
1999 LPDATAOBJECT pDataObject,
2000 DWORD grfUpdf,
2001 LPVOID pReserved)
2002 {
2003 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2004 return E_NOTIMPL;
2005 }
2006
2007 static HRESULT WINAPI DataCache_DiscardCache(
2008 IOleCache2* iface,
2009 DWORD dwDiscardOptions)
2010 {
2011 DataCache *This = impl_from_IOleCache2(iface);
2012 DataCacheEntry *cache_entry;
2013 HRESULT hr = S_OK;
2014
2015 TRACE("(%d)\n", dwDiscardOptions);
2016
2017 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2018 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2019
2020 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2021 {
2022 hr = DataCacheEntry_DiscardData(cache_entry);
2023 if (FAILED(hr))
2024 break;
2025 }
2026
2027 return hr;
2028 }
2029
2030
2031 /*********************************************************
2032 * Method implementation for the IOleCacheControl
2033 * part of the DataCache class.
2034 */
2035
2036 /************************************************************************
2037 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2038 */
2039 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2040 IOleCacheControl* iface,
2041 REFIID riid,
2042 void** ppvObject)
2043 {
2044 DataCache *this = impl_from_IOleCacheControl(iface);
2045
2046 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2047 }
2048
2049 /************************************************************************
2050 * DataCache_IOleCacheControl_AddRef (IUnknown)
2051 */
2052 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2053 IOleCacheControl* iface)
2054 {
2055 DataCache *this = impl_from_IOleCacheControl(iface);
2056
2057 return IUnknown_AddRef(this->outerUnknown);
2058 }
2059
2060 /************************************************************************
2061 * DataCache_IOleCacheControl_Release (IUnknown)
2062 */
2063 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2064 IOleCacheControl* iface)
2065 {
2066 DataCache *this = impl_from_IOleCacheControl(iface);
2067
2068 return IUnknown_Release(this->outerUnknown);
2069 }
2070
2071 /************************************************************************
2072 * DataCache_OnRun (IOleCacheControl)
2073 */
2074 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2075 {
2076 DataCache *This = impl_from_IOleCacheControl(iface);
2077 DataCacheEntry *cache_entry;
2078
2079 TRACE("(%p)->(%p)\n", iface, data_obj);
2080
2081 if(This->running_object) return S_OK;
2082
2083 /* No reference is taken on the data object */
2084 This->running_object = data_obj;
2085
2086 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2087 {
2088 setup_sink(This, cache_entry);
2089 }
2090
2091 return S_OK;
2092 }
2093
2094 /************************************************************************
2095 * DataCache_OnStop (IOleCacheControl)
2096 */
2097 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2098 {
2099 DataCache *This = impl_from_IOleCacheControl(iface);
2100 DataCacheEntry *cache_entry;
2101
2102 TRACE("(%p)\n", iface);
2103
2104 if(!This->running_object) return S_OK;
2105
2106 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2107 {
2108 if(cache_entry->sink_id)
2109 {
2110 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2111 cache_entry->sink_id = 0;
2112 }
2113 }
2114
2115 /* No ref taken in OnRun, so no Release call here */
2116 This->running_object = NULL;
2117 return S_OK;
2118 }
2119
2120 /************************************************************************
2121 * IAdviseSink methods.
2122 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2123 * give access to the cache's other interfaces. We don't maintain a ref count,
2124 * the object exists as long as the cache is around.
2125 */
2126 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2127 {
2128 *obj = NULL;
2129 if (IsEqualIID(&IID_IUnknown, iid) ||
2130 IsEqualIID(&IID_IAdviseSink, iid))
2131 {
2132 *obj = iface;
2133 }
2134
2135 if(*obj)
2136 {
2137 IAdviseSink_AddRef(iface);
2138 return S_OK;
2139 }
2140 return E_NOINTERFACE;
2141 }
2142
2143 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2144 {
2145 return 2;
2146 }
2147
2148 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2149 {
2150 return 1;
2151 }
2152
2153 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2154 {
2155 DataCache *This = impl_from_IAdviseSink(iface);
2156 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2157 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2158 }
2159
2160 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2161 {
2162 FIXME("stub\n");
2163 }
2164
2165 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2166 {
2167 FIXME("stub\n");
2168 }
2169
2170 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2171 {
2172 FIXME("stub\n");
2173 }
2174
2175 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2176 {
2177 FIXME("stub\n");
2178 }
2179
2180 /*
2181 * Virtual function tables for the DataCache class.
2182 */
2183 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2184 {
2185 DataCache_NDIUnknown_QueryInterface,
2186 DataCache_NDIUnknown_AddRef,
2187 DataCache_NDIUnknown_Release
2188 };
2189
2190 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2191 {
2192 DataCache_IDataObject_QueryInterface,
2193 DataCache_IDataObject_AddRef,
2194 DataCache_IDataObject_Release,
2195 DataCache_GetData,
2196 DataCache_GetDataHere,
2197 DataCache_QueryGetData,
2198 DataCache_GetCanonicalFormatEtc,
2199 DataCache_IDataObject_SetData,
2200 DataCache_EnumFormatEtc,
2201 DataCache_DAdvise,
2202 DataCache_DUnadvise,
2203 DataCache_EnumDAdvise
2204 };
2205
2206 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2207 {
2208 DataCache_IPersistStorage_QueryInterface,
2209 DataCache_IPersistStorage_AddRef,
2210 DataCache_IPersistStorage_Release,
2211 DataCache_GetClassID,
2212 DataCache_IsDirty,
2213 DataCache_InitNew,
2214 DataCache_Load,
2215 DataCache_Save,
2216 DataCache_SaveCompleted,
2217 DataCache_HandsOffStorage
2218 };
2219
2220 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2221 {
2222 DataCache_IViewObject2_QueryInterface,
2223 DataCache_IViewObject2_AddRef,
2224 DataCache_IViewObject2_Release,
2225 DataCache_Draw,
2226 DataCache_GetColorSet,
2227 DataCache_Freeze,
2228 DataCache_Unfreeze,
2229 DataCache_SetAdvise,
2230 DataCache_GetAdvise,
2231 DataCache_GetExtent
2232 };
2233
2234 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2235 {
2236 DataCache_IOleCache2_QueryInterface,
2237 DataCache_IOleCache2_AddRef,
2238 DataCache_IOleCache2_Release,
2239 DataCache_Cache,
2240 DataCache_Uncache,
2241 DataCache_EnumCache,
2242 DataCache_InitCache,
2243 DataCache_IOleCache2_SetData,
2244 DataCache_UpdateCache,
2245 DataCache_DiscardCache
2246 };
2247
2248 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2249 {
2250 DataCache_IOleCacheControl_QueryInterface,
2251 DataCache_IOleCacheControl_AddRef,
2252 DataCache_IOleCacheControl_Release,
2253 DataCache_OnRun,
2254 DataCache_OnStop
2255 };
2256
2257 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2258 {
2259 DataCache_IAdviseSink_QueryInterface,
2260 DataCache_IAdviseSink_AddRef,
2261 DataCache_IAdviseSink_Release,
2262 DataCache_OnDataChange,
2263 DataCache_OnViewChange,
2264 DataCache_OnRename,
2265 DataCache_OnSave,
2266 DataCache_OnClose
2267 };
2268
2269 /*********************************************************
2270 * Method implementation for DataCache class.
2271 */
2272 static DataCache* DataCache_Construct(
2273 REFCLSID clsid,
2274 LPUNKNOWN pUnkOuter)
2275 {
2276 DataCache* newObject = 0;
2277
2278 /*
2279 * Allocate space for the object.
2280 */
2281 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2282
2283 if (newObject==0)
2284 return newObject;
2285
2286 /*
2287 * Initialize the virtual function table.
2288 */
2289 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2290 newObject->IUnknown_iface.lpVtbl = &DataCache_NDIUnknown_VTable;
2291 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2292 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2293 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2294 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2295 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2296
2297 /*
2298 * Start with one reference count. The caller of this function
2299 * must release the interface pointer when it is done.
2300 */
2301 newObject->ref = 1;
2302
2303 /*
2304 * Initialize the outer unknown
2305 * We don't keep a reference on the outer unknown since, the way
2306 * aggregation works, our lifetime is at least as large as its
2307 * lifetime.
2308 */
2309 if (pUnkOuter==NULL)
2310 pUnkOuter = &newObject->IUnknown_iface;
2311
2312 newObject->outerUnknown = pUnkOuter;
2313
2314 /*
2315 * Initialize the other members of the structure.
2316 */
2317 newObject->sinkAspects = 0;
2318 newObject->sinkAdviseFlag = 0;
2319 newObject->sinkInterface = 0;
2320 newObject->presentationStorage = NULL;
2321 list_init(&newObject->cache_list);
2322 newObject->last_cache_id = 1;
2323 newObject->dirty = FALSE;
2324 newObject->running_object = NULL;
2325
2326 return newObject;
2327 }
2328
2329 /******************************************************************************
2330 * CreateDataCache [OLE32.@]
2331 *
2332 * Creates a data cache to allow an object to render one or more of its views,
2333 * whether running or not.
2334 *
2335 * PARAMS
2336 * pUnkOuter [I] Outer unknown for the object.
2337 * rclsid [I]
2338 * riid [I] IID of interface to return.
2339 * ppvObj [O] Address where the data cache object will be stored on return.
2340 *
2341 * RETURNS
2342 * Success: S_OK.
2343 * Failure: HRESULT code.
2344 *
2345 * NOTES
2346 * The following interfaces are supported by the returned data cache object:
2347 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2348 * IViewObject and IViewObject2.
2349 */
2350 HRESULT WINAPI CreateDataCache(
2351 LPUNKNOWN pUnkOuter,
2352 REFCLSID rclsid,
2353 REFIID riid,
2354 LPVOID* ppvObj)
2355 {
2356 DataCache* newCache = NULL;
2357 HRESULT hr = S_OK;
2358
2359 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2360
2361 /*
2362 * Sanity check
2363 */
2364 if (ppvObj==0)
2365 return E_POINTER;
2366
2367 *ppvObj = 0;
2368
2369 /*
2370 * If this cache is constructed for aggregation, make sure
2371 * the caller is requesting the IUnknown interface.
2372 * This is necessary because it's the only time the non-delegating
2373 * IUnknown pointer can be returned to the outside.
2374 */
2375 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2376 return CLASS_E_NOAGGREGATION;
2377
2378 /*
2379 * Try to construct a new instance of the class.
2380 */
2381 newCache = DataCache_Construct(rclsid,
2382 pUnkOuter);
2383
2384 if (newCache == 0)
2385 return E_OUTOFMEMORY;
2386
2387 /*
2388 * Make sure it supports the interface required by the caller.
2389 */
2390 hr = IUnknown_QueryInterface(&newCache->IUnknown_iface, riid, ppvObj);
2391
2392 /*
2393 * Release the reference obtained in the constructor. If
2394 * the QueryInterface was unsuccessful, it will free the class.
2395 */
2396 IUnknown_Release(&newCache->IUnknown_iface);
2397
2398 return hr;
2399 }